| **Validazione** | `test_validazione` | 20 seed generati al volo da `extern/gen_data`, confrontati con i suoi **parametri veri** | `extern/gen_data`, da scaricare con `./scarica_gen_data.sh` (altrimenti i test sono saltati) |
(il gradino è un solo campione). La verità è nota, quindi si controllano i parametri recuperati. `segnale(...)` accetta rumore, seme, gradini e durata per
costruire casi particolari; `scrivi_csv(...)` scrive un CSV nel formato di `gen_data`. `dT_C` = $T - T_\text{amb}$. Fixture: `cfg` (config reale), `sintetico`.
`extern/gen_data` sorteggia a ogni seed i parametri di una corsa (numero e istanti dei gradini, ampiezze, $k$, rumore, scarti: [assunzioni.md](assunzioni.md), «Origine dei dati di
prova»). Poiché il sorteggio è riproducibile (`genera.sorteggia(cfg, default_rng(seed))`), per ogni seed si conoscono i valori veri. Il test, per i seed 1–20,
genera il CSV, lancia l'analisi e controlla:
| Controllo | Tolleranza | Osservato su 60 seed |
|---|---|---|
| numero di gradini trovati = numero vero | esatto | 60/60 |
| istante di ogni gradino | < 0.3 s (due campioni) | ≤ 0.15 s |
| $\tau$ del raffreddamento finale ($\tau\cdot k = 1$) | ± 3 % | massimo 1.99 %, scarto quadratico medio 0.39 % |
| ampiezza $A$ di ogni raffreddamento (su `dT_C`) = somma dei decadimenti dei gradini precedenti | ± 4 % | massimo 2.14 %, media +0.45 % (ritardo del sensore, A25) |
| salto $\Delta$ stimato (modelli o misura corretta) = ampiezza vera del gradino | ± 5 % | massimo 3.16 %, media +0.33 % (124 salti, tutti dai modelli) |
| un raffreddamento è indeterminato solo se ha meno campioni del minimo con parametri fissi | esatto | nessun caso |
Misure fatte per decidere, non verificate dal test: il $\tau$ vero cade nell'intervallo al 95 % nel 73 % dei casi ([limiti.md](limiti.md)); la scala robusta dei residui del
modello giusto è 0.97–1.40 volte $\sigma$ su 120 raffreddamenti finali. Le tolleranze lasciano margine: se un seed nuovo le supera è un segnale di regressione o di un caso non coperto.
| `test_gradino_distribuito_su_due_campioni_sotto_soglia` | salita di 38 °C divisa in 19 + 19: nessun salto supera la soglia ma la salita complessiva sì → è un gradino |
| `test_salita_complessiva_sotto_soglia_non_e_un_gradino` | 16 °C in due campioni (< 20) → nessun gradino |
| `test_tau_libero_non_identificabile_su_tratto_corto_e_rumoroso` (5 seed) | su 3 s con disturbi di 2 °C, $\tau$ libero è «non identificabile» (motivo del fissaggio) |
| `test_analisi_completa_sintetico` | 7 domini; finale con $\tau$ entro il 3 % e nessun parametro fisso; intermedi con `c`, `tau` fissi uguali al finale e $A$ entro il 5 % |
| `test_salto_con_tratto_adiacente_indeterminato_usa_la_misura_corretta` | tratto intermedio indeterminato: `stima` = `misura corretta`, più vicina al vero della misura e entro il 3 % |
| `test_raffreddamento_corto_con_parametri_fissi_si_fitta` | tratto intermedio sotto `n_min_punti` ma sopra il minimo con parametri fissi: fittato, $A$ entro il 3 % |
| `test_troppo_corto_anche_per_i_parametri_fissi` | tratto di 1–2 campioni → indeterminato, il motivo cita `n_min_punti_parametri_fissi` |
| `test_dati_non_finiti_non_convergono_senza_eccezioni` | `NaN` in `y` → ogni modello restituisce `convergenza` falsa, senza eccezioni (regressione: `TypeError`) |
Su fit finti: vince il modello con meno parametri entro $\Delta\mathrm{AICc}$; vince il migliore oltre la soglia; si scartano non convergenti, a limite, non identificabili; nessun valido
→ indeterminato; si preferiscono i modelli adeguati (scala robusta dei residui) anche con AICc peggiore; l'adeguatezza usa la scala robusta e non la RMSE; nessun adeguato → scelto
ma segnalato (`adeguato` = `false`); σ non stimabile → adeguatezza non valutabile (`null`); il motivo cita la parsimonia solo se ci sono più modelli equivalenti.
`config.toml` reale valido; chiave mancante; lista dei modelli vuota per un tipo; file di configurazione inesistente; CSV valido (conversione ms → s); colonna
Su CSV sintetici: nessun «indeterminato: indeterminato» e il motivo cita il minimo; `risultati.json` è JSON valido anche con domini indeterminati (nessun NaN, `sigma``null`); `_senza_nan`; la scala robusta dei residui è nel report; nessun $R^2 = -0.0000$ e nessun $R^2$ per `costante`; intervallo del dominio
$t_0 \le t \le t_1$; salto «stimato dai modelli adiacenti (misurato sui campioni: …)»; motivo senza clausola di parsimonia con un solo modello; il grafico di un
dominio indeterminato ha un solo pannello (senza residui); equazione `lineare` con segno; salto «misurato sui campioni»; grafici con campioni esclusi (`scarta_dopo_salto_n` > 0) e modelli alternativi tratteggiati.
`fitseg domini` scrive solo `01_domini/`; `analizza --domini` (domini corretti a mano) scrive sovrapposizione e report, che rimanda alle immagini giuste e ha le formule
principali in LaTeX con i `$` bilanciati su ogni riga; CSV inesistente o senza dati → exit 4; configurazione inesistente → exit 3; `domini.toml` non contiguo o inesistente → exit 6.