diff --git a/fit_raffreddamento.png b/fit_raffreddamento.png deleted file mode 100644 index 3235ca2..0000000 Binary files a/fit_raffreddamento.png and /dev/null differ diff --git a/fit_raffreddamento_1tratto.png b/fit_raffreddamento_1tratto.png new file mode 100644 index 0000000..4cd7a98 Binary files /dev/null and b/fit_raffreddamento_1tratto.png differ diff --git a/fit_raffreddamento.py b/fit_raffreddamento_1tratto.py similarity index 62% rename from fit_raffreddamento.py rename to fit_raffreddamento_1tratto.py index 3b88c56..2db7aa1 100644 --- a/fit_raffreddamento.py +++ b/fit_raffreddamento_1tratto.py @@ -7,10 +7,11 @@ from scipy.optimize import curve_fit 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] -T0 = 117.5 # inizio finestra di fit [s] +T_INF = 22.99 # temperatura ambiente media ponderata [°C] +T0 = 115.0 # inizio finestra di fit [s] +T_END = 115.9 # fine finestra di fit [s] -mask = df["time_s"] >= T0 +mask = (df["time_s"] >= T0) & (df["time_s"] <= T_END) t_fit = df.loc[mask, "time_s"].values T_fit = df.loc[mask, "temp_obj IR [C]"].values @@ -18,8 +19,7 @@ T_fit = df.loc[mask, "temp_obj IR [C]"].values def modello(t, A, tau): return T_INF + A * np.exp(-(t - T0) / tau) -# Stima iniziale: A dal primo punto, tau arbitrario -A0 = T_fit[0] - T_INF +A0 = T_fit[0] - T_INF tau0 = 20.0 popt, pcov = curve_fit( @@ -31,37 +31,35 @@ popt, pcov = curve_fit( A_fit, tau_fit = popt # --- R² --- -T_pred = modello(t_fit, *popt) -ss_res = np.sum((T_fit - T_pred) ** 2) -ss_tot = np.sum((T_fit - T_fit.mean()) ** 2) -r2 = 1 - ss_res / ss_tot +T_pred = modello(t_fit, *popt) +ss_res = np.sum((T_fit - T_pred) ** 2) +ss_tot = np.sum((T_fit - T_fit.mean()) ** 2) +r2 = 1 - ss_res / ss_tot print(f"A = {A_fit:.4f} °C") print(f"tau = {tau_fit:.4f} s") print(f"R² = {r2:.6f}") # --- Curva continua per il plot --- -t_curve = np.linspace(T0, df["time_s"].max(), 500) +t_curve = np.linspace(T0, T_END, 500) T_curve = modello(t_curve, *popt) # --- Plot --- fig, ax = plt.subplots(figsize=(12, 5)) -df_plot = df[df["time_s"] >= 115] +df_plot = df[(df["time_s"] >= T0) & (df["time_s"] <= T_END)] ax.plot(df_plot["time_s"], df_plot["temp_obj IR [C]"], color="steelblue", linewidth=0.8, label="Dati raw (temp_obj)") ax.plot(t_curve, T_curve, color="tomato", linewidth=2, linestyle="--", label=f"Fit: $T_{{\\infty}}$ + {A_fit:.2f}·exp(-(t-{T0})/{tau_fit:.1f})") -ax.axvline(T0, color="gray", linewidth=0.8, linestyle=":") -ax.text(T0 + 0.5, ax.get_ylim()[0], f"t₀ = {T0} s", color="gray", fontsize=8, va="bottom") ax.set_xlabel("Tempo [s]") ax.set_ylabel("Temperatura [°C]") -ax.set_title(f"Fit raffreddamento esponenziale | R² = {r2:.4f}") +ax.set_title(f"Fit 1° tratto [{T0}–{T_END} s] | R² = {r2:.4f}") ax.legend() ax.grid(True, alpha=0.3) plt.tight_layout() -plt.savefig("fit_raffreddamento.png", dpi=150, bbox_inches="tight") +plt.savefig("fit_raffreddamento_1tratto.png", dpi=150, bbox_inches="tight") plt.show() diff --git a/fit_raffreddamento_pesi.png b/fit_raffreddamento_pesi.png deleted file mode 100644 index 9983744..0000000 Binary files a/fit_raffreddamento_pesi.png and /dev/null differ diff --git a/fit_raffreddamento_pesi.py b/fit_raffreddamento_pesi.py deleted file mode 100644 index ef8383c..0000000 --- a/fit_raffreddamento_pesi.py +++ /dev/null @@ -1,80 +0,0 @@ -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() diff --git a/report.md b/report.md index 8cc7f8a..2d04a22 100644 --- a/report.md +++ b/report.md @@ -73,6 +73,37 @@ $$T(t) = 22.99 + 185.18 \cdot e^{-\frac{t - 115.0}{16.27}} \quad [°C]$$ --- +### 2.2 Raffreddamento 1° tratto + +Fit sul primo sotto-tratto di raffreddamento **[115.0, 115.9 s]**, la finestra precedente alla zona di transizione. Pesi uniformi (w = 1 su tutti i punti). Parametri liberi: $A$, $\tau$. + +**Finestra:** t₀ = 115.0 s → 115.9 s. + +#### Parametri stimati + +| Parametro | Descrizione | Valore | +|---|---|---| +| $A$ | Sovratemperatura iniziale | **194.51 °C** | +| $\tau$ | Costante di tempo | **13.17 s** | + +#### Curva stimata + +$$T(t) = 22.99 + 194.51 \cdot e^{-\frac{t - 115.0}{13.17}} \quad [°C]$$ + +#### Bontà del fit + +| Metrica | Valore | +|---|---| +| $R^2$ | **0.9998** | + +#### Grafico + +![Fit 1° tratto](fit_raffreddamento_1tratto.png) + +*Dati raw `temp_obj IR [C]` (blu) e curva di fit (rosso tratteggiato) nella finestra [115.0–115.9 s].* + +--- + ### 2.3 Raffreddamento 2° tratto Fit sul solo tratto di raffreddamento stazionario, a partire dall'istante in cui la scatola ha completato l'uscita dal forno. In questa finestra i dati seguono il modello esponenziale senza discontinuità, quindi non sono necessari pesi espliciti.