148 lines
4.6 KiB
Python
148 lines
4.6 KiB
Python
"""
|
|
Utility functions for radar-related mathematical calculations.
|
|
"""
|
|
import numpy as np
|
|
from scipy.constants import c
|
|
|
|
# --- Conversion Constants ---
|
|
METERS_PER_NAUTICAL_MILE = 1852.0
|
|
METERS_PER_SECOND_TO_KNOTS = 1.94384
|
|
|
|
def calculate_max_unambiguous_range(prf: float) -> float:
|
|
"""
|
|
Calculates the maximum unambiguous range for a given PRF.
|
|
|
|
Args:
|
|
prf: Pulse Repetition Frequency in Hertz (Hz).
|
|
|
|
Returns:
|
|
The maximum unambiguous range in meters (m).
|
|
"""
|
|
if prf <= 0:
|
|
return float('inf')
|
|
return c / (2 * prf)
|
|
|
|
def calculate_max_unambiguous_velocity(carrier_frequency: float, prf: float) -> float:
|
|
"""
|
|
Calculates the maximum unambiguous velocity for a given radar configuration.
|
|
|
|
Args:
|
|
carrier_frequency: Carrier frequency in Hertz (Hz).
|
|
prf: Pulse Repetition Frequency in Hertz (Hz).
|
|
|
|
Returns:
|
|
The maximum unambiguous (Nyquist) velocity in m/s.
|
|
"""
|
|
if carrier_frequency <= 0:
|
|
return float('inf')
|
|
wavelength = c / carrier_frequency
|
|
return (prf * wavelength) / 4
|
|
|
|
def calculate_dwell_time(beamwidth_deg: float, scan_speed_deg_s: float) -> float:
|
|
"""
|
|
Calculates the time a target spends within the antenna's beam.
|
|
|
|
Args:
|
|
beamwidth_deg: The 3dB beamwidth of the antenna in degrees.
|
|
scan_speed_deg_s: The angular scan speed of the antenna in degrees/sec.
|
|
|
|
Returns:
|
|
The dwell time in seconds (s).
|
|
"""
|
|
if scan_speed_deg_s <= 0:
|
|
return float('inf') # Staring mode
|
|
return beamwidth_deg / scan_speed_deg_s
|
|
|
|
def calculate_pulses_on_target(dwell_time_s: float, prf: float) -> int:
|
|
"""
|
|
Calculates the number of pulses that hit a target during the dwell time.
|
|
|
|
Args:
|
|
dwell_time_s: The dwell time in seconds.
|
|
prf: The Pulse Repetition Frequency in Hz.
|
|
|
|
Returns:
|
|
The number of pulses hitting the target.
|
|
"""
|
|
if np.isinf(dwell_time_s):
|
|
return -1 # Represents continuous illumination (staring)
|
|
return int(dwell_time_s * prf)
|
|
|
|
def calculate_gaussian_gain(angle_off_boresight_deg: float, beamwidth_deg: float) -> float:
|
|
"""
|
|
Calculates antenna gain based on a Gaussian beam shape model.
|
|
This models the two-way (transmit and receive) gain pattern.
|
|
|
|
Args:
|
|
angle_off_boresight_deg: Angle between target and antenna centerline (degrees).
|
|
beamwidth_deg: The 3dB one-way beamwidth of the antenna in degrees.
|
|
|
|
Returns:
|
|
A dimensionless gain factor (from 0.0 to 1.0).
|
|
"""
|
|
# The standard deviation (sigma) of the Gaussian beam is related to the 3dB beamwidth
|
|
sigma = beamwidth_deg / (2 * np.sqrt(2 * np.log(2)))
|
|
|
|
# We use angle^2 / (2 * sigma^2) for the one-way power gain pattern.
|
|
# The two-way voltage gain is the square of the one-way voltage gain,
|
|
# which is equivalent to the one-way power gain.
|
|
gain = np.exp(-(angle_off_boresight_deg**2) / (sigma**2))
|
|
return gain
|
|
|
|
# --- Unit Conversion Functions ---
|
|
|
|
def meters_to_nm(meters: float) -> float:
|
|
"""Converts meters to nautical miles."""
|
|
return meters / METERS_PER_NAUTICAL_MILE
|
|
|
|
def nm_to_meters(nm: float) -> float:
|
|
"""Converts nautical miles to meters."""
|
|
return nm * METERS_PER_NAUTICAL_MILE
|
|
|
|
def mps_to_knots(mps: float) -> float:
|
|
"""Converts meters per second to knots."""
|
|
return mps * METERS_PER_SECOND_TO_KNOTS
|
|
|
|
def knots_to_mps(knots: float) -> float:
|
|
"""Converts knots to meters per second."""
|
|
return knots / METERS_PER_SECOND_TO_KNOTS
|
|
|
|
def cartesian_to_spherical(x: float, y: float, z: float) -> tuple[float, float, float]:
|
|
"""
|
|
Converts Cartesian coordinates (x, y, z) to Spherical coordinates.
|
|
|
|
Args:
|
|
x, y, z: Coordinates in meters.
|
|
|
|
Returns:
|
|
A tuple containing (range_m, azimuth_deg, elevation_deg).
|
|
"""
|
|
range_m = np.sqrt(x**2 + y**2 + z**2)
|
|
if range_m == 0:
|
|
return 0.0, 0.0, 0.0
|
|
|
|
azimuth_deg = np.rad2deg(np.arctan2(y, x))
|
|
elevation_deg = np.rad2deg(np.arcsin(z / range_m))
|
|
|
|
return range_m, azimuth_deg, elevation_deg
|
|
|
|
def spherical_to_cartesian(range_m: float, azimuth_deg: float, elevation_deg: float) -> list[float]:
|
|
"""
|
|
Converts Spherical coordinates to Cartesian coordinates (x, y, z).
|
|
|
|
Args:
|
|
range_m: Range in meters.
|
|
azimuth_deg: Azimuth in degrees.
|
|
elevation_deg: Elevation in degrees.
|
|
|
|
Returns:
|
|
A list containing [x, y, z] coordinates in meters.
|
|
"""
|
|
az_rad = np.deg2rad(azimuth_deg)
|
|
el_rad = np.deg2rad(elevation_deg)
|
|
|
|
x = range_m * np.cos(el_rad) * np.cos(az_rad)
|
|
y = range_m * np.cos(el_rad) * np.sin(az_rad)
|
|
z = range_m * np.sin(el_rad)
|
|
|
|
return [x, y, z] |