Files
EquationMiner/docs/algoritmi.md
T
davideandClaude Sonnet 5.5 f28bddc5a2 Documentazione completa in docs/: assunzioni, algoritmi, moduli, configurazione, output, test, limiti
- docs/SPEC.md sostituito da un file per argomento (indice in docs/README.md)
- assunzioni A1-A24 con dove nel codice e cosa succede se false
- formule in LaTeX corrette (nessuno spazio prima del dollaro di chiusura), simboli e chiavi in tabella
- diagrammi Mermaid per il flusso degli algoritmi e le dipendenze dei moduli
- figura dei domini sul seed 1 (docs/img/domini_esempio.png)
- README ridotto a indice con avvio rapido; CLAUDE.md e docstring allineati

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
2026-10-29 10:44:41 +01:00

12 KiB
Raw Blame History

Algoritmi

Tutti i passi, nell'ordine in cui il programma li esegue. Le assunzioni richiamate (A1, A2, …) sono in assunzioni.md; le chiavi di configurazione (in_questo_formato) in configurazione.md; il modulo che implementa ogni passo in moduli.md.

Visione d'insieme

flowchart TD
    CSV(["CSV in input/"]) --> P1

    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"]
    end

    P1 --> RIP["<b>Riposo</b>"]
    P1 --> RIS["<b>Riscaldamento</b><br/>2–3 campioni"]
    P1 --> INT["<b>Raffreddamenti intermedi</b><br/>tra due gradini, corti"]
    P1 --> FIN["<b>Raffreddamento finale</b><br/>l'ultimo, il più lungo"]

    subgraph P2["PASSO 2 · Equazioni"]
        direction TB
        F0["<b>5 · Fit</b><br/>costante, lineare,<br/>esponenziale"]
        F1["<b>5 · Fit esponenziale</b><br/>c, A, τ liberi"]
        F2["<b>5b · Fit esponenziale</b><br/>c e τ fissi, solo A libera"]
        SALTO["<b>7 · Salto Δ</b><br/>descritto, non fittato"]
        SC["<b>6 · Scelta del modello</b><br/>validi → adeguati → meno parametri"]
        F0 --> SC
        F1 --> SC
        F2 --> SC
    end

    RIP --> F0
    FIN --> F1
    INT --> F2
    RIS --> SALTO
    F1 -. "passa c, τ" .-> F2

    SC --> REP
    SALTO --> REP
    REP(["<b>PASSO 3</b> · Sovrapposizione e report<br/>dati grezzi contro equazioni<br/>report.md · grafici · risultati.json"])

    classDef dato fill:#eceff1,stroke:#607d8b,color:#263238
    classDef calcolo fill:#e3f2fd,stroke:#1a73e8,color:#0d47a1
    classDef dominio fill:#fff8e1,stroke:#f9a825,color:#5d4037
    classDef uscita fill:#e8f5e9,stroke:#2e7d32,color:#1b5e20
    class CSV dato
    class L,S,G,D,F0,F1,F2,SC,SALTO calcolo
    class RIP,RIS,INT,FIN dominio
    class REP uscita

    linkStyle 15 stroke:#e65100,stroke-width:2px,color:#e65100

Come si legge: dall'alto in basso. I numeri nei riquadri sono i paragrafi di questo documento. Colori: grigio dati, azzurro calcoli, giallo tipi di dominio, verde risultati. Il Passo 1 produce i domini; ogni tipo ha il suo trattamento nel Passo 2; la freccia arancione tratteggiata indica che il raffreddamento finale passa c e \tau ai raffreddamenti intermedi (§5b), per questo si elabora per primo. Il riscaldamento non si fitta: se ne riporta il salto (§7).

Simboli e chiavi di configurazione

Nelle formule si usano questi simboli; a destra la chiave di configurazione.md con il valore.

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_\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
\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

1. Lettura dei dati (dati.leggi_csv)

Legge l'intestazione, controlla che ci siano la colonna del tempo e tutte le serie (A2), converte il tempo in secondi (A3) e verifica che sia strettamente crescente (A1). Restituisce t (array in secondi) e un dizionario serie {nome: array}.

2. Stima del rumore (domini.sigma_rumore)

Per un rumore bianco \varepsilon_i di deviazione \sigma, la derivata seconda discreta \Delta^2 y_i = y_{i+2} - 2y_{i+1} + y_i elimina le componenti lisce (costante, lineare, e in buona parte l'esponenziale) e ha varianza 6\sigma^2. Per renderla robusta agli outlier si usa la 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.

3. Rilevamento dei gradini (domini.trova_gradini)

Sulla serie_riferimento:

  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.
  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).

4. Costruzione dei domini (domini.proponi)

Dati N gradini, in ordine di tempo:

  • riposo: dall'inizio al primo gradino (o tutto il segnale se non ci sono gradini);
  • per ogni gradino: un dominio riscaldamento sui suoi campioni di salita, seguito da un dominio raffreddamento fino al gradino successivo (o alla fine). Un raffreddamento senza campioni (gradini adiacenti) non viene creato.

Con N gradini i domini sono quindi 1 + 2N. I domini sono contigui e coprono tutti i campioni. L'utente può sostituire la proposta con domini.toml (A21), che viene validato: tipi ammessi, intervalli non vuoti, contiguità.

5. Fit (fit.adatta)

5.1 Modelli (modelli.MODELLI, t' = t - t_0)

Modello Equazione Parametri Dove si prova
costante y = a a riposo
lineare y = a + b\,t' a, b riposo
esp_decad y = c + A\,e^{-t'/\tau} c, A, \tau riposo, raffreddamento

Nel raffreddamento c è l'asintoto (≈ ambiente per T_C, ≈ 0 per dT_C), A l'ampiezza a t'=0 e \tau = 1/k la costante di tempo.

5.2 Partenza

  • Polinomi (costante, lineare): soluzione dei minimi quadrati lineari.
  • esp_decad: proiezione delle variabili. Per \tau fissato il modello è lineare in (c, A). Si provano n_griglia_tau valori di \tau su una griglia logaritmica tra \alpha_{\min} L e \alpha_{\max} L, per ognuno si risolvono (c, A) in modo lineare e si tiene il \tau con \mathrm{RSS} minima. Poi il raffinamento non lineare parte da lì: nessuna partenza casuale (A22).
  • Se c e \tau sono fissi e solo A è libero: A = \sum (y - c)\,e^{-t'/\tau} \big/ \sum e^{-2t'/\tau}.

5.3 Minimizzazione

scipy.optimize.least_squares sui soli parametri liberi, con x_scale="jac", limiti \tau \in [\alpha_{\min} L,\ \alpha_{\max} L] e perdita robusta (perdita, default soft_l1):

\min_p \sum_i \rho\!\left(\frac{r_i^2}{s^2}\right), \quad \rho(z) = 2\left(\sqrt{1+z}-1\right), \quad s = \kappa\,\sigma, \quad r_i = f(t'_i; p) - y_i

Per |r_i| \ll s si comporta come i minimi quadrati; per |r_i| \gg s cresce linearmente, così gli scarti casuali pesano molto meno (A14). Se \sigma non è finita o è nulla la scala è 1 (A20).

5.4 Incertezze

s^2 = \frac{\mathrm{RSS}}{n-k}, \qquad \mathrm{cov}(p) = s^2\,(J^\top J)^{-1}, \qquad \mathrm{IC}_{95\%} = \pm 1.96\,\sqrt{\mathrm{diag}(\mathrm{cov})}\cdot f_\rho

k è il numero di parametri liberi, J lo jacobiano dei residui nella soluzione (con la pseudo-inversa di J^\top J), \mathrm{RSS} = \sum r_i^2 (A16). Il fattore di autocorrelazione vale f_\rho = \sqrt{(1+\rho_1)/(1-\rho_1)} se correggi_autocorrelazione è attivo e \rho_1 > \theta_\rho, altrimenti 1 (A17). Per i parametri fissi l'incertezza è 0 (A18).

5.5 Metriche

Metrica Definizione
\mathrm{RMSE} \sqrt{\mathrm{RSS}/n}
R^2 1 - \mathrm{RSS}/\mathrm{TSS}, con \mathrm{TSS} = \sum (y_i - \bar y)^2
\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
condizione numero di condizione di J con le colonne normalizzate in norma euclidea

AICc e BIC sono calcolati da \mathrm{RSS}, quindi senza peso robusto (A19).

5.6 Validità e identificabilità

Un fit è valido se converge, nessun parametro libero è sul limite (distanza dal limite inferiore a 10^{-3} volte il limite stesso: \tau al bordo della griglia), il numero di condizione non supera soglia_condizione e l'AICc è finito. Un fit è non identificabile se la condizione supera la soglia oppure un parametro libero diverso da a e c ha 1.96\,\sigma_p > |p| (intervallo che include lo zero: il parametro non è distinguibile da 0).

5b. Costanti condivise (analisi.analizza_domini)

Per A8 i raffreddamenti hanno lo stesso \tau e lo stesso c. L'ordine di elaborazione è quindi:

  1. il raffreddamento finale (ultimo dominio di tipo raffreddamento) si fitta per primo con c, A, \tau liberi;
  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.

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).
  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. Con un solo modello candidato (raffreddamento) la scelta è lui, se valido: il flag adeguato resta informativo.

7. Riscaldamento come salto (analisi._gradino)

Il dominio di riscaldamento ha 2–3 campioni: nessun fit. Si riporta, per ogni serie, con i_0, i_1 gli estremi del dominio:

\Delta = y_{i_1-1} - y_{i_0-1}, \qquad \text{durata} = t_{i_1-1} - t_{i_0-1}

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.

Esempio di calcolo completo (seed 1, T_C, raffreddamento finale)

  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).