55 """Test basic bounds update."""
59 x_meas = self.
x_prev.copy()
60 x_meas[IDX_P_COPV] += 1e5
69 self.assertIsNotNone(state.w_bar_array)
70 self.assertEqual(len(state.w_bar_array), N_STATE)
73 self.assertTrue(np.all(state.w_bar_array >= 0))
76 self.assertGreater(state.w_bar_array[IDX_P_COPV], 0)
79 """Test that bounds increase when residual spikes."""
83 x_meas_small = self.
x_prev.copy()
84 x_meas_small[IDX_P_COPV] += 1e4
91 w_bar_initial = state.w_bar_array[IDX_P_COPV].copy()
94 x_meas_large = self.
x_prev.copy()
95 x_meas_large[IDX_P_COPV] += 1e6
102 w_bar_after_spike = state.w_bar_array[IDX_P_COPV]
105 self.assertGreater(w_bar_after_spike, w_bar_initial,
106 f
"Bounds should increase after spike: {w_bar_after_spike} > {w_bar_initial}")
109 """Test exponential moving average behavior."""
113 residual_magnitude = 1e5
114 x_meas = self.
x_prev.copy()
115 x_meas[IDX_P_COPV] += residual_magnitude
122 w_bar_1 = state.w_bar_array[IDX_P_COPV]
129 w_bar_2 = state.w_bar_array[IDX_P_COPV]
134 expected_w_bar_2 = (0.9 * w_bar_1 + 0.1 * residual_magnitude) * 1.1
136 self.assertAlmostEqual(w_bar_2, expected_w_bar_2, delta=1e3,
137 msg=
"EMA update should follow formula")
183 """Test basic tube propagation."""
185 x_nom = self.
x_prev.copy()
186 w_bar = np.array([1e5, 1e5, 1e5, 1e5, 1e5, 1e5, 1e-4, 1e-4], dtype=np.float64)
192 x_lo_next, x_hi_next = tube_propagate(
198 self.assertEqual(x_lo_next.shape, (N_STATE,))
199 self.assertEqual(x_hi_next.shape, (N_STATE,))
202 self.assertTrue(np.all(x_lo_next <= x_hi_next),
203 "Lower bound must be <= upper bound")
206 self.assertTrue(np.all(x_lo_next >= 0),
207 "Lower bound must be non-negative")
210 """Test that tube propagation widens uncertainty."""
212 x_nom = self.
x_prev.copy()
213 w_bar_small = np.full(N_STATE, 1e4, dtype=np.float64)
215 x_lo = x_nom - w_bar_small
216 x_hi = x_nom + w_bar_small
219 x_lo_next, x_hi_next = tube_propagate(
225 width_before = np.sum(x_hi - x_lo)
226 width_after = np.sum(x_hi_next - x_lo_next)
230 self.assertGreaterEqual(width_after, width_before * 0.9,
231 f
"Tube should widen: {width_after} >= {width_before * 0.9}")
234 """Test tube propagation with large uncertainty bounds."""
235 x_nom = self.
x_prev.copy()
236 w_bar_large = np.full(N_STATE, 1e6, dtype=np.float64)
238 x_lo = x_nom - w_bar_large
239 x_hi = x_nom + w_bar_large
242 x_lo_next, x_hi_next = tube_propagate(
248 self.assertTrue(np.all(x_lo_next <= x_hi_next))
249 self.assertTrue(np.all(x_lo_next >= 0))
250 self.assertTrue(np.all(np.isfinite(x_lo_next)))
251 self.assertTrue(np.all(np.isfinite(x_hi_next)))
254 """Test tube propagation input validation."""
257 w_bar = np.full(N_STATE, 1e5, dtype=np.float64)
260 x_lo_next, x_hi_next = tube_propagate(
264 self.assertIsNotNone(x_lo_next)
267 with self.assertRaises(ValueError):
274 with self.assertRaises(ValueError):
281 """Test getting w_bar as array."""
285 w_bar_test = np.array([1e5, 2e5, 3e5, 4e5, 5e5, 6e5, 1e-4, 2e-4], dtype=np.float64)
286 set_w_bar_array(state, w_bar_test)
288 w_bar_retrieved = get_w_bar_array(state)
289 np.testing.assert_array_equal(w_bar_retrieved, w_bar_test)
304 w_bar_from_dict = get_w_bar_array(state2)
305 np.testing.assert_array_almost_equal(w_bar_from_dict, w_bar_test, decimal=2)
308 """Test setting w_bar from array."""
311 w_bar_test = np.array([1e5, 2e5, 3e5, 4e5, 5e5, 6e5, 1e-4, 2e-4], dtype=np.float64)
312 set_w_bar_array(state, w_bar_test)
315 self.assertIsNotNone(state.w_bar_array)
316 np.testing.assert_array_equal(state.w_bar_array, w_bar_test)
319 self.assertEqual(state.w_bar[
"P_copv"], 1e5)
320 self.assertEqual(state.w_bar[
"P_reg"], 2e5)
323 with self.assertRaises(ValueError):
324 set_w_bar_array(state, np.array([1, 2, 3]))
327 """Test update_bounds with engine wrapper."""
328 from unittest.mock
import Mock
331 mock_wrapper = Mock()
332 mock_wrapper.estimate_from_pressures.return_value =
EngineEstimate(
343 x_meas = self.
x_prev.copy()
344 x_meas[IDX_P_COPV] += 1e5
349 engine_wrapper=mock_wrapper, dt=self.
config.dt
353 mock_wrapper.estimate_from_pressures.assert_called_once()
356 self.assertIsNotNone(state.w_bar_array)
357 self.assertGreater(state.w_bar_array[IDX_P_COPV], 0)