diff --git a/README.md b/README.md index 15fc4a6..b66ac3f 100644 --- a/README.md +++ b/README.md @@ -1,39 +1,111 @@ -# Simulatore Termico 1D — Induttore Mobile, Sensore Fisso +# Simulatore Termico 2D — Fascetta, Sorgenti a Induzione Mobili, Sensore IR Fisso -Questo progetto genera misurazioni CSV pseudo-realistiche per una piastra riscaldata da un induttore in movimento. +Questo progetto genera misurazioni CSV pseudo-realistiche della temperatura di una +fascetta (anello cilindrico sottile) riscaldata da un gruppo di sorgenti a induzione +in movimento, osservata da un sensore a infrarossi fisso. Lo scopo è produrre dataset +per l'addestramento e la validazione di modelli di stima/regressione termica. -## Idea fisica +## Geometria -La geometria è semplificata a 1D attraverso lo spessore della piastra: +La fascetta è un anello cilindrico definito da tre dimensioni: + +- **diametro** (default 70 mm) — il diametro del cilindro; +- **spessore** (default 0.12 mm) — lo spessore della parete; +- **lunghezza** (default 100 mm) — l'estensione assiale lungo `x`. + +Il dominio simulato è la **sezione rettangolare lunghezza × spessore**. Il sistema di +coordinate ha l'origine `(0, 0)` nel vertice in alto a sinistra della sezione: ```text -lato caldo, z = 0 -[sorgente / induttore] ---------------------- piastra - | - | spessore - | ---------------------- -[sensore] -lato freddo, z = L + sorgenti (induttori), in moto verso -x + ▼ ▼ ▼ + (0,0) ─────────────────────────────────────► x + │ ┌───────────────────────────────────┐ z = 0 lato ESTERNO + │ │ sezione della fascetta │ (flusso termico) + │ └───────────────────────────────────┘ z = spessore lato INTERNO + ▼ ┆ + z ┆ linea di vista + ▲ + sensore IR (fisso, x = 50 mm, + a 10 mm dalla parete interna) ``` -L'induttore si muove lungo `x`, mentre il sensore è fisso. Poiché il modello è 1D, il movimento della sorgente è convertito in un flusso termico dipendente dal tempo: +- **x** = direzione della lunghezza, da `0` a `lunghezza`. Le sorgenti viaggiano in + direzione `-x` sul lato esterno. +- **z** = direzione dello spessore, da `0` (lato esterno, dove arriva il flusso + termico) a `spessore` (lato interno, osservato dal sensore). +- **y** = coordinata circonferenziale (lungo la circonferenza π·diametro). Non è + risolta spazialmente: vedi sotto come viene trattata. -```text -q(t) è massimo quando x_sorgente(t) è allineata con x_sensore -``` +Il **sensore** è un pirometro a infrarossi posto all'interno della fascetta, a una +distanza configurabile dalla parete interna (default 10 mm). Essendo senza contatto, +la distanza non influenza la misura: il sensore legge la temperatura della superficie +interna nel punto `x` configurato (default 50 mm, al centro della lunghezza). -Il calore viene depositato attraverso lo spessore con un decadimento esponenziale basato sulla skin depth. +## Modello fisico + +Non è una simulazione FEM elettromagnetica + termica completa: è un generatore +pratico di dataset. La catena di approssimazioni è la seguente. + +1. **Sorgenti gaussiane in moto** — ogni sorgente ha un'impronta gaussiana di raggio + `sigma_punto_m`. Un gruppo di `numero_sorgenti` sorgenti equidistanti + (`distanza_sorgenti_m`) si muove rigidamente a velocità costante. Il profilo di + flusso sul lato esterno è la somma dei contributi: + `q(x, t) = Σᵢ q_picco · efficienza · exp(-((x - xᵢ(t))² + Δy²) / (2σ²))`. + L'offset circonferenziale `Δy` tra il percorso delle sorgenti e il punto osservato + dal sensore non è risolto spazialmente: entra come attenuazione gaussiana del flusso. + +2. **Skin depth** — il riscaldamento a induzione è approssimato come riscaldamento + volumetrico che decade esponenzialmente con la profondità `z`: + `q_vol(x, z) = q(x) · exp(-z/δ) / (δ·(1 - exp(-spessore/δ)))`, normalizzato in modo + da conservare il flusso superficiale. La skin depth `δ = √(2ρₑ/(ωμ))` è calcolata + dalla resistività elettrica e dalla permeabilità del materiale alla frequenza di + induzione, oppure può essere imposta con `skin_depth_fissa_m`. Per la banda + stagnata a 20 kHz risulta ≈ 0.1 mm, confrontabile con lo spessore: la parete è + quasi isoterma attraverso lo spessore. + +3. **Diffusione 2D del calore** — l'equazione del calore è integrata nella sezione + `(x, z)` con volumi finiti ed Eulero implicito (incondizionatamente stabile). + +4. **Scambi con l'esterno** — la sezione scambia calore con l'ambiente su tutto il + contorno: + - convezione sul lato esterno (`h_esterno_W_m2K`), sul lato interno + (`h_interno_W_m2K`) e sui due bordi in x (`h_bordi_W_m2K`); + - **conduzione circonferenziale**: la sezione cede calore per conduzione lungo `y` + al resto della fascetta, assunto a temperatura ambiente. Il termine è + `q_y = -k·(T - T_amb)/L_y²` con `L_y = lunghezza_conduzione_y_mm`, la distanza + caratteristica su cui si sviluppa il gradiente circonferenziale (valore più + piccolo = pozzo termico più aggressivo). + +5. **Temperatura iniziale** — il campo parte uniformemente alla temperatura ambiente + del run (che è randomizzata, quindi varia run per run). + +6. **Sensore realistico** — la lettura aggiunge alla temperatura vera della superficie + interna: inerzia del primo ordine (`costante_tempo_s`), rumore gaussiano + (`rumore_std_C`) e quantizzazione (`quantizzazione_C`). + +## Metodo numerico + +- Griglia a volumi finiti `n_nodi_x × n_nodi_z` (default 100 × 15); le incognite sono + i centri cella. +- Eulero implicito con passo `dt_interno_s` (default 0.2 ms), più fine del periodo di + campionamento CSV. +- Tutti i termini (diffusione, convezione, conduzione circonferenziale) sono lineari e + costanti nel run: la matrice sparsa viene costruita e **fattorizzata LU una sola + volta per run** (`scipy.sparse.linalg.splu`); ogni passo temporale risolve solo i + sistemi triangolari. Un run da 30 s simulati richiede ~20 s di calcolo. +- Se in futuro si introducessero proprietà dipendenti dalla temperatura, la matrice + andrebbe ricostruita e rifattorizzata a ogni passo. ## File ```text -config.py tutti i parametri di simulazione -materials.py proprietà dei materiali -simulate.py genera i file CSV -plot_csv.py utilità di visualizzazione rapida -dataset/ file CSV generati dopo aver eseguito simulate.py +config.py tutti i parametri di simulazione +materials.py proprietà termofisiche ed elettriche dei materiali +simulate.py motore fisico + generazione dei CSV +plot_csv.py grafici rapidi (temperature e flusso) del primo run +plot_animazione.py animazione della sezione: campo T(x,z), sorgenti, sensore +dataset/ output generato da simulate.py (ricreato a ogni esecuzione) ``` ## Installazione @@ -44,106 +116,90 @@ source .venv/bin/activate pip install -r requirements.txt ``` -## Generare i file CSV +## Uso ```bash +# genera il dataset (ATTENZIONE: cancella e ricrea la cartella dataset/) python simulate.py -``` -La cartella di output conterrà: - -```text -dataset/run_0001.csv -dataset/run_0002.csv -... -dataset/metadata.csv -``` - -## Visualizzare un run - -```bash +# grafici statici del primo run (temperatura e flusso nel tempo) python plot_csv.py + +# animazione della sezione durante il passaggio delle sorgenti +python plot_animazione.py ``` -## Principali punti di configurazione +Gli script di visualizzazione aprono finestre interattive (backend Qt); se il backend +non è interattivo (es. sessione senza display) salvano automaticamente PNG/GIF in +`dataset/`. -Modifica `config.py`. +L'animazione riproduce esattamente la fisica di `run_0001` (stesso seed) e mostra tre +pannelli allineati: il profilo di flusso `q(x)` con le sorgenti in transito, il campo +di temperatura nella sezione con il sensore IR, e la temperatura nel punto osservato +(vera e con inerzia del sensore). Finestra temporale e cadenza dei fotogrammi si +regolano con le costanti in testa a `plot_animazione.py`. -### Piastra +## Configurazione -```python -PIASTRA = { - "spessore_m": 0.005, - "n_nodi": 61, - "temperatura_iniziale_C": 25.0, - "materiale": "acciaio_basso_carbonio", -} -``` +Tutto si modifica in `config.py`. I dizionari principali: -### Sorgente mobile +| Dizionario | Contenuto | +|------------------|---------------------------------------------------------------------------| +| `SIMULAZIONE` | numero di run, durata, campionamento CSV, passo interno, seed, cartella | +| `FASCETTA` | diametro, lunghezza, spessore, griglia, conduzione circonferenziale, materiale | +| `ARIA` | temperatura ambiente e coefficienti di convezione dei quattro lati | +| `SORGENTE` | corsa, velocità (il segno dà il verso), gruppo di sorgenti, gaussiana, flusso, frequenza | +| `SENSORE` | posizione (x e distanza dalla parete), inerzia, rumore, quantizzazione | +| `RANDOMIZZAZIONE`| entità delle perturbazioni per run | -```python -SORGENTE = { - "x_inizio_m": -0.08, - "x_fine_m": 0.08, - "velocita_m_s": 0.004, - "sigma_punto_m": 0.012, - "flusso_termico_picco_W_m2": 70000.0, - "efficienza_riscaldamento": 0.35, - "frequenza_hz": 20000.0, -} -``` +Punti da conoscere: -### Aria +- **Corsa delle sorgenti**: `x_inizio_m` è la distanza dal sensore, all'inizio della + corsa, della sorgente più avanzata (quella che lo raggiunge per prima); + `x_fine_m` è la distanza dal sensore, a fine corsa, della sorgente più arretrata + (quella che lo supera per ultima). Con `zero_dopo_fine` ogni sorgente si spegne + alla fine della propria corsa. +- **Materiale**: `FASCETTA["materiale"]` deve essere una chiave di `MATERIALI` in + `materials.py`. Per aggiungere un materiale basta una nuova voce nel dizionario + (conducibilità, densità, calore specifico, resistività elettrica, permeabilità). +- **Randomizzazione**: ogni run perturba velocità, flusso di picco, sigma, offset y, + temperatura ambiente e rumore del sensore con estrazioni da un RNG a seed fisso + (`SIMULAZIONE["seed"]`): il dataset è riproducibile. -```python -ARIA = { - "temperatura_ambiente_C": 25.0, - "h_caldo_W_m2K": 12.0, - "h_freddo_W_m2K": 8.0, -} -``` +## Output -### Sensore +### `dataset/run_XXXX.csv` — serie temporale del run -```python -SENSORE = { - "costante_tempo_s": 1.5, - "rumore_std_C": 0.15, - "quantizzazione_C": 0.25, -} -``` +| Colonna | Significato | +|--------------------------------|--------------------------------------------------------------------| +| `id_run` | identificativo del run | +| `tempo_s` | tempo simulato | +| `x_sorgente_m` | posizione della sorgente di riferimento del gruppo | +| `offset_y_sorgente_m` | offset circonferenziale del percorso (costante nel run) | +| `flusso_termico_sorgente_W_m2` | flusso efficace nel punto x del sensore | +| `skin_depth_m` | skin depth usata (costante nel run) | +| `T_vera_lato_sensore_C` | temperatura vera della superficie interna nel punto del sensore | +| `T_misurata_sensore_C` | lettura del sensore (inerzia + rumore + quantizzazione) | +| `T_lato_caldo_C` | temperatura della superficie esterna nello stesso punto x | +| `T_ambiente_C` | temperatura ambiente del run | +| `velocita_m_s`, `sigma_punto_m`, `flusso_picco_W_m2` | parametri randomizzati del run | +| `materiale` | chiave del materiale | -## Colonne CSV +### `dataset/metadata.csv` — una riga per run -Ogni `run_XXXX.csv` contiene: +Contiene tutti i parametri effettivi del run (geometria, griglia, coefficienti di +scambio, parametri delle sorgenti e del sensore, valori randomizzati) e le temperature +di picco vera e misurata: utile come ground truth e per filtrare i run. -```text -id_run -tempo_s -x_sorgente_m -offset_y_sorgente_m -flusso_termico_sorgente_W_m2 -skin_depth_m -T_vera_lato_sensore_C -T_misurata_sensore_C -T_lato_caldo_C -T_ambiente_C -velocita_m_s -sigma_punto_m -flusso_picco_W_m2 -materiale -``` +## Limitazioni -## Limitazione importante - -Questo non è una simulazione FEM elettromagnetica + termica completa. È un generatore pratico di dataset. - -La sorgente a induzione è approssimata da: - -1. un'impronta termica gaussiana in movimento; -2. un flusso termico efficace; -3. deposizione esponenziale del calore attraverso lo spessore tramite skin depth; -4. diffusione del calore 1D attraverso la piastra; -5. perdite per convezione su entrambi i lati; -6. inerzia, rumore e quantizzazione del sensore. +1. Il campo elettromagnetico non è simulato: l'accoppiamento induttivo è ridotto a + impronta gaussiana × efficienza × decadimento esponenziale in z. +2. La coordinata circonferenziale y non è risolta: offset del percorso e conduzione + verso il resto della fascetta sono modelli collassati (attenuazione gaussiana e + scambio lineare verso T ambiente). +3. Le proprietà dei materiali sono costanti con la temperatura; per gli acciai + ferromagnetici la skin depth reale varia fortemente con temperatura e campo + (punto di Curie non modellato). +4. Irraggiamento non modellato: a ~220 °C le perdite radiative non sono del tutto + trascurabili rispetto alla convezione.