11 KiB
Assunzioni
Ogni assunzione ha un identificativo (A1, A2, …) richiamato nel codice e negli altri documenti. Per ognuna: cosa si assume, perché è
ragionevole, dove il codice ne dipende e cosa succede se è falsa. Le assunzioni sul segnale valgono per i dati del generatore
extern/gen_data (sezione finale): su dati reali vanno verificate.
Dati
| ID | Assunzione | Dove | Se è falsa |
|---|---|---|---|
| A1 | Il tempo è strettamente crescente, anche non uniforme (jitter del campionamento) | dati.leggi_csv |
il CSV è rifiutato (exit 4). Il programma non riordina né deduplica |
| A2 | Il CSV ha l'intestazione e tutte le colonne richieste da [dati] (tempo e serie), tutte numeriche, senza celle vuote |
dati.leggi_csv |
exit 4 con il nome della colonna mancante |
| A3 | Il tempo è in ms o s come dichiarato in [dati] unita_tempo |
dati.leggi_csv |
tutti i tempi e le costanti \tau risultano scalati di 1000 senza avvisi: controlla l'unità |
| A4 | Le serie condividono gli stessi domini (stessi istanti di rottura) | analisi.analizza_domini, domini.proponi |
i domini sono cercati solo su serie_riferimento (default T_C); una serie con gradini diversi non è gestita: si lancia l'analisi due volte |
Struttura del segnale
| ID | Assunzione | Dove | Se è falsa |
|---|---|---|---|
| A5 | I gradini di riscaldamento sono salite positive molto più grandi del rumore e degli scarti casuali: la salita complessiva dei campioni consecutivi in salita supera soglia_gradino_c (20 °C), mentre uno scarto casuale è ≤ 4 °C |
domini.trova_gradini |
gradini con salita complessiva sotto la soglia non sono visti (il segnale resta un unico tratto); scarti consecutivi che sommati superano la soglia sono scambiati per gradini. Soluzione: adattare la soglia o correggere domini.toml a mano. La soglia è un valore fisso, non derivato dai dati: misure e alternative in limiti.md |
| A6 | La salita dura pochi campioni (2–4): la costante di tempo del sensore ($\tau_\text{sensore} \approx 0.04$–0.12 s) è dell'ordine dell'intervallo di campionamento (≈ 0.15 s), quindi un gradino si distribuisce su 2–4 campioni, anche ognuno sotto la soglia |
domini.trova_gradini (campioni in salita raggruppati, soglia sulla salita complessiva), analisi._gradino |
con un sensore più lento la salita avrebbe più campioni: sarebbe comunque raggruppata finché ogni salto supera soglia_bordo_sigma\cdot\sigma_d e i campioni in salita distano meno di distanza_min_salti_campioni, ma non sarebbe fittata |
| A7 | Dopo ogni gradino la temperatura decade esponenzialmente verso un asintoto: y = c + A\,e^{-t'/\tau} |
modelli.MODELLI["esp_decad"] |
residui sistematici, ρ₁ alto, «modello non adeguato». Con più processi di raffreddamento servirebbe un modello a più esponenziali (non presente, vedi limiti.md) |
| A8 | Tutti i raffreddamenti hanno la stessa costante di tempo \tau e lo stesso asintoto $c$ (stesso processo fisico: dispersione verso l'ambiente). Anche nel generatore il decadimento dopo più gradini è la somma di esponenziali con lo stesso k, quindi un'unica esponenziale |
analisi.analizza_domini (parametri raffreddamento_intermedio_fissa_da_finale) |
gli intermedi sono forzati a \tau e c del finale: se in realtà differiscono, il fit dell'ampiezza A è distorto e i residui lo mostrano. Per rimuovere il vincolo: raffreddamento_intermedio_fissa_da_finale = [] |
| A9 | Il raffreddamento finale è l'ultimo dominio ed è abbastanza lungo (centinaia di campioni) da stimare c, A, \tau liberamente; i raffreddamenti intermedi, anche di 4–6 campioni, bastano per stimare la sola A con c e \tau fissi (n_min_punti_parametri_fissi) |
analisi.analizza_domini, analisi._serie |
se il CSV finisce subito dopo un gradino, il finale è corto e \tau può risultare non identificabile; allora anche gli intermedi restano liberi (con n_min_punti) e possono essere indeterminati. Tratti intermedi con meno di 4 campioni (gradini a meno di ≈ 1.2 s) restano indeterminati |
| A10 | Il riposo (prima del primo gradino) è una baseline costante, lineare o esponenziale lenta (l'ambiente che si assesta) | [fit.modelli_per_tipo] riposo |
il modello scelto è solo descrittivo: con una deriva lenta vince lineare o esp_decad |
| A11 | Ogni dominio è indipendente: nessun vincolo di continuità tra domini | analisi |
i modelli adiacenti possono non combaciare ai confini; il «salto» tra due raffreddamenti è il gradino |
| A12 | Non esistono gradini discendenti (un calo brusco non è un evento): si cercano solo salti positivi | domini.trova_gradini (d > soglia) |
un calo brusco resterebbe dentro un raffreddamento, aumentando RMSE e \rho_1 |
| A25 | Il ritardo di risposta del sensore ($\tau_\text{sensore} \approx 0.04$–0.12 s) è trascurabile rispetto a \tau del raffreddamento: il modello esp_decad non lo include |
modelli.MODELLI (esp_decad) |
un esponenziale filtrato da un filtro del primo ordine ha lo stesso \tau ma ampiezza moltiplicata per 1/(1-\tau_\text{sensore}/\tau): A risulta sovrastimata di circa \tau_\text{sensore}/\tau \approx 0.5 % (misurato: +0.45 % in media su 60 seed). \tau non è affetta |
Rumore
| ID | Assunzione | Dove | Se è falsa |
|---|---|---|---|
| A13 | Il rumore è circa gaussiano bianco, con \sigma stimabile per dominio da \sigma = 1.4826\,\mathrm{MAD}(\Delta^2 y)/\sqrt{6} su almeno 8 campioni: con meno, la MAD di pochi \Delta^2 y quantizzati può annullarsi |
domini.sigma_rumore (N_MIN_SIGMA) |
\sigma sottostimata: l'adeguatezza è valutata male. Sotto 8 campioni \sigma è «non stimabile» (null): scala della perdita 1, adeguatezza non valutabile. La stima ignora la parte lenta del rumore (vedi A14) |
| A14 | Sul rumore bianco si aggiungono disturbi che il modello non descrive: deriva lenta (Ornstein–Uhlenbeck, \tau \approx 3.5 s) e scarti casuali (±4 °C, rientro < 1 s) |
fit.adatta (perdita robusta), uscita (residui) |
sono trattati come outlier dalla perdita soft_l1 (non spostano molto il fit) ma lasciano residui autocorrelati (\rho_1 \approx 0.7) e intervalli di confidenza troppo stretti. Non è un errore del fit |
| A15 | La quantizzazione (T a 0.01 °C, ambiente a 0.1 °C) è trascurabile rispetto al rumore | — | nessun trattamento specifico |
Statistica
| ID | Assunzione | Dove | Se è falsa |
|---|---|---|---|
| A16 | Gli intervalli al 95 % sono gaussiani asintotici: \pm 1.96\,\sigma_p con \mathrm{cov} = s^2 (J^\top J)^{-1}, s^2 = \mathrm{RSS}/(n-k) |
fit.adatta |
con pochi campioni o residui non gaussiani sono approssimati |
| A17 | L'autocorrelazione dei residui è di tipo AR(1): gli errori si allargano di \sqrt{(1+\rho_1)/(1-\rho_1)} se \rho_1 supera soglia_acf |
fit.adatta |
approssimazione insufficiente: su 60 seed il \tau vero cade nell'intervallo al 95 % nel 73 % dei casi. La deviazione standard dell'errore su \tau è 3.7 volte l'errore standard non corretto, perché gli scarti casuali sono concentrati all'inizio del raffreddamento (dove la sensibilità a \tau è massima), quindi non stazionari. Provate e scartate: correzione a più lag di Bartlett (77 %) e stimatore sandwich HAC (≤ 62 %). Vedi limiti.md |
| A18 | Per i parametri fissi l'incertezza non si propaga: gli intervalli di A nei raffreddamenti intermedi sono condizionati a c e \tau del finale |
fit.adatta, uscita._params |
sono sottostimati rispetto all'incertezza totale |
| A19 | AICc e BIC si calcolano da \mathrm{RSS} come se i residui fossero gaussiani, anche se il fit usa la perdita robusta |
fit.adatta |
confronto tra modelli approssimato; sensibile agli outlier |
| A20 | Se \sigma non è stimabile (meno di 8 campioni, o nulla) la scala della perdita robusta è 1 e l'adeguatezza non è valutabile |
fit.adatta, analisi.scegli |
solo robustezza ridotta; il fit resta valido |
Progetto
| ID | Assunzione | Dove |
|---|---|---|
| A21 | La suddivisione in domini la decide l'utente: la proposta automatica è modificabile (domini.toml) e il fit non la cambia mai |
cli._passo_domini, domini.leggi_toml |
| A22 | Il programma è deterministico: nessuna partenza casuale, nessun seme | fit._partenza (griglia su \tau, minimi quadrati lineari) |
| A23 | Il riscaldamento non si fitta (2–4 campioni). Il salto \Delta si stima nell'ordine da: modelli dei domini adiacenti valutati all'istante del gradino; misura riportata a quell'istante con c e \tau del raffreddamento finale; misura sui campioni (y_\text{fine salita} - y_\text{prima}), che è per difetto (fino a ≈ 10–20 %: parte della salita cade sul campione precedente e l'ultimo campione è già decaduto) |
analisi._gradino, analisi._affina_salti |
| A24 | I modelli provati sono fissati per tipo di dominio in configurazione, non scelti dal programma | [fit.modelli_per_tipo] |
Origine dei dati di prova (extern/gen_data)
I CSV di prova si generano con extern/gen_data, che a ogni corsa (seed) sorteggia i parametri da intervalli: ogni seed è un segnale diverso
(dettaglio: extern/gen_data/docs/SPEC.md e extern/gen_data/config.toml). Gli intervalli che fondano le assunzioni sopra:
| Aspetto | Valore nel generatore | Assunzioni |
|---|---|---|
| intervallo di campionamento | 150.5 ms con jitter ±0.6 ms (fisso) | A1, A6 |
| numero e istanti dei gradini | 1–3; il primo a 8–25 s, distanza tra gradini 1–6 s | A5, A9 |
| ampiezza dei gradini | 40–90 °C | A5, A7 |
| raffreddamento | $k = 0.05$–0.09\ \mathrm{s^{-1}}, cioè $ au = 1/k = 11$–20 s |
A7, A8 |
| risposta del sensore | filtro del primo ordine, $ au_ ext{sensore} = 0.04$–0.12 s |
A6 |
| rumore bianco | $\sigma = 0.06$–0.16 °C a freddo, $0.15$–0.30 a caldo |
A13 |
| deriva lenta | Ornstein–Uhlenbeck, $\sigma = 0.02$–0.08 °C, $ au = 2$–6 s |
A14 |
| scarti casuali | in riscaldamento: 0.4–1.2 Hz, \sigma 1.5–3.5 °C, rientro 0.3 s; in raffreddamento: 0.1–0.5 Hz, media −1 °C, \sigma 1.5–3.5 °C, rientro 0.7 s; ampiezza ≤ 4 °C |
A5, A14 |
| ambiente | 20–26 °C a regime, deriva iniziale ±0.8 °C con au 30–90 s; non sale quando T è alta |
A10; c di dT_C ≈ 0 |
dT_C |
T - T_\text{amb} calcolato dopo rumore e quantizzazione di entrambi i canali |
A4 |
Poiché il sorteggio è riproducibile dal seed (genera.sorteggia), per ogni seed si conoscono i valori veri (gradini, ampiezze, \tau): il test
tests/test_validazione.py li confronta con i risultati di fitseg su 20 seed (test.md).