Skip to content

Commit d5dfec6

Browse files
some od reading bugs
1 parent 1db356e commit d5dfec6

File tree

2 files changed

+44
-6
lines changed

2 files changed

+44
-6
lines changed

core/pioreactor/background_jobs/od_reading.py

Lines changed: 19 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -476,7 +476,9 @@ def _sin_regression_with_known_freq(
476476
if SSE > 1e-20:
477477
AIC = n * np.log(SSE / n) + 2 * 3
478478
else:
479-
AIC = math.inf
479+
# Perfect (or numerically-perfect) fits should rank best when selecting
480+
# between candidate AC frequencies.
481+
AIC = -math.inf
480482

481483
if np.sqrt(b**2 + c**2) <= 1e-20:
482484
A = 0
@@ -1319,10 +1321,20 @@ def _determine_best_ir_led_intensity(
13191321

13201322
_, REF_on_signal = on_reading.popitem()
13211323

1322-
ir_intensity_argmax_REF_can_be = initial_ir_intensity / REF_on_signal.reading * 0.250
1324+
def _safe_ratio(numerator: float, denominator: float) -> float:
1325+
# Very small / zero sensor values can occur during startup or hardware faults.
1326+
# Treating the ratio as +inf preserves current behavior (falls back to MAX)
1327+
# while avoiding runtime crashes.
1328+
if denominator <= 0.0:
1329+
return float("inf")
1330+
return numerator / denominator
1331+
1332+
ir_intensity_argmax_REF_can_be = _safe_ratio(initial_ir_intensity, REF_on_signal.reading) * 0.250
13231333

13241334
# divide by N since the culture is unlikely to Nx.
1325-
ir_intensity_argmax_ANGLE_can_be = (initial_ir_intensity / culture_on_signal.reading) * 3.0 / 50
1335+
ir_intensity_argmax_ANGLE_can_be = (
1336+
_safe_ratio(initial_ir_intensity, culture_on_signal.reading) * 3.0 / 50
1337+
)
13261338

13271339
ir_led_intensity = min(
13281340
MAX, ir_intensity_argmax_ANGLE_can_be, ir_intensity_argmax_REF_can_be
@@ -1496,10 +1508,12 @@ def stop_ir_led(self) -> None:
14961508
############
14971509

14981510
def on_sleeping(self) -> None:
1499-
self.record_from_adc_timer.pause()
1511+
if hasattr(self, "record_from_adc_timer"):
1512+
self.record_from_adc_timer.pause()
15001513

15011514
def on_sleeping_to_ready(self) -> None:
1502-
self.record_from_adc_timer.unpause()
1515+
if hasattr(self, "record_from_adc_timer"):
1516+
self.record_from_adc_timer.unpause()
15031517

15041518
def on_disconnected(self) -> None:
15051519
try:

core/tests/test_od_reading.py

Lines changed: 25 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -685,6 +685,18 @@ def test_ADC_picks_to_correct_freq_even_if_slight_noise_in_freq() -> None:
685685
assert best_freq == actual_freq
686686

687687

688+
def test_ADC_picks_exact_frequency_for_perfect_signal() -> None:
689+
actual_freq = 50.0
690+
# Use a non-aliased sample grid so the linear solve is non-singular.
691+
x = [i / 29 for i in range(29)]
692+
y = [10.0 + np.sin(actual_freq * 2 * np.pi * _x + 0.3) for _x in x]
693+
694+
adc_reader = ADCReader(channels=["1"])
695+
696+
best_freq = adc_reader.determine_most_appropriate_AC_hz({"1": x}, {"1": y})
697+
assert best_freq == actual_freq
698+
699+
688700
def test_error_thrown_if_wrong_angle() -> None:
689701
with pytest.raises(ValueError):
690702
start_od_reading(make_channels("100", "135"), fake_data=True, experiment="test_error_thrown_if_wrong_angle") # type: ignore
@@ -736,7 +748,7 @@ def test_sin_regression_all_negative() -> None:
736748

737749
(C, A, phi), AIC = adc_reader._sin_regression_with_known_freq(x, y, freq)
738750
assert C == -2
739-
assert AIC == float("inf")
751+
assert AIC == -float("inf")
740752

741753

742754
@pytest.mark.slow
@@ -915,6 +927,8 @@ def test_outliers_are_removed_in_sin_regression() -> None:
915927
def test_interval_is_empty() -> None:
916928
with start_od_reading(make_channels("90", "REF"), interval=None, fake_data=True) as od:
917929
assert not hasattr(od, "record_from_adc_timer")
930+
od.on_sleeping()
931+
od.on_sleeping_to_ready()
918932

919933

920934
def test_determine_best_ir_led_intensity_values() -> None:
@@ -950,6 +964,16 @@ def test_determine_best_ir_led_intensity_values() -> None:
950964
== 50 # 6.0
951965
)
952966

967+
assert (
968+
_determine_best_ir_led_intensity(
969+
{"2": "90"},
970+
50,
971+
{"1": structs.RawPDReading(0.0, "1"), "2": structs.RawPDReading(0.0, "2")},
972+
{"1": structs.RawPDReading(0.001, "1"), "2": structs.RawPDReading(0.001, "2")},
973+
)
974+
== 85.0
975+
)
976+
953977

954978
def test_calibration_not_requested() -> None:
955979
with start_od_reading(make_channels("90", "REF"), interval=None, fake_data=True, calibration=False) as od:

0 commit comments

Comments
 (0)