Files
simulatore-induttori/README.md
T

228 lines
13 KiB
Markdown
Raw Normal View History

# Analisi Termica FEM — Fascetta, Sorgenti a Induzione Mobili, Sensore IR Fisso
2026-07-05 11:58:52 +02:00
Questo progetto calcola il transitorio termico di una fascetta (anello cilindrico
sottile) riscaldata da un gruppo di sorgenti a induzione in movimento, osservata da un
sensore a infrarossi fisso. La fascetta è discretizzata con una mesh a elementi shell
quadrangolari e il campo di temperatura è risolto a elementi finiti, poi visualizzato in
un'animazione 3D isometrica o esportato in CSV come serie temporale (temperatura vera
della parete e lettura del sensore).
2026-07-05 11:58:52 +02:00
## Geometria
2026-07-05 11:58:52 +02:00
La fascetta è un anello cilindrico definito da tre dimensioni:
- **diametro** (default 70 mm) — il diametro esterno del cilindro;
- **spessore** (default 0.18 mm) — lo spessore della parete;
- **lunghezza** (default 100 mm) — l'estensione assiale lungo `x`.
Il dominio discretizzato è la **superficie media** del cilindro (raggio =
(diametro spessore)/2). Lo spessore non è discretizzato: è un attributo degli
elementi shell.
2026-07-05 11:58:52 +02:00
```text
sorgenti (induttori), in moto lungo x sulla superficie esterna
▼ ▼ ▼
┌───────────────────────────────────┐
x = 0 │ superficie media del cilindro │ x = lunghezza
└───────────────────────────────────┘
┆ linea di vista
sensore IR (fisso, x = 50 mm, theta = 0,
a 10 mm dalla parete interna)
2026-07-05 11:58:52 +02:00
```
- **x** = asse del cilindro, da `0` a `lunghezza`.
- **theta** = coordinata circonferenziale, con `theta = 0` sul piano del sensore;
nelle formule si usa la lunghezza d'arco `s = R·theta`.
- Coordinate globali per la visualizzazione: `x`, `y = R·sin(theta)`,
`z = R·cos(theta)`.
2026-07-05 11:58:52 +02:00
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 parete nel nodo
più vicino a `x = 50 mm` sul piano `theta = 0`.
2026-07-05 11:58:52 +02:00
## Modello fisico
L'equazione risolta è quella del calore per unità di superficie media:
```text
rho·cp·t ∂T/∂t = k·t ∇²T + q(x, s, t) (h_est + h_int)·(T T_amb)
```
con `t` = spessore della parete e `∇²` il laplaciano nel piano `(x, s)`.
1. **Collasso dello spessore** — la temperatura è uniforme attraverso la parete. Con
spessore 0.18 mm il numero di Biot `h·t/k` vale ~1e-7 e il tempo di diffusione
attraverso la parete `t²/alpha` è di pochi millisecondi, molto più rapido del
transito delle sorgenti. Di conseguenza la profondità di penetrazione del
riscaldamento a induzione non entra nel modello: conta solo il flusso totale
assorbito per unità di superficie. La skin depth
`δ = √(2ρₑ/(ωμ))` è comunque calcolata dalla frequenza dell'induttore
(`frequenza_hz`, oppure imposta con `skin_depth_fissa_m`) e riportata come
grandezza diagnostica: per la banda stagnata a 20 kHz risulta ≈ 0.14 mm,
confrontabile con lo spessore, il che conferma che la parete è quasi isoterma
attraverso lo spessore.
2. **Sorgenti gaussiane in moto** — ogni sorgente ha un'impronta gaussiana isotropa nel
piano `(x, s)` di raggio `sigma_punto_m`. Un gruppo di `numero_sorgenti` sorgenti
equidistanti (`distanza_sorgenti_m`) si muove rigidamente a velocità costante:
`q(x, s, t) = Σᵢ q_picco · efficienza · exp(-((x - xᵢ(t))² + (s - s₀)²) / (2σ²))`.
La distanza circonferenziale è valutata sull'immagine più vicina, perché la
superficie è chiusa. L'offset `s₀` del percorso rispetto al piano del sensore è
`offset_y_percorso_m`.
3. **Scambi con l'ambiente** — convezione sulla faccia esterna (`h_esterno_W_m2K`) e su
quella interna (`h_interno_W_m2K`) su tutta la superficie, più convezione sui due
bordi anulari `x = 0` e `x = lunghezza` (`h_bordi_W_m2K`, su un'area pari a
spessore × perimetro).
4. **Temperatura iniziale** — il campo parte uniformemente alla temperatura ambiente
dell'analisi (randomizzabile).
5. **Sensore reale** — la lettura aggiunge alla temperatura vera della parete nel punto
osservato: inerzia del primo ordine (`costante_tempo_s`), rumore gaussiano
(`rumore_std_C`) e quantizzazione (`quantizzazione_C`), gli ultimi due applicati a
ogni campionamento.
6. **Randomizzazione** — con `RANDOMIZZAZIONE["abilitata"]` ogni analisi perturba
velocità, flusso di picco, sigma dello spot, offset y del percorso, temperatura
ambiente e rumore del sensore con estrazioni gaussiane/uniformi da un RNG con seed
fisso (`FEM["seed"]`): analisi diverse dello stesso setup differiscono come
differirebbero due passaggi reali, restando riproducibili.
Irraggiamento non modellato e proprietà dei materiali costanti con la temperatura: a
~210 °C le perdite radiative non sono del tutto trascurabili rispetto alla convezione, e
per gli acciai ferromagnetici la skin depth reale varia fortemente con temperatura e
campo (punto di Curie non modellato).
## Metodo numerico
- **Mesh** (`mesh.py`): griglia strutturata `n_elementi_x × n_elementi_circonferenza`
di quadrilateri a 4 nodi (default 40 × 48), chiusa lungo la circonferenza senza nodi
duplicati sulla cucitura.
- **Elementi**: shell bilineari a 4 nodi. Tutti gli elementi sono rettangoli identici
`dx × ds`, quindi le matrici di elemento (massa e rigidezza) sono calcolate una volta
sola e assemblate in forma vettorizzata. La matrice di massa di superficie è riusata
per capacità termica, convezione sulle facce e carico della sorgente; la convezione
sui bordi anulari usa una matrice di massa 1D sull'anello di nodi.
- **Integrazione temporale**: Eulero implicito con passo `FEM["dt_s"]` (default 1 ms).
Tutti i termini sono lineari e costanti, quindi la matrice di sistema è **assemblata e
fattorizzata LU una sola volta** (`scipy.sparse.linalg.splu`) in `prepara_stato_fem`;
ogni passo assembla solo il termine noto e risolve i sistemi triangolari.
- **Flusso nodale**: l'impronta gaussiana isotropa è separabile,
`q(x, s) = q_x(x) · q_s(s)`, e il fattore circonferenziale è costante nel tempo
(precalcolato). A ogni passo si valuta quindi solo il fattore assiale sui `n_x + 1`
nodi distinti in x, espanso con un prodotto esterno.
- Se in futuro si introducessero proprietà dipendenti dalla temperatura, la matrice
andrebbe ricostruita e rifattorizzata a ogni passo.
2026-07-05 11:58:52 +02:00
## File
```text
main.py punto di ingresso da riga di comando
config.py tutti i parametri (geometria, mesh, FEM, aria, sorgente, sensore)
materials.py proprietà termofisiche ed elettriche dei materiali
mesh.py generazione della mesh a elementi shell
fem.py solutore termico transitorio a elementi finiti
plot_mesh.py disegno della sola mesh
plot_animazione_fem.py animazione 3D del campo di temperatura
esporta_csv.py export CSV della serie temporale
output/ immagini e GIF salvate quando il backend non è interattivo
output/csv/ CSV esportati (ricreata a ogni esecuzione)
2026-07-05 11:58:52 +02:00
```
## Installazione
```bash
python -m venv .venv
source .venv/bin/activate
pip install -r requirements.txt
```
## Uso
2026-07-05 11:58:52 +02:00
```bash
python main.py # elenco delle azioni disponibili
python main.py mesh # disegna la sola mesh a elementi shell
python main.py fem # integra il campo FEM e lo anima in 3D
python main.py csv # esporta la serie temporale in output/csv/
2026-07-05 11:58:52 +02:00
```
Ogni modulo resta eseguibile anche direttamente (`python plot_mesh.py`,
`python plot_animazione_fem.py`, `python esporta_csv.py`).
2026-07-05 11:58:52 +02:00
Gli script aprono finestre interattive (backend Qt); se il backend non è interattivo
(es. sessione senza display) salvano automaticamente PNG/GIF in `output/`.
L'animazione FEM mostra due pannelli: la fascetta in vista isometrica con il campo di
temperatura dipinto sugli elementi shell e i marker delle sorgenti in transito, e la
storia della temperatura nel punto osservato dal sensore (valore nodale vero e lettura
del sensore reale). Finestra temporale iniziale e cadenza dei fotogrammi si
regolano con le costanti in testa a `plot_animazione_fem.py`; la durata simulata è
`FEM["durata_s"]`.
2026-07-05 11:58:52 +02:00
## Output CSV
`python main.py csv` cancella e ricrea `output/csv/`, poi esporta `FEM["num_run"]` analisi
(una per file `run_XXXX.csv`) più un `metadata.csv` con una riga per analisi. Le righe
sono campionate a `FEM["frequenza_campionamento_hz"]`, indipendente dal passo di
integrazione.
### `output/csv/run_XXXX.csv` — serie temporale
| Colonna | Significato |
|-------------------------|-----------------------------------------------------------------|
| `id_run` | identificativo dell'analisi |
| `tempo_s` | tempo simulato |
| `x_sorgente_m` | posizione della sorgente di riferimento del gruppo |
| `T_vera_sensore_C` | temperatura vera della parete nel punto osservato (valore nodale FEM) |
| `T_misurata_sensore_C` | lettura del sensore (inerzia + rumore + quantizzazione) |
| `T_massima_fascetta_C` | temperatura nodale massima su tutta la fascetta in quell'istante |
| `T_ambiente_C` | temperatura ambiente dell'analisi |
| `offset_y_sorgente_m`, `velocita_m_s`, `sigma_punto_m`, `flusso_picco_W_m2` | parametri effettivi dell'analisi (variano se la randomizzazione è attiva) |
| `skin_depth_m` | skin depth diagnostica |
| `materiale` | chiave del materiale |
### `output/csv/metadata.csv` — una riga per analisi
Tutti i parametri effettivi (geometria, mesh, coefficienti di scambio, sorgenti, sensore)
e i valori di picco: `T_vera_max_sensore_C`, `T_misurata_max_sensore_C`,
`T_massima_fascetta_C`.
## Configurazione
2026-07-05 11:58:52 +02:00
Tutto si modifica in `config.py`. I dizionari principali:
2026-07-05 11:58:52 +02:00
| Dizionario | Contenuto |
|-------------|---------------------------------------------------------------------------|
| `FASCETTA` | diametro, lunghezza, spessore, materiale |
| `MESH` | numero di elementi shell lungo x e lungo la circonferenza |
| `FEM` | passo temporale, durata, seed, campionamento CSV, numero di analisi |
| `ARIA` | temperatura ambiente e coefficienti di convezione (facce e bordi) |
| `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 analisi |
| `USCITA` | cartella per immagini e animazioni salvate |
2026-07-05 11:58:52 +02:00
Punti da conoscere:
2026-07-05 11:58:52 +02:00
- **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à termica, densità, calore specifico, resistività elettrica,
permeabilità relativa).
- **Proprietà di `banda_stagnata`**: la banda stagnata è un nastro di acciaio a basso
tenore di carbonio (0,150,25% C) rivestito su entrambe le facce da un sottile
strato di stagno elettrolitico, dello spessore di pochi micrometri — trascurabile
rispetto allo spessore tipico della parete (es. 0,18 mm) e quindi ininfluente sulle
proprietà termiche, elettriche e magnetiche in massa. I valori in `materials.py` sono
quindi quelli dell'acciaio dolce sottostante:
[Banda stagnata: tutto quello che c'è da sapere (MUNDOLATAS)](https://mundolatas.com/it/banda-stagnata-tutto-quello-che-ce-da-sapere/),
[Bande stagnate elettrolitiche (EUROPERF)](https://www.europerf.it/it/banda-stagnata-elettrolitica.php),
[Differenza tra banda stagnata e acciaio inossidabile (Wuxi Bright Packing)](https://it.brightmetalcan.com/info/difference-between-tinplate-and-stainless-stee-48700260.html).