import re import pandas as pd import numpy as np import matplotlib.pyplot as plt from scipy.optimize import curve_fit from pathlib import Path # --- Dati --- ROOT = Path(__file__).parent.parent df = pd.read_csv(ROOT / "data.csv") df["time_s"] = df["time since start [ms]"] / 1000.0 def _leggi_t_inf() -> float: report = ROOT / "start" / "report.md" if not report.exists(): raise FileNotFoundError("start/report.md non trovato. Esegui prima 'Calcola T ambiente'.") m = re.search(r"media ponderata\*\*\s*\|\s*\*\*([0-9.]+)\s*°C", report.read_text(encoding="utf-8")) if not m: raise ValueError("T∞ non trovata in start/report.md.") return float(m.group(1)) T_INF = _leggi_t_inf() # temperatura ambiente [°C], letta da start/report.md T0 = 112.02 # inizio intervallo [s] T_END = 113.95 # fine intervallo [s] 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 # --- Modello: esponenziale di Newton --- def modello(t, A, tau): return T_INF + A * np.exp(-(t - T0) / tau) A0 = T_fit[0] - T_INF tau0 = 5.0 popt, pcov = curve_fit( modello, t_fit, T_fit, p0=[A0, tau0], method="trf", bounds=([-np.inf, 0.01], [np.inf, np.inf]) ) A_fit, tau_fit = popt perr = np.sqrt(np.diag(pcov)) # --- 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 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}") print(f"\nEquazione: T(t) = {T_INF} + {A_fit:.4f} * exp(-(t - {T0}) / {tau_fit:.4f})") # --- Curva continua per il plot --- t_curve = np.linspace(T0, T_END, 500) T_curve = modello(t_curve, *popt) # --- Plot --- fig, ax = plt.subplots(figsize=(10, 6)) ax.scatter(t_fit, T_fit, color="steelblue", s=60, edgecolors="white", linewidths=0.5, zorder=3, label="Dati raw (temp_obj)") ax.plot(t_curve, T_curve, color="tomato", linewidth=2.5, label="Fit esponenziale") ax.set_xlabel("Tempo [s]", fontsize=13) ax.set_ylabel("Temperatura [°C]", fontsize=13) ax.set_title(f"Induttore 2 — Fit esponenziale [{T0}–{T_END} s]", fontsize=14, fontweight="bold") ax.tick_params(labelsize=11) ax.legend(fontsize=11, framealpha=0.9) ax.grid(True, which="both", alpha=0.3) ax.minorticks_on() eq_text = (f"$T(t) = {T_INF} + {A_fit:.2f}\\cdot e^{{-(t-{T0})/{tau_fit:.3f}}}$\n" f"$R^2 = {r2:.4f}$") ax.text(0.97, 0.95, eq_text, transform=ax.transAxes, fontsize=11, verticalalignment="top", horizontalalignment="right", bbox=dict(boxstyle="round,pad=0.4", facecolor="white", alpha=0.8)) plt.tight_layout() plt.savefig(Path(__file__).parent / "induttore2.png", dpi=200, bbox_inches="tight") plt.show() # --- Report --- report = Path(__file__).parent / "report2.md" with open(report, "w", encoding="utf-8") as f: f.write("# Report Induttore 2\n\n") f.write("## Intervallo di campionamento\n\n") f.write(f"| Parametro | Valore |\n|---|---|\n") f.write(f"| Inizio | {T0} s |\n") f.write(f"| Fine | {T_END} s |\n") f.write(f"| Numero di punti | {len(t_fit)} |\n\n") f.write("## Equazione trovata\n\n") f.write(f"$$T(t) = {T_INF} + {A_fit:.4f} \\cdot e^{{-(t - {T0}) / {tau_fit:.4f}}}$$\n\n") f.write("| Parametro | Valore | Incertezza (1σ) |\n|---|---|---|\n") f.write(f"| A | {A_fit:.4f} °C | +/- {perr[0]:.4f} °C |\n") f.write(f"| τ | {tau_fit:.4f} s | +/- {perr[1]:.4f} s |\n\n") f.write("## Qualità del fit\n\n") f.write(f"| R² | {r2:.6f} |\n|---|---|\n") print("report2.md generato.")