Skip to content

Commit 3bf8df6

Browse files
adding new versions to monitor
1 parent 60df614 commit 3bf8df6

File tree

5 files changed

+31
-15
lines changed

5 files changed

+31
-15
lines changed

CHANGELOG.md

+3-1
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,7 @@
11
### Upcoming
2-
- introducing some outlier protection in growth rate calculations
2+
- fixed `datum` bug in the Overview that was crashing the UI. Sorry!
3+
- introducing some outlier protection in growth rate calculations. This is tunable with the `ekf_outlier_std_threshold` value under `[growth_rate_calculating.config]`. The default value, 5.0, is pretty conservative, and will still allow some spikes to permeate to the growth rate and nOD. Try a value of 3.5 or 4.0 if you want to see more. Don't put it less than 3.0 - that's silly.
4+
35

46
### 24.2.11
57
- boot-up performance improvements

pioreactor/background_jobs/growth_rate_calculating.py

+9-6
Original file line numberDiff line numberDiff line change
@@ -181,20 +181,25 @@ def initialize_extended_kalman_filter(
181181
]
182182

183183
self.logger.debug(f"{angles=}")
184-
outlier_std_threshold = config.getfloat(
184+
ekf_outlier_std_threshold = config.getfloat(
185185
"growth_rate_calculating.config",
186-
"outlier_std_threshold",
186+
"ekf_outlier_std_threshold",
187187
fallback=5.0,
188188
)
189-
self.logger.debug(f"{outlier_std_threshold=}")
189+
if ekf_outlier_std_threshold <= 2.0:
190+
raise ValueError(
191+
"outlier_std_threshold should not be less than 2.0 - that's eliminating too many data points."
192+
)
193+
194+
self.logger.debug(f"{ekf_outlier_std_threshold=}")
190195

191196
return CultureGrowthEKF(
192197
initial_state,
193198
initial_covariance,
194199
process_noise_covariance,
195200
observation_noise_covariance,
196201
angles,
197-
outlier_std_threshold,
202+
ekf_outlier_std_threshold,
198203
)
199204

200205
def create_obs_noise_covariance(self, obs_std): # typing: ignore
@@ -326,12 +331,10 @@ def get_filtered_od_from_cache_or_computed(self) -> float:
326331
allow_retained=True, # maybe?
327332
timeout=10,
328333
)
329-
print(f"pioreactor/{self.unit}/{self.experiment}/od_reading/ods")
330334
if msg is None:
331335
return 1.0 # default?
332336

333337
od_readings = decode(msg.payload, type=structs.ODReadings)
334-
print(od_readings)
335338
scaled_ods = self.scale_raw_observations(self._batched_raw_od_readings_to_dict(od_readings.ods))
336339
assert scaled_ods is not None
337340
return mean(scaled_ods.values())

pioreactor/background_jobs/monitor.py

+13-6
Original file line numberDiff line numberDiff line change
@@ -88,7 +88,7 @@ def off(): # functions don't take any arguments, nothing is passed in
8888
published_settings = {
8989
"computer_statistics": {"datatype": "json", "settable": False},
9090
"button_down": {"datatype": "boolean", "settable": False},
91-
"versions": {"datatype": "json", "settable": False},
91+
"versions": {"datatype": "json", "settable": True},
9292
"voltage_on_pwm_rail": {"datatype": "Voltage", "settable": False},
9393
"ipv4": {"datatype": "string", "settable": False},
9494
"wlan_mac_address": {"datatype": "string", "settable": False},
@@ -109,20 +109,21 @@ def pretty_version(info: tuple) -> str:
109109
# Sol2: pio update app republishes this data, OR publishes an event that Monitor listens to.
110110
#
111111
self.versions = {
112-
"software": pretty_version(version.software_version_info),
112+
"app": pretty_version(version.software_version_info),
113113
"hat": pretty_version(version.hardware_version_info),
114+
"firmware": pretty_version(version.get_firmware_version()),
114115
"hat_serial": version.serial_number,
116+
"rpi_machine": version.rpi_version_info,
115117
"timestamp": current_utc_timestamp(),
116118
}
117119

118-
self.logger.debug(f"Pioreactor software version: {pretty_version(version.software_version_info)}")
120+
self.logger.debug(f"Pioreactor software version: {self.versions['app']}")
121+
self.logger.debug(f"Raspberry Pi: {self.versions['rpi_machine']}")
119122

120123
if whoami.am_I_active_worker():
121124
self.logger.debug(f"Pioreactor HAT version: {self.versions['hat']}")
122125

123-
self.logger.debug(
124-
f"Pioreactor firmware version: {pretty_version(version.get_firmware_version())}"
125-
)
126+
self.logger.debug(f"Pioreactor firmware version: {self.versions['firmware']}")
126127

127128
self.logger.debug(f"Pioreactor HAT serial number: {self.versions['hat_serial']}")
128129

@@ -716,6 +717,12 @@ def flicker_error_code_from_mqtt(self, message: MQTTMessage) -> None:
716717
error_code = int(message.payload)
717718
Thread(target=self.flicker_led_with_error_code, args=(error_code,), daemon=True).start()
718719

720+
def set_versions(self, data: dict):
721+
# TODO: this can also be a dict merge
722+
for key, value in data.items():
723+
if key in self.versions:
724+
self.versions[key] = value
725+
719726
def start_passive_listeners(self) -> None:
720727
self.subscribe_and_callback(
721728
self.flicker_led_response_okay_and_publish_state,

pioreactor/cli/pio.py

+6
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,7 @@
3636
from pioreactor.utils.networking import add_local
3737
from pioreactor.utils.networking import is_using_local_access_point
3838
from pioreactor.utils.timing import catchtime
39+
from pioreactor.utils.timing import current_utc_timestamp
3940

4041

4142
JOBS_TO_SKIP_KILLING = [
@@ -605,6 +606,11 @@ def update_app(
605606
logger.debug(p.stdout)
606607

607608
logger.notice(f"Updated {whoami.get_unit_name()} to version {version_installed}.") # type: ignore
609+
# everything work? Let's publish to MQTT. This is a terrible hack, as monitor should do this.
610+
pubsub.publish(
611+
f"pioreactor/{whoami.get_unit_name()}/{whoami.UNIVERSAL_EXPERIMENT}/monitor/versions/set",
612+
{"app": version_installed, "timestamp": current_utc_timestamp()},
613+
)
608614

609615

610616
@update.command(name="firmware")

pioreactor/utils/streaming_calculations.py

-2
Original file line numberDiff line numberDiff line change
@@ -280,12 +280,10 @@ def update(self, observation_: list[float], dt: float):
280280
+ self.state_[0] * self.observation_noise_covariance
281281
)
282282

283-
# print(abs(residual_state[0])/np.sqrt(residual_covariance[0, 0]))
284283
# check if outlier
285284
if self.ignore_outliers and (
286285
abs(residual_state[0]) > self.outlier_std_threshold * np.sqrt(residual_covariance[0, 0])
287286
):
288-
print("OUTLIER!")
289287
# don't update, but allow randomly
290288
if np.random.random() > 0.1:
291289
return self.state_, self.covariance_

0 commit comments

Comments
 (0)