37 """Test duty quantization."""
39 self.assertAlmostEqual(quantize_duty(0.0, 0.01), 0.0)
40 self.assertAlmostEqual(quantize_duty(0.5, 0.01), 0.5)
41 self.assertAlmostEqual(quantize_duty(1.0, 0.01), 1.0)
44 self.assertAlmostEqual(quantize_duty(0.005, 0.01), 0.0)
45 self.assertAlmostEqual(quantize_duty(0.015, 0.01), 0.02)
46 self.assertAlmostEqual(quantize_duty(0.495, 0.01), 0.5)
49 self.assertAlmostEqual(quantize_duty(-0.1, 0.01), 0.0)
50 self.assertAlmostEqual(quantize_duty(1.1, 0.01), 1.0)
53 self.assertAlmostEqual(quantize_duty(0.25, 0.1), 0.2)
54 self.assertAlmostEqual(quantize_duty(0.75, 0.1), 0.8)
57 """Test dwell enforcement when dwell time is satisfied."""
65 u_output, dwell_timer_new = enforce_dwell(
66 u_new, u_prev, dwell_timer, dwell_time, dt
70 self.assertAlmostEqual(u_output, u_new)
71 self.assertAlmostEqual(dwell_timer_new, 0.0)
74 """Test dwell enforcement when dwell time is not satisfied."""
82 u_output, dwell_timer_new = enforce_dwell(
83 u_new, u_prev, dwell_timer, dwell_time, dt
87 self.assertAlmostEqual(u_output, u_prev)
88 self.assertAlmostEqual(dwell_timer_new, dwell_timer + dt)
91 """Test dwell enforcement when control unchanged."""
99 u_output, dwell_timer_new = enforce_dwell(
100 u_new, u_prev, dwell_timer, dwell_time, dt
104 self.assertAlmostEqual(u_output, u_new)
105 self.assertAlmostEqual(dwell_timer_new, dwell_timer + dt)
108 """Test binary actuation with threshold method."""
110 duty_output, onoff = binary_actuation(0.3, 0.01, self.
cfg,
None)
111 self.assertFalse(onoff)
112 self.assertEqual(duty_output, 0.0)
114 duty_output, onoff = binary_actuation(0.7, 0.01, self.
cfg,
None)
115 self.assertTrue(onoff)
116 self.assertEqual(duty_output, 1.0)
119 """Test binary actuation with sigma-delta modulation."""
127 duty_output, onoff = binary_actuation(0.3, 0.01, self.
cfg, accumulator)
128 outputs.append(duty_output)
130 accumulator = accumulator + (0.3 - duty_output)
134 avg_duty = np.mean(outputs)
135 self.assertGreater(avg_duty, 0.0)
136 self.assertLess(avg_duty, 1.0)
139 """Test compute_actuation with PWM backend."""
140 u_relaxed = np.array([0.75, 0.45])
142 cmd = compute_actuation(
146 backend=ExecutionBackend.PWM,
150 self.assertIsInstance(cmd, ActuationCommand)
151 self.assertEqual(cmd.backend, ExecutionBackend.PWM)
154 self.assertAlmostEqual(cmd.u_F_quantized, 0.75)
155 self.assertAlmostEqual(cmd.u_O_quantized, 0.45)
158 self.assertGreaterEqual(cmd.duty_F, 0.0)
159 self.assertLessEqual(cmd.duty_F, 1.0)
160 self.assertGreaterEqual(cmd.duty_O, 0.0)
161 self.assertLessEqual(cmd.duty_O, 1.0)
164 self.assertEqual(cmd.u_F_onoff, cmd.duty_F > 0.0)
165 self.assertEqual(cmd.u_O_onoff, cmd.duty_O > 0.0)
168 """Test compute_actuation with binary backend."""
169 u_relaxed = np.array([0.75, 0.25])
171 cmd = compute_actuation(
175 backend=ExecutionBackend.BINARY,
179 self.assertIsInstance(cmd, ActuationCommand)
180 self.assertEqual(cmd.backend, ExecutionBackend.BINARY)
183 self.assertIn(cmd.duty_F, [0.0, 1.0])
184 self.assertIn(cmd.duty_O, [0.0, 1.0])
187 self.assertEqual(cmd.u_F_onoff, cmd.duty_F > 0.0)
188 self.assertEqual(cmd.u_O_onoff, cmd.duty_O > 0.0)
214 """Test compute_actuation allows change when dwell satisfied."""
217 u_prev={
"P_u_fuel": 0.5,
"P_u_ox": 0.5},
218 dwell_timers={
"P_u_fuel": 0.1,
"P_u_ox": 0.1},
222 u_relaxed = np.array([0.8, 0.3])
224 cmd = compute_actuation(
226 state=state_satisfied,
228 backend=ExecutionBackend.PWM,
232 self.assertAlmostEqual(cmd.dwell_timer_F, 0.0)
233 self.assertAlmostEqual(cmd.dwell_timer_O, 0.0)
236 """Test updating dwell timers in state."""
238 u_prev={
"P_u_fuel": 0.0,
"P_u_ox": 0.0},
239 dwell_timers={
"P_u_fuel": 0.0,
"P_u_ox": 0.0},
249 backend=ExecutionBackend.PWM,
254 update_state_dwell_timers(state, cmd)
257 self.assertAlmostEqual(state.dwell_timers[
"P_u_fuel"], 0.05)
258 self.assertAlmostEqual(state.dwell_timers[
"P_u_ox"], 0.03)
261 self.assertAlmostEqual(state.u_prev[
"P_u_fuel"], 0.75)
262 self.assertAlmostEqual(state.u_prev[
"P_u_ox"], 0.25)
265 """Test duty grid creation."""
266 grid = create_duty_grid(0.1)
269 self.assertEqual(len(grid), 11)
270 self.assertAlmostEqual(grid[0], 0.0)
271 self.assertAlmostEqual(grid[-1], 1.0)
272 self.assertAlmostEqual(grid[5], 0.5)
275 grid = create_duty_grid(0.01)
276 self.assertEqual(len(grid), 101)
277 self.assertAlmostEqual(grid[0], 0.0)
278 self.assertAlmostEqual(grid[-1], 1.0)
281 """Test duty quantization edge cases."""
283 self.assertAlmostEqual(quantize_duty(0.123456, 0.001), 0.123, places=3)
286 self.assertAlmostEqual(quantize_duty(0.75, 0.5), 1.0)
291 self.assertAlmostEqual(quantize_duty(0.5, 1e-6), 0.5, places=6)
294 """Test compute_actuation clamps inputs."""
296 u_relaxed = np.array([-0.1, 1.5])
298 cmd = compute_actuation(
302 backend=ExecutionBackend.PWM,
306 self.assertGreaterEqual(cmd.duty_F, 0.0)
307 self.assertLessEqual(cmd.duty_F, 1.0)
308 self.assertGreaterEqual(cmd.duty_O, 0.0)
309 self.assertLessEqual(cmd.duty_O, 1.0)