aggiunta la visualizzazione ppi in debug
This commit is contained in:
parent
c69de401e1
commit
db645b13ce
@ -2,7 +2,7 @@
|
|||||||
"general": {
|
"general": {
|
||||||
"scan_limit": 60,
|
"scan_limit": 60,
|
||||||
"max_range": 100,
|
"max_range": 100,
|
||||||
"geometry": "1200x1024+85+163",
|
"geometry": "1200x1024+501+367",
|
||||||
"last_selected_scenario": "scenario2",
|
"last_selected_scenario": "scenario2",
|
||||||
"connection": {
|
"connection": {
|
||||||
"target": {
|
"target": {
|
||||||
@ -76,8 +76,10 @@
|
|||||||
"maneuver_type": "Fly to Point",
|
"maneuver_type": "Fly to Point",
|
||||||
"duration_s": 10.0,
|
"duration_s": 10.0,
|
||||||
"target_range_nm": 10.0,
|
"target_range_nm": 10.0,
|
||||||
"target_azimuth_deg": 1.0,
|
"target_azimuth_deg": -3.0,
|
||||||
"target_altitude_ft": 10000.0,
|
"target_altitude_ft": 10000.0,
|
||||||
|
"target_velocity_fps": 0.0,
|
||||||
|
"target_heading_deg": 0.0,
|
||||||
"longitudinal_acceleration_g": 0.0,
|
"longitudinal_acceleration_g": 0.0,
|
||||||
"lateral_acceleration_g": 0.0,
|
"lateral_acceleration_g": 0.0,
|
||||||
"vertical_acceleration_g": 0.0,
|
"vertical_acceleration_g": 0.0,
|
||||||
|
|||||||
@ -75,6 +75,14 @@ def build_tgtset_selective(target_id: int, updates: Dict[str, Any]) -> str:
|
|||||||
]
|
]
|
||||||
params = [str(updates.get(key, "*")) for key in param_order]
|
params = [str(updates.get(key, "*")) for key in param_order]
|
||||||
command_parts = ["tgtset", str(target_id)] + params
|
command_parts = ["tgtset", str(target_id)] + params
|
||||||
|
|
||||||
|
qualifiers = []
|
||||||
|
if "active" in updates:
|
||||||
|
qualifiers.append("/s" if updates["active"] else "/-s")
|
||||||
|
if "traceable" in updates:
|
||||||
|
qualifiers.append("/t" if updates["traceable"] else "/-t")
|
||||||
|
command_parts.extend(qualifiers)
|
||||||
|
|
||||||
full_command = " ".join(command_parts)
|
full_command = " ".join(command_parts)
|
||||||
logger.debug(f"Built selective command: {full_command!r}")
|
logger.debug(f"Built selective command: {full_command!r}")
|
||||||
return full_command
|
return full_command
|
||||||
|
|||||||
@ -24,9 +24,10 @@ class PPIDisplay(ttk.Frame):
|
|||||||
super().__init__(master)
|
super().__init__(master)
|
||||||
self.max_range = max_range_nm
|
self.max_range = max_range_nm
|
||||||
self.scan_limit_deg = scan_limit_deg
|
self.scan_limit_deg = scan_limit_deg
|
||||||
|
# Artists for dynamic target display (dots, lines)
|
||||||
# Artists for dynamic target display
|
|
||||||
self.target_artists = []
|
self.target_artists = []
|
||||||
|
# Artists for numeric labels next to targets
|
||||||
|
self.target_label_artists = []
|
||||||
self.active_targets: List[Target] = []
|
self.active_targets: List[Target] = []
|
||||||
|
|
||||||
# Artists for trajectory preview display
|
# Artists for trajectory preview display
|
||||||
@ -147,22 +148,51 @@ class PPIDisplay(ttk.Frame):
|
|||||||
|
|
||||||
def update_targets(self, targets: List[Target]):
|
def update_targets(self, targets: List[Target]):
|
||||||
"""Updates the display with the current state of active targets."""
|
"""Updates the display with the current state of active targets."""
|
||||||
|
# Keep only active targets
|
||||||
self.active_targets = [t for t in targets if t.active]
|
self.active_targets = [t for t in targets if t.active]
|
||||||
|
|
||||||
# Clear previous target artists
|
# Clear previous target artists
|
||||||
for artist in self.target_artists:
|
for artist in self.target_artists:
|
||||||
artist.remove()
|
artist.remove()
|
||||||
self.target_artists.clear()
|
self.target_artists.clear()
|
||||||
|
# Clear previous numeric label artists (avoid label accumulation)
|
||||||
|
for l in getattr(self, "target_label_artists", []):
|
||||||
|
try:
|
||||||
|
l.remove()
|
||||||
|
except Exception:
|
||||||
|
pass
|
||||||
|
self.target_label_artists.clear()
|
||||||
|
|
||||||
vector_len_nm = self.range_var.get() / 20.0 # Length of heading vector
|
vector_len_nm = max(1.0, self.range_var.get() / 20.0) # Length of heading vector
|
||||||
|
|
||||||
|
# Ensure plot radial limit matches selected range
|
||||||
|
try:
|
||||||
|
current_range = self.range_var.get()
|
||||||
|
self.ax.set_ylim(0, current_range)
|
||||||
|
self._update_scan_lines()
|
||||||
|
except Exception:
|
||||||
|
pass
|
||||||
|
|
||||||
|
# Diagnostic logging (kept lightweight)
|
||||||
|
try:
|
||||||
|
import logging
|
||||||
|
logger = logging.getLogger(__name__)
|
||||||
|
logger.debug("PPIDisplay.update_targets: received %d active target(s)", len(self.active_targets))
|
||||||
|
for t in self.active_targets:
|
||||||
|
try:
|
||||||
|
logger.debug("PPIDisplay target id=%s r_nm=%.2f az=%.2f hdg=%.2f", getattr(t, 'target_id', None), getattr(t, 'current_range_nm', 0.0), getattr(t, 'current_azimuth_deg', 0.0), getattr(t, 'current_heading_deg', 0.0))
|
||||||
|
except Exception:
|
||||||
|
pass
|
||||||
|
except Exception:
|
||||||
|
pass
|
||||||
|
|
||||||
for target in self.active_targets:
|
for target in self.active_targets:
|
||||||
# Target's polar coordinates
|
# Target's polar coordinates
|
||||||
r_nm = target.current_range_nm
|
r_nm = target.current_range_nm
|
||||||
theta_rad = np.deg2rad(target.current_azimuth_deg)
|
theta_rad = np.deg2rad(target.current_azimuth_deg)
|
||||||
|
|
||||||
# Draw the target dot
|
# Draw the target dot (slightly larger for visibility)
|
||||||
(dot,) = self.ax.plot(theta_rad, r_nm, "o", markersize=6, color="red")
|
(dot,) = self.ax.plot(theta_rad, r_nm, "o", markersize=8, color="red")
|
||||||
self.target_artists.append(dot)
|
self.target_artists.append(dot)
|
||||||
|
|
||||||
# Draw the heading vector
|
# Draw the heading vector
|
||||||
@ -182,7 +212,25 @@ class PPIDisplay(ttk.Frame):
|
|||||||
)
|
)
|
||||||
self.target_artists.append(line)
|
self.target_artists.append(line)
|
||||||
|
|
||||||
self.canvas.draw_idle()
|
# Add numeric label near the dot showing target id (if available)
|
||||||
|
try:
|
||||||
|
tid = getattr(target, "target_id", None)
|
||||||
|
if tid is not None:
|
||||||
|
# place label slightly outward from the dot
|
||||||
|
label_r = r_nm + (vector_len_nm * 0.7)
|
||||||
|
txt = self.ax.text(theta_rad, label_r, f"{tid}", color="white", fontsize=8, ha="center", va="center")
|
||||||
|
self.target_label_artists.append(txt)
|
||||||
|
except Exception:
|
||||||
|
pass
|
||||||
|
|
||||||
|
# Force immediate redraw to make sure UI shows the changes
|
||||||
|
try:
|
||||||
|
self.canvas.draw()
|
||||||
|
except Exception:
|
||||||
|
try:
|
||||||
|
self.canvas.draw_idle()
|
||||||
|
except Exception:
|
||||||
|
pass
|
||||||
|
|
||||||
def draw_trajectory_preview(self, waypoints: List[Waypoint], use_spline: bool):
|
def draw_trajectory_preview(self, waypoints: List[Waypoint], use_spline: bool):
|
||||||
"""
|
"""
|
||||||
|
|||||||
@ -180,11 +180,11 @@ class SfpDebugWindow(tk.Toplevel):
|
|||||||
self.logger.exception("Toggle PPI failed")
|
self.logger.exception("Toggle PPI failed")
|
||||||
|
|
||||||
def update_ppi_targets(self, targets):
|
def update_ppi_targets(self, targets):
|
||||||
if self._ppi_visible:
|
try:
|
||||||
try:
|
if self.ris_ppi_widget:
|
||||||
self.ris_ppi_widget.update_targets(targets)
|
self.ris_ppi_widget.update_targets(targets)
|
||||||
except Exception:
|
except Exception:
|
||||||
self.logger.exception("Failed to update RIS PPI targets")
|
self.logger.exception("Failed to update RIS PPI targets")
|
||||||
|
|
||||||
def on_ris_status_update(self, ris_status_payload):
|
def on_ris_status_update(self, ris_status_payload):
|
||||||
# Convert RIS targets to Target objects (minimal, for display)
|
# Convert RIS targets to Target objects (minimal, for display)
|
||||||
@ -203,6 +203,7 @@ class SfpDebugWindow(tk.Toplevel):
|
|||||||
t.current_azimuth_deg = math.degrees(math.atan2(ris_tgt.x, ris_tgt.y))
|
t.current_azimuth_deg = math.degrees(math.atan2(ris_tgt.x, ris_tgt.y))
|
||||||
t.current_altitude_ft = ris_tgt.z
|
t.current_altitude_ft = ris_tgt.z
|
||||||
t.current_heading_deg = getattr(ris_tgt, 'heading', 0.0)
|
t.current_heading_deg = getattr(ris_tgt, 'heading', 0.0)
|
||||||
|
t.active = True
|
||||||
targets.append(t)
|
targets.append(t)
|
||||||
self.update_ppi_targets(targets)
|
self.update_ppi_targets(targets)
|
||||||
|
|
||||||
@ -1000,6 +1001,89 @@ class SfpDebugWindow(tk.Toplevel):
|
|||||||
self.ris_tree.insert("", tk.END, values=(None, None, str(t.get("heading")), str(t.get("x")), str(t.get("y")), str(t.get("z"))))
|
self.ris_tree.insert("", tk.END, values=(None, None, str(t.get("heading")), str(t.get("x")), str(t.get("y")), str(t.get("z"))))
|
||||||
except Exception:
|
except Exception:
|
||||||
pass
|
pass
|
||||||
|
# --- Update PPI with active targets that fit the current PPI scale/sector ---
|
||||||
|
try:
|
||||||
|
# Only proceed if we have a PPI widget available
|
||||||
|
ppi = getattr(self, "ris_ppi_widget", None)
|
||||||
|
if ppi is not None:
|
||||||
|
ppi_targets = []
|
||||||
|
METERS_PER_NM = 1852.0
|
||||||
|
# Determine current display range from the PPI widget
|
||||||
|
current_range = ppi.range_var.get() if hasattr(ppi, "range_var") else ppi.max_range
|
||||||
|
# Debug: show parsed target count and sample raw values
|
||||||
|
try:
|
||||||
|
self._log_to_widget(f"PPI: parsed {len(targets)} JSON target(s); current_range={current_range}", "DEBUG")
|
||||||
|
for i, tt in enumerate(targets[:6]):
|
||||||
|
try:
|
||||||
|
fx = tt.get('flags', None)
|
||||||
|
tx = tt.get('x', None)
|
||||||
|
ty = tt.get('y', None)
|
||||||
|
tz = tt.get('z', None)
|
||||||
|
# compute derived quantities
|
||||||
|
try:
|
||||||
|
xm = float(tx)
|
||||||
|
ym = float(ty)
|
||||||
|
zm = float(tz)
|
||||||
|
rng_m = (xm * xm + ym * ym) ** 0.5
|
||||||
|
rng_nm = rng_m / 1852.0
|
||||||
|
az_deg = math.degrees(math.atan2(xm, ym))
|
||||||
|
# elevation from z and slant range
|
||||||
|
elev_rad = math.atan2(zm, rng_m) if rng_m > 0 else 0.0
|
||||||
|
elev_deg = math.degrees(elev_rad)
|
||||||
|
except Exception:
|
||||||
|
rng_m = rng_nm = az_deg = elev_deg = None
|
||||||
|
msg = f"PPI RAW[{i}]: flags={fx} x={tx} y={ty} z={tz} | range_m={rng_m:.1f} range_nm={rng_nm:.2f} az={az_deg:.2f}° elev={elev_deg:.2f}°" if rng_m is not None else f"PPI RAW[{i}]: flags={fx} x={tx} y={ty} z={tz}"
|
||||||
|
self._log_to_widget(msg, "DEBUG")
|
||||||
|
except Exception:
|
||||||
|
pass
|
||||||
|
except Exception:
|
||||||
|
pass
|
||||||
|
for t in targets:
|
||||||
|
raw_flags = t.get("flags", 0)
|
||||||
|
# Only show enabled/active targets (non-zero flags)
|
||||||
|
if int(raw_flags) == 0:
|
||||||
|
continue
|
||||||
|
x = float(t.get("x", 0.0))
|
||||||
|
y = float(t.get("y", 0.0))
|
||||||
|
z = float(t.get("z", 0.0))
|
||||||
|
# Compute range in NM assuming x/y are meters
|
||||||
|
range_nm = ((x ** 2 + y ** 2) ** 0.5) / METERS_PER_NM
|
||||||
|
if range_nm > current_range:
|
||||||
|
continue
|
||||||
|
# Compute azimuth in degrees using same convention as PPIDisplay
|
||||||
|
az_deg = math.degrees(math.atan2(x, y))
|
||||||
|
# Heading in JSON is in radians -> convert to degrees
|
||||||
|
heading = t.get("heading", 0.0)
|
||||||
|
try:
|
||||||
|
hdg_deg = float(heading) * (180.0 / math.pi)
|
||||||
|
except Exception:
|
||||||
|
hdg_deg = 0.0
|
||||||
|
|
||||||
|
tgt = Target(target_id=int(t.get("index", 0)), trajectory=[], active=True, traceable=True)
|
||||||
|
tgt.current_range_nm = range_nm
|
||||||
|
tgt.current_azimuth_deg = az_deg
|
||||||
|
tgt.current_heading_deg = hdg_deg
|
||||||
|
# convert altitude from meters to feet
|
||||||
|
try:
|
||||||
|
tgt.current_altitude_ft = float(z) * 3.280839895
|
||||||
|
except Exception:
|
||||||
|
tgt.current_altitude_ft = 0.0
|
||||||
|
tgt.active = True
|
||||||
|
ppi_targets.append(tgt)
|
||||||
|
# Push to PPI (log debug info)
|
||||||
|
try:
|
||||||
|
self._log_to_widget(f"PPI: prepared {len(ppi_targets)} target(s) for display", "DEBUG")
|
||||||
|
if ppi_targets:
|
||||||
|
for pt in ppi_targets[:5]:
|
||||||
|
self._log_to_widget(
|
||||||
|
f"PPI target sample: id={getattr(pt, 'target_id', None)} r_nm={getattr(pt,'current_range_nm',None):.2f} az={getattr(pt,'current_azimuth_deg',None):.2f} hdg={getattr(pt,'current_heading_deg',None):.2f}",
|
||||||
|
"DEBUG",
|
||||||
|
)
|
||||||
|
self.update_ppi_targets(ppi_targets)
|
||||||
|
except Exception:
|
||||||
|
self.logger.exception("Failed to push targets to PPI")
|
||||||
|
except Exception:
|
||||||
|
self.logger.exception("Error while preparing RIS targets for PPI")
|
||||||
except Exception:
|
except Exception:
|
||||||
pass
|
pass
|
||||||
self.after(self.GUI_POLL_INTERVAL_MS, self._process_latest_payloads)
|
self.after(self.GUI_POLL_INTERVAL_MS, self._process_latest_payloads)
|
||||||
|
|||||||
7
todo.md
7
todo.md
@ -3,13 +3,12 @@
|
|||||||
## bachi
|
## bachi
|
||||||
|
|
||||||
quando faccio la traiettoria ad alti 9 sbaglia a disegnare la curva, rivedere il caso specifico ed anche con o senza spline
|
quando faccio la traiettoria ad alti 9 sbaglia a disegnare la curva, rivedere il caso specifico ed anche con o senza spline
|
||||||
|
La traiettoria a 9 g viene reindirizzataa scatti invece che con una curva
|
||||||
## sviluppi
|
## sviluppi
|
||||||
|
|
||||||
|
fare in modo di aggiornare la label della simulazione per evitare la scia.
|
||||||
|
girare le label sulla ppi a sinistra sono gli azimuth positivi, a destra i negativi
|
||||||
leggere le informazioni dell'antenna del messaggio di stato
|
leggere le informazioni dell'antenna del messaggio di stato
|
||||||
leggere la flag per capire se il target è attivo
|
|
||||||
scomporre il campo flag in bit per avere le informazioni dello stato del target (attivo, tracable)
|
scomporre il campo flag in bit per avere le informazioni dello stato del target (attivo, tracable)
|
||||||
fare simulazione con moviumento dell'aereo letto da protocollo
|
fare simulazione con moviumento dell'aereo letto da protocollo
|
||||||
visualizzare informaizoni dinamiche dell'areo durante la simulazione
|
visualizzare informaizoni dinamiche dell'areo durante la simulazione
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user