add engine

This commit is contained in:
VALLONGOL 2025-09-29 14:29:49 +02:00
parent 08d46eea8c
commit 4bec0e6d34

View File

@ -0,0 +1,109 @@
"""
Core module for radar signal simulation.
This module provides the classes and functions necessary to generate
synthetic I/Q data for specified radar configurations and target scenarios.
"""
from dataclasses import dataclass
import numpy as np
from scipy.constants import c
@dataclass
class RadarConfig:
"""
Stores the configuration parameters for the simulated radar.
Attributes:
carrier_frequency (float): Carrier frequency in Hertz (Hz).
prf (float): Pulse Repetition Frequency in Hertz (Hz).
pulse_width (float): Duration of a single radar pulse in seconds (s).
sample_rate (float): Sampling rate of the ADC in samples per second (Hz).
"""
carrier_frequency: float
prf: float
pulse_width: float
sample_rate: float
@dataclass
class Target:
"""
Represents a single point target in the simulation.
Attributes:
initial_position (np.ndarray): 3D initial position [x, y, z] in meters (m).
velocity (np.ndarray): 3D constant velocity [vx, vy, vz] in m/s.
rcs (float): Radar Cross Section in square meters (m^2).
"""
initial_position: np.ndarray
velocity: np.ndarray
rcs: float
def generate_iq_data(config: RadarConfig, target: Target, num_pulses: int) -> np.ndarray:
"""
Generates the I/Q data matrix for a single target scenario.
This function simulates the received echo from a single point target with
constant velocity over a specified number of pulses (Coherent Processing
Interval - CPI).
Args:
config: The radar configuration parameters.
target: The target's properties.
num_pulses: The total number of pulses to simulate.
Returns:
A 2D numpy array of complex numbers representing the I/Q data.
Shape: (num_pulses, num_samples_per_pulse).
"""
# --- Derived parameters calculation
wavelength = c / config.carrier_frequency
pri = 1.0 / config.prf # Pulse Repetition Interval
# Calculate the number of samples within one pulse's duration
num_samples_per_pulse = int(config.pulse_width * config.sample_rate)
# --- Initialize output data structure
# This matrix will store the complex I/Q data for each pulse
iq_matrix = np.zeros((num_pulses, num_samples_per_pulse), dtype=np.complex128)
# --- Main simulation loop (over slow-time)
for pulse_index in range(num_pulses):
# Current time relative to the start of the CPI
current_slow_time = pulse_index * pri
# Update target position based on its constant velocity
current_position = target.initial_position + target.velocity * current_slow_time
# Calculate range from radar (at origin) to target
range_to_target = np.linalg.norm(current_position)
# Calculate the two-way time delay for the echo
time_delay = 2 * range_to_target / c
# Simplified signal amplitude based on radar range equation (power ~ 1/R^4)
# We use sqrt(rcs) because we are modeling voltage/amplitude, not power.
amplitude = np.sqrt(target.rcs) / (range_to_target**2)
# The core of the simulation: calculate the complex phase shift
# This phase is determined by the round-trip path length in wavelengths
phase_shift = np.exp(-1j * 4 * np.pi * range_to_target / wavelength)
signal_complex_amplitude = amplitude * phase_shift
# Model a simple rectangular pulse
pulse_shape = np.ones(num_samples_per_pulse)
received_pulse = signal_complex_amplitude * pulse_shape
# --- Place the received pulse into the I/Q matrix at the correct time delay
start_sample = int(round(time_delay * config.sample_rate))
if 0 <= start_sample < iq_matrix.shape[1]:
# This handles cases where the pulse might partially go out of the sampling window
samples_to_write = min(num_samples_per_pulse, iq_matrix.shape[1] - start_sample)
iq_matrix[
pulse_index, start_sample : start_sample + samples_to_write
] = received_pulse[:samples_to_write]
return iq_matrix