Files
PLFM_RADAR/8_Utils/Python/CSV_radar.py
T
2026-04-02 01:04:55 +01:00

189 lines
7.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)
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")