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
This commit is contained in:
80
fit_raffreddamento_pesi.py
Normal file
80
fit_raffreddamento_pesi.py
Normal file
@@ -0,0 +1,80 @@
|
||||
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_pesi.png", dpi=150, bbox_inches="tight")
|
||||
plt.show()
|
||||
Reference in New Issue
Block a user