2.8 KiB
CLAUDE.md
This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository.
Project purpose
Thermal analysis of a box passing through a production oven, measured with IR sensors. The goal is to find the mathematical law that best interpolates the temperature data in data.csv. The user directs the analysis and Claude implements the requested models in Python.
Setup
python -m venv venv
venv\Scripts\activate
pip install -r requirements.txt
Running scripts
python <script_name>.py
Each script is standalone and produces a PNG plot. No test suite exists.
Data
data.csv columns used for fitting:
time since start [ms]— converted to seconds in every script (/1000)temp_obj IR [C]— box temperature, the fitting targettemp_amb IR [C]— ambient temperature, used to compute T∞
All fits start from t = 105 s. The transition zone [115.9–117.2 s] is excluded by setting sigma = 1e10 for those points (weighted least squares, not deletion). T∞ = 22.99°C is a fixed constant computed once in calcola_t_amb.py and hardcoded in the other scripts.
Fitting architecture
All fits use scipy.optimize.curve_fit(..., method="trf") (Trust Region Reflective, nonlinear least squares). The base pattern shared across every fit script:
popt, pcov = curve_fit(model, t_fit, T_fit, p0=[...], bounds=([...], [...]),
sigma=sigma, absolute_sigma=True, method="trf")
residuals = T_fit - model(t_fit, *popt)
ss_res = np.sum((residuals / sigma_clean)**2) # ignores excluded zone
ss_tot = np.sum((T_fit[mask] - np.mean(T_fit[mask]))**2)
R2 = 1 - ss_res / ss_tot
perr = np.sqrt(np.diag(pcov)) # parameter uncertainties (1σ)
Models implemented
| Script | Model | Fixed params |
|---|---|---|
fit_raffreddamento_intero.py |
T∞ + A·exp(-(t-t0)/τ) — full range, weighted |
T∞, t0=115.0s |
fit_raffreddamento_1tratto.py |
same — segment [115.0–115.9s] | T∞, t0=115.0s |
fit_raffreddamento_2tratto.py |
same — segment [117.5s–end] | T∞, t0=117.5s |
fit_doppio_esponenziale.py |
T∞ + A1·exp(-(t-t1)/τ1) + A2·exp(-(t-t2)/τ2) |
T∞, t1=115.0s, t2=117.5s |
The double exponential (fit_doppio_esponenziale.py) is the best model: R² = 0.9991, decomposing cooling into a fast surface component (τ₁ ≈ 1.8 s) and a slow core component (τ₂ ≈ 17.6 s).
Adding a new fit
- Copy an existing fit script as a template.
- Define the model function with T∞ baked in or passed as a fixed parameter.
- Set
p0from physical intuition or from a preliminary simpler fit. - Use
sigma = np.where(mask_exclude, 1e10, 1.0)to down-weight bad zones. - Compute R² only over the unmasked points (
mask_clean). - Save output as a new PNG; do not overwrite existing plots.