Keyboard shortcuts

Press ← or → to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

How calibration works

For a numbered walk-through on real data, with the settings and troubleshooting, see Tutorial 2: Calibrate.

A raw frame from a camera is not a picture of the sky. Each pixel carries a fixed electronic offset (the bias), a signal that grows with time even in the dark (the dark current), and a sensitivity that varies across the sensor and through dust and vignetting (the flat field). Calibration undoes all three:

calibrated = (light - bias - k * dark) / flat

Valerian builds the three masters from your calibration frames and applies them. This page says what it does and what it does not do yet. The functions live in valerian_core::calibrate (frames already in memory) and valerian_core::streaming (frames read from files); the command is valerian calibrate.

Masters

  • Master bias: the rejected mean of the bias frames.
  • Master dark: the rejected mean of the dark frames. Given a master bias, the bias is subtracted first, so the master holds only dark current and can be scaled to another exposure time (the header says BIASSUB = T). Without a bias it holds bias plus dark current, and can only be subtracted as it is, from lights of the same exposure and temperature.
  • Master flat: each flat has a master dark flat (or a master bias, if you took none) subtracted, is scaled to a common level by its median so that a lamp that drifts does not look like noise, and the frames are combined and normalised to a mean of one. For one-shot-colour cameras the normalisation is either global, which keeps the colour balance the flat records, or per colour, which corrects vignetting and dust only.

Memory: masters are streamed

Rejection works one pixel position at a time: the samples at a position never depend on any other position. So a master does not need every frame in memory. valerian calibrate reads a band of rows from every file, combines the band with the chosen rejection, keeps the result and moves on to the next band. The master is bit for bit the one you would get with every frame loaded, and the memory used follows --memory (in MiB, default 1024) and not the number of frames. One row of each frame is the least it can work with, so the budget is a target for the band, not a hard cap: the finished masters, the light being calibrated and the pixel map are held on top of it.

The one number that needs a whole frame is a flat's level (the median that brings the flats to a common brightness). It is found first, reading the flats one at a time.

Measured on a 24-core machine without a GPU, at the commit this page was written for: a bias master of 70 frames of 4656 by 3520 pixels (16-bit, 31 MB each) took 5.8 GiB of memory when every frame was loaded, and 0.53 GiB with the default budget and 0.41 GiB with --memory 256, in the same time (4 to 5 seconds), with an identical result. Ten darks, thirty dark flats and thirty flats with the pixel map and one light: 4.8 GiB before, 1.4 GiB now, 19 s before and 11 s now.

Rejection

Combining uses per-pixel rejection of outliers (cosmic rays, hot pixels that flicker, satellite trails), implemented once for masters and for the final stack:

SchemeUse it for
Winsorised sigma clippingFewer than about 15 frames. A single bright outlier cannot be caught by plain sigma clipping with so few frames, because it inflates the deviation it is judged by.
Sigma clipping15 to 30 frames.
Linear fit clippingMore than about 30 frames, and stacks whose level varies.
Min/maxA crude fallback.

Rejection::auto picks one from the number of frames. Each result also records how many samples every input frame lost to rejection, which is the quickest way to find a frame that is bad as a whole.

Dark scaling

By default the dark is subtracted as it is. If your darks and lights differ in exposure, scaling can be turned on: exposure multiplies the dark by the ratio of the exposure times, and optimise fits the multiplier to the light itself from its hot pixels, which also copes with a temperature difference. Scaling needs a bias-subtracted dark and is refused otherwise.

Hot and cold pixels

A pixel map is built from the master dark: every pixel is compared with the median of its eight same-colour neighbours (two pixels away on a Bayer sensor), so slow gradients such as amp glow do not trip it, and flagged if it is more than a chosen number of robust sigmas above (hot) or below (cold). Dead pixels are added from the flat. Flagged pixels are replaced by the median of their unflagged neighbours after calibration.

How many pixels the map flags depends on the sensor. On the ASI1600MM used for testing, about one pixel in a hundred is warm in a five-minute dark, and dark subtraction already handles those; asking only for the extreme ones (40 sigma) leaves 0.06 % to be repaired.

The limits are --hot-sigma (default 40) and --cold-sigma (default 12), in robust sigmas of the difference between a pixel and the median of its neighbours in the master dark. Lower --hot-sigma to repair more pixels, each replaced by a median of its neighbours; raise it to repair fewer. --cold-sigma works the same way for pixels below their neighbours. With --auto-cosmetic (no dark) the hot limit used is the smaller of --hot-sigma and 8.

A light frame can also be checked on its own, without a dark. A pixel is flagged only when its neighbours do not share the excess, which is what keeps the core of an undersampled star from being mistaken for a hot pixel. This is a heuristic; a master dark is better.

One-shot colour

Calibration works on the raw mosaic, then the frame is demosaiced (Malvar-He-Cutler, or bilinear) into red, green and blue planes. The Bayer pattern comes from BAYERPAT, shifted by XBAYROFF and YBAYROFF, and is applied to the array as stored in the file.

A flat is normally divided by its overall mean. On a one-shot colour sensor the flat then also carries the colour response of the filter array, so the corrected light has its colour balance changed. --flat-per-channel divides each Bayer colour by its own mean instead, so the flat corrects vignetting and dust and leaves the colour balance to the colour calibration step. It has no effect on a mono sensor, whose flat has no Bayer pattern.

Not done yet

  • Scaled dark flats: the dark flat must match the flat's exposure.
  • Streaming the lights: the lights are calibrated one at a time already, but stacking still holds all its frames (see How stacking works).
  • Calibration on the GPU is there (--backend gpu) but is slower than the CPU for one frame at a time, because of the copies across the bus; see The GPU kernels.