79 lines
3.9 KiB
Markdown
79 lines
3.9 KiB
Markdown
# Generatore CSV `T` e `ΔT` con rumore realistico — specifica minima
|
||
|
||
**Obiettivo**: un solo script, un solo file di configurazione, un CSV con la temperatura `T` e la differenza `ΔT = T − T_amb`,
|
||
con rumore, quantizzazione e jitter dei tempi simili a un sensore IR reale.
|
||
|
||
**Assunzione da confermare**: `T` = temperatura oggetto del sensore IR, `T_amb` = temperatura ambiente dello stesso sensore
|
||
(non scritta nel CSV, serve solo per `ΔT`).
|
||
|
||
## 1. Output
|
||
|
||
```
|
||
t_ms,T_C,dT_C
|
||
150,24.50,1.80
|
||
301,24.41,1.71
|
||
```
|
||
- `t_ms`: intero; `T_C`, `dT_C`: due decimali (`passo_T_c`). Separatore `,`, fine riga `\n`.
|
||
- `ΔT` è calcolato **dopo** rumore e quantizzazione di entrambi i canali, quindi eredita il passo a gradini dell'ambiente.
|
||
|
||
## 2. Configurazione
|
||
|
||
Tutti i valori sono in [`config.toml`](../config.toml) (unica fonte: questo documento non li ripete). Gruppi:
|
||
tempi · ambiente (anche baseline di T) · rumore · gradini di riscaldamento e raffreddamento.
|
||
Nessun valore è scritto nello script: chiave mancante ⇒ errore.
|
||
|
||
## 3. Modello (5 passi)
|
||
|
||
1. **Tempi**: `t_i = t_{i−1} + dt_ms + U(−jitter_ms, +jitter_ms)`, fino a `durata_s`.
|
||
2. **T vera** = ambiente vero + eccesso termico (T parte da `T_amb`, sale con i gradini e ridiscende fino a `T_amb`):
|
||
- ambiente vero `B(t) = amb_inf + amb_A·exp(−t/τ_amb)` (stessa curva del passo 5, senza rumore né quantizzazione);
|
||
- eccesso `x(t) = Σ_j ΔT_j · exp(−k·(t − t_j))` per `t ≥ t_j` (un gradino per ogni `t_impulsi_s`, poi raffreddamento esponenziale);
|
||
- `T_vera = B + x`.
|
||
3. **Risposta del sensore**: filtro del 1° ordine `y' = (T_vera − y)/τ_sens` (griglia fine, 5 ms, poi interpolazione ai `t_i`).
|
||
4. **Rumore di T**: `T_i = y_i + w_i + σ(x_i)·N(0,1)`, con
|
||
- `σ(x) = σ + (σ_caldo − σ)·min(1, x/x_rif)`;
|
||
- `w` = deriva lenta (Ornstein-Uhlenbeck): `w_{i+1} = φ·w_i + σ_w·√(1−φ²)·N(0,1)`, `φ = exp(−Δt/τ_w)`.
|
||
Poi arrotondamento a `passo_T_c`.
|
||
5. **Ambiente e ΔT**: `amb_i = round_{amb_passo}( amb_inf + amb_A·exp(−t/τ_amb) + N(0, amb_sigma²) )`; `dT_i = round_{passo}( T_i − amb_i )`.
|
||
|
||
## 4. Uso con uv (un solo file, nessun progetto)
|
||
|
||
`genera.py` con dipendenza dichiarata in testa (PEP 723):
|
||
```python
|
||
# /// script
|
||
# requires-python = ">=3.11"
|
||
# dependencies = ["numpy"]
|
||
# ///
|
||
```
|
||
```bash
|
||
uv run genera.py config.toml -o out.csv --seed 42 # riproducibile
|
||
uv run genera.py config.toml > out.csv # seed casuale, stampato su stderr
|
||
```
|
||
Opzioni: `config` (posizionale), `-o/--output` (default stdout), `--seed` (default: casuale, stampato su stderr).
|
||
Uscita con errore (exit 1) e messaggio in italiano se manca una chiave, se `t_impulsi_s` e `dT_impulsi_c` hanno lunghezze diverse
|
||
o se il file non è scrivibile. La lettura TOML usa `tomllib` (standard library): unica dipendenza esterna `numpy`.
|
||
|
||
## 5. Controlli di accettazione (con la configurazione d'esempio)
|
||
|
||
Verificati su un prototipo (30 seed):
|
||
|
||
| Controllo | Atteso |
|
||
|---|---|
|
||
| `T` a inizio run | ≈ `T_amb` (≈ 22.65 °C) |
|
||
| Rumore a freddo: `std(diff(T))/√2` sui primi ~100 s | 0.105 – 0.115 |
|
||
| Picco di `T` | ≈ 224 °C (da ricontrollare col prototipo) |
|
||
| `T` a 134 s | ≈ 80.5 °C |
|
||
| `T` a fine run | ≈ `T_amb` (≈ 23.1 °C, entro ~0.1 °C) |
|
||
| `ΔT` a inizio run | ≈ 0 °C (solo rumore) |
|
||
| `ΔT` a fine run | ≈ 0 °C (solo rumore) |
|
||
| Intervalli `dt` | tutti in `dt_ms ± jitter_ms` |
|
||
| Stesso `--seed` e stessa config | file identico |
|
||
|
||
## 6. Limiti (accettati per semplicità)
|
||
|
||
- Un solo tempo di raffreddamento esponenziale (nessuna distinzione conduzione/convezione).
|
||
- Gradini istantanei (nessun transito sotto l'induttore e nessuna dipendenza dalla velocità).
|
||
- L'ambiente non sale quando T è alta (nessun riscaldamento dell'ambiente del sensore): `ΔT` è leggermente sovrastimato durante e subito dopo il riscaldamento.
|
||
- Nessun glitch di campionamento né disturbi a salto durante il raffreddamento.
|
||
- Rumore tarato su un solo sensore: ricalibrare `sigma_c`, `wander_*`, `amb_*` con i propri dati.
|