Files
gen_data/docs/SPEC.md
T

5.8 KiB
Raw Blame History

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 (unica fonte: questo documento non li ripete). Gruppi: tempi · ambiente (anche baseline di T) · rumore · gradini di riscaldamento e raffreddamento · salti. Nessun valore è scritto nello script: chiave mancante ⇒ errore.

Parametri casuali per corsa: le chiavi scritte come intervallo [min, max] (ambiente amb_inf_c, amb_A_c, amb_tau_s; rumore sigma_c, sigma_caldo_c, wander_*; k_raffreddamento_hz, tau_sensore_s; frequenze e σ dei salti) vengono sorteggiate uniformi a ogni corsa ([x, x] = valore fisso). I gradini sono generati da n_gradini (intero, estremi inclusi, min ≥ 1), t_primo_gradino_s, distanza_gradini_s (tra gradini consecutivi) e dT_gradino_c (ampiezza di ciascuno). Intervallo non valido (non una coppia di numeri, o min > max) ⇒ 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 istante sorteggiato, poi raffreddamento esponenziale);
    • variabilità: a ogni corsa numero, istanti e ampiezze dei gradini, k, ambiente, livelli di rumore e frequenza dei salti sono sorteggiati dagli intervalli di config, quindi curva, picco e rumore cambiano molto 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:

# /// script
# requires-python = ">=3.11"
# dependencies = ["numpy"]
# ///
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 un intervallo [min, max] non è valido 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 60 seed (valori min–max; con parametri sorteggiati gli intervalli sono larghi, ma T e ΔT restano coerenti con ambiente e rumore della corsa):

Controllo Atteso
T a inizio run ≈ T_amb della corsa (20.1 – 26.2 °C)
Rumore a freddo: std(diff(T))/√2 prima del primo gradino (~15 s) 0.06 – 0.19 (segue sigma_c sorteggiato)
Picco di T 66 – 227 °C (dipende da numero e ampiezza dei gradini)
T a fine run ≈ T_amb della corsa: 20.0 – 26.4 °C
ΔT a inizio run ≈ 0 °C (solo rumore): −0.18 – 0.15
ΔT a fine run −0.08 – 1.6 °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.