Documentazione aggiornata: assunzioni A17/A25, limiti, algoritmi, test, output e figura

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
This commit is contained in:
davideandClaude Sonnet 5.5 committed 2026-10-29 11:54:09 +01:00
1 parent b223cf5fdc
commit c37ca1e03d
13 files changed
+241 -144

No files matched your search

+66 -32
View File
@@ -12,11 +12,11 @@ flowchart TD
subgraph P1["PASSO 1 · Domini"]
direction LR
L["<b>1 · Lettura</b><br/>validazione"] --> S["<b>2 · Rumore</b><br/>stima di σ"] --> G["<b>3 · Gradini</b><br/>salti sopra soglia"] --> D["<b>4 · Domini</b><br/>divisione del tempo"]
L["<b>1 · Lettura</b><br/>validazione"] --> S["<b>2 · Rumore</b><br/>stima di σ"] --> G["<b>3 · Gradini</b><br/>salite sopra soglia"] --> D["<b>4 · Domini</b><br/>divisione del tempo"]
end
P1 --> RIP["<b>Riposo</b>"]
P1 --> RIS["<b>Riscaldamento</b><br/>2–3 campioni"]
P1 --> RIS["<b>Riscaldamento</b><br/>2–4 campioni"]
P1 --> INT["<b>Raffreddamenti intermedi</b><br/>tra due gradini, corti"]
P1 --> FIN["<b>Raffreddamento finale</b><br/>l'ultimo, il più lungo"]
@@ -65,12 +65,12 @@ Nelle formule si usano questi simboli; a destra la chiave di [configurazione.md]
| Simbolo | Chiave | Significato |
|---|---|---|
| $\theta_g$ | `soglia_gradino_c` | salto positivo minimo che segna un gradino [°C] |
| $\theta_b$ | `soglia_bordo_sigma` | soglia, in multipli di $\sigma_d$, per estendere la salita ai campioni adiacenti |
| $\theta_g$ | `soglia_gradino_c` | salita complessiva minima che segna un gradino [°C] |
| $\theta_b$ | `soglia_bordo_sigma` | soglia, in multipli di $\sigma_d$, sopra la quale un campione è «in salita» |
| $\theta_\rho$ | `soglia_acf` | soglia di $\rho_1$ oltre la quale si allargano gli intervalli |
| $\kappa$ | `scala_perdita_sigma` | scala della perdita robusta, in multipli di $\sigma$ |
| $\alpha_{\min},\ \alpha_{\max}$ | `tau_min_rel`, `tau_max_rel` | limiti di $\tau$ come frazione di $L$ |
| $\lambda$ | `rmse_vs_rumore_max` | un modello è «adeguato» se $\mathrm{RMSE} \le \lambda\,\sigma$ |
| $\lambda$ | `scala_residui_vs_rumore_max` | un modello è «adeguato» se $\hat\sigma_\text{res} \le \lambda\,\sigma$ (scala robusta dei residui, §5.5) |
| $\delta$ | `soglia_delta_aicc` | tolleranza su $\Delta\mathrm{AICc}$ per preferire il modello più semplice |
| $L$ | — | durata del dominio, $t_\text{ultimo} - t_\text{primo}$ |
| $n$, $k$ | — | campioni usati nel fit; parametri **liberi** del modello |
@@ -90,19 +90,22 @@ deviazione mediana assoluta:
$$\sigma = \frac{1.4826\,\mathrm{MAD}(\Delta^2 y)}{\sqrt{6}}, \qquad \mathrm{MAD}(x) = \mathrm{mediana}\,|x_i - \mathrm{mediana}(x)|$$
Il fattore 1.4826 rende la MAD uguale a $\sigma$ per dati gaussiani. La stima si calcola **per dominio** (A13) sui campioni usati nel fit
e serve come scala della perdita robusta e come soglia di «adeguatezza» (§6). Ignora la deriva lenta (A14) e restituisce `nan` con meno
di 4 campioni.
e serve come scala della perdita robusta e come riferimento per l'«adeguatezza» (§6). Ignora la deriva lenta (A14).
**Servono almeno 8 campioni** (`domini.N_MIN_SIGMA`): con meno, la MAD di pochi $\Delta^2 y$ può annullarsi, perché i valori sono quantizzati e
due $\Delta^2 y$ su tre possono coincidere. Con $\sigma \approx 0$ la scala della perdita robusta diventa quasi nulla, ogni residuo è trattato come
outlier, lo jacobiano pesato tende a zero e gli intervalli di confidenza esplodono (fit scartato come «non identificabile» pur essendo corretto). Sotto 8
campioni $\sigma$ è «non stimabile»: `sigma` vale `null`, la scala della perdita è 1 e l'adeguatezza non è valutabile.
## 3. Rilevamento dei gradini (`domini.trova_gradini`)
Sulla `serie_riferimento`:
Sulla `serie_riferimento`, con $d_i = y_{i+1} - y_i$ e $\sigma_d = 1.4826\,\mathrm{MAD}(d)$ calcolata su **tutti** i salti:
1. **Candidati**: $d_i = y_{i+1} - y_i$; sono forti gli indici con $d_i > \theta_g$ (solo salti positivi, A5, A12).
2. **Raggruppamento**: candidati a meno di `distanza_min_salti_campioni` indici l'uno dall'altro appartengono allo stesso gradino (la salita
si distribuisce su 2 campioni, ognuno con un salto grande).
3. **Estensione ai bordi**: il gruppo si estende all'indietro e in avanti ai campioni adiacenti ancora in salita, cioè finché
$d_i > \theta_b\,\sigma_d$, con $\sigma_d = 1.4826\,\mathrm{MAD}(d)$ calcolata su **tutti** i salti (A6). Serve a
non lasciare un campione a metà salita dentro il tratto vicino.
1. **Campioni in salita**: gli indici con $d_i > \theta_b\,\sigma_d$ (solo salite, A12). Il rumore bianco e la pendenza del raffreddamento restano sotto questa soglia.
2. **Raggruppamento**: i campioni in salita a meno di `distanza_min_salti_campioni` indici l'uno dall'altro formano una **salita** (un gradino si
distribuisce su 2–4 campioni, A6).
3. **Gradino**: una salita è un gradino se la sua **salita complessiva** $y_{\text{ultimo}+1} - y_{\text{primo}}$ supera $\theta_g$ (A5). Si somma su tutta la
salita perché ogni singolo salto può restare sotto soglia: un gradino di 38 °C diviso in 19 + 19 è un gradino, e uno scarto casuale (≤ 4 °C) no.
4. Ogni gradino diventa la coppia $(i_0, i_1)$: $i_0$ è il primo campione già in salita e $i_1$ il campione successivo all'ultimo in salita
(estremo escluso). I **campioni di salita** sono quelli in $[i_0, i_1)$.
@@ -162,6 +165,7 @@ Per i parametri fissi l'incertezza è 0 (A18).
|---|---|
| $\mathrm{RMSE}$ | $\sqrt{\mathrm{RSS}/n}$ |
| $R^2$ | $1 - \mathrm{RSS}/\mathrm{TSS}$, con $\mathrm{TSS} = \sum (y_i - \bar y)^2$ |
| $\hat\sigma_\text{res}$ | **scala robusta dei residui**: $1.4826\,\mathrm{MAD}(r)$, con $r$ i residui. Come la perdita del fit, ignora gli scarti casuali (la RMSE no) |
| $\rho_1$ | autocorrelazione dei residui a lag 1: $\sum_{i} \tilde r_{i+1}\tilde r_i \big/ \sum_i \tilde r_i^2$, con $\tilde r = r - \bar r$ |
| $\mathrm{AICc}$ | $n\ln(\mathrm{RSS}/n) + 2k + \dfrac{2k(k+1)}{n-k-1}$ (infinito se $n-k-1 \le 0$) |
| $\mathrm{BIC}$ | $n\ln(\mathrm{RSS}/n) + k\ln n$ |
@@ -184,37 +188,67 @@ Per A8 i raffreddamenti hanno lo stesso $\tau$ e lo stesso $c$. L'ordine di elab
2. se la scelta è valida, i valori di $c$ e $\tau$ (parametri in `raffreddamento_intermedio_fissa_da_finale`) sono salvati per serie;
3. ogni **raffreddamento intermedio** si fitta con quei valori **fissi**, e solo $A$ libera ($k = 1$).
Motivo: un intermedio ha 12–25 campioni con scarti casuali, e $\tau$ da solo non è identificabile (su dati puliti lo sarebbe: i test lo
verificano). Se il finale non dà un fit valido o la lista è vuota gli intermedi restano liberi.
Motivo: un intermedio ha pochi campioni (da 4 a qualche decina) con scarti casuali, e $\tau$ da solo non è identificabile (su dati puliti lo sarebbe: i test lo
verificano). Con un solo parametro libero bastano pochi campioni: il minimo per questi fit è `n_min_punti_parametri_fissi` (default 4) invece di
`n_min_punti` (6), così anche i tratti tra gradini ravvicinati (1–2 s) si fittano. Se il finale non dà un fit valido o la lista è vuota gli intermedi
restano liberi.
## 6. Scelta del modello (`analisi.scegli`)
Per ogni (dominio, serie) con più modelli candidati:
1. **Scarto**: via i fit non validi (§5.6). Se non ne resta nessuno: `indeterminato`.
2. **Adeguatezza**: sono *adeguati* i fit con $\mathrm{RMSE} \le \lambda\,\sigma$. Se ce n'è almeno uno si sceglie tra questi, altrimenti tra
tutti i validi (e il dominio è segnato *non adeguato*).
2. **Adeguatezza**: sono *adeguati* i fit con $\hat\sigma_\text{res} \le \lambda\,\sigma$ (scala **robusta** dei residui, §5.5). Se ce n'è almeno uno si
sceglie tra questi, altrimenti tra tutti i validi (e il dominio è segnato *non adeguato*). Se $\sigma$ non è stimabile (meno di 8 campioni)
l'adeguatezza non è valutabile (`adeguato` = `null`) e si sceglie tra tutti i validi.
3. **Parsimonia**: tra i candidati con $\mathrm{AICc} \le \mathrm{AICc}_{\min} + \delta$ vince quello con **meno parametri**
(a parità, AICc minore).
Un dominio con meno di `n_min_punti` campioni non viene fittato (`indeterminato`); un modello con più parametri di $n - 2$ non viene provato.
Un dominio con meno di `n_min_punti` campioni (`n_min_punti_parametri_fissi` se $c$ e $\tau$ sono fissi) non viene fittato (`indeterminato`); un modello con più di $n - 2$ parametri **liberi** non viene provato.
Con un solo modello candidato (raffreddamento) la scelta è lui, se valido: il flag *adeguato* resta informativo.
## 7. Riscaldamento come salto (`analisi._gradino`)
*Perché la scala robusta e non la RMSE*: gli scarti casuali del sensore gonfiano la RMSE ($\mathrm{RMSE}/\sigma$ da 1.07 a 5.26 per il modello **giusto**) ma
non la scala robusta ($\hat\sigma_\text{res}/\sigma$ da 0.97 a 1.40 su 120 raffreddamenti finali). Con un modello sbagliato (lineare o costante sullo stesso tratto) la scala
robusta vale da 11 a 100 volte $\sigma$, quindi discrimina bene. Con la RMSE solo il 27 % dei fit corretti risultava «adeguato»; con la scala robusta il 100 %.
Il dominio di riscaldamento ha 2–3 campioni: nessun fit. Si riporta, per ogni serie, con $i_0, i_1$ gli estremi del dominio:
## 7. Riscaldamento come salto (`analisi._gradino`, `analisi._affina_salti`)
$$\Delta = y_{i_1-1} - y_{i_0-1}, \qquad \text{durata} = t_{i_1-1} - t_{i_0-1}$$
Il dominio di riscaldamento ha 2–4 campioni: nessun fit. Per ogni serie si riporta il salto $\Delta$ con due stime.
cioè il salto dal campione **prima** della salita all'ultimo campione di salita, e il tempo che separa i due (per 2 campioni di salita ≈ 2
intervalli, circa 300 ms). Poiché parte della salita può cadere sul campione precedente, $\Delta$ è una stima per difetto dell'ampiezza del
gradino (A23). `sigma` vale `null` e `fit` è vuoto.
**Misura sui campioni** (`delta_misurato`), con $i_0, i_1$ gli estremi del dominio:
## Esempio di calcolo completo (seed 1, `T_C`, raffreddamento finale)
$$\Delta_\text{misurato} = y_{i_1-1} - y_{i_0-1}, \qquad \text{durata} = t_{i_1-1} - t_{i_0-1}$$
1. $n = 651$ campioni da $t_0 = 22.12$ s (dopo `scarta_dopo_salto_n = 1`, 650 usati nel fit); $\sigma = 0.145$ °C.
2. Griglia su $\tau \in [0.05 L,\ 50 L]$ con $L \approx 97.8$ s → $\tau_0$ vicino a 16 s, $c, A$ lineari.
3. Raffinamento `soft_l1` con scala $3\sigma = 0.44$ °C: $c = 23.00 \pm 0.12$, $A = 179.6 \pm 0.48$, $\tau = 16.08 \pm 0.07$ s.
4. Metriche: $\mathrm{RMSE} = 0.356$, $\rho_1 = 0.71$ (> 0.3: intervalli moltiplicati per $\sqrt{1.71/0.29} = 2.43$), $R^2 = 0.9999$.
5. $\mathrm{RMSE} > 1.3 \cdot 0.145 = 0.189$: **non adeguato** (residui autocorrelati per gli scarti casuali), ma unico modello valido → scelto.
6. Gli intermedi 3 e 5 usano $c = 23.00$, $\tau = 16.08$ e stimano solo $A$ ($84.3$ e $148.3$).
cioè dal campione **prima** della salita all'ultimo campione di salita. È una stima **per difetto**: l'ultimo campione di salita ha già cominciato a decadere
(0.3–0.45 s dopo il gradino) e l'errore cresce con la temperatura, fino a ≈ 10 % (A23).
**Stima dai modelli adiacenti** (`delta`, usata quando disponibile). L'istante del gradino $t_s$ è il punto medio tra l'ultimo campione prima della salita e
il primo in salita. Con $f_\text{prima}$ e $f_\text{dopo}$ i modelli scelti per il dominio precedente (riposo o raffreddamento) e per il successivo
(raffreddamento), valutati in $t_s$ con $t' = t - t_0$ del rispettivo dominio:
$$\Delta = f_\text{dopo}(t_s) - f_\text{prima}(t_s)$$
Per due raffreddamenti, che condividono $c$ e $\tau$, equivale a $A_\text{dopo}\,e^{(t_{0,\text{dopo}}-t_s)/\tau} - A_\text{prima}\,e^{-(t_s-t_{0,\text{prima}})/\tau}$.
I campi `da` e `a` sono allora i valori dei due modelli in $t_s$.
**Misura corretta** (se manca un modello adiacente, p.es. un tratto indeterminato, ma c'è il raffreddamento finale). Si riportano i due campioni all'istante del
gradino con la legge di decadimento del finale ($c$ e $\tau$ condivisi):
$$y_\text{prima}^* = c + (y_{i_0-1} - c)\,e^{-(t_s - t_{i_0-1})/\tau}, \qquad y_\text{dopo}^* = c + (y_{i_1-1} - c)\,e^{(t_{i_1-1} - t_s)/\tau}, \qquad \Delta = y_\text{dopo}^* - y_\text{prima}^*$$
**Ripiego finale**: la misura sui campioni, se non c'è nemmeno il raffreddamento finale (gradino senza fit dopo), o se la stima si discosta più del 50 % dalla misura
(guardia contro fit anomali). Il campo `stima` vale `"modelli"`, `"misura corretta"` o `"misura"`; il report mostra sempre anche la misura. `sigma` vale `null` e `fit` è vuoto.
**Accuratezza** (validazione su 60 seed di `gen_data`, [test.md](test.md)): con la stima dai modelli l'errore sull'ampiezza vera del gradino ha media +0.33 %, scarto
quadratico medio 0.86 % e massimo 3.16 % su 124 salti (con `scarta_dopo_salto_n = 0` nessun salto ha richiesto il ripiego). Con la sola misura l'errore medio era −5.5 % e
arrivava a −20 %; la misura corretta, usata da sola, ha errore mediano 1.85 % e massimo 11.9 % (è un ripiego, non un sostituto dei modelli).
## Esempio di calcolo completo (seed 7 di `gen_data`, `T_C`, raffreddamento finale)
1. $n = 620$ campioni da $t_0 = 26.79$ s (`scarta_dopo_salto_n = 0`: tutti usati nel fit); $\sigma = 0.115$ °C.
2. Griglia su $\tau \in [0.05 L,\ 50 L]$ con $L \approx 93$ s → $\tau_0$ vicino a 12 s, $c, A$ lineari.
3. Raffinamento `soft_l1` con scala $3\sigma = 0.35$ °C: $c = 23.92 \pm 0.06$, $A = 163.2 \pm 0.33$, $\tau = 12.12 \pm 0.04$ s (valore vero $\tau = 12.07$ s).
4. Metriche: $\mathrm{RMSE} = 0.247$, $\hat\sigma_\text{res} = 0.159$, $\rho_1 = 0.61$ (> 0.3: intervalli moltiplicati per $\sqrt{1.61/0.39} = 2.03$).
5. $\hat\sigma_\text{res} = 0.159 \le 1.5 \cdot 0.115 = 0.173$: **adeguato**, anche se $\mathrm{RMSE} = 0.247 > 1.5\,\sigma$ per gli scarti casuali (con il vecchio criterio sarebbe stato scartato).
6. Gli intermedi 3 e 5 usano $c = 23.92$, $\tau = 12.12$ e stimano solo $A$ ($76.7$ e $124.5$).
7. Il salto del terzo gradino: misurato $+80.9$, stimato dai modelli $+90.2$ (ampiezza vera $+89.4$).