Files
gen_data/docs/SPEC.md
T

83 lines
5.0 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# 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 · variabilità tra corse · salti.
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);
- **variabilità**: a ogni corsa istanti, ampiezze e `k` dei gradini sono perturbati a caso (σ in `impulsi_jitter_*`, `k_jitter_rel`), quindi la forma cambia con il seed;
- **salti** (stocastici, scarti casuali con rientro `exp(−t/τ)`, come i gradini irregolari osservati su un sensore reale):
durante il **riscaldamento** (tra il primo e l'ultimo gradino) con `salti_risc_*`, ampiezza `N(media, σ²)` nei due versi;
durante il **raffreddamento** (dopo l'ultimo gradino, mentre `x ≥ salti_x_min_c`) con `salti_*`; istanti di tipo Poisson in entrambi i casi; ampiezza limitata a ±`salti_max_c` (niente scarti estremi);
- `T_vera = B + x + salti`.
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 (script unico, ambiente `.venv`)
`genera.py` con dipendenza dichiarata in testa (PEP 723, usata anche da `uv run`); ambiente `.venv` creato con `uv venv` e `uv pip install numpy`:
```python
# /// script
# requires-python = ">=3.11"
# dependencies = ["numpy"]
# ///
```
```bash
python genera.py config.toml --seed 42 # riproducibile -> output/gen_42.csv
python genera.py config.toml -o out.csv # percorso a scelta, seed casuale (stampato su stderr)
python genera.py config.toml -o - > out.csv # stdout
```
Opzioni: `config` (posizionale), `-o/--output` (default `output/gen_<seed>.csv`, cartella creata se manca; `-` = 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 30 seed (valori min–max; picco e `T`/`ΔT` finali dipendono dalla variabilità dei gradini e dai salti):
| Controllo | Atteso |
|---|---|
| `T` a inizio run | ≈ `T_amb` (≈ 22.65 °C) |
| Rumore a freddo: `std(diff(T))/√2` prima del primo gradino (~15 s) | 0.09 – 0.13 |
| Picco di `T` | 197 – 209 °C |
| `T` a fine run | ≈ `T_amb`: 23.1 – 23.7 °C |
| `ΔT` a inizio run | ≈ 0 °C (solo rumore) |
| `ΔT` a fine run | 0.3 – 0.65 °C (residuo del raffreddamento) |
| Intervalli `dt` | tutti in `dt_ms ± jitter_ms` (prima di arrotondare `t_ms` a intero: nel CSV le differenze sono 149–152) |
| 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; i salti durante il raffreddamento sono un modello statistico semplice (rientro esponenziale), non un fenomeno fisico.
- Rumore tarato su un solo sensore: ricalibrare `sigma_c`, `wander_*`, `amb_*` con i propri dati.