Tutorial: analyse a spectrum¶
A complete, guided analysis - from a FITS file to fitted lines and an exported result. It assumes you have installed spectro-kernel.
We will do the same analysis three times - as a library, as a pipeline, and from the CLI - so you can see that the three doors really do lead to the same room.
The goal¶
Take a stellar spectrum, and:
- normalise its continuum,
- measure its signal-to-noise ratio,
- fit the H-alpha line,
- export the normalised spectrum.
Step 0 - a spectrum to work with¶
If you do not have a FITS file handy, make a synthetic one:
import numpy as np
from spectro_kernel.io import write_fits
from spectro_kernel.types import Spectrum1D
wave = np.linspace(6300, 6800, 2000)
flux = 1000 + 80 * np.exp(-0.5 * ((wave - 6562.8) / 3.0) ** 2) # H-alpha in emission
flux += np.random.default_rng(42).normal(0, 8, wave.size) # noise
write_fits(Spectrum1D(wave, flux, meta={"object": "demo star"}), "demo.fits")
Approach 1 - step by step, as a library¶
from spectro_kernel import WorkContext, run_algorithm
from spectro_kernel.io import read_fits
ctx = WorkContext(spectrum=read_fits("demo.fits"))
run_algorithm("normalize_polynomial", ctx, {"order": 3})
run_algorithm("snr_der", ctx)
run_algorithm("fit_gaussian_line", ctx,
{"line_center_angstrom": 6562.8, "window_angstrom": 30, "label": "H-alpha"})
run_algorithm("export_fits", ctx, {"path": "demo_normalised.fits"})
fit = ctx.line_fits["H-alpha"]
print(f"SNR : {ctx.metrics['snr_der']:.0f}")
print(f"H-alpha centre : {fit.line_center_angstrom:.2f} Å")
print(f"H-alpha FWHM : {fit.fwhm_angstrom:.2f} Å")
print(f"emission? : {fit.is_emission}")
Notice that nothing is passed between the calls explicitly - each algorithm reads from
and writes to the shared WorkContext.
Inspect what happened¶
for step in ctx.history:
print(step) # [ok] normalize_polynomial v1.0.0 (2.1ms) …
print(ctx.summary()) # everything the context now holds
That history is the audit trail - see Pipelines →
Reproducibility.
Approach 2 - as a pipeline¶
The same four steps, declared once and run as a unit:
from spectro_kernel import PipelineBuilder, WorkContext
from spectro_kernel.io import read_fits
pipeline = (
PipelineBuilder()
.named("h-alpha analysis")
.add("normalize_polynomial", order=3)
.add("snr_der")
.add("fit_gaussian_line", line_center_angstrom=6562.8, window_angstrom=30, label="H-alpha")
.add("export_fits", path="demo_normalised.fits")
.build()
)
result = pipeline.execute(WorkContext(spectrum=read_fits("demo.fits")))
print("success:", result.success)
print(result.context.metrics)
Approach 3 - from the command line¶
No Python at all:
spectro run normalize_polynomial -i demo.fits -p order=3 -o demo_normalised.fits
spectro run snr_der -i demo.fits
spectro run fit_gaussian_line -i demo.fits -p line_center_angstrom=6562.8 -p window_angstrom=30
Or, capturing the snr_check preset's full output as JSON:
What you have learned¶
- A
WorkContextcarries the analysis; algorithms read and write it. run_algorithmruns one step; aPipelineruns many.- The library, the CLI (and the MCP server) all drive the same catalogue.
- Every run leaves a reproducible audit trail.
Next: make the catalogue your own → Tutorial: add an algorithm.