SpectrumFit
SpectrumFit is the analyzer that comes with plesty-lib, in plesty.lib.analyzer.
It fits every emission line in every spectrum of a SpectrumData (a stack of spectra,
one per step of a scan; see
Example: SpectrumData), each on a
background, and returns the lines’ positions, widths and heights with their
uncertainties.
It needs SciPy, from the fit extra (see Install), and says
so if it is missing.
Each spectrum in the stack is called a frame. SpectrumData.from_run builds the
stack from a run: one frame per step that saved a spectrum, with the values scanned in
that step (here the angle hwp_deg) kept as the frame’s coordinates.
from plesty.lib.analyzer import SpectrumFit
from plesty.lib.data import SpectrumData
spectrum = SpectrumData.from_run(run_dir, coordinates=("hwp_deg",))
outputs = SpectrumFit(prominence=250, window=0.05, center_tolerance=0.1)(spectrum=spectrum)
fit = outputs["fit"] # SpectrumFitData
fit["center"], fit["area_err"] # (frames, peaks)
fit.coordinates["hwp_deg"] # one angle per row
outputs["curve"] # the fitted model, nan outside fitted ranges
How it fits:
Lines —
peaks="auto"finds them in the average of the selected frames (prominence,distance); a list of positions is used as given, or relocated to the strongest local maximum withintolerance. Withaverage="median"the average is the per-pixel median: a cosmic ray hits one frame and drops out of the median, while in the mean of a few dozen frames it can still stand out as a line.Groups — each line’s FWHM is estimated on the average; neighbours closer than
overlap× the larger FWHM are fitted together.Range — a group is fitted over
windowbeyond its outer lines, re-centred on each frame’s starting centres so it follows a drifting line; without a window, up to halfway to the neighbouring groups.Frames — the average seeds the first frame in
order; withtrack, each frame seeds the next, andcenter_tolerancekeeps a line near its seed. A frame whose fit fails isnan.Quality — reported, never acted on. With
track, each frame’s range is centred on the previous frame’s fitted position. When a line is weak in one frame, its fit can move onto a brighter neighbouring spectral line inside that range and stay on it for all later frames. Per line,fit.metadata["diagnostics"]counts the frames that show this, and aFitQualityWarningnames every line with a non-zero count:Counter
Counts
failedframes whose fit did not converge (
nan)no_errorframes whose centre error could not be estimated
center_at_boundframes with the centre at its window or
center_toleranceedgewidth_at_boundframes with the FWHM at a width bound (not checked for Voigt)
jumpssteps between consecutive frames larger than the line’s FWHM
outlierscentres more than 5 robust σ (MAD) from the line’s median
A steadily drifting line raises none of them. Filter the warning with
warnings.simplefilter("ignore", FitQualityWarning)once the counts are read.
Parameter |
Default |
Meaning |
|---|---|---|
|
|
|
|
|
|
|
|
|
|
halfway to neighbours |
Fitted range beyond a group’s outer lines |
|
all, in index order |
Frames to fit, and the order to fit them in |
|
|
Seed each frame with the previous frame’s fit |
|
|
Grouping factor on the FWHM; |
|
none / |
Line detection for |
|
|
|
|
none |
Relocate given positions to a local maximum this close |
|
estimated / none |
Initial FWHM and its bounds |
|
fitted range |
Maximum distance of a line from its seed |
|
|
Keep heights at or above zero |
Outputs: fit, a SpectrumFitData, and curve, a SpectrumData. Both keep the
input spectrum’s provenance and frame coordinates; the parameters enter the
provenance stamp.
SpectrumFitData holds every quantity as an array (frames, peaks): center,
fwhm, height, area, background_offset, background_slope, each with
<name>_err, plus r_squared, with nan where a frame’s fit failed. frame
names the spectrum frame of each row, x_ref the position each background offset
refers to, and coordinates the rows’ sweep values. Units follow the spectrum
(area in intensity × wavelength). fit["center"] reads an array; fit.peak(i)
gives one line’s quantities over the frames.
Analyzers that fit something other than a spectrum stack — a line centre
across a polarization sweep, say — build on the same primitives:
fit_spectrum(x, y, [Peak(...), ...], model, background, sigma=...) fits
several lines with bounds and per-point errors and returns a
SpectrumFitResult (per line center, fwhm, height, area, each ±
error; background; r_squared; evaluate(x)); fit_peak is its one-line
form.