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