Files
Jason 2106e24952 fix: enforce strict ruff lint (17 rule sets) across entire repo
- Expand ruff config from E/F to 17 rule sets (B, RUF, SIM, PIE, T20,
  ARG, ERA, A, BLE, RET, ISC, TCH, UP, C4, PERF)
- Fix 907 lint errors across all Python files (GUI, FPGA cosim,
  schematics scripts, simulations, utilities, tools)
- Replace all blind except-Exception with specific exception types
- Remove commented-out dead code (ERA001) from cosim/simulation files
- Modernize typing: deprecated typing.List/Dict/Tuple to builtins
- Fix unused args/loop vars, ambiguous unicode, perf anti-patterns
- Delete legacy GUI files V1-V4
- Add V7 test suite, requirements files
- All CI jobs pass: ruff (0 errors), py_compile, pytest (92/92),
  MCU tests (20/20), FPGA regression (25/25)
2026-04-12 14:21:03 +05:45

179 lines
6.5 KiB
Python

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)
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)
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)
return df
def analyze_generated_data(df):
"""
Analyze the generated data to verify target detection
"""
# Basic statistics
df[df['chirp_type'] == 'LONG']
df[df['chirp_type'] == 'SHORT']
# 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]
# Group by chirp type
targets_detected[targets_detected['chirp_type'] == 'LONG']
targets_detected[targets_detected['chirp_type'] == 'SHORT']
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)