Aggiunge il pannello T-t del sensore all'animazione FEM
Sotto la vista 3D compare la storia della temperatura nel nodo osservato dal sensore, con il cursore sull'istante corrente: la curva nodale calcolata dal FEM e la stessa filtrata dall'inerzia del sensore. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
This commit is contained in:
+40
-5
@@ -102,10 +102,14 @@ def main() -> None:
|
||||
norm = matplotlib.colors.Normalize(vmin=T_ambiente, vmax=T_max)
|
||||
cmap = matplotlib.colormaps["inferno"]
|
||||
|
||||
fig = plt.figure(figsize=(9, 7))
|
||||
ax = fig.add_subplot(projection="3d")
|
||||
fig = plt.figure(figsize=(9, 8.5))
|
||||
griglia = fig.add_gridspec(2, 1, height_ratios=[2.6, 1.0], hspace=0.05)
|
||||
ax = fig.add_subplot(griglia[0], projection="3d")
|
||||
ax_storia = fig.add_subplot(griglia[1])
|
||||
ax.view_init(elev=35.264, azim=45)
|
||||
ax.set_box_aspect((lunghezza_m, 2 * raggio_m, 2 * raggio_m))
|
||||
# zoom > 1 riempie il riquadro: con set_axis_off gli assi 3D lascerebbero
|
||||
# altrimenti molto margine vuoto sopra il pannello della storia.
|
||||
ax.set_box_aspect((lunghezza_m, 2 * raggio_m, 2 * raggio_m), zoom=1.12)
|
||||
ax.set_axis_off()
|
||||
ax.set_xlim(0.0, lunghezza_m)
|
||||
ax.set_ylim(-raggio_m, raggio_m)
|
||||
@@ -120,11 +124,38 @@ def main() -> None:
|
||||
|
||||
mappabile = cm.ScalarMappable(cmap=cmap, norm=norm)
|
||||
mappabile.set_array([])
|
||||
barra = fig.colorbar(mappabile, ax=ax, shrink=0.6, pad=0.05)
|
||||
# La colorbar è agganciata a entrambi i pannelli per non restringere solo
|
||||
# quello 3D: così i due riquadri restano della stessa larghezza.
|
||||
barra = fig.colorbar(mappabile, ax=(ax, ax_storia), shrink=0.6, pad=0.02, aspect=30)
|
||||
barra.set_label("T [°C]")
|
||||
|
||||
titolo = ax.set_title("")
|
||||
|
||||
# Pannello inferiore: storia della temperatura nel punto osservato dal
|
||||
# sensore. T_vere è il valore nodale calcolato dal FEM, T_lette lo stesso
|
||||
# segnale filtrato dall'inerzia del primo ordine del sensore.
|
||||
# Con la costante di tempo del sensore le due curve sono quasi
|
||||
# sovrapposte: la prima è tracciata spessa e trasparente perché la seconda,
|
||||
# tratteggiata, resti leggibile sopra di essa.
|
||||
linea_vera, = ax_storia.plot(
|
||||
[], [], color="tab:blue", linewidth=3.0, alpha=0.4,
|
||||
label="T nodo del sensore (FEM)",
|
||||
)
|
||||
linea_letta, = ax_storia.plot(
|
||||
[], [], color="tab:red", linewidth=1.2, linestyle="--",
|
||||
label="T misurata dal sensore (con inerzia)",
|
||||
)
|
||||
cursore = ax_storia.axvline(tempi[indice_inizio], color="gray", linewidth=0.8)
|
||||
ax_storia.set_xlim(0.0, tempi[-1])
|
||||
ax_storia.set_ylim(
|
||||
T_ambiente - 0.05 * (T_max - T_ambiente),
|
||||
max(dati["T_vere"].max(), dati["T_lette"].max()) * 1.08,
|
||||
)
|
||||
ax_storia.set_xlabel("Tempo [s]")
|
||||
ax_storia.set_ylabel("T [°C]")
|
||||
ax_storia.legend(loc="upper left")
|
||||
ax_storia.grid(True, alpha=0.3)
|
||||
|
||||
def disegna_frame(k: int):
|
||||
T_elementi = dati["campi"][k][elementi].mean(axis=1)
|
||||
colori = cmap(norm(T_elementi))
|
||||
@@ -142,11 +173,15 @@ def main() -> None:
|
||||
np.full(n_visibili, raggio_m * np.cos(theta_sorgente) * 1.06),
|
||||
)
|
||||
|
||||
linea_vera.set_data(tempi[: k + 1], dati["T_vere"][: k + 1])
|
||||
linea_letta.set_data(tempi[: k + 1], dati["T_lette"][: k + 1])
|
||||
cursore.set_xdata([tempi[k], tempi[k]])
|
||||
|
||||
titolo.set_text(
|
||||
f"FEM shell — t = {tempi[k]:.2f} s — "
|
||||
f"T sensore = {dati['T_lette'][k]:.1f} °C"
|
||||
)
|
||||
return collezione, marker_sorgenti, titolo
|
||||
return collezione, marker_sorgenti, linea_vera, linea_letta, cursore, titolo
|
||||
|
||||
animazione = FuncAnimation(
|
||||
fig, disegna_frame, frames=indici_frame,
|
||||
|
||||
Reference in New Issue
Block a user