Add files via upload

This commit is contained in:
NawfalMotii79
2026-03-09 00:11:57 +00:00
committed by GitHub
parent 4b7eb54ee8
commit 8974a38ff6
11 changed files with 18979 additions and 0 deletions
+188
View File
@@ -0,0 +1,188 @@
import numpy as np
import pandas as pd
import math
def generate_radar_csv(filename="pulse_compression_output.csv"):
"""
Generate realistic radar CSV data for testing the Python GUI
"""
# Radar parameters matching your testbench
num_long_chirps = 16
num_short_chirps = 16
samples_per_chirp = 512 # Reduced for manageable file size
fs_adc = 400e6 # 400 MHz ADC
timestamp_ns = 0
# Target parameters
targets = [
{'range': 3000, 'velocity': 25, 'snr': 30, 'azimuth': 10, 'elevation': 5}, # Fast moving target
{'range': 5000, 'velocity': -15, 'snr': 25, 'azimuth': 20, 'elevation': 2}, # Approaching target
{'range': 8000, 'velocity': 5, 'snr': 20, 'azimuth': 30, 'elevation': 8}, # Slow moving target
{'range': 12000, 'velocity': -8, 'snr': 18, 'azimuth': 45, 'elevation': 3}, # Distant target
]
# Noise parameters
noise_std = 5
clutter_std = 10
data = []
chirp_number = 0
# Generate Long Chirps (30µs duration equivalent)
print("Generating Long Chirps...")
for chirp in range(num_long_chirps):
for sample in range(samples_per_chirp):
# Base noise
i_val = np.random.normal(0, noise_std)
q_val = np.random.normal(0, noise_std)
# Add clutter (stationary targets)
clutter_range = 2000 # Fixed clutter at 2km
if sample < 100: # Simulate clutter in first 100 samples
i_val += np.random.normal(0, clutter_std)
q_val += np.random.normal(0, clutter_std)
# Add moving targets with Doppler shift
for target in targets:
# Calculate range bin (simplified)
range_bin = int(target['range'] / 20) # ~20m per bin
doppler_phase = 2 * math.pi * target['velocity'] * chirp / 100 # Doppler phase shift
# Target appears around its range bin with some spread
if abs(sample - range_bin) < 10:
# Signal amplitude decreases with range
amplitude = target['snr'] * (10000 / target['range'])
phase = 2 * math.pi * sample / 50 + doppler_phase
i_val += amplitude * math.cos(phase)
q_val += amplitude * math.sin(phase)
# Calculate derived values
magnitude_squared = i_val**2 + q_val**2
data.append({
'timestamp_ns': timestamp_ns,
'chirp_number': chirp_number,
'chirp_type': 'LONG',
'sample_index': sample,
'I_value': int(i_val),
'Q_value': int(q_val),
'magnitude_squared': int(magnitude_squared)
})
timestamp_ns += int(1e9 / fs_adc) # 2.5ns per sample at 400MHz
chirp_number += 1
timestamp_ns += 137000 # Add listening period (137µs)
# Guard time between long and short chirps
timestamp_ns += 175400 # 175.4µs guard time
# Generate Short Chirps (0.5µs duration equivalent)
print("Generating Short Chirps...")
for chirp in range(num_short_chirps):
for sample in range(samples_per_chirp):
# Base noise
i_val = np.random.normal(0, noise_std)
q_val = np.random.normal(0, noise_std)
# Add clutter (different characteristics for short chirps)
if sample < 50: # Less clutter for short chirps
i_val += np.random.normal(0, clutter_std/2)
q_val += np.random.normal(0, clutter_std/2)
# Add moving targets with different Doppler for short chirps
for target in targets:
# Range bin calculation (different for short chirps)
range_bin = int(target['range'] / 40) # Different range resolution
doppler_phase = 2 * math.pi * target['velocity'] * (chirp + 5) / 80 # Different Doppler
# Target appears around its range bin
if abs(sample - range_bin) < 8:
# Different amplitude characteristics for short chirps
amplitude = target['snr'] * 0.7 * (8000 / target['range']) # 70% amplitude
phase = 2 * math.pi * sample / 30 + doppler_phase
i_val += amplitude * math.cos(phase)
q_val += amplitude * math.sin(phase)
# Calculate derived values
magnitude_squared = i_val**2 + q_val**2
data.append({
'timestamp_ns': timestamp_ns,
'chirp_number': chirp_number,
'chirp_type': 'SHORT',
'sample_index': sample,
'I_value': int(i_val),
'Q_value': int(q_val),
'magnitude_squared': int(magnitude_squared)
})
timestamp_ns += int(1e9 / fs_adc) # 2.5ns per sample
chirp_number += 1
timestamp_ns += 174500 # Add listening period (174.5µs)
# Create DataFrame
df = pd.DataFrame(data)
# Save to CSV
df.to_csv(filename, index=False)
print(f"Generated CSV file: {filename}")
print(f"Total samples: {len(df)}")
print(f"Long chirps: {num_long_chirps}, Short chirps: {num_short_chirps}")
print(f"Samples per chirp: {samples_per_chirp}")
print(f"File size: {len(df) // 1000}K samples")
return df
def analyze_generated_data(df):
"""
Analyze the generated data to verify target detection
"""
print("\n=== Data Analysis ===")
# Basic statistics
long_chirps = df[df['chirp_type'] == 'LONG']
short_chirps = df[df['chirp_type'] == 'SHORT']
print(f"Long chirp samples: {len(long_chirps)}")
print(f"Short chirp samples: {len(short_chirps)}")
print(f"Unique chirp numbers: {df['chirp_number'].nunique()}")
# Calculate actual magnitude and phase for analysis
df['magnitude'] = np.sqrt(df['I_value']**2 + df['Q_value']**2)
df['phase_rad'] = np.arctan2(df['Q_value'], df['I_value'])
# Find high-magnitude samples (potential targets)
high_mag_threshold = df['magnitude'].quantile(0.95) # Top 5%
targets_detected = df[df['magnitude'] > high_mag_threshold]
print(f"\nTarget detection threshold: {high_mag_threshold:.2f}")
print(f"High magnitude samples: {len(targets_detected)}")
# Group by chirp type
long_targets = targets_detected[targets_detected['chirp_type'] == 'LONG']
short_targets = targets_detected[targets_detected['chirp_type'] == 'SHORT']
print(f"Targets in long chirps: {len(long_targets)}")
print(f"Targets in short chirps: {len(short_targets)}")
return df
if __name__ == "__main__":
# Generate the CSV file
df = generate_radar_csv("test_radar_data.csv")
# Analyze the generated data
analyze_generated_data(df)
print("\n=== CSV File Ready ===")
print("You can now test the Python GUI with this CSV file!")
print("The file contains:")
print("- 16 Long chirps + 16 Short chirps")
print("- 4 simulated targets at different ranges and velocities")
print("- Realistic noise and clutter")
print("- Proper I/Q data for Doppler processing")
+97
View File
@@ -0,0 +1,97 @@
import numpy as np
import pandas as pd
import math
def generate_small_radar_csv(filename="small_test_radar_data.csv"):
"""
Generate a smaller, faster-to-process radar CSV
"""
# Reduced parameters for faster processing
num_long_chirps = 8 # Reduced from 16
num_short_chirps = 8 # Reduced from 16
samples_per_chirp = 128 # Reduced from 512
fs_adc = 400e6
targets = [
{'range': 3000, 'velocity': 25, 'snr': 40},
{'range': 5000, 'velocity': -15, 'snr': 35},
]
data = []
chirp_number = 0
timestamp_ns = 0
# Generate Long Chirps
for chirp in range(num_long_chirps):
for sample in range(samples_per_chirp):
i_val = np.random.normal(0, 3)
q_val = np.random.normal(0, 3)
# Add targets
for target in targets:
range_bin = int(target['range'] / 40)
doppler_phase = 2 * math.pi * target['velocity'] * chirp / 50
if abs(sample - range_bin) < 5:
amplitude = target['snr'] * (8000 / target['range'])
phase = 2 * math.pi * sample / 30 + doppler_phase
i_val += amplitude * math.cos(phase)
q_val += amplitude * math.sin(phase)
magnitude_squared = i_val**2 + q_val**2
data.append({
'timestamp_ns': timestamp_ns,
'chirp_number': chirp_number,
'chirp_type': 'LONG',
'sample_index': sample,
'I_value': int(i_val),
'Q_value': int(q_val),
'magnitude_squared': int(magnitude_squared)
})
timestamp_ns += int(1e9 / fs_adc)
chirp_number += 1
timestamp_ns += 137000
# Generate Short Chirps
for chirp in range(num_short_chirps):
for sample in range(samples_per_chirp):
i_val = np.random.normal(0, 3)
q_val = np.random.normal(0, 3)
for target in targets:
range_bin = int(target['range'] / 60)
doppler_phase = 2 * math.pi * target['velocity'] * (chirp + 2) / 40
if abs(sample - range_bin) < 4:
amplitude = target['snr'] * 0.6 * (6000 / target['range'])
phase = 2 * math.pi * sample / 25 + doppler_phase
i_val += amplitude * math.cos(phase)
q_val += amplitude * math.sin(phase)
magnitude_squared = i_val**2 + q_val**2
data.append({
'timestamp_ns': timestamp_ns,
'chirp_number': chirp_number,
'chirp_type': 'SHORT',
'sample_index': sample,
'I_value': int(i_val),
'Q_value': int(q_val),
'magnitude_squared': int(magnitude_squared)
})
timestamp_ns += int(1e9 / fs_adc)
chirp_number += 1
timestamp_ns += 174500
df = pd.DataFrame(data)
df.to_csv(filename, index=False)
print(f"Generated small CSV: {filename}")
print(f"Total samples: {len(df)}")
return df
generate_small_radar_csv()
+34
View File
@@ -0,0 +1,34 @@
import numpy as np
from numpy.fft import fft, ifft
import matplotlib.pyplot as plt
n = np.arange(0, 61, 1)
Fs=125e6
Ts = 1.0 / Fs
Tb=1e-6
y = 1 + np.sin(2*np.pi*(29e6*(n**2)*(Ts**2)/(2.0*Tb)+1e6*n*Ts))
t = Ts*np.arange(0,61,1)
Y = fft(y)
M =len(Y)
m = np.arange(M)
T = M*Ts
freq = m/T
plt.figure(figsize = (12, 6))
plt.subplot(121)
plt.stem(freq, np.abs(Y), 'b', \
markerfmt=" ", basefmt="-b")
plt.xlabel('Freq (Hz)')
plt.ylabel('FFT Amplitude |Y(freq)|')
plt.xlim(0, 40*pow(10,6))
plt.ylim(0, 20)
plt.subplot(122)
plt.plot(t, ifft(Y), 'r')
plt.xlabel('Time (s)')
plt.ylabel('Amplitude')
plt.tight_layout()
plt.show()
+46
View File
@@ -0,0 +1,46 @@
import numpy as np
from numpy.fft import fft, ifft
import matplotlib.pyplot as plt
fs=125*pow(10,6) #sampling frequency
Ts=1/fs # sampling time
Tb=0.25*pow(10,-6) # burst time
Tau=1.5*pow(10,-6) # pulse repetition time
fmax=32*pow(10,6) # maximum frequency on ramp
fmin=1*pow(10,6) # minimum frequency on ramp
n=int(Tb/Ts) # number of samples per ramp
N = np.arange(0, n, 1)
theta_n= 2*np.pi*(pow(N,2)*pow(Ts,2)*(fmax-fmin)/(2*Tb)+fmin*N*Ts) # instantaneous phase
y = 1 + np.sin(theta_n) # ramp signal in time domain
M = np.arange(n, 2*n, 1)
theta_m= 2*np.pi*(pow(M,2)*pow(Ts,2)*(-fmax+fmin)/(2*Tb)+(-fmin+2*fmax)*M*Ts)-2*np.pi*((fmin-fmax)*Tb/2+(2*fmax-fmin)*Tb) # instantaneous phase
z = 1 + np.sin(theta_m) # ramp signal in time domain
x = np.concatenate((y, z))
t = Ts*np.arange(0,2*n,1)
X = fft(x)
L =len(X)
l = np.arange(L)
T = L*Ts
freq = l/T
plt.figure(figsize = (12, 6))
plt.subplot(121)
plt.stem(freq, np.abs(X), 'b', \
markerfmt=" ", basefmt="-b")
plt.xlabel('Freq (Hz)')
plt.ylabel('FFT Amplitude |Y(freq)|')
plt.xlim(0, (fmax+fmax/10))
plt.ylim(0, 20)
plt.subplot(122)
plt.plot(2*n, y)
plt.xlabel('Time (s)')
plt.ylabel('Amplitude')
plt.tight_layout()
plt.show()
+41
View File
@@ -0,0 +1,41 @@
import numpy as np
from numpy.fft import fft, ifft
import matplotlib.pyplot as plt
fs=125*pow(10,6) #sampling frequency
Ts=1/fs # sampling time
Tb=0.5*pow(10,-6) # burst time
Tau=900*pow(10,-6) # pulse repetition time
fmax=30*pow(10,6) # maximum frequency on ramp
fmin=10*pow(10,6) # minimum frequency on ramp
n=int(Tb/Ts) # number of samples per ramp
N = np.arange(0, n, 1)
theta_n= 2*np.pi*(pow(N,2)*pow(Ts,2)*(fmax-fmin)/(2*Tb)+fmin*N*Ts) # instantaneous phase
y = 1 + np.sin(theta_n) # ramp signal in time domain
t = Ts*np.arange(0,n,1)
Y = fft(y)
M =len(Y)
m = np.arange(M)
T = M*Ts
freq = m/T
plt.figure(figsize = (12, 6))
plt.subplot(121)
plt.stem(freq, np.abs(Y), 'b', \
markerfmt=" ", basefmt="-b")
plt.xlabel('Freq (Hz)')
plt.ylabel('FFT Amplitude |Y(freq)|')
plt.xlim(0, (1.3*fmax))
plt.ylim(0, 60)
plt.subplot(122)
plt.plot(t, ifft(Y), 'r')
plt.xlabel('Time (s)')
plt.ylabel('Amplitude')
plt.tight_layout()
plt.show()
@@ -0,0 +1,49 @@
import numpy as np
from numpy.fft import fft, ifft
import matplotlib.pyplot as plt
fs=125*pow(10,6) #sampling frequency
Ts=1/fs # sampling time
Tb=0.25*pow(10,-6) # burst time
Tau=1.5*pow(10,-6) # pulse repetition time
fmax=32*pow(10,6) # maximum frequency on ramp
fmin=1*pow(10,6) # minimum frequency on ramp
n=int(Tb/Ts) # number of samples per ramp
N = np.arange(0, n, 1)
theta_n= 2*np.pi*(pow(N,2)*pow(Ts,2)*(fmax-fmin)/(2*Tb)+fmin*N*Ts) # instantaneous phase
y = 1 + np.sin(theta_n) # ramp signal in time domain
M = np.arange(n, 2*n, 1)
theta_m= 2*np.pi*(pow(M,2)*pow(Ts,2)*(-fmax+fmin)/(2*Tb)+(-fmin+2*fmax)*M*Ts)-2*np.pi*((fmin-fmax)*Tb/2+(2*fmax-fmin)*Tb) # instantaneous phase
z = 1 + np.sin(theta_m) # ramp signal in time domain
x = np.concatenate((y, z))
t = Ts*np.arange(0,2*n,1)
plt.plot(t, x)
X = fft(x)
L =len(X)
l = np.arange(L)
T = L*Ts
freq = l/T
print("The Array is: ", x) #printing the array
plt.figure(figsize = (12, 6))
plt.subplot(121)
plt.stem(freq, np.abs(X), 'b', \
markerfmt=" ", basefmt="-b")
plt.xlabel('Freq (Hz)')
plt.ylabel('FFT Amplitude |Y(freq)|')
plt.xlim(0, (fmax+fmax/10))
plt.ylim(0, 20)
plt.subplot(122)
plt.plot(t, ifft(X), 'r')
plt.xlabel('Time (s)')
plt.ylabel('Amplitude')
plt.tight_layout()
plt.show()
+24
View File
@@ -0,0 +1,24 @@
import numpy as np
# Define parameters
fs = 120e6 # Sampling frequency
Ts = 1 / fs # Sampling time
Tb = 1e-6 # Burst time
Tau = 30e-6 # Pulse repetition time
fmax = 15e6 # Maximum frequency on ramp
fmin = 1e6 # Minimum frequency on ramp
# Compute number of samples per ramp
n = int(Tb / Ts)
N = np.arange(0, n, 1)
# Compute instantaneous phase
theta_n = 2 * np.pi * ((N**2 * Ts**2 * (fmax - fmin) / (2 * Tb)) + fmin * N * Ts)
# Generate waveform and scale it to 8-bit unsigned values (0 to 255)
y = 1 + np.sin(theta_n) # Normalize from 0 to 2
y_scaled = np.round(y * 127.5).astype(int) # Scale to 8-bit range (0-255)
# Print values in Verilog-friendly format
for i in range(n):
print(f"waveform_LUT[{i}] = 8'h{y_scaled[i]:02X};")
+7
View File
@@ -0,0 +1,7 @@
import numpy as np
import matplotlib.pyplot as plt
n = np.arange(0, 61, 1)
Ts=8*pow(10,-9)
y = 1 + np.sin(2*np.pi*(-16*pow(10,12)*pow(n,2)*pow(Ts,2)+16*pow(10,6)*n*Ts))
plt.plot(n, y)
plt.show()
+59
View File
@@ -0,0 +1,59 @@
import numpy as np
def calculate_patch_antenna_parameters(frequency, epsilon_r, h_sub, h_cu, array):
# Constants
c = 3e8 # Speed of light in m/s
# Convert height from mm to meters
h_sub_m = h_sub * 1e-3
h_cu_m = h_cu * 1e-3
# Calculate Lambda
lamb = c /(frequency * 1e9)
# Calculate the effective dielectric constant
epsilon_eff = (epsilon_r + 1) / 2 + (epsilon_r - 1) / 2 * (1 + 12 * h_sub_m / (array[1] * h_cu_m)) ** (-0.5)
# Calculate the width of the patch
W = c / (2 * frequency * 1e9) * np.sqrt(2 / (epsilon_r + 1))
# Calculate the effective length
delta_L = 0.412 * h_sub_m * (epsilon_eff + 0.3) * (W / h_sub_m + 0.264) / ((epsilon_eff - 0.258) * (W / h_sub_m + 0.8))
# Calculate the length of the patch
L = c / (2 * frequency * 1e9 * np.sqrt(epsilon_eff)) - 2 * delta_L
# Calculate the separation distance in the horizontal axis (dx)
dx = lamb/2 # Typically 1.5 times the width of the patch
# Calculate the separation distance in the vertical axis (dy)
dy = lamb/2 # Typically 1.5 times the length of the patch
# Calculate the feeding line width (W_feed)
Z0 = 50 # Characteristic impedance of the feeding line (typically 50 ohms)
A = Z0 / 60 * np.sqrt((epsilon_r + 1) / 2) + (epsilon_r - 1) / (epsilon_r + 1) * (0.23 + 0.11 / epsilon_r)
W_feed = 8 * h_sub_m / np.exp(A) - 2 * h_cu_m
# Convert results back to mm
W_mm = W * 1e3
L_mm = L * 1e3
dx_mm = dx * 1e3
dy_mm = dy * 1e3
W_feed_mm = W_feed * 1e3
return W_mm, L_mm, dx_mm, dy_mm, W_feed_mm
# Example usage
frequency = 10.5 # Frequency in GHz
epsilon_r = 3.48 # Relative permittivity of the substrate
h_sub = 0.102 # Height of substrate in mm
h_cu = 0.07 # Height of copper in mm
array = [2, 2] # 2x2 array
W_mm, L_mm, dx_mm, dy_mm, W_feed_mm = calculate_patch_antenna_parameters(frequency, epsilon_r, h_sub, h_cu, array)
print(f"Width of the patch: {W_mm:.4f} mm")
print(f"Length of the patch: {L_mm:.4f} mm")
print(f"Separation distance in horizontal axis: {dx_mm:.4f} mm")
print(f"Separation distance in vertical axis: {dy_mm:.4f} mm")
print(f"Feeding line width: {W_feed_mm:.2f} mm")
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff