Files
simulatore-induttori/README.md
T
davideandClaude Opus 5 1631d6c94e Rimuove il modello ai volumi finiti lasciando la sola analisi FEM
Il progetto conteneva due discretizzazioni indipendenti della stessa fisica:
i volumi finiti sulla sezione x-z di simulate.py (con generazione del dataset
CSV e le sue animazioni 2D/3D) e gli elementi finiti sulla mesh shell di
fem.py. Resta solo il secondo, che risolve la circonferenza invece di
collassarla in un'attenuazione gaussiana.

Eliminati simulate.py, plot_csv.py, plot_animazione.py e plot_animazione_3d.py.
Il FEM dipendeva da simulate.py per la cinematica del gruppo di sorgenti e per
la configurazione del run, quindi fem.py assorbe _x_riferimento_iniziale_m,
_x_riferimento_finale_m, _intervallo_attivo e configurazione_randomizzata; la
lettura del sensore (inerzia, rumore, quantizzazione) è ora applicata dentro
simula_campo_fem e la skin depth resta calcolata dalla frequenza dell'induttore
come sola grandezza diagnostica, dato che nel modello shell lo spessore è
collassato.

config.py perde i parametri che servivano solo ai volumi finiti (griglia
n_nodi_x/n_nodi_z, campionamento e cartella del dataset, numero di processi) e
guadagna FEM["durata_s"], FEM["seed"] e USCITA["cartella"]: le immagini e le
animazioni vanno in output/ invece che in dataset/.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-08-03 11:44:58 +02:00

196 lines
10 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# Analisi Termica FEM — Fascetta, Sorgenti a Induzione Mobili, Sensore IR Fisso
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.
## Geometria
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.
```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)
```
- **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)`.
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`.
## 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.
## 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
output/ immagini e GIF salvate quando il backend non è interattivo
```
## Installazione
```bash
python -m venv .venv
source .venv/bin/activate
pip install -r requirements.txt
```
## Uso
```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
```
Ogni modulo resta eseguibile anche direttamente (`python plot_mesh.py`,
`python plot_animazione_fem.py`).
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"]`.
## Configurazione
Tutto si modifica in `config.py`. I dizionari principali:
| Dizionario | Contenuto |
|-------------|---------------------------------------------------------------------------|
| `FASCETTA` | diametro, lunghezza, spessore, materiale |
| `MESH` | numero di elementi shell lungo x e lungo la circonferenza |
| `FEM` | passo temporale, durata dell'analisi transitoria, seed |
| `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 |
Punti da conoscere:
- **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).