3939PreprocessingStep = Callable [[SingleRunData ], SingleRunData ]
4040
4141
42- def _replace (data : SingleRunData , cpp_name : str , new_values : NDArray [float64 ]) -> None :
43- """Overwrite the value_np of an existing DataInstance in-place (mutates dict)."""
44- var_id = data .cpp_name_to_id [cpp_name ]
45- old = data .id_to_instance [var_id ]
46- data .id_to_instance [var_id ] = DataInstance (
47- timestamp_np = old .timestamp_np ,
48- value_np = new_values ,
49- label = old .label ,
50- var_id = old .var_id ,
51- cpp_name = old .cpp_name ,
52- )
53-
54-
55- def _add (
56- data : SingleRunData ,
57- cpp_name : str ,
58- label : str ,
59- timestamp_np : NDArray [float64 ],
60- value_np : NDArray [float64 ],
61- ) -> None :
62- """Insert a new derived DataInstance using a synthetic negative ID."""
63- synthetic_id = - (len (data .id_to_instance ) + 1 )
64- di = DataInstance (
65- timestamp_np = timestamp_np ,
66- value_np = value_np ,
67- label = label ,
68- var_id = synthetic_id ,
69- cpp_name = cpp_name ,
70- )
71- data .id_to_instance [synthetic_id ] = di
72- data .cpp_name_to_id [cpp_name ] = synthetic_id
73- data .id_to_cpp_name [synthetic_id ] = cpp_name
74- data .id_to_descript [synthetic_id ] = label
75-
76-
7742def patch_ned_velocity (data : SingleRunData ) -> SingleRunData :
7843 """Correct a VectorNav bug where velocityBody.x/y/z contains NED instead of body-frame velocities.
7944
@@ -108,14 +73,39 @@ def patch_ned_velocity(data: SingleRunData) -> SingleRunData:
10873 vel_d = vel_d1 .value_np
10974 yaw_rad = np .radians (yaw_deg .value_np )
11075
111- _add (data , "velN" , "NED North velocity (raw)" , vel_n1 .timestamp_np , vel_n .copy ())
112- _add (data , "velE" , "NED East velocity (raw)" , vel_e1 .timestamp_np , vel_e .copy ())
113- _add (data , "velD" , "NED Down velocity (raw)" , vel_d1 .timestamp_np , vel_d .copy ())
76+ data ["velN" ] = DataInstance (
77+ timestamp_np = vel_n1 .timestamp_np ,
78+ value_np = vel_n .copy (),
79+ label = "NED North velocity (raw)" ,
80+ cpp_name = "velN" ,
81+ )
82+ data ["velE" ] = DataInstance (
83+ timestamp_np = vel_e1 .timestamp_np ,
84+ value_np = vel_e .copy (),
85+ label = "NED East velocity (raw)" ,
86+ cpp_name = "velE" ,
87+ )
88+ data ["velD" ] = DataInstance (
89+ timestamp_np = vel_d1 .timestamp_np ,
90+ value_np = vel_d .copy (),
91+ label = "NED Down velocity (raw)" ,
92+ cpp_name = "velD" ,
93+ )
11494
11595 cos_y = np .cos (yaw_rad )
11696 sin_y = np .sin (yaw_rad )
117- _replace (data , VECTORNAV_BODY_VEL_X , vel_n * cos_y + vel_e * sin_y ) # forward
118- _replace (data , VECTORNAV_BODY_VEL_Y , - vel_n * sin_y + vel_e * cos_y ) # right
97+ data [VECTORNAV_BODY_VEL_X ] = DataInstance (
98+ timestamp_np = vel_n1 .timestamp_np ,
99+ value_np = vel_n * cos_y + vel_e * sin_y ,
100+ label = data [VECTORNAV_BODY_VEL_X ].label ,
101+ cpp_name = VECTORNAV_BODY_VEL_X ,
102+ ) # forward
103+ data [VECTORNAV_BODY_VEL_Y ] = DataInstance (
104+ timestamp_np = vel_e1 .timestamp_np ,
105+ value_np = - vel_n * sin_y + vel_e * cos_y ,
106+ label = data [VECTORNAV_BODY_VEL_Y ].label ,
107+ cpp_name = VECTORNAV_BODY_VEL_Y ,
108+ ) # right
119109 # vel_z (down) is identical in NED and FRD — no change needed
120110
121111 print (
@@ -147,14 +137,18 @@ def convert_wheelspeeds_to_m_per_s(data: SingleRunData) -> SingleRunData:
147137 di = data [col ]
148138 backup_name = col + "_mph"
149139 if backup_name not in data :
150- _add (
151- data ,
152- backup_name ,
153- (di .label or col ) + " (mph backup)" ,
154- di .timestamp_np ,
155- di .value_np .copy (),
140+ data [backup_name ] = DataInstance (
141+ timestamp_np = di .timestamp_np ,
142+ value_np = di .value_np .copy (),
143+ label = (di .label or col ) + " (mph backup)" ,
144+ cpp_name = backup_name ,
156145 )
157- _replace (data , col , mph_to_m_per_s (di .value_np ))
146+ data [col ] = DataInstance (
147+ timestamp_np = di .timestamp_np ,
148+ value_np = mph_to_m_per_s (di .value_np ),
149+ label = di .label ,
150+ cpp_name = col ,
151+ )
158152
159153 print (
160154 f"convert_wheelspeeds_to_m_per_s: converted { len (cols )} channels mph → m/s, backups in *_mph"
@@ -182,27 +176,30 @@ def correct_motor_data(data: SingleRunData) -> SingleRunData:
182176
183177 backup_name = MOTOR_RPM + "_raw"
184178 if backup_name not in data :
185- _add (
186- data ,
187- backup_name ,
188- "Motor RPM raw (pre-flip)" ,
189- di .timestamp_np ,
190- raw_rpm .copy (),
179+ data [backup_name ] = DataInstance (
180+ timestamp_np = di .timestamp_np ,
181+ value_np = raw_rpm .copy (),
182+ label = "Motor RPM raw (pre-flip)" ,
183+ cpp_name = backup_name ,
191184 )
192185
193186 flipped = - raw_rpm
194- _replace (data , MOTOR_RPM , flipped )
187+ data [MOTOR_RPM ] = DataInstance (
188+ timestamp_np = di .timestamp_np ,
189+ value_np = flipped ,
190+ label = di .label ,
191+ cpp_name = MOTOR_RPM ,
192+ )
195193
196194 tire_radius_m = in_to_m (TIRE_RADIUS_IN )
197195 wheel_speed : NDArray [float64 ] = (
198196 flipped * 2.0 * np .pi * tire_radius_m / (60.0 * GEAR_RATIO )
199197 )
200- _add (
201- data ,
202- MOTOR_WHEELSPEED ,
203- "Driven wheel speed from motor RPM (m/s)" ,
204- di .timestamp_np ,
205- wheel_speed ,
198+ data [MOTOR_WHEELSPEED ] = DataInstance (
199+ timestamp_np = di .timestamp_np ,
200+ value_np = wheel_speed ,
201+ label = "Driven wheel speed from motor RPM (m/s)" ,
202+ cpp_name = MOTOR_WHEELSPEED ,
206203 )
207204
208205 print (
@@ -275,24 +272,19 @@ def __call__(
275272 backup_name = STEERING_ANGLE + "_original"
276273 if STEERING_ANGLE in data and backup_name not in data :
277274 orig = data [STEERING_ANGLE ]
278- _add (
279- data ,
280- backup_name ,
281- (orig .label or STEERING_ANGLE ) + " (original)" ,
282- orig .timestamp_np ,
283- orig .value_np .copy (),
275+ data [backup_name ] = DataInstance (
276+ timestamp_np = orig .timestamp_np ,
277+ value_np = orig .value_np .copy (),
278+ label = (orig .label or STEERING_ANGLE ) + " (original)" ,
279+ cpp_name = backup_name ,
284280 )
285281
286- if STEERING_ANGLE in data :
287- _replace (data , STEERING_ANGLE , recomputed )
288- else :
289- _add (
290- data ,
291- STEERING_ANGLE ,
292- "Steering angle recomputed from raw voltage (deg)" ,
293- raw_di .timestamp_np ,
294- recomputed ,
295- )
282+ data [STEERING_ANGLE ] = DataInstance (
283+ timestamp_np = raw_di .timestamp_np ,
284+ value_np = recomputed ,
285+ label = "Steering angle recomputed from raw voltage (deg)" ,
286+ cpp_name = STEERING_ANGLE ,
287+ )
296288
297289 cal_str = ", " .join (f"({ v :.2f} V, { a :+.1f} °)" for v , a in self .pts )
298290 print (
@@ -302,6 +294,9 @@ def __call__(
302294 return data
303295
304296
297+ # This is the global callable that should actually be used in the preprocessing pipeline.
298+ # Either pass it directly, or with a custom calibration correct_steering_angle(calibration=...)
299+ # This should be treated like a function that supports partial application.
305300correct_steering_angle = CorrectSteeringAngleLambda ()
306301
307302
0 commit comments