# CLAUDE.md This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository. `fitseg` legge un CSV `t_ms,T_C,dT_C` (temperatura di un sensore IR), lo divide in **domini** (riposo / riscaldamento = gradini / raffreddamento) e trova per ogni (dominio, serie) l'equazione che meglio lo approssima. Documentazione, commenti e messaggi sono in italiano: mantieni la lingua. Fonti di verità (non duplicarne il contenuto): [docs/SPEC.md](docs/SPEC.md) (algoritmi, limiti), [README.md](README.md) (uso, test), [config.toml](config.toml) (unica fonte dei valori: nessun default nel codice, ogni chiave nuova va in `CHIAVI` di [src/fitseg/config.py](src/fitseg/config.py) e in SPEC). ## Comandi ```bash uv venv .venv && uv pip install -e ".[dev]" .venv/bin/fitseg domini dati/gen_1.csv # suddivisione: lavoro/domini.toml + proposta.png, nessun fit .venv/bin/fitseg analizza dati/gen_1.csv [--domini lavoro/domini.toml] # → lavoro/out/ (report.md, risultati.json, dominio*_*.png) .venv/bin/pytest # tutti; singolo: -k raffreddamento o tests/test_fit.py .venv/bin/ruff check src tests ``` `--config`/`--lavoro` vanno **prima** del sottocomando. `lavoro/` e `dati/*.csv` sono ignorati da git. ## Architettura (`src/fitseg/`, un modulo per responsabilità) `cli.py` (due sottocomandi, unico punto d'ingresso) → `config.py`, `dati.py` (lettura) → `domini.py` (gradini ⇒ domini, I/O di `domini.toml`) → `analisi.py` (ordina i domini, sceglie il modello) → `fit.py` (`adatta`) con `modelli.py` (registro `MODELLI`) → `uscita.py` (report, JSON, grafici). - I domini derivano **solo dai gradini positivi** di `serie_riferimento` (`diff > soglia_gradino_c`), con arretramento ai campioni di transizione; `domini.toml` è modificabile e deve essere contiguo. - `analisi.analizza_domini`: i domini di raffreddamento si fittano **per primi**; i loro `c`/`tau` sono fissati nei domini di riscaldamento (`riscaldamento_fissa_da_raffreddamento`, `adatta(..., fissi=)`). I modelli provati dipendono dal tipo (`[fit.modelli_per_tipo]`: riscaldamento e raffreddamento solo `esp_decad`). - `fit.adatta`: `least_squares` con perdita robusta; l'esponenziale parte da una griglia su τ. "Non identificabile" = condizione > soglia **o** IC 95 % > |valore| per un parametro diverso da `a`/`c`. σ del rumore **per dominio** da `MAD(d²y)`; tempo traslato a `t' = t − t0`. - Nuovo modello = voce in `modelli.py` + riga in SPEC §3 + nome in `[fit.modelli_per_tipo]`. Non ci sono partenze casuali: il programma è deterministico. ## Test Unitari su un segnale sintetico generato in [tests/conftest.py](tests/conftest.py) (τ = 16 s, 3 gradini, nessun disturbo a salto): non servono i CSV. Integrazione su `dati/gen_{1,2,3}.csv` (prodotti da `../gen_data`: `.venv/bin/python genera.py config.toml --seed N -o ...`) e sulla CLI: saltati se i CSV mancano. Verità di `gen_data`: τ = 1/k = 15.9 s (k perturbato del 2 % per seed), 3 gradini a ≈15.7/17.8/21.7 s, ambiente ≈ 23 °C, scarti casuali ≤ 4 °C che rendono i residui autocorrelati (limite noto, non un bug). ## Gotcha - `scarta_dopo_salto_n` deve coprire i campioni di transizione del sensore (τ_sensore 0.07 s, dt 0.15 s ⇒ ≥ 2–3 campioni); se troppo basso 1–2 punti a ~100 °C sporcano la fine del dominio. - Domini di riscaldamento di 14–26 campioni: con gli scarti casuali τ non è identificabile da solo (su dati puliti sì), quindi è fisso al valore del raffreddamento; gli IC di `A` sono condizionati. Senza un raffreddamento valido il riscaldamento torna al fit libero e può risultare indeterminato. - Cambiando la config di `gen_data` (gradini, rumore) ricontrolla `soglia_gradino_c` e i test di integrazione. - Exit code: 0 ok · 2 uso · 3 config · 4 CSV · 6 domini non validi.