Add files via upload
This commit is contained in:
@@ -0,0 +1,309 @@
|
||||
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()
|
||||
Reference in New Issue
Block a user