Coverage for src/cgse_dummy/sim_data.py: 78%
55 statements
« prev ^ index » next coverage.py v7.10.6, created at 2025-09-11 18:19 +0200
« prev ^ index » next coverage.py v7.10.6, created at 2025-09-11 18:19 +0200
1import time
3import numpy as np
4from datetime import datetime, timedelta
7def _simulate_temperature_data(
8 start_temp=25, # Room temperature (ºC)
9 first_target=-70, # First cooling target (ºC)
10 second_target=-40, # Heating target (ºC)
11 final_target=-180, # Final cooling target (ºC)
12 total_time=720, # Total time in minutes (12 hours)
13 sample_rate=10, # Seconds between measurements
14) -> tuple[list[datetime], list[float]]:
15 """
16 Simulate temperature sensor data with a plateau phase and a cooling period.
18 The default arguments will generate temperature data for twelve hours cooling
19 down from room temperature to -180ºC. We introduced two plateau of one hour
20 duration, (1) the first plateau at -70ºC starts after one hour of cooling and
21 (2) the second plateau at -40ºC starts after heating for one hour and twenty
22 minutes. After the second plateau we cool down until -180ºC.
24 This code was generated by Claude 3.5 Sonnet with small adjustments.
26 Returns:
27 - timestamp and temperature as a tuple.
28 """
29 # Calculate number of samples
30 n_samples = int((total_time * 60) / sample_rate)
32 # Create time array in minutes
33 time = np.linspace(0, total_time, n_samples)
35 # Initialize temperature array
36 temp = np.zeros(n_samples)
38 # Define phase transition points (in minutes)
39 phase1_end = 60 # First cooling phase
40 phase2_end = 120 # First plateau
41 phase3_end = 200 # Heating phase
42 phase4_end = 260 # Second plateau
44 # Find indices for different phases
45 idx1 = np.where(time >= phase1_end)[0][0]
46 idx2 = np.where(time >= phase2_end)[0][0]
47 idx3 = np.where(time >= phase3_end)[0][0]
48 idx4 = np.where(time >= phase4_end)[0][0]
50 # Phase 1: Initial cooling to -70°C (exponential)
51 initial_time = time[:idx1]
52 temp[:idx1] = start_temp + (first_target - start_temp) * (
53 1 - np.exp(-initial_time / 15) # Time constant for first cooling
54 )
56 # Phase 2: First plateau at -70°C
57 temp[idx1:idx2] = first_target
59 # Phase 3: Heating to -40°C (exponential approach)
60 heating_time = time[idx2:idx3] - time[idx2]
61 temp[idx2:idx3] = first_target + (second_target - first_target) * (
62 1 - np.exp(-heating_time / 10) # Time constant for heating
63 )
65 # Phase 4: Second plateau at -40°C
66 temp[idx3:idx4] = second_target
68 # Phase 5: Final cooling to -180°C
69 final_time = time[idx4:] - time[idx4]
70 temp[idx4:] = second_target + (final_target - second_target) * (
71 1 - np.exp(-final_time / 100) # Time constant for final cooling
72 )
74 # Add different levels of noise for each phase
75 base_noise = np.random.normal(0, 0.2, n_samples)
77 # Add occasional spikes
78 spike_locations = np.random.choice(
79 n_samples, size=int(n_samples * 0.005), replace=False
80 )
81 spike_noise = np.zeros(n_samples)
82 spike_noise[spike_locations] = np.random.normal(0, 3, size=len(spike_locations))
84 # Add slow drift
85 drift = np.sin(np.linspace(0, 8 * np.pi, n_samples)) * 0.8
87 # Combine all noise components
88 total_noise = base_noise + spike_noise + drift
89 temp += total_noise
91 # Create timestamps
92 start_time = datetime.now()
93 timestamps = [
94 start_time + timedelta(seconds=i * sample_rate) for i in range(n_samples)
95 ]
97 return timestamps, temp.tolist()
100class SimulatedTemperature:
101 """
102 This is an iterator over simulated temperature data.
104 Generate simulate temperature sensor data with a plateau phase and a cooling period.
106 The default arguments will generate temperature data for twelve hours cooling
107 down from room temperature to -180ºC. We introduced two plateau of one hour
108 duration, (1) the first plateau at -70ºC starts after one hour of cooling and
109 (2) the second plateau at -40ºC starts after heating for one hour and twenty
110 minutes. After the second plateau we cool down until -180ºC.
112 """
114 def __init__(self):
115 self.timestamps: list[datetime]
116 self.temperatures: list[float]
118 self.timestamps, self.temperatures = _simulate_temperature_data()
120 self.count: int = len(self.timestamps)
121 """The number of data points."""
122 self.idx: int = 0
123 """A pointer in the list of data points, the next data point to return."""
125 def __iter__(self):
126 return self
128 def __next__(self):
129 x, y = self.timestamps[self.idx], self.temperatures[self.idx]
130 if self.idx >= self.count:
131 raise StopIteration
132 self.idx += 1
133 return x, y
136if __name__ == "__main__": 136 ↛ 142line 136 didn't jump to line 142 because the condition on line 136 was never true
138 # for timestamp, temperature in SimulatedTemperature():
139 # print(f"{timestamp = }, {temperature = }")
140 # time.sleep(1.0)
142 import matplotlib.pyplot as plt
144 x, y = _simulate_temperature_data()
146 plt.plot(x, y)
147 plt.show()