- rimossi scripts/, stadi.py, docs/USO.md, modelli non usati, partenze casuali, output ridondanti - uscita unica (report.md con grafici per dominio, risultati.json, proposta.png) - test: unitari su segnale sintetico, integrazione su dati/gen_*.csv (saltati se mancano) Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
97 lines
6.1 KiB
Markdown
97 lines
6.1 KiB
Markdown
# fitseg
|
||
|
||
Legge un CSV `t_ms,T_C,dT_C` (temperatura di un sensore IR che si scalda e si raffredda), riconosce **riposo**, **riscaldamento** (gradini di flusso in entrata) e **raffreddamento**, lo divide in **domini** e trova per ogni dominio e ogni serie l'equazione che lo approssima meglio, con minimi quadrati non lineari.
|
||
|
||
Risultato per dominio: modello scelto, parametri con intervallo di confidenza al 95 %, metriche (RMSE, R², AICc, BIC, autocorrelazione dei residui), un grafico dati/equazioni e un report Markdown.
|
||
|
||
## Installazione
|
||
|
||
Python ≥ 3.11 e [uv](https://docs.astral.sh/uv/) (`curl -LsSf https://astral.sh/uv/install.sh | sh`):
|
||
|
||
```bash
|
||
uv venv .venv
|
||
uv pip install -e ".[dev]" # numpy, scipy, matplotlib; pytest e ruff per lo sviluppo
|
||
```
|
||
|
||
## Dati di ingresso
|
||
|
||
CSV con intestazione, tempo crescente e le serie indicate in [config.toml](config.toml) (`[dati]`: colonne, unità `ms`/`s`, separatore). I CSV di prova vengono dal generatore `../gen_data`; i test di integrazione usano i seed 1–3 in `dati/` (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
|
||
.venv/bin/fitseg domini dati/gen_1.csv # come verrebbero suddivisi i dati: tabella, lavoro/domini.toml, lavoro/proposta.png (nessun fit)
|
||
.venv/bin/fitseg analizza dati/gen_1.csv # domini + regressione + report in lavoro/out/
|
||
```
|
||
`--config PATH` (default `config.toml`) e `--lavoro DIR` (default `lavoro`) vanno **prima** del sottocomando.
|
||
|
||
**Correggere i domini a mano**: apri `lavoro/domini.toml`, modifica i tempi (i domini devono restare contigui) e rilancia
|
||
```bash
|
||
.venv/bin/fitseg analizza dati/gen_1.csv --domini 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)
|
||
```
|
||
|
||
### Cosa produce (in `lavoro/`, ignorata da git)
|
||
|
||
| File | Contenuto |
|
||
|---|---|
|
||
| `domini.toml`, `proposta.png` | domini proposti e grafico dei dati con la suddivisione |
|
||
| `out/report.md` | per dominio e serie: grafico, modello scelto con parametri ± IC 95 %, metriche, tabella di tutti i modelli provati |
|
||
| `out/dominio<k>_<serie>.png` | dati grezzi contro il modello scelto (colore del dominio) e gli altri modelli validi (tratteggiati), più residui; campioni esclusi dal fit in grigio |
|
||
| `out/risultati.json` | tutti i fit con tutte le metriche |
|
||
|
||
Come leggere il report: **non adeguato** = RMSE oltre 1.3 volte il rumore stimato (guarda l'ACF1 dei residui); **indeterminato** = nessun modello valido o dominio con meno di `n_min_punti` campioni. Nel raffreddamento `τ` è la costante di tempo e `c` l'asintoto (≈ ambiente per `T_C`, ≈ 0 per `dT_C`).
|
||
|
||
## Come funziona
|
||
|
||
1. **Domini** (`domini.py`): un salto positivo tra due campioni consecutivi sopra `soglia_gradino_c` è un gradino di riscaldamento. Prima del primo gradino: `riposo`; tra due gradini: `riscaldamento`; dopo l'ultimo: `raffreddamento`.
|
||
2. **Modelli** (`modelli.py`): `riposo` → `costante`, `lineare`, `esp_decad`; `riscaldamento` e `raffreddamento` → solo `esp_decad` `y = c + A·exp(−t'/τ)`, con `t' = t − t0` del dominio.
|
||
3. **Fit** (`fit.py`): `scipy.optimize.least_squares` con perdita robusta; partenza dell'esponenziale da una griglia su τ. I domini di raffreddamento si fittano per primi e nei domini di riscaldamento `c` e `τ` sono **fissati** ai loro valori (stesse costanti fisiche; in 2–4 s di dati con scarti casuali τ non si stima da solo), restando libera solo `A`. Gli IC di `A` sono condizionati ai valori fissi.
|
||
4. **Scelta** (`analisi.py`): scarta i modelli non convergenti, con parametri a limite o non identificabili; preferisce i modelli «adeguati» (RMSE ≤ `rmse_vs_rumore_max` × σ rumore); tra quelli entro `soglia_delta_aicc` dal miglior AICc vince chi ha meno parametri.
|
||
|
||
Specifica e limiti: [docs/SPEC.md](docs/SPEC.md).
|
||
|
||
## Configurazione
|
||
|
||
Tutti i valori sono in [config.toml](config.toml), nessun default nel codice (chiave mancante = errore, exit 3). Le principali: `[domini] soglia_gradino_c` (20 °C), `scarta_dopo_salto_n` (campioni di transizione esclusi dal fit), `n_min_punti`; `[fit.modelli_per_tipo]` (modelli per tipo di dominio); `[fit] riscaldamento_fissa_da_raffreddamento` (`["c", "tau"]`, `[]` = parametri liberi), `soglia_delta_aicc`, `rmse_vs_rumore_max`.
|
||
|
||
Nuovo modello: voce in `MODELLI` di [src/fitseg/modelli.py](src/fitseg/modelli.py), riga in SPEC §4 e nome in `[fit.modelli_per_tipo]`.
|
||
|
||
## Test
|
||
|
||
```bash
|
||
.venv/bin/pytest # tutti (≈ 4 s)
|
||
.venv/bin/pytest tests/test_fit.py # un file
|
||
.venv/bin/pytest -k raffreddamento # per nome
|
||
.venv/bin/ruff check src tests
|
||
```
|
||
|
||
| File | Verifica | Servono i CSV? |
|
||
|---|---|---|
|
||
| `test_domini.py` | 3 gradini, nessun gradino, un solo gradino, gradino sotto soglia, confini vicini ai gradini veri, `domini.toml` (andata e ritorno, non contiguo, tipo non valido) | no |
|
||
| `test_fit.py` | recupero di τ, `c`, `A` su segnale sintetico (τ = 16 s), parametri fissi, τ non identificabile su tratti corti e rumorosi, analisi completa, dominio troppo corto, riproducibilità | no |
|
||
| `test_selezione.py` | regola di scelta | no |
|
||
| `test_config_dati.py` | errori di config e CSV | no |
|
||
| `test_integrazione.py` | domini e τ su `dati/gen_{1,2,3}.csv`; CLI `domini` e `analizza --domini`; codici di uscita | sì (altrimenti saltati) |
|
||
|
||
I test unitari generano il segnale da soli (`tests/conftest.py`). Prova manuale: `fitseg analizza dati/gen_1.csv` e controlla in `lavoro/out/report.md` 4 domini (riposo, due riscaldamenti, raffreddamento) con τ ≈ 16 s.
|
||
|
||
Codici di uscita: 0 ok · 3 configurazione non valida · 4 CSV illeggibile/non valido · 6 `domini.toml` non valido.
|
||
|
||
## 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 IC sono troppo stretti e il dominio risulta «non adeguato».
|
||
- Ogni dominio è fittato in modo indipendente (nessun vincolo di continuità); provato su pochi seed e con la config d'esempio di `gen_data`.
|