add engine
This commit is contained in:
parent
08d46eea8c
commit
4bec0e6d34
109
scenario_simulator/core/simulation_engine.py
Normal file
109
scenario_simulator/core/simulation_engine.py
Normal 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
|
||||
Loading…
Reference in New Issue
Block a user