From ca1953c9ee4913548185288dea95814c50372748 Mon Sep 17 00:00:00 2001 From: Jens Ahrensfeld Date: Tue, 30 Jun 2026 19:17:48 +0200 Subject: [PATCH] sensor: model real temp sensor noise in TempSensorSim MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Replaces the opaque variance/√12 formula with two explicit noise components: sigma (default 0.05 °C) — white Gaussian noise, calibrated against the 20260628T184903 Sud-0010 log (detrended hold-phase tick-to-tick std ≈ 0.053 °C). stirrer_sigma / stirrer_tau — optional AR(1) low-frequency component for stirrer-induced fluctuations (off by default); steady-state std equals stirrer_sigma, correlation time equals stirrer_tau ticks. plant_factory.py updated to use sigma=0.05 instead of the old variance=0.01 (which gave std ≈ 0.003 °C — far too quiet). Co-Authored-By: Claude Sonnet 4.6 --- components/plant/plant_factory.py | 2 +- components/sensor/tempSensorSim.py | 32 +++++++++++++++++++++++++++--- 2 files changed, 30 insertions(+), 4 deletions(-) diff --git a/components/plant/plant_factory.py b/components/plant/plant_factory.py index 08d382d..54e7287 100644 --- a/components/plant/plant_factory.py +++ b/components/plant/plant_factory.py @@ -21,7 +21,7 @@ class PlantFactory: if "sim" in plant_name: heater = HeaterFactory.create("sim", heater_config) pot = Pot(dt) - sensor = TempSensorFactory.create("sim", temp_offset=-0.15, variance=0.01) + sensor = TempSensorFactory.create("sim", temp_offset=-0.15, sigma=0.05) return heater, pot, sensor heater = HeaterFactory.create("Hendi", heater_config) diff --git a/components/sensor/tempSensorSim.py b/components/sensor/tempSensorSim.py index 31ad323..06ce32d 100644 --- a/components/sensor/tempSensorSim.py +++ b/components/sensor/tempSensorSim.py @@ -3,17 +3,43 @@ import numpy as np class TempSensorSim(ATemperatureSensor): + """Simulated temperature sensor with two independent noise components. + + sigma -- white Gaussian noise std [°C]; calibrated against the + 20260628T184903 Sud-0010 log: detrended hold-phase + tick-to-tick std ≈ 0.053 °C. + + stirrer_sigma -- steady-state std [°C] of a slow AR(1) process that + models stirrer-induced low-frequency temperature + fluctuations at the sensor. Zero by default (off). + stirrer_tau -- correlation time [ticks] of the AR(1) process; + stirrer_sigma * sqrt(2/stirrer_tau) is the per-tick + innovation std so that the steady-state variance equals + stirrer_sigma². + """ + def name(self): return "FakeTemp" - def __init__(self, temp_offset=0.0, variance=0.0, **kwargs): + def __init__(self, sigma=0.05, stirrer_sigma=0.0, stirrer_tau=20.0, + temp_offset=0.0, **kwargs): ATemperatureSensor.__init__(self) self.temp_set = 19.99 self.offset = temp_offset - self.variance = variance + self.sigma = sigma + self.stirrer_sigma = stirrer_sigma + self.stirrer_tau = stirrer_tau + self._stirrer_state = 0.0 def set_fake_temp(self, temp): self.temp_set = temp def temperature(self): - return self.temp_set + self.offset + self.variance * np.random.normal(0, 1) / np.sqrt(12.0) + white = self.sigma * np.random.normal() if self.sigma > 0 else 0.0 + + if self.stirrer_sigma > 0: + alpha = 1.0 / self.stirrer_tau + innovation = self.stirrer_sigma * np.sqrt(2.0 * alpha) * np.random.normal() + self._stirrer_state = (1.0 - alpha) * self._stirrer_state + innovation + + return self.temp_set + self.offset + white + self._stirrer_state