How it works

Stacking, made
visible.

Stacking is the single most important idea in deep-sky imaging, and the hardest to explain. SNRflow doesn't explain it — it shows it happening, on your own frames, with the numbers running alongside.

Why stacking works

Signal adds up frame after frame. Noise, being random, only grows with the square root of the number of frames. Stack four subs and you double your signal-to-noise ratio; stack a hundred and you multiply it by ten.

That is the whole trick — and it is why an hour of total exposure beats a single one-hour shot.

Where it stops paying off

Because the curve is a square root, it flattens. Going from 10 to 40 frames is transformative; going from 200 to 230 is barely visible.

Watching the measured curve bend tells you when your night has given what it had — and when it is time to move to another target.

Step by step

What actually happens when you press Generate

01

It reads your session

The FITS headers already hold the exposure time, the target name, the filter and the capture dates. SNRflow reads a sample of your frames and fills the fields in for you.

02

It places the measurement zones

SNR needs two regions: something bright, and something empty. One click and the app scans the frame — brightest window for the signal, darkest and flattest for the background, never overlapping. You can still drag them wherever you like.

03

Siril calibrates and registers

Masters are built from your darks, flats and biases, the lights are calibrated and aligned. If you already have a registered sequence, this step is skipped entirely.

04

It stacks — one frame at a time

Rather than stacking everything at once, SNRflow adds one light, re-measures, renders a frame, and repeats. That running average is exactly what you see building up on screen.

05

It measures, honestly

SNR = (mean of signal − median of background) ÷ noise of background. The orange curve is that measurement. The dashed grey one is the √n law anchored on your first frames — the ideal you are chasing.

06

ffmpeg wraps it up

A vertical H.264 clip at the duration you asked for. Change your mind about the length and it re-encodes in seconds, reusing the frames already rendered.

The maths

Every number, and where it comes from.

Nothing here is a rule of thumb copied off a forum. Four formulas, each derived below, each fed with values measured on your own frames.

01

What SNR actually means here

Signal-to-noise ratio is a ratio of two things you can point at in the frame: how far the object rises above the sky, divided by how much the empty sky wobbles.

SNR = ( µsignal − medbackground ) ⁄ σbackground
µsignal — mean level inside the signal box
medbackground — median level inside the background box
σbackground — standard deviation inside that same box

The median is used for the sky and the mean for the object on purpose: a faint star drifting through the background box would drag a mean upwards, but barely moves a median. Subtracting the sky level is what makes the number comparable between a dark site and a city balcony.

02

Why stacking follows a square root

Stack n frames and average them. The signal is the same in every frame, so it survives the average untouched. The noise is random and different in every frame, so it partly cancels.

signal → S     noise → σ ⁄ √n
⇒   SNR(n) = ( S ⁄ σ ) · √n = k · √n
k — the SNR a single sub is worth, in your sky, on your target

Adding independent random variables adds their variances, not their standard deviations: n frames give a total variance of n·σ², so the average carries σ/√n. That single fact is the whole of stacking.

SNRflow does not assume k — it fits it on your measured curve by least squares, so the model is anchored on your night:

k = Σ ( √ni · SNRi ) ⁄ Σ ni
03

How many hours should this target get?

This is the question the curve is really there to answer. Because SNR grows as the square root of time, the time needed grows as the square of the SNR you want. Invert the law:

Tneeded = Tnow · ( SNRtarget ⁄ SNRnow )2
+41 % of SNR → twice the time  ·  ×2 of SNR → four times the time  ·  ×3 → nine times

Worked example — the session in the clip above

81 subs × 300 s = 6 h 45 min, measured SNR 36.8. Say you want to reach 45.

T = 6.75 h × ( 45 ⁄ 36.8 )2 = 6.75 × 1.50 = 10.1 h
→ about 3 h 20 min more on the same target.

And when do you stop?

Adding ΔT to an integration of T multiplies the SNR by √(1 + ΔT⁄T) — which shrinks as T grows. Decide the smallest gain worth a night out, call it tol, and solve for the total beyond which one more block is no longer worth it:

√( 1 + ΔT ⁄ T ) < 1 + tol   ⇒   T > ΔT ⁄ [ (1 + tol)2 − 1 ]
ΔT = 1 h, tol = 5 % → T > 1 ⁄ 0.1025 = 9 h 45 min
past that total, another hour buys you less than 5 % of SNR

At 6 h 45 you are not there yet: the next hour is still worth +7.2 %. At 12 h it would be +4.1 %, and that hour is better spent on a different object.

The honesty check

All of that assumes your stack really does follow the law. So SNRflow also measures the exponent your curve actually followed, by fitting log SNR against log n:

SNR ∝ na   —   a = 0.50 expected
a ≈ 0.50 — textbook behaviour, the prediction holds
a < 0.45 — something is capping you: gradients, tracking drift, dew, a brightening sky. Extra hours will pay less than predicted.

That is the difference between an extrapolation and a guess: the app tells you when its own prediction should not be trusted.

04

How long to match an image you have seen?

The same inversion answers the question everyone actually asks. You have a number in mind — the SNR of a version of this object you would like to match. Set it as the goal and the app solves the law for it:

nneeded = ( SNRgoal ⁄ k )2     Tneeded = nneeded · tsub
k — the SNR of a single sub, fitted across your whole curve
tsub — your own sub length, read from the FITS header

k is the only thing that carries your conditions in it — your sky, your optics, your filter, your night. Which is why the answer is yours and not a number off a chart: the same goal costs a different number of hours from a Bortle 9 balcony than from a dark site, and the fit knows it because it was measured on your own frames.

Worked example — matching SNR 50 on the Crescent

k = 36.8 ⁄ √81 = 4.09   →   n = (50 ⁄ 4.09)2 = 150 subs   →   12 h 28 m
81 subs of 300 s already shot (6 h 45 m, SNR 36.8) → 5 h 43 m left to shoot.

Where this stops being true: the goal has to be an SNR measured the same way, on the same object, with boxes placed on the same kind of signal and sky. Comparing against a figure that came out of a different measurement is comparing two different quantities — the arithmetic will still run, and the answer will still be wrong.

Before you start

What you need

SNRflow

One installer, no dependencies to chase. It also downloads ffmpeg for you during setup if you don't have it.

Download

Siril

Free and open source. It handles calibration and registration — the two things SNRflow deliberately doesn't reinvent.

Get Siril

Your frames

A folder with lights/, and optionally darks/, flats/ and biases/. Already registered? Point SNRflow at it and Siril is never launched.

No data yet? The app can generate test frames.