Test: validazione contro i parametri veri di gen_data, report, CLI e regressioni
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
This commit is contained in:
1 parent
cbcbb7122b
commit
b223cf5fdc
7 files changed
+281
-58
No files matched your search
+81
-4
@@ -5,7 +5,7 @@ import pytest
|
||||
from conftest import GRADINI, TAU, segnale
|
||||
|
||||
from fitseg import domini
|
||||
from fitseg.analisi import analizza_domini
|
||||
from fitseg.analisi import analizza_domini, fit_scelto
|
||||
from fitseg.fit import adatta
|
||||
from fitseg.modelli import MODELLI, valuta
|
||||
|
||||
@@ -79,8 +79,10 @@ def test_riscaldamento_descritto_come_salto_non_fittato(sintetico, cfg):
|
||||
for i, (_, ampiezza) in zip((1, 3, 5), GRADINI, strict=True):
|
||||
vs = ris[i]["serie"]["dT_C"]
|
||||
assert vs["fit"] == [] and vs["scelta"] is None
|
||||
assert vs["gradino"]["delta"] == pytest.approx(ampiezza, rel=0.15) # salto sul canale ΔT, meno il decadimento
|
||||
assert vs["gradino"]["n"] <= 3
|
||||
g = vs["gradino"]
|
||||
assert g["stima"] == "modelli" and g["n"] <= 3
|
||||
assert g["delta"] == pytest.approx(ampiezza, rel=0.03) # stimato dai modelli adiacenti all'istante del gradino
|
||||
assert g["delta_misurato"] == pytest.approx(ampiezza, rel=0.15) # misura sui campioni (stima per difetto)
|
||||
|
||||
|
||||
def test_un_solo_raffreddamento_resta_libero(cfg):
|
||||
@@ -94,7 +96,7 @@ def test_dominio_troppo_corto_indeterminato(sintetico, cfg):
|
||||
t, serie = sintetico
|
||||
ds = [{"tipo": "riposo", "i0": 0, "i1": 5}]
|
||||
vs = analizza_domini(t, serie, ds, cfg)[0]["serie"]["T_C"]
|
||||
assert vs["scelta"] is None and "indeterminato" in vs["motivo"]
|
||||
assert vs["scelta"] is None and "n_min_punti" in vs["motivo"]
|
||||
|
||||
|
||||
def test_riproducibile(sintetico, cfg):
|
||||
@@ -103,3 +105,78 @@ def test_riproducibile(sintetico, cfg):
|
||||
a = analizza_domini(t, serie, ds, cfg)
|
||||
b = analizza_domini(t, serie, ds, cfg)
|
||||
assert a == b
|
||||
|
||||
|
||||
def test_salto_senza_modelli_adiacenti_resta_la_misura(sintetico, cfg):
|
||||
t, serie = sintetico
|
||||
ds = domini.proponi(t, serie, cfg)[:2] # riposo + riscaldamento: nessun raffreddamento dopo il gradino
|
||||
g = analizza_domini(t, serie, ds, cfg)[1]["serie"]["dT_C"]["gradino"]
|
||||
assert g["stima"] == "misura" and g["delta"] == g["delta_misurato"]
|
||||
|
||||
|
||||
def test_raffreddamento_corto_con_parametri_fissi_si_fitta(cfg):
|
||||
# due gradini a 0.9 s: il tratto in mezzo ha pochi campioni, ma con c e τ fissi basta stimare A
|
||||
t, serie = segnale(gradini=[(20.0, 80.0), (20.9, 60.0)], durata=80.0)
|
||||
ds = domini.proponi(t, serie, cfg)
|
||||
ris = analizza_domini(t, serie, ds, cfg)
|
||||
intermedio = ris[2]
|
||||
assert intermedio["tipo"] == "raffreddamento" and intermedio["n_fit"] < cfg["domini"]["n_min_punti"]
|
||||
vs = intermedio["serie"]["dT_C"]
|
||||
assert vs["scelta"] == "esp_decad" and fit_scelto(vs)["fissi"] == ["c", "tau"]
|
||||
atteso = 80.0 * np.exp(-(intermedio["t0_s"] - 20.0) / TAU)
|
||||
assert fit_scelto(vs)["parametri"]["A"] == pytest.approx(atteso, rel=0.03)
|
||||
|
||||
|
||||
def test_troppo_corto_anche_per_i_parametri_fissi(cfg):
|
||||
t, serie = segnale(gradini=[(20.0, 80.0), (20.5, 60.0)], durata=80.0) # tratto intermedio di 1-2 campioni
|
||||
ris = analizza_domini(t, serie, domini.proponi(t, serie, cfg), cfg)
|
||||
vs = ris[2]["serie"]["dT_C"]
|
||||
assert vs["scelta"] is None and "n_min_punti_parametri_fissi" in vs["motivo"]
|
||||
|
||||
|
||||
def test_sigma_non_stimabile_con_pochi_campioni():
|
||||
from fitseg.domini import N_MIN_SIGMA, sigma_rumore
|
||||
y = np.random.default_rng(0).standard_normal(N_MIN_SIGMA)
|
||||
assert np.isnan(sigma_rumore(y[:-1])) and np.isfinite(sigma_rumore(y))
|
||||
|
||||
|
||||
def test_tratto_corto_e_quantizzato_non_diventa_non_identificabile(cfg):
|
||||
# 5 campioni quantizzati a 0.01: la MAD delle derivate seconde si annullerebbe (σ ≈ 0) e la perdita robusta degenererebbe
|
||||
from fitseg.analisi import _serie
|
||||
ty = np.arange(5) * 0.15
|
||||
yy = np.round(115.67 * np.exp(-ty / 15.8), 2)
|
||||
vs = _serie(ty, yy, sigma_rumore_di(yy), "raffreddamento", {"c": 0.0, "tau": 15.8}, cfg)
|
||||
assert vs["sigma"] is None and vs["adeguato"] is None
|
||||
assert vs["scelta"] == "esp_decad" and fit_scelto(vs)["parametri"]["A"] == pytest.approx(115.67, rel=0.01)
|
||||
|
||||
|
||||
def sigma_rumore_di(y):
|
||||
from fitseg.domini import sigma_rumore
|
||||
return sigma_rumore(y)
|
||||
|
||||
|
||||
def test_adeguatezza_ignora_gli_scarti_casuali(cfg):
|
||||
# modello giusto con pochi scarti casuali, solo a caldo come in gen_data (−3 °C che rientrano in 0.7 s): la RMSE sale oltre
|
||||
# la soglia del vecchio criterio, la scala robusta dei residui no
|
||||
t, serie = segnale(gradini=[(20.0, 80.0)], durata=80.0)
|
||||
T = serie["T_C"].copy()
|
||||
for tj, ampiezza in ((21.5, -3.5), (24.0, -3.0), (26.5, 3.0), (29.0, -4.0)):
|
||||
T += ampiezza * np.exp(-(t - tj) / 0.7) * (t >= tj)
|
||||
S = {"T_C": T, "dT_C": T - 23.0}
|
||||
vs = analizza_domini(t, S, domini.proponi(t, S, cfg), cfg)[-1]["serie"]["T_C"]
|
||||
fit = fit_scelto(vs)
|
||||
assert fit["rmse"] > 1.3 * vs["sigma"] # il vecchio criterio lo scartava…
|
||||
assert fit["scala_residui"] <= 1.5 * vs["sigma"] and vs["adeguato"] is True # …la scala robusta no
|
||||
assert fit["parametri"]["tau"] == pytest.approx(TAU, rel=0.03)
|
||||
|
||||
|
||||
def test_salto_con_tratto_adiacente_indeterminato_usa_la_misura_corretta(cfg):
|
||||
# due gradini a 0.5 s: il tratto in mezzo (1-2 campioni) è indeterminato, ma c'è il raffreddamento finale con c e τ
|
||||
t, serie = segnale(gradini=[(20.0, 80.0), (20.5, 60.0)], durata=80.0)
|
||||
ris = analizza_domini(t, serie, domini.proponi(t, serie, cfg), cfg)
|
||||
assert ris[2]["serie"]["dT_C"]["scelta"] is None
|
||||
for i, ampiezza in ((1, 80.0), (3, 60.0)):
|
||||
g = ris[i]["serie"]["dT_C"]["gradino"]
|
||||
assert g["stima"] == "misura corretta"
|
||||
assert abs(g["delta"] - ampiezza) <= abs(g["delta_misurato"] - ampiezza) + 1e-9
|
||||
assert g["delta"] == pytest.approx(ampiezza, rel=0.03)
|
||||
Reference in new issue
Block a user