Files
PLFM_RADAR/8_Utils/Python/RADAR_eq.py
T
2026-03-10 02:17:16 +00:00

310 lines
13 KiB
Python
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
import tkinter as tk
from tkinter import ttk, messagebox
import math
import numpy as np
class RadarCalculatorGUI:
def __init__(self, root):
self.root = root
self.root.title("RADAR Parameters Calculator")
self.root.geometry("850x750")
# Configure colors
self.bg_color = '#f0f0f0'
self.root.configure(bg=self.bg_color)
# Create main container
self.main_frame = ttk.Frame(root, padding="10")
self.main_frame.pack(fill=tk.BOTH, expand=True)
# Title
title_label = tk.Label(self.main_frame, text="RADAR PARAMETERS CALCULATOR",
font=('Arial', 16, 'bold'), bg=self.bg_color)
title_label.pack(pady=10)
# Create notebook for tabs
self.notebook = ttk.Notebook(self.main_frame)
self.notebook.pack(fill=tk.BOTH, expand=True, pady=10)
# Input tab
self.input_frame = ttk.Frame(self.notebook)
self.notebook.add(self.input_frame, text="Input Parameters")
# Results tab
self.results_frame = ttk.Frame(self.notebook)
self.notebook.add(self.results_frame, text="Results")
# Create input fields
self.create_input_fields()
# Create results display
self.create_results_display()
# Create button frame (outside notebook)
self.button_frame = ttk.Frame(self.main_frame)
self.button_frame.pack(fill=tk.X, pady=10)
# Create calculate button
self.create_calculate_button()
# Constants
self.c = 3e8 # Speed of light in m/s
def create_input_fields(self):
"""Create all input fields with labels and units"""
# Create a canvas with scrollbar for input fields
canvas = tk.Canvas(self.input_frame, borderwidth=0)
scrollbar = ttk.Scrollbar(self.input_frame, orient="vertical", command=canvas.yview)
scrollable_frame = ttk.Frame(canvas)
scrollable_frame.bind(
"<Configure>",
lambda e: canvas.configure(scrollregion=canvas.bbox("all"))
)
canvas.create_window((0, 0), window=scrollable_frame, anchor="nw")
canvas.configure(yscrollcommand=scrollbar.set)
# Input fields with default values
inputs = [
("Frequency (GHz):", "10.0"),
("Pulse duration (μs):", "1.0"),
("PRF (Hz):", "1000"),
("Emitted power (dBm):", "30"),
("Antenna gain (dBi):", "20"),
("Receiver sensitivity (dBm):", "-90"),
("Radar cross section (m²):", "1.0"),
("System losses (dB):", "3"),
("Noise figure (dB):", "3"),
("Boltzmann constant (k) - optional:", "1.38e-23"),
("Temperature (K):", "290")
]
self.entries = {}
for i, (label, default) in enumerate(inputs):
# Create a frame for each input row
row_frame = ttk.Frame(scrollable_frame)
row_frame.pack(fill=tk.X, pady=5)
# Label
ttk.Label(row_frame, text=label, width=30, anchor='w').pack(side=tk.LEFT, padx=5)
# Entry
entry = ttk.Entry(row_frame, width=20, font=('Arial', 10))
entry.pack(side=tk.LEFT, padx=5)
entry.insert(0, default)
self.entries[label] = entry
# Additional notes
notes_label = tk.Label(scrollable_frame,
text="Note: All values must be numeric. Use point (.) for decimals.",
font=('Arial', 9, 'italic'), fg='gray')
notes_label.pack(pady=20)
# Pack canvas and scrollbar
canvas.pack(side="left", fill="both", expand=True)
scrollbar.pack(side="right", fill="y")
def create_calculate_button(self):
"""Create the calculate button"""
calculate_btn = tk.Button(self.button_frame,
text="CALCULATE RADAR PARAMETERS",
command=self.calculate_parameters,
bg='#4CAF50', fg='white',
font=('Arial', 12, 'bold'),
padx=30, pady=10,
cursor='hand2')
calculate_btn.pack()
# Bind hover effect
calculate_btn.bind("<Enter>", lambda e: calculate_btn.config(bg='#45a049'))
calculate_btn.bind("<Leave>", lambda e: calculate_btn.config(bg='#4CAF50'))
def create_results_display(self):
"""Create the results display area"""
# Results title
title_label = tk.Label(self.results_frame, text="RADAR PERFORMANCE PARAMETERS",
font=('Arial', 14, 'bold'))
title_label.pack(pady=(20, 20))
# Create frame for results with scrollbar
canvas = tk.Canvas(self.results_frame, borderwidth=0)
scrollbar = ttk.Scrollbar(self.results_frame, orient="vertical", command=canvas.yview)
scrollable_frame = ttk.Frame(canvas)
scrollable_frame.bind(
"<Configure>",
lambda e: canvas.configure(scrollregion=canvas.bbox("all"))
)
canvas.create_window((0, 0), window=scrollable_frame, anchor="nw")
canvas.configure(yscrollcommand=scrollbar.set)
# Results fields
results = [
("Maximum detectable range:", "range_result"),
("Range resolution:", "range_res_result"),
("Maximum unambiguous range:", "max_range_result"),
("Maximum detectable speed:", "speed_result"),
("Speed resolution:", "speed_res_result"),
("Doppler frequency resolution:", "doppler_res_result"),
("Pulse width (s):", "pulse_width_result"),
("Bandwidth (Hz):", "bandwidth_result"),
("SNR (dB):", "snr_result")
]
self.results_labels = {}
for i, (label, key) in enumerate(results):
# Create a frame for each result row
row_frame = ttk.Frame(scrollable_frame)
row_frame.pack(fill=tk.X, pady=10, padx=20)
# Label
ttk.Label(row_frame, text=label, font=('Arial', 11, 'bold'),
width=30, anchor='w').pack(side=tk.LEFT)
# Value
value_label = ttk.Label(row_frame, text="---", font=('Arial', 11),
foreground='blue', anchor='w')
value_label.pack(side=tk.LEFT, padx=(20, 0))
self.results_labels[key] = value_label
# Add separator
ttk.Separator(scrollable_frame, orient='horizontal').pack(fill=tk.X, pady=20)
# Add explanatory note
note_text = """
NOTES:
• Maximum detectable range is calculated using the radar equation
• Range resolution = c × τ / 2, where τ is pulse duration
• Maximum unambiguous range = c / (2 × PRF)
• Maximum detectable speed = λ × PRF / 4
• Speed resolution = λ × PRF / (2 × N) where N is number of pulses (assumed 1)
• λ (wavelength) = c / f
"""
note_label = tk.Label(scrollable_frame, text=note_text, font=('Arial', 9),
justify=tk.LEFT, bg='#f8f9fa', relief='solid',
padx=10, pady=10)
note_label.pack(fill=tk.X, padx=20, pady=10)
# Pack canvas and scrollbar
canvas.pack(side="left", fill="both", expand=True)
scrollbar.pack(side="right", fill="y")
def get_float_value(self, entry, default=None):
"""Safely get float value from entry"""
try:
return float(entry.get())
except ValueError:
return default
def calculate_parameters(self):
"""Perform all RADAR calculations"""
try:
# Get all input values
f_ghz = self.get_float_value(self.entries["Frequency (GHz):"])
pulse_duration_us = self.get_float_value(self.entries["Pulse duration (μs):"])
prf = self.get_float_value(self.entries["PRF (Hz):"])
p_dbm = self.get_float_value(self.entries["Emitted power (dBm):"])
g_dbi = self.get_float_value(self.entries["Antenna gain (dBi):"])
sens_dbm = self.get_float_value(self.entries["Receiver sensitivity (dBm):"])
rcs = self.get_float_value(self.entries["Radar cross section (m²):"])
losses_db = self.get_float_value(self.entries["System losses (dB):"])
nf_db = self.get_float_value(self.entries["Noise figure (dB):"])
k = self.get_float_value(self.entries["Boltzmann constant (k) - optional:"])
temp = self.get_float_value(self.entries["Temperature (K):"])
# Validate inputs
if None in [f_ghz, pulse_duration_us, prf, p_dbm, g_dbi, sens_dbm, rcs, losses_db, nf_db, temp]:
messagebox.showerror("Error", "Please enter valid numeric values for all fields")
return
# Convert units
f_hz = f_ghz * 1e9
pulse_duration_s = pulse_duration_us * 1e-6
wavelength = self.c / f_hz
# Convert dB values to linear
p_linear = 10 ** ((p_dbm - 30) / 10) # Convert dBm to Watts
g_linear = 10 ** (g_dbi / 10)
sens_linear = 10 ** ((sens_dbm - 30) / 10)
losses_linear = 10 ** (losses_db / 10)
nf_linear = 10 ** (nf_db / 10)
# Calculate receiver noise power
if k is None:
k = 1.38e-23 # Default Boltzmann constant
# Calculate SNR
snr_linear = (p_linear * g_linear**2 * wavelength**2 * rcs) / (
(4 * np.pi)**3 * sens_linear * losses_linear)
snr_db = 10 * math.log10(snr_linear) if snr_linear > 0 else float('-inf')
# Maximum detectable range using radar equation
if snr_linear > 0:
range_max = ((p_linear * g_linear**2 * wavelength**2 * rcs) /
((4 * np.pi)**3 * sens_linear * losses_linear)) ** (1/4)
else:
range_max = 0
# Range resolution
range_res = (self.c * pulse_duration_s) / 2
# Maximum unambiguous range
max_unambiguous_range = self.c / (2 * prf)
# Maximum detectable speed (using half the Nyquist sampling theorem)
max_speed = (wavelength * prf) / 4
# Speed resolution (for a single pulse, approximate)
speed_res = max_speed # For single pulse, resolution equals max speed
# Doppler frequency resolution
doppler_res = 1 / pulse_duration_s
# Bandwidth
bandwidth = 1 / pulse_duration_s
# Update results display with formatted values
self.results_labels["range_result"].config(
text=f"{range_max:.2f} m ({range_max/1000:.2f} km)")
self.results_labels["range_res_result"].config(
text=f"{range_res:.2f} m")
self.results_labels["max_range_result"].config(
text=f"{max_unambiguous_range:.2f} m ({max_unambiguous_range/1000:.2f} km)")
self.results_labels["speed_result"].config(
text=f"{max_speed:.2f} m/s ({max_speed*3.6:.2f} km/h)")
self.results_labels["speed_res_result"].config(
text=f"{speed_res:.2f} m/s ({speed_res*3.6:.2f} km/h)")
self.results_labels["doppler_res_result"].config(
text=f"{doppler_res:.2f} Hz")
self.results_labels["pulse_width_result"].config(
text=f"{pulse_duration_s:.2e} s")
self.results_labels["bandwidth_result"].config(
text=f"{bandwidth:.2e} Hz")
self.results_labels["snr_result"].config(
text=f"{snr_db:.2f} dB")
# Switch to results tab
self.notebook.select(1)
# Show success message
messagebox.showinfo("Success", "Calculation completed successfully!")
except Exception as e:
messagebox.showerror("Calculation Error", f"An error occurred during calculation:\n{str(e)}")
def main():
root = tk.Tk()
app = RadarCalculatorGUI(root)
root.mainloop()
if __name__ == "__main__":
main()