139 lines
8.8 KiB
Markdown
139 lines
8.8 KiB
Markdown
# Moduli
|
||
|
||
Mappa del codice in `src/fitseg/`. Un modulo ha una sola responsabilità; le dipendenze vanno in una sola direzione.
|
||
|
||
```mermaid
|
||
flowchart TD
|
||
cli[cli.py] --> config[config.py]
|
||
cli --> dati[dati.py]
|
||
cli --> domini[domini.py]
|
||
cli --> analisi[analisi.py]
|
||
cli --> uscita[uscita.py]
|
||
analisi --> domini
|
||
analisi --> fit[fit.py]
|
||
analisi --> modelli[modelli.py]
|
||
fit --> modelli
|
||
uscita --> analisi
|
||
uscita --> modelli
|
||
```
|
||
`config.py`, `dati.py`, `domini.py` e `modelli.py` non importano niente del pacchetto; `fit.py` importa solo `modelli`; `analisi.py` importa `domini`, `fit`, `modelli`;
|
||
`uscita.py` importa `analisi` (per `valido` e `fit_scelto`) e `modelli`. Nessun modulo di calcolo scrive file.
|
||
|
||
## Strutture dati comuni
|
||
|
||
**Domini** (lista, ordinata e contigua): ogni elemento è `{"tipo": "riposo"|"riscaldamento"|"raffreddamento", "i0": int, "i1": int}`, con
|
||
`i0` primo campione e `i1` escluso. `domini[k]["i1"] == domini[k+1]["i0"]`.
|
||
|
||
**Risultato** (lista, una voce per dominio; è anche il contenuto di `risultati.json`):
|
||
|
||
| Campo | Significato |
|
||
|---|---|
|
||
| `k` | numero del dominio (da 1) |
|
||
| `tipo`, `t0_s`, `t1_s` | tipo; tempo del primo e dell'ultimo campione del dominio (in secondi) |
|
||
| `n`, `n_fit` | campioni del dominio; campioni usati nel fit (meno `scarta_dopo_salto_n` nei raffreddamenti) |
|
||
| `serie` | `{nome serie: voce}` (sotto) |
|
||
|
||
**Voce di serie**: `sigma` (σ del rumore; `null` nel riscaldamento e se non è stimabile, cioè meno di 8 campioni), `fit` (lista dei fit provati), `scelta` (nome del modello o
|
||
`null`), `motivo` (testo), `adeguato` (`true`/`false`; `null` se σ non è stimabile; assente nel riscaldamento e nei domini troppo corti); nel riscaldamento al posto dei fit c'è `gradino`:
|
||
`{n, da, a, delta, delta_misurato, stima, durata_s, istante_s}`: `delta` è il salto usato; `stima` vale `"modelli"` (differenza dei modelli adiacenti all'istante
|
||
`istante_s`), `"misura corretta"` (misura riportata a quell'istante con $c$ e $\tau$ del raffreddamento finale) o `"misura"` (sui campioni); `da`/`a` sono i valori
|
||
prima/dopo usati.
|
||
|
||
**Fit** (elemento di `fit`): `modello`, `equazione` (LaTeX), `n_parametri` ($k$ liberi), `n`, `fissi` (nomi dei parametri fissi), `parametri`
|
||
`{nome: valore}`, `ic95` `{nome: ±}`, `rss`, `rmse`, `scala_residui` ($\hat\sigma_\text{res} = 1.4826\,\mathrm{MAD}$ dei residui), `r2`, `aicc`, `bic`, `acf1` ($\rho_1$), `condizione`, `parametri_a_limite`, `non_identificabile`,
|
||
`convergenza`. Se la minimizzazione fallisce: solo `modello`, `convergenza: false`, `n_parametri`.
|
||
|
||
## `cli.py` — punto d'ingresso
|
||
|
||
| | |
|
||
|---|---|
|
||
| Responsabilità | argomenti da riga di comando, orchestrazione dei passi, codici di uscita |
|
||
| Funzioni | `main(argv)`, `cmd_domini`, `cmd_analizza`, `_passo_domini(args)`, `errore(msg, codice)` |
|
||
| Entra | `--config`, `--output`, sottocomando `domini CSV` o `analizza CSV [--domini FILE]` |
|
||
| Esce | codici 0 ok, 2 uso errato (argparse), 3 `ErroreConfig`, 4 `ErroreDati`, 6 `domini.toml` non valido |
|
||
|
||
`_passo_domini` è il passo 1 comune ai due comandi: legge config e dati, crea `output/<nome csv>/` con le tre sottocartelle, ricava i domini
|
||
(da `--domini` oppure dalla proposta), scrive `01_domini/domini.toml` e `domini.png`, stampa la tabella dei domini. `cmd_analizza` poi chiama
|
||
`analizza_domini` e scrive sovrapposizione e report. Con `--domini` il file passato viene riscritto normalizzato in `01_domini/`.
|
||
|
||
## `config.py` — configurazione
|
||
|
||
| | |
|
||
|---|---|
|
||
| Responsabilità | leggere `config.toml`, rifiutare chiavi mancanti (**nessun default nel codice**) |
|
||
| Funzioni | `leggi(percorso) → dict`; costante `CHIAVI` (elenco obbligatorio per sezione); eccezione `ErroreConfig` |
|
||
| Controlli | chiavi presenti; `unita_tempo` ∈ {ms, s}; `serie_riferimento` ∈ `serie`; `modelli_per_tipo` ha liste non vuote per `riposo` e `raffreddamento` |
|
||
|
||
Una chiave nuova va aggiunta a `CHIAVI`, a `config.toml` e a [configurazione.md](configurazione.md).
|
||
|
||
## `dati.py` — lettura del CSV
|
||
|
||
| | |
|
||
|---|---|
|
||
| Funzioni | `leggi_csv(percorso, cfg) → (t, serie)`; eccezione `ErroreDati` |
|
||
| Garanzie | `t` in secondi, strettamente crescente (A1); `serie` = `{nome: array}` per le colonne di `[dati] serie`; nessun valore mancante |
|
||
|
||
## `domini.py` — suddivisione in domini
|
||
|
||
| Funzione | Cosa fa | Vedi |
|
||
|---|---|---|
|
||
| `sigma_robusto(d)` | $1.4826\,\mathrm{MAD}$ di un campione | [algoritmi.md](algoritmi.md) §2 |
|
||
| `sigma_rumore(y)` | $\sigma$ del rumore bianco da $\Delta^2 y$; `nan` con meno di `N_MIN_SIGMA` = 8 campioni | §2 |
|
||
| `trova_gradini(y, cfg)` | lista di $(i_0, i_1)$ dei campioni di salita: campioni in salita raggruppati, gradino se la salita complessiva supera `soglia_gradino_c` | §3 |
|
||
| `proponi(t, serie, cfg)` | lista dei domini (riposo + riscaldamento/raffreddamento per gradino) | §4 |
|
||
| `scrivi_toml(percorso, domini, t)` | scrive `domini.toml` (tempi con 4 decimali) | [uso.md](uso.md) |
|
||
| `leggi_toml(percorso, t)` | rilegge e **valida** i domini (tipi, intervalli, contiguità); `ValueError` se non validi | [uso.md](uso.md) |
|
||
|
||
Nel `domini.toml` `t1_s` è l'estremo **escluso** (tempo del primo campione del dominio successivo); per l'ultimo dominio è l'ultimo campione. Gli
|
||
indici si ricalcolano dal tempo con tolleranza $10^{-6}$ s.
|
||
|
||
## `modelli.py` — registro dei modelli
|
||
|
||
| | |
|
||
|---|---|
|
||
| Dati | `MODELLI = {nome: (funzione, [nomi parametri], equazione LaTeX, indice di τ o None)}` |
|
||
| Funzioni | `valuta(nome, t, p)` valuta un modello in $t$ con parametri `p` (lista nell'ordine dei nomi) |
|
||
|
||
Contiene `costante`, `lineare`, `esp_decad`. **Aggiungere un modello**: una funzione, una voce in `MODELLI`, il nome nelle liste di
|
||
`[fit.modelli_per_tipo]`, una riga in [algoritmi.md](algoritmi.md) §5.1; se il modello ha un nuovo tipo di parametro-tempo, indicare l'indice
|
||
in `MODELLI` e la partenza in `fit._partenza`; in `uscita._eq_numerica` aggiungere il ramo per l'equazione con i valori.
|
||
|
||
## `fit.py` — regressione di un modello
|
||
|
||
| Funzione | Cosa fa |
|
||
|---|---|
|
||
| `adatta(t, y, nome, sigma, cfg, fissi=None) → dict` | fit di un modello su un dominio; `fissi = {parametro: valore}` tenuti costanti. Restituisce il dizionario *Fit* sopra |
|
||
| `_partenza(t, y, nome, cfg, L)` | minimi quadrati per i polinomi, griglia su $\tau$ (VARPRO) per l'esponenziale |
|
||
| `_acf1(r)` | autocorrelazione dei residui a lag 1 |
|
||
|
||
Dettagli: [algoritmi.md](algoritmi.md) §5. Nessun accesso a file, nessuna casualità.
|
||
|
||
## `analisi.py` — scelta e orchestrazione dei domini
|
||
|
||
| Funzione | Cosa fa |
|
||
|---|---|
|
||
| `valido(fit)` | convergente, nessun parametro a limite, identificabile, AICc finito |
|
||
| `fit_scelto(voce)` | il fit scelto di una voce di serie, o `None` (indeterminato, riscaldamento) |
|
||
| `scegli(fit_list, sigma, cfg) → (fit, motivo, adeguato)` | regola di scelta ([algoritmi.md](algoritmi.md) §6); adeguato = scala robusta dei residui ≤ soglia·σ; `None` se σ non stimabile |
|
||
| `_gradino(t, y, d)` | descrive il riscaldamento come salto misurato sui campioni ([algoritmi.md](algoritmi.md) §7) |
|
||
| `_valore(dominio, nome, t)`, `_finale(risultati)`, `_affina_salti(t, serie, risultati, domini)` | valore del modello scelto in $t$; raffreddamento finale; sostituisce la misura del salto con la stima dai modelli adiacenti o, in mancanza, con la misura corretta con $c$, $\tau$ del finale (§7) |
|
||
| `_serie(ty, yy, sigma, tipo, fissi, cfg)` | fit di tutti i modelli del tipo per una serie e scelta; `indeterminato` se i campioni sono meno di `n_min_punti` (`n_min_punti_parametri_fissi` con parametri fissi) |
|
||
| `analizza_domini(t, serie, domini, cfg) → list` | un *Risultato* per dominio; ordine: raffreddamento finale, poi gli altri ([algoritmi.md](algoritmi.md) §5b) |
|
||
|
||
## `uscita.py` — cartelle, grafici, report
|
||
|
||
| Funzione | Cosa produce |
|
||
|---|---|
|
||
| `cartelle(base)` | crea `01_domini`, `02_sovrapposizione`, `03_report` e le restituisce |
|
||
| `colori_domini(tipi)` | un colore per dominio (grigio riposo, rosso riscaldamento, colori diversi per ogni raffreddamento) |
|
||
| `grafico_domini(percorso, t, serie, domini)` | passo 1: `domini.png` |
|
||
| `sovrapposizione_generale(...)` | passo 2a: `sovrapposizione_<serie>.png` |
|
||
| `sovrapposizione_domini(...)` | passo 2b: `dominio<k>_<serie>.png` |
|
||
| `scrivi_report(cartella, risultati, nome_csv, serie_nomi, cfg)` | passo 3: `report.md` e `risultati.json` |
|
||
| `_senza_nan(x)` | copia con NaN/∞ sostituiti da `None`: `risultati.json` è sempre JSON valido (`allow_nan=False`) |
|
||
| `_num`, `_params`, `_eq_numerica`, `_salto` | formattazione LaTeX (valori, parametri ± IC, equazione con i valori sostituiti, salto) |
|
||
|
||
Il report incorpora le immagini con percorsi **relativi** (`../01_domini/domini.png`, …): cambiando nomi di file o cartelle vanno aggiornati
|
||
`PASSI` e i riferimenti. Le grandezze matematiche del report sono sempre in LaTeX e i `$` devono restare bilanciati per riga (c'è un test).
|
||
Descrizione di file e grafici: [output.md](output.md).
|