-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathplot_trajectories.py
More file actions
152 lines (135 loc) · 4.85 KB
/
plot_trajectories.py
File metadata and controls
152 lines (135 loc) · 4.85 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
import numpy as np
import pandas as pd
import plotly.graph_objects as go
from pathlib import Path
import sys
import polars as pl
from parse_data import load_window
from geometry import sensor_direction_vector_enu, lla_to_enu
def compute_global_vectors_enu(df):
"""
For each row in the DataFrame, compute and add the sensor direction vector
components in ENU coordinates.
The resulting vector is stored as [East, North, Up] in new DataFrame columns.
"""
evx, evy, evz = [], [], []
for _, row in df.iterrows():
d_enu = sensor_direction_vector_enu(
row["azimuth"],
row["elevation"],
row["sensor_yaw"],
row["sensor_pitch"],
row["sensor_roll"],
)
evx.append(d_enu[0])
evy.append(d_enu[1])
evz.append(d_enu[2])
df["global_vector_east"] = evx
df["global_vector_north"] = evy
df["global_vector_up"] = evz
return df
def plot_trajectories(df, ray_length=1000, ray_interval=1000):
"""
Plot sensor and emitter trajectories (converted to local ENU coordinates)
along with sensor rays, using a dark mode theme.
Since all our computations are now in ENU (with axes: [East, North, Up]),
we directly use these coordinates.
"""
# Use the emitter's first position as the ENU reference.
lat_ref = df["emitter_lat"].iloc[0]
lon_ref = df["emitter_lon"].iloc[0]
alt_ref = df["emitter_alt"].iloc[0]
# Compute sensor and emitter positions in ENU.
sensor_enu = np.array([
lla_to_enu(row["sensor_lat"], row["sensor_lon"], row["sensor_alt"],
lat_ref, lon_ref, alt_ref)
for _, row in df.iterrows()
])
emitter_enu = np.array([
lla_to_enu(row["emitter_lat"], row["emitter_lon"], row["emitter_alt"],
lat_ref, lon_ref, alt_ref)
for _, row in df.iterrows()
])
# Build traces for sensor and emitter trajectories.
trace_sensor = go.Scatter3d(
x=sensor_enu[:, 0],
y=sensor_enu[:, 1],
z=sensor_enu[:, 2],
mode="lines+markers",
name="Sensor Trajectory",
line=dict(color="lemonchiffon"),
marker=dict(size=3, color="cyan"),
)
trace_emitter = go.Scatter3d(
x=emitter_enu[:, 0],
y=emitter_enu[:, 1],
z=emitter_enu[:, 2],
mode="lines+markers",
name="Emitter Trajectory",
line=dict(color="white"),
marker=dict(size=8, color="tomato"),
)
# Build sensor rays using the already computed ENU sensor direction vectors.
ray_x, ray_y, ray_z = [], [], []
for i in range(0, len(sensor_enu), ray_interval):
start = sensor_enu[i]
# Use the ENU direction vector from the DataFrame (already in ENU).
d_enu = np.array([
df["global_vector_east"].iloc[i],
df["global_vector_north"].iloc[i],
df["global_vector_up"].iloc[i],
])
ray_endpoint = start + ray_length * d_enu
ray_x.extend([start[0], ray_endpoint[0], None])
ray_y.extend([start[1], ray_endpoint[1], None])
ray_z.extend([start[2], ray_endpoint[2], None])
trace_rays = go.Scatter3d(
x=ray_x,
y=ray_y,
z=ray_z,
mode="lines",
name="Sensor Rays",
line=dict(color="lemonchiffon", width=1, dash="solid"),
)
# Assemble the figure with dark mode settings.
fig = go.Figure(data=[trace_sensor, trace_emitter, trace_rays])
fig.update_layout(
template="plotly_dark",
paper_bgcolor="rgba(50, 50, 50, 1)", # dark grey background for the paper
plot_bgcolor="rgba(50, 50, 50, 1)", # dark grey background for the plot area
scene=dict(
xaxis=dict(
title="East (m)",
backgroundcolor="rgba(50, 50, 50, 1)",
color="white"
),
yaxis=dict(
title="North (m)",
backgroundcolor="rgba(50, 50, 50, 1)",
color="white"
),
zaxis=dict(
title="Up (m)",
backgroundcolor="rgba(50, 50, 50, 1)",
color="white"
),
),
title="Sensor & Emitter Trajectories with Direction Rays"
)
fig.show()
if __name__ == "__main__":
file_path = Path(sys.argv[1])
df_pl = load_window(file_path)
emitter = "Emitter1"
df_pl = df_pl.filter(pl.col("emitter") == emitter).drop("emitter")
columns = [
'arrival_time', 'azimuth', 'elevation',
'sensor_lat', 'sensor_lon', 'sensor_alt',
'sensor_yaw', 'sensor_pitch', 'sensor_roll',
'emitter_lat', 'emitter_lon', 'emitter_alt'
]
df_pl = df_pl.select(columns)
df = df_pl.to_pandas()
df.set_index("arrival_time", inplace=True)
df = compute_global_vectors_enu(df)
plot_trajectories(df, ray_length=50000, ray_interval=1000)