Files
report-temperatura/fit_raffreddamento_intero.py
Davide Grilli 3ac42966b1 aggiunti script di fit esponenziale e report di analisi termica
- fit_raffreddamento_intero.py: fit TRF su finestra completa [115s–fine] con pesi nulli sulla zona di transizione [115.9–117.2s]
- fit_raffreddamento_2tratto.py: fit TRF sul solo tratto di raffreddamento [117.5s–fine], pesi uniformi
- report.md: analisi strutturata con calcolo T∞, parametri stimati e grafici per entrambi gli approcci
2026-04-01 10:38:37 +02:00

81 lines
2.4 KiB
Python
Raw Permalink 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.
import pandas as pd
import numpy as np
import matplotlib.pyplot as plt
from scipy.optimize import curve_fit
# --- Dati ---
df = pd.read_csv("data.csv")
df["time_s"] = df["time since start [ms]"] / 1000.0
T_INF = 22.99 # temperatura ambiente media ponderata [°C]
T_START = 115.0 # inizio finestra di fit [s]
T0 = T_START # t0 coincide con il primo punto
W_ZERO_START = 115.9
W_ZERO_END = 117.2
mask = df["time_s"] >= T_START
t_fit = df.loc[mask, "time_s"].values
T_fit = df.loc[mask, "temp_obj IR [C]"].values
# Pesi espliciti: w=0 nell'intervallo escluso, w=1 altrove
# curve_fit usa sigma come deviazione standard -> sigma grande = peso nullo
sigma = np.where(
(t_fit >= W_ZERO_START) & (t_fit <= W_ZERO_END),
1e10, # peso ~ 0
1.0 # peso pieno
)
# --- Modello con A e tau liberi (ottimizza R²) ---
def modello(t, A, tau):
return T_INF + A * np.exp(-(t - T0) / tau)
A0 = T_fit[0] - T_INF
tau0 = 20.0
popt, pcov = curve_fit(
modello, t_fit, T_fit,
p0=[A0, tau0],
sigma=sigma,
absolute_sigma=True,
method="trf",
bounds=([0, 0.1], [np.inf, np.inf])
)
A_fit, tau_fit = popt
perr = np.sqrt(np.diag(pcov))
# --- R² (solo sui punti con peso pieno) ---
mask_w = (t_fit < W_ZERO_START) | (t_fit > W_ZERO_END)
T_pred_w = modello(t_fit[mask_w], *popt)
ss_res = np.sum((T_fit[mask_w] - T_pred_w) ** 2)
ss_tot = np.sum((T_fit[mask_w] - T_fit[mask_w].mean()) ** 2)
r2 = 1 - ss_res / ss_tot
print(f"A = {A_fit:.4f} ± {perr[0]:.4f} °C")
print(f"tau = {tau_fit:.4f} ± {perr[1]:.4f} s")
print(f"R² = {r2:.6f} (calcolato sui punti con peso pieno)")
# --- Curva continua ---
t_curve = np.linspace(T_START, df["time_s"].max(), 500)
T_curve = modello(t_curve, *popt)
# --- Plot ---
fig, ax = plt.subplots(figsize=(12, 5))
ax.plot(t_fit, T_fit,
color="steelblue", linewidth=0.8, label="Dati raw (temp_obj)")
ax.axvspan(W_ZERO_START, W_ZERO_END,
color="orange", alpha=0.25, label=f"Zona esclusa [{W_ZERO_START}{W_ZERO_END} s]")
ax.plot(t_curve, T_curve,
color="tomato", linewidth=2, linestyle="--",
label=f"Fit: $T_{{\\infty}}$ + {A_fit:.2f}·exp(-(t-{T0})/{tau_fit:.2f})")
ax.set_xlabel("Tempo [s]")
ax.set_ylabel("Temperatura [°C]")
ax.set_title(f"Fit con pesi espliciti (w=0 in [{W_ZERO_START}{W_ZERO_END} s]) | R² = {r2:.4f}")
ax.legend()
ax.grid(True, alpha=0.3)
plt.tight_layout()
plt.savefig("fit_raffreddamento_intero.png", dpi=150, bbox_inches="tight")
plt.show()