NOAA APT weather image decoder, for Linux, Windows and OSX
Clone or download
Latest commit a6f3be4 Oct 20, 2018


NOAA APT image decoder. Runs on Linux, Windows and OSX.

Takes a recorded WAV file (from GQRX, SDR#, etc.) and decodes the raw image. Later you can rotate the image and adjust the contrast with something like GIMP or Photoshop.

Works with WAV files of any sample rate, 32 bit float or 16 bit integer encoded. When loading audio files with more than one channel, only the first one is used.

If you get some kind of error or bad result don't hesitate to open a Issue or to send me an email. You can try to run the program with the --debug option for more info.

Table of contents



Run by clicking the executable, or from terminal without arguments. You can do two things:

  • Decode a WAV file into a PNG.

  • Resample a WAV into another WAV, this is useful if you want to try a program like atp-dec/apt-dec that requires a specific sample rate.



$ ./noaa-apt --help

    ./target/release/noaa-apt [OPTIONS] [INPUT_FILENAME]

Decode NOAA APT images from WAV files. Run without arguments to launch the GUI

positional arguments:
  input_filename        Input WAV file.

optional arguments:
  -h,--help             show this help message and exit
  -d,--debug            Print debugging messages.
  -q,--quiet            Don't print info messages.
  -o,--output FILENAME  Set output path. When decoding images the default is
                        './output.png', when resampling the default is
  -r,--resample SAMPLE_RATE
                        Resample WAV file to a given sample rate, no APT image
                        will be decoded.


You can download executables for Linux or Windows from the releases page. Your options are:

  • Linux:

    • Last version binary: Has GUI. Needs GTK and GLIBC version at least 2.19. I think that should work in most common distros.

    • Build yourself the last version.

    • Version 0.9.1 binary: Doesn't have GUI, only terminal. Should work everywhere.

  • Windows:

    • Download binary for the last version.

    • Build yourself the last version (never tried to do that from Windows).

  • OSX:

    • Build yourself the last version.


From a WAV file I found somewhere on Internet, the US upside down:

Example image

The output is upside down if the satellite went from south to north instead of north to south that day.



Build with --release, Rust does some optimizations and it works MUCH faster. Really, otherwise it takes FOREVER.

  • Install rustup (you need rustc --version at least 1.27.0).

  • sudo apt install libgtk-3-dev.

  • cargo build --release.

Linux portable

I can't make gtk-rs to work with the x86_64-unknown-linux-musl target, so I'm building with the default x86_64-unknown-linux-gnu on Debian Jessie. I think the binary works on any linux with GLIBC newer than the one used when building, that's why I'm using a Debian Jessie docker image.

  • Set up:

    • Install Docker.

    • sudo apt install libgtk-3-dev.

    • Move to root folder.

    • docker build ./linux-docker/ -t noaa-apt-linux-build-image.

    • docker create -v $(pwd):/src --name noaa-apt-linux-build noaa-apt-linux-build-image.

  • Building the binary:

    • docker start -ai noaa-apt-linux-build.

    • The build is on ./target/x86_64-unknown-linux-gnu/.

Mac / OSX

Build with --release, Rust does some optimizations and it works MUCH faster. Really, otherwise it takes FOREVER.

  • Install rustup (you need rustc --version at least 1.27.0). The 'unix installer' is fine for Macs.

  • Install dependencies via Homebrew: brew install gtk+3 adwaita-icon-theme.

  • cargo build --release.

Windows portable

I never tried to compile from Windows, I cross-compile from Linux to Windows. I tried to get a mingw64-gtk environment to work on Debian without success. So I use a Docker image I found here.

  • Set up:

    • Install Docker.

    • sudo apt install libgtk-3-dev.

    • Move to root folder.

    • docker build ./windows-docker/ -t noaa-apt-windows-build-image.

    • docker create -v $(pwd):/home/rustacean/src --name noaa-apt-windows-build noaa-apt-windows-build-image.

  • Building the package:

    • docker start -ai noaa-apt-windows-build.

    • The build is on ./target/x86_64-pc-windows-gnu/package/.


These are the alternatives I found, as of August 2018:

Others I found on GitHub:

I measured the speed of most of them using the time utility from bash, and made a comparison of the results on ./extra/comparison.ods.



This program starts a new line when it receives a sync frame (those seven white and black stripes), works well if the signal has clear sync frames.

The first time I recorded a NOAA APT signal the bright parts had lot's of noise (I think the FM demodulator bandwith was too narrow and had saturation when receiving white), the sync frames were really low quality and the alignment was really bad.

Every decoder I've tested, excluding WXtoIMG, has the same problem.


You need the GNU Scientific Library: sudo apt install libgsl0-dev libgsl0.

cargo test

If you get something like a wall of errors because linking with GSL fails, run with the GSLv2 feature:

cargo test --features GSLv2

Things to do

  • Split README into multiple pages and make a better website. Maybe using Jekyll.

  • Improve syncing performance.

  • Option for disabling syncing.

  • Separate thread for GUI.

  • The parameters used for filter design are hardcoded.

  • Add optional lowpass filter before demodulation, there is already one to prevent aliasing but I want to filter noise outside the AM bandwidth.

  • Optionally filter DC component before demodulation, I think it's useful if the FM demodulation had offset (because of Doppler effect). Looks like otherwise we get bad contrast.

  • Optionally output raw samples as WAV at various steps for debugging, maybe plot the FFT too.

  • Do and fix tests, first I have to fix (or remove) the GSL dependency.

  • Separate GUI and no GUI builds.

  • Check and fix Cargo.toml dev buils.

  • Make OSX binaries, I don't have a Mac. I should cross-compile or get a virtual machine to work.

  • For some reason the --debug does not work when using the GUI.

How it works


  • Load samples from WAV.

  • Resample to a intermediate sample rate: 20800Hz.

    • Get L (interpolation factor) and M (decimation factor) by looking at the greatest common divisor (GCD) between input and output sample rates.

    • Get interpolating lowpass filter inpulse response by window method.

      • Get kaiser window.

      • Sample and window the function sin(n*cutout)/(n*pi).

    • Do the equivalent of:

      • Insertion of L-1 zeros between samples.

      • Filter by doing the convolution with the impulse response.

      • Decimate by M.

  • Demodulate AM signal to get the APT signal.

    • Iterate over samples, get amplitude by looking at current and previous sample, see below.
  • Find the position of the sync frames of the APT signal (the white and black stripes that you can see in the final image).

    • Calculate the cross correlation between a hardcoded sync frame and the APT signal.

    • The peaks of that cross correlation show the locations of the sync frames in the APT signal.

  • Map the values of the signal to numbers between 0 and 255.

  • Generate the final image starting a new line on every sync frame.

Resampling algorithm

I did something like what you can see here but with a easier (and slower) implementation.

Resampling algorithm

For each output sample, we calculate the sum of the products between input samples and filter coefficients.

AM demodulation

Previously I used a Hilbert filter to get the analytic signal, then the absolute value of the analytic signal is the modulated signal.

Then I found a very fast demodulator implemented on pietern/apt137. For each output sample, you only need the current input sample, the previous one and the carrier frequency:

AM demodulation formula

Where theta is the AM carrier frequency divided by the sample rate.

I couldn't find the theory behind that method, looks similar to I/Q demodulation. I was able to reach that final expression (which is used by pietern/apt137) by hand and I wrote the steps on extra/demodulation.pdf. I think it only works if the input AM signal is oversampled, maybe that's why I can't find anything about it on the web.


  • Modulation:

    • The signal is modulated first on AM and then on FM.

    • FM frequencies:

      • NOAA 15: 137.62MHz.

      • NOAA 18: 137.9125MHz.

      • NOAA 19: 137.1MHz.

    • AM carrier: 2400Hz.

  • APT signal:

    • 8 bits/pixel.

    • The signal amplitude represents the brightness of each pixel.

    • Two lines per second, 4160 pixels per second.

    • 2080 pixels per line, 909 useful pixels per line.

    • Each line has:

      • Sync A: Seven black and seven white pixels.

      • Space A: Some black pixels (periodically white ones too).

      • Image A: Visible/Infrared.

      • Telemetry A: For calibration I think?

      • Sync B: Some white and black pixels but I don't know the frequency.

      • Space B: Some white pixels (periodically black ones too).

      • Image B: Infrared.

      • Telemetry B: For calibration I think?