Files
EquationMiner/docs/SPEC.md
T
davideandClaude Sonnet 5.5 b8c8aeb60e Riscaldamento e raffreddamento esponenziali con c e tau condivisi; grafici per dominio nel report
- modelli per tipo di dominio ([fit.modelli_per_tipo])
- nei domini di riscaldamento c e tau fissati ai valori del raffreddamento
- un grafico dati/modelli per dominio e serie, incorporato in report.md

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

130 lines
8.7 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# `fitseg` — domini di riscaldamento/raffreddamento e equazione per ciascuno — specifica
**Obiettivo**: leggere un CSV (`t_ms,T_C,dT_C`, p.es. prodotto da `gen_data`), riconoscere quando c'è **riscaldamento** (flusso in
entrata: gradini di temperatura) e quando c'è **raffreddamento**, dividere il tempo in **domini**, e per ogni (dominio, serie)
trovare con minimi quadrati non lineari l'equazione che approssima meglio i dati. Valori configurabili: solo in
[`config.toml`](../config.toml). Uso pratico: [USO.md](USO.md).
## 1. Stato di implementazione
| Parte | Stato |
|---|---|
| Riconoscimento dei domini (§3), fit (§5), regola di scelta (§5.3), report, grafici, `valuta` | **implementato** (`src/fitseg/`) |
| Modifica manuale dei domini (`domini.toml` + `analizza --domini`) | **implementato** (senza editor interattivo) |
| PELT/fusione BIC per cambi di regime non legati ai gradini | **eliminato**: i domini derivano dai gradini di riscaldamento (§3) |
## 2. Flusso
```
CSV ─► [1 DOMINI] gradini ⇒ riposo | riscaldamento… | raffreddamento ─► lavoro/domini.toml (modificabile)
▼
[2 FIT] per ogni (dominio, serie): tutti i modelli abilitati ─► regola di scelta ─► lavoro/out/
▼
[3 RIEPILOGO] report.md, equazioni.md, modello_finale.json, risultati.json, fit_<serie>.png
```
Il **motore Python** fa tutti i calcoli (deterministici, seed in config); la scelta del modello segue una regola automatica (§5.3).
## 3. Domini (`fitseg domini`)
Struttura fisica del segnale (vedi `gen_data/docs/SPEC.md`): T parte dall'ambiente, **gradini istantanei positivi** (riscaldamento,
2–4 s uno dall'altro) ognuno seguito da un decadimento esponenziale; dopo l'ultimo gradino resta solo il **raffreddamento**
esponenziale verso l'ambiente. Durante il riscaldamento e il raffreddamento compaiono anche scarti casuali (±4 °C, rientro < 1 s).
Algoritmo (nessun LLM), sulla serie `serie_riferimento`:
1. `d = diff(y)`; gradino = `d > soglia_gradino_c`; rilevazioni più vicine di `distanza_min_salti_campioni` sono lo stesso gradino.
2. Il gradino parte dal primo campione già in salita: si arretra finché `d > soglia_bordo_sigma · σ_d` (σ_d = MAD dei salti). Quel
campione apre il nuovo dominio; i primi `scarta_dopo_salto_n` campioni del dominio sono esclusi dal fit (transizione del sensore).
3. Tipi: prima del primo gradino `riposo`; tra due gradini `riscaldamento`; dopo l'ultimo `raffreddamento`. Senza gradini: un solo `riposo`.
Ipotesi: tempo crescente (H1); rumore circa gaussiano con σ stimato per dominio da `1.4826·MAD(d²y)/√6` (H2); le serie condividono i
domini (H3); i gradini sono salti positivi ≫ rumore e scarti casuali (H4, `soglia_gradino_c` ≫ `salti_max_c` del generatore).
`domini.toml` (scritto in `lavoro/`, modificabile; `analizza --domini FILE` lo usa al posto della proposta):
```toml
[[dominio]]
tipo = "riscaldamento" # riposo | riscaldamento | raffreddamento
t0_s = 15.8 # incluso
t1_s = 17.76 # escluso (ultimo dominio: fino a fine dati)
```
I domini devono essere contigui; in caso contrario exit 6.
## 4. Modelli (`modelli.py`, t' = t − t0 del dominio)
| Id | Equazione | Parametri |
|---|---|---|
| `costante` | `y = a` | a |
| `lineare` | `y = a + b·t'` | a, b |
| `quadratico` | `y = a + b·t' + c·t'²` | a, b, c |
| `esp_decad` | `y = c + A·exp(−t'/τ)` | c, A, τ |
| `esp_doppio` | `y = c + A1·exp(−t'/τ1) + A2·exp(−t'/τ2)`, τ1 < τ2 | c, A1, τ1, A2, τ2 |
| `logistica` | `y = c + A / (1 + exp(−(t'−t_m)/w))`, 0 ≤ t_m ≤ L | c, A, t_m, w |
Nuovo modello = nuova voce nel registro `MODELLI` e nuova riga qui. I modelli provati dipendono dal tipo di dominio (`[fit.modelli_per_tipo]`): `riposo` → `costante`, `lineare`, `esp_decad`; `riscaldamento` e `raffreddamento` → solo `esp_decad` (sono decadimenti esponenziali). Nel raffreddamento `c` è la temperatura asintotica (≈ ambiente) e
`τ = 1/k`; nel riposo `costante`/`lineare` descrivono la baseline.
## 5. Fit
1. Dati del dominio senza i primi `scarta_dopo_salto_n` campioni (se non `riposo`); tempo traslato.
2. Partenze: lineari per i polinomi; **proiezione delle variabili** per `esp_decad`/`esp_doppio` (griglia log-spaziata su τ tra
`tau_min_rel·L` e `tau_max_rel·L`, L = durata, ampiezze per minimi quadrati lineari); `n_start` partenze casuali per `logistica`.
3. `scipy.optimize.least_squares` con perdita `perdita` (robusta `soft_l1`, scala `scala_perdita_sigma·σ`) e limiti sui parametri.
4. Incertezze: `s²(JᵀJ)⁻¹`, IC 95 % = ±1.96σ_p; con `correggi_autocorrelazione` e ACF1 > `soglia_acf` moltiplicate per `√((1+ρ)/(1−ρ))`.
5. Metriche: RSS, RMSE, R², AICc, BIC, ACF1 dei residui, parametri a limite, numero di condizione (jacobiano normalizzato).
**Non identificabile** se condizione > `soglia_condizione` oppure un parametro (escluso il primo) ha IC 95 % > |valore|.
### 5.2 Costanti condivise tra riscaldamento e raffreddamento
Dopo ogni gradino la temperatura decade con la stessa legge del raffreddamento finale (stessa costante di tempo, stesso asintoto ≈ ambiente).
I domini di raffreddamento si fittano per primi; nei domini di riscaldamento i parametri di `riscaldamento_fissa_da_raffreddamento`
(default `c` e `tau`) sono **fissati** ai valori del raffreddamento e resta libera solo l'ampiezza `A`. Motivo: in 2–4 s di dati τ non si
identifica da solo. Gli IC 95 % di `A` sono condizionati ai valori fissi (l'incertezza di `c` e `τ` non si propaga); i parametri fissi sono
marcati "(fisso)" nel report. Se manca un raffreddamento valido, o la lista è vuota, i parametri restano liberi. Con `[]` si torna al fit libero.
### 5.3 Regola di scelta (`selezione.py`)
Scarta non convergenti, con parametri a limite o non identificabili. Se esistono modelli con `RMSE ≤ rmse_vs_rumore_max·σ` ("adeguati")
si sceglie tra questi, altrimenti tra tutti i validi; tra i modelli entro `soglia_delta_aicc` dal miglior AICc vince quello con meno
parametri. Se nessun modello è valido il dominio è **indeterminato**; un dominio con meno di `n_min_punti` campioni non viene
fittato. Un modello scelto ma con RMSE > soglia·σ è segnalato come **non adeguato** nel report.
## 6. CLI
| Comando | Funzione |
|---|---|
| `fitseg domini CSV` | Propone i domini, stampa la tabella, scrive `lavoro/domini.toml` |
| `fitseg analizza CSV [--domini FILE]` | Domini + fit + scelta + report in `lavoro/out/` |
| `fitseg modelli` | Elenca il catalogo |
| `fitseg valuta modello_finale.json --t 12.5 …` | Valuta il modello a tratti agli istanti dati (NaN se indeterminato) |
Opzioni globali (prima del sottocomando): `--config PATH` (default `config.toml`), `--lavoro DIR`.
Exit code: 0 ok · 2 uso errato · 3 config non valida · 4 CSV illeggibile · 6 domini non validi.
## 7. File in `lavoro/`
| File | Contenuto |
|---|---|
| `domini.toml` | proposta (o input) dei domini |
| `dati.csv` | copia del CSV analizzato |
| `out/risultati.json` | tutti i fit per (dominio, serie), con metriche e scelta |
| `out/modello_finale.json` | per dominio e serie: modello scelto e parametri |
| `out/report.md`, `out/equazioni.md` | tabelle di confronto, equazioni con IC 95 % |
| `out/fit_<serie>.png` | panoramica: dati, fit a tratti (colore per tipo di dominio) e residui |
| `out/dominio<k>_<serie>.png` | per dominio e serie: dati grezzi vs modello scelto e altri modelli validi, residui; incorporati nel `report.md` |
## 8. Test (`uv run pytest`, dati in `dati/gen_<seed>.csv`)
| ID | Test | Esito |
|---|---|---|
| T1 | Domini sui seed 1–3 | `riposo, riscaldamento, riscaldamento, raffreddamento` ✔ |
| T2 | Raffreddamento | `esp_decad` scelto per T e ΔT, τ entro il 10 % di 15.9 s ✔ (seed 1: τ = 16.08 ± 0.07 s) |
| T2b | Riscaldamento | `esp_decad` con `c` e `τ` fissi uguali a quelli del raffreddamento, `A` > 0 ✔ |
| T3 | Riposo | `costante` per ΔT ✔ |
| — | da fare | più seed, robustezza a config diverse (nessun gradino, un solo gradino), `domini.toml` manuale, riproducibilità |
## 9. Limiti noti
- **Residui autocorrelati nel raffreddamento** (ACF1 ≈ 0.7, RMSE ≈ 0.36 contro σ ≈ 0.15): scarti casuali e deriva lenta non sono
nel modello; i parametri sono buoni ma gli IC 95 % sono troppo stretti (nonostante la correzione) e il dominio risulta "non adeguato".
- **Domini di riscaldamento corti** (14–26 campioni, 2–4 s): τ non è identificabile da solo, per questo è fissato al valore del raffreddamento (§5.2).
Il secondo tratto di riscaldamento ha ACF1 ≈ 0.7 e RMSE ≈ 2 σ (scarti casuali): risulta "non adeguato" anche se la forma è giusta.
- La soglia `soglia_gradino_c` va adattata se i gradini reali sono più piccoli di 20 °C o gli scarti più grandi.
- Il vincolo di continuità tra domini è solo ignorato: ogni dominio è fittato in modo indipendente.