Files
EquationMiner/README.md
T
2026-10-29 09:52:56 +01:00

146 lines
6.6 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
Legge un CSV `t_ms,T_C,dT_C` (temperatura di un sensore IR che si scalda e si raffredda), riconosce quando c'è **riscaldamento** (gradini di flusso in entrata) e quando c'è **raffreddamento**, divide il tempo in **domini** e trova per ogni dominio e ogni serie l'equazione che approssima meglio i dati, con minimi quadrati non lineari.
Risultato per ogni dominio: modello scelto, parametri con intervallo di confidenza al 95 %, metriche (RMSE, R², AICc, BIC, autocorrelazione dei residui), grafici e un report in Markdown.
## Requisiti
- Python ≥ 3.11
- [uv](https://docs.astral.sh/uv/) (consigliato): `curl -LsSf https://astral.sh/uv/install.sh | sh`
- Dipendenze: `numpy`, `scipy`, `matplotlib` (più `pytest` e `ruff` per lo sviluppo)
## Installazione
```bash
uv venv .venv
uv pip install -e ".[dev]"
```
Il programma si lancia con `.venv/bin/fitseg` (oppure `source .venv/bin/activate` e poi `fitseg`).
## Dati di ingresso
Un CSV con intestazione, tempo crescente e una o più serie:
```
t_ms,T_C,dT_C
151,22.90,0.20
301,22.63,0.03
```
I nomi delle colonne, l'unità del tempo (`ms` o `s`) e il separatore sono in [config.toml](config.toml), sezione `[dati]`.
I CSV di prova vengono dal generatore `../gen_data` (repository separato). I test usano i seed 1, 2 e 3 in `dati/` (cartella ignorata da git):
```bash
mkdir -p dati
for s in 1 2 3; do
(cd ../gen_data && .venv/bin/python genera.py config.toml --seed $s -o ../EquationMiner/dati/gen_$s.csv)
done
```
## Uso
```bash
fitseg domini dati/gen_1.csv # solo i domini: tabella a schermo + lavoro/domini.toml
fitseg analizza dati/gen_1.csv # domini + fit + scelta + report in lavoro/out/
fitseg modelli # catalogo dei modelli con equazioni e parametri
fitseg valuta lavoro/out/modello_finale.json --t 10 30 60 # valuta il modello a tratti in questi istanti
```
Le opzioni globali `--config PATH` (default `config.toml`) e `--lavoro DIR` (default `lavoro`) vanno **prima** del sottocomando:
```bash
fitseg --config altra.toml --lavoro prova1 analizza dati/gen_2.csv
```
### Correggere i domini a mano
`fitseg domini` (e `analizza`) scrive la proposta automatica in `lavoro/domini.toml`:
```toml
[[dominio]]
tipo = "riscaldamento" # riposo | riscaldamento | raffreddamento
t0_s = 15.8 # incluso
t1_s = 17.76 # escluso (l'ultimo dominio arriva a fine dati)
```
Modifica i tempi, aggiungi o togli blocchi `[[dominio]]` (devono restare contigui) e rilancia:
```bash
fitseg analizza dati/gen_1.csv --domini lavoro/domini.toml
```
## Cosa produce
Tutto in `lavoro/` (ignorata da git):
| File | Contenuto |
|---|---|
| `domini.toml` | proposta dei domini (o quelli che hai usato) |
| `dati.csv` | copia del CSV analizzato |
| `out/report.md` | per dominio e serie: modello scelto, parametri ± IC 95 %, metriche, tabella di confronto di tutti i modelli |
| `out/equazioni.md` | solo le equazioni scelte |
| `out/modello_finale.json` | modello e parametri per dominio e serie (input di `valuta`) |
| `out/risultati.json` | tutti i fit con tutte le metriche |
| `out/fit_<serie>.png` | dati, fit a tratti (un colore per tipo di dominio) e residui |
### Come leggere il report
- **Scelto**: il modello con meno parametri tra quelli equivalenti per AICc (ΔAICc ≤ 2) e validi (convergenti, parametri lontani dai limiti, identificabili).
- **modello non adeguato**: l'RMSE supera 1.3 volte il rumore stimato. Il modello migliore disponibile non spiega tutto: guarda l'ACF1 dei residui.
- **Indeterminato**: nessun modello è valido, oppure il dominio ha meno di `n_min_punti` campioni.
- Nel raffreddamento, `τ` è la costante di tempo e `c` la temperatura asintotica (≈ ambiente per `T_C`, ≈ 0 per `dT_C`).
## Come funziona
1. **Domini**: un salto positivo tra due campioni consecutivi sopra `soglia_gradino_c` è un gradino di riscaldamento. Prima del primo gradino il dominio è `riposo`, tra due gradini `riscaldamento`, dopo l'ultimo `raffreddamento`.
2. **Fit**: in ogni dominio, con il tempo traslato a `t' = t − t0`, si fittano tutti i modelli di `modelli_abilitati` con `scipy.optimize.least_squares` e perdita robusta.
3. **Scelta**: regola automatica (SPEC §5.3), senza intervento umano.
Dettagli, modelli e limiti: [docs/SPEC.md](docs/SPEC.md). Uso esteso: [docs/USO.md](docs/USO.md).
## Modelli
| Id | Equazione |
|---|---|
| `costante` | `y = a` |
| `lineare` | `y = a + b·t'` |
| `quadratico` | `y = a + b·t' + c·t'²` |
| `esp_decad` | `y = c + A·exp(−t'/τ)` |
| `esp_doppio` | `y = c + A1·exp(−t'/τ1) + A2·exp(−t'/τ2)` |
| `logistica` | `y = c + A / (1 + exp(−(t'−t_m)/w))` |
Per aggiungerne uno: nuova voce in `MODELLI` di [src/fitseg/modelli.py](src/fitseg/modelli.py), nuova riga in SPEC §4 e nome in `modelli_abilitati`.
## Configurazione
Tutti i valori sono in [config.toml](config.toml); non c'è nessun default nel codice (chiave mancante = errore). Quelle che conviene conoscere:
| Chiave | Effetto |
|---|---|
| `[domini] soglia_gradino_c` | salto minimo che segna un gradino (20 °C); da adattare se i gradini reali sono più piccoli |
| `[domini] scarta_dopo_salto_n` | campioni esclusi all'inizio di un dominio dopo un gradino (transizione del sensore) |
| `[domini] n_min_punti` | campioni minimi per dominio |
| `[fit] modelli_abilitati` | modelli provati in ogni dominio |
| `[fit] soglia_delta_aicc` | entro questa differenza vince il modello con meno parametri |
| `[fit] rmse_vs_rumore_max` | soglia di «adeguato» (RMSE ≤ valore × σ rumore) |
| `[fit] seed` | seme delle partenze multiple: stessi dati e stessa config danno gli stessi risultati |
## Test
```bash
.venv/bin/pytest # tutti
.venv/bin/pytest -k raffreddamento # uno solo
```
I test verificano, sui seed 1–3, che i domini siano `riposo, riscaldamento, riscaldamento, raffreddamento`, che nel raffreddamento vinca `esp_decad` con τ entro il 10 % di 15.9 s e che il riposo sia `costante`. Richiedono `dati/gen_1.csv`, `gen_2.csv`, `gen_3.csv` (vedi sopra).
## Codici di uscita
0 ok · 2 uso errato · 3 configurazione non valida · 4 CSV illeggibile o non valido · 6 domini non validi.
## Limiti noti
- Nel raffreddamento i residui sono autocorrelati (ACF1 ≈ 0.7) per scarti casuali e deriva lenta del sensore: i parametri sono buoni, ma gli intervalli di confidenza sono troppo stretti e il dominio risulta «non adeguato».
- I domini di riscaldamento sono corti (2–4 s): il decadimento è quasi lineare e τ non è identificabile; vince un modello semplice, con valore descrittivo e non fisico.
- Ogni dominio è fittato in modo indipendente: nessun vincolo di continuità tra domini.
- Provato su 3 seed; non su file senza gradini o con un solo gradino.