M
2025-10-24 17:43:28 -04:00
|
|
|
import pathlib
|
|
|
|
|
|
|
|
|
|
MAX_PLOT_POINTS = 100_000
|
|
|
|
|
COLORS = {
|
|
|
|
|
"primary": "#6366f1",
|
|
|
|
|
"secondary": "#8b5cf6",
|
|
|
|
|
"accent": "#06b6d4",
|
|
|
|
|
"dark": "#1e293b",
|
|
|
|
|
"light": "#f8fafc",
|
|
|
|
|
"text": "#334155",
|
|
|
|
|
"muted": "#64748b",
|
|
|
|
|
"success": "#10b981",
|
|
|
|
|
"warning": "#f59e0b",
|
|
|
|
|
"error": "#ef4444",
|
|
|
|
|
"purple": "#8b5cf6",
|
|
|
|
|
"magenta": "#d946ef",
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
def decimate(x, max_points=MAX_PLOT_POINTS):
|
|
|
|
|
if len(x) <= max_points:
|
|
|
|
|
return x
|
|
|
|
|
step = len(x) // max_points
|
|
|
|
|
return x[::step]
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
def extract_metadata_fields(metadata):
|
|
|
|
|
sample_rate = next((v for k, v in metadata.items() if "sample_rate" in k), 1)
|
|
|
|
|
center_freq = next((v for k, v in metadata.items() if "center_freq" in k), 0)
|
|
|
|
|
sdr = next((v for k, v in metadata.items() if "sdr" in k), "Unknown")
|
|
|
|
|
return sample_rate, center_freq, sdr
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
def set_path(output_path):
|
F
2026-04-28 11:27:47 -04:00
|
|
|
path = pathlib.Path(output_path)
|
|
|
|
|
|
|
|
|
|
# If only filename provided (no directory), use default 'images' folder
|
|
|
|
|
if len(path.parts) == 1:
|
|
|
|
|
folder = pathlib.Path("images")
|
|
|
|
|
file = path.name
|
M
2025-10-24 17:43:28 -04:00
|
|
|
else:
|
F
2026-04-28 11:27:47 -04:00
|
|
|
folder = path.parent
|
|
|
|
|
file = path.name
|
M
2025-10-24 17:43:28 -04:00
|
|
|
|
|
|
|
|
split_file = file.split(".")
|
|
|
|
|
if len(split_file) == 2:
|
|
|
|
|
extension = split_file[1]
|
|
|
|
|
else:
|
|
|
|
|
extension = "no extension"
|
|
|
|
|
if extension != "png" and extension != "svg":
|
|
|
|
|
print(f"{extension} not supported, saving as .png.")
|
|
|
|
|
extension = "png"
|
|
|
|
|
file = file + ".png"
|
|
|
|
|
|
F
2026-04-28 11:27:47 -04:00
|
|
|
folder.mkdir(parents=True, exist_ok=True)
|
|
|
|
|
return str(folder / file), extension
|