Motivation. Outliers (cosmic rays, spikes) are currently handled only by hard 0/1 weighting in weights.py. A robust loss down-weights large residuals smoothly and improves fits on spiky spectra without manual masking.
Approach. Add an optional loss key to fit_params ("linear" default = current behavior, plus "soft_l1", "huber"). Implement via IRLS-style residual scaling inside the LM residual/cost computation in optimizer.py: multiply residuals and Jacobian rows by sqrt(ρ'(r²)). Keep "linear" bit-identical to today.
Scope.
optimizer.py: apply robust weight factor when loss != "linear".
Thread loss through VBFengine.fit_spectra and api/fitting.py.
Tests: a spectrum with injected spikes recovers the true peak better under soft_l1 than linear; linear path unchanged (determinism test still bit-identical).
Risks. Off by default → existing fits untouched. Robust weighting interacts with coef_noise weighting; document the composition order.
Motivation. Outliers (cosmic rays, spikes) are currently handled only by hard 0/1 weighting in weights.py. A robust loss down-weights large residuals smoothly and improves fits on spiky spectra without manual masking.
Approach. Add an optional loss key to fit_params ("linear" default = current behavior, plus "soft_l1", "huber"). Implement via IRLS-style residual scaling inside the LM residual/cost computation in optimizer.py: multiply residuals and Jacobian rows by sqrt(ρ'(r²)). Keep "linear" bit-identical to today.
Scope.
optimizer.py: apply robust weight factor when loss != "linear".
Thread loss through VBFengine.fit_spectra and api/fitting.py.
Tests: a spectrum with injected spikes recovers the true peak better under soft_l1 than linear; linear path unchanged (determinism test still bit-identical).
Risks. Off by default → existing fits untouched. Robust weighting interacts with coef_noise weighting; document the composition order.