After successfully setting up a minimalist NOAA APT decoding station, the next logical step was to try downlinking images from the Russian Meteor-M N2 weather satellite.
This turns out to be rather more of a challenge - for a number of reasons:
The point of this, in simple terms, is that you can't just record the audio to a .wav file for processing; you need to record the raw baseband ('IQ') data. Most popular SDR control programs will let you do this. (Annoyingly, though, not CubicSDR).
Challenge 2: The LRPT signal from Meteor has a bandwidth of 120 kHz. The APT signal is only 34 kHz. This means that the TX power is spread across four times the bandwidth; for the same transmitter power, the received signal is going to be a bit lower.
Challenge 3: While there are ways to decode Meteor in real time, they mainly seem to rely on Windows software. Once again, because I'm restricted to Linux, I was forced to adopt a slightly more manual, less glamorous approach. (You can actually do it in Linux with scripts).
But that's OK. It's actually nice to spend time on the command line again - it's been a long time! And the results are just as good regardless of the platform.
Challenge 4: Unlike the NOAA satellites where you can expect maybe 4-6 usable passes a day, Meteor is all alone. You'll get one morning and one evening pass, which limits the time you have to mess about dialing things in. (It did have a partner - Meteor-M N2-2, which used almost exactly the same encoding system. However, Meteor-M N2-2 was damaged during a micrometeorite impact.)
Worse - although Meteor carries IR cameras, they're not broadcasting. Passes during the night are black. But don't worry - we will still find them useful
As usual, we start with the basic station setup. From a hardware point of view, you can use exactly the same gear as for decoding NOAA APT satellites. In my case this is a Nooelec NESDR dongle, home-brew V-dipole antenna, and a Macbook Pro running Linux under Parallels Desktop. A QFH or turnstile antenna will give better results.
I've modified the antenna to use a pair of telescopic whip antennas from Mercadolibre.mx, at a cost of around US$6:
Why? One word: Performance.
MATE is a bare bones distribution and desktop, specifically designed to run on old/low-spec hardware. It doesn't have the fancy window effects of other distros, and keeps running background processes to a minimum. But it is a maintained distribution, so it's kept up to date in line with the latest releases of Ubuntu. I'm using 20.04 Focal Fossa.
With Mint I kept running into problems with multiple apps. Even running WXtoImg, gpredict and gqrx at the same time would sometimes max out the processor. Momentarily, usually - but enough to cause audio dropout or stuttering. I tried all kinds of settings and optimisations, but in the end decided to try MATE. It was a good call - I may describe my Linux/Mac/Parallels setup in a future post.
Software And Workflow
As so often, there are lots of solutions for Windows, but fewer for Linux. It's possible to entirely automate the process if you want to use rtl_fm and some scripting. However, for the purposes of this article I want to show my working. I think it's more useful to learn in steps, before doing it all in one go.
We're going to need a few specialised pieces of software for this task, apart from gqrx which we've met in previous articles:
sox: a sound processing and transformation tool. May be installed as part of your distribution, if not something like this (for Ubuntu) should do it:
$ sudo apt-get install sox
meteor_demod: a tool by Davide Belloli which does the PSK decoding of the Meteor signal
medet: another tool (author Artyom Litvinovich) which processes the output from meteor_demod into an image file
rectify.py: process the output file to correct for the curvature of the earth (also Davide Belloli)
Make sure these are installed and somewhere in your path. We'll go through the exact process later.
Find Your Satellite!
The first task, as with all satellites which aren't in geosynchronous orbit, is to work out when the satellite is going to pass over your location. I won't cover this in detail here, as I did so in the previous post about decoding NOAA satellites - but you can use a variety of web pages to do this, or software like gpredict.
Setting Up gqrx
We need to set the SDR up to record the signal. Be aware that you may need to use different device settings to your regular listening or decoding settings.
We need to make sure we're recording at least the 120 kHz bandwidth - and ideally add a safety factor if you're not correcting for doppler. As that's usually about +/- 2 kHz, 130 kHz is a good figure to aim for. If you're using gpredict or another rig control program to track doppler, you can go a little lower.
Here's how to set up gqrx. First of all, make sure the radio is running at a bandwidth of at least 130 kHz. You may need to experiment with sampling rate and decimation values. If it's higher than 130k, the files will be bigger and take longer to process. If lower, you won't capture the full signal:
Note that if you're using an LNA such as the Nooelec SAWbird, you may need to drive this via bias-T. In that case, the device string should read:
assuming you only have one SDR connected to your system. The NESDR Smartee has a permanently-enabled bias-T, so it isn't needed for my setup.
Next, go to Receiver Options. There's really nothing you need to do here - we're not actually using the RX demodulators inside gqrx, we're going to do all that on the command line. These controls won't affect the process.
In fact, you can actually turn the demodulators off. However, I like to leave it as below so I can see the panadapter running and monitor the signal:
The input controls are pretty straightforward. DC Remove should be on to remove the characteristic central 'spike' at the demodulator frequency.
I need to use AGC to get acceptable results. I have local QRM which I tried to get rid of by fiddling with the gain manually: it didn't work! Letting the radio do its own thing dramatically improved my success. Your mileage may vary!
You'll probably want to add some bookmarks. Set the frequency to 137.1 MHz and the bandwidth to something like 140 kHz. This is mainly a mnemonic! The bandwidth we set here is the audio bandwidth. The important thing is the baseband bandwidth - 150 kHz or so, that we set up when we did the receiver settings.
As we're not processing the demodulated audio output, it doesn't matter what the audio bandwidth is. But I like to have it in there so I can immediately spot the line, and don't confuse it with NOAA-19.
It also lets me see in the panadapter where the Meteor signal is, so I can check if there's any QRM or co-channel interference.
Finally, hit the 'Start' icon and we're ready to rock!
Recording The Signal
gqrx supports two different recording options. It can record the audio output of the demodulator, or the raw IQ data.
The 'Audio' panel shown to the right is the one we use, unsurprisingly, for recording the audio output. This is not what we want to use for Meteor.
We actually want to select the icon at the top of screen which looks like an oscilloscope, which will open another dialog box.
Note: I record my IQ files to an external hard drive. If you're recording a 150 kHz signal for 13-15 minutes, those files get big. It's not uncommon for them to run to 1 GB.
The .wav and other intermediate files also take up space. So be aware that if you're not careful you may have a problem with disc space!
This is the dialog box you want. You can select a path to the recording directory using the 'Select' button. Here you can see I'm pointing to my external hard drive mounted at /media.
Note also the file format.
gqrx names IQ files with a time and date stamp, followed by the demodulator centre frequency, then the record bandwidth (here 150k). This makes it easy to see what and when the data was recorded - although it does make it a bit annoying to scroll through on the command line 😀
gqrx IQ filename format:
gqrx_ [YYYYMMDD]_[HHMMSS]_[recorded frequency in Hz]_[recorded bandwidth]_fc.raw
At the appointed time of the pass, hit 'Rec' to start recording. On my desktop (Ubuntu MATE) it's not especially obvious when the button is depressed. I've lost recordings because of this. Check at the bottom of the main gqrx display for a message like this one - it pops up for a few seconds after you hit record:
As the pass progresses, you should see the signal get stronger in the waterfall, and a characteristic 'hump' form showing in the panadapter. I enable Peak Detect and Hold in the FFT panel so it's easier to visualise.
The strongest part of the pass will usually be around half way through.
After the pass ends, hit 'Rec' again to stop recording, and drop to the command line.
Processing The Data
OK: All being well, we have an IQ recording in the bag and it's ready to process. Exactly how do we go about that?
The baseband recording stores each data point as 2 x 32 bit values - one for I, one for Q.
We use sox to transcode this into 2 x 16 bit values as a .wav file, so that meteor_demod can read it
meteor_demod performs the QPSK demodulation of the .wav file, and creates a symbol file (.s)
medet processes the symbol file, and decodes it to generate a .bmp image file
Optionally, rectify.py can be used to transform the image to account for the curvature of the earth
Here's a diagram which should make things clear:
Example: let's assume we have an IQ file called example.raw. The sequence of commands would be as follows:
1: Convert the .raw file to a .wav, from 32 to 16 bit, using sox:
$ sox -t raw -e floating-point -b 32 -c 2 -r 150000 example.raw \ -t wav -e signed-integer -b 16 -c 2 -r 150000 example.wav
2: Demodulate the .wav file. This will take several minutes, depending on processor speed:
$ meteor_demod -O 8 -f 128 -m qpsk -o example.s [-B -R 65000]
The '-B -R 65000' switches tell it to run in batch mode, with minimal output. If you are doing this by hand rather than a script, you can ignore them. Interactively, the program displays a nice constellation display as it processes the file:
3: Decode the symbol file and generate a bitmap (example.bmp in this case):
$ medet example.s example -r 65 -g 65 -b 64
4: The final image is quite distorted. We can correct for this using rectify.py:
$ rectify.py example.bmp
Rectify will generate a file called example.png.
For all the reasons given at the start of the post, decoding Meteor-M N2 is a more complex technical challenge than decoding APT from the NOAA satellites. It took me nearly a week before I got a single image I could decode - and it wasn't exactly what you'd call impressive:
The image (left) was an evening pass, in darkness, and as we noted earlier Meteor isn't broadcasting an IR signal (unlike NOAA). However: if you turn your monitor brightness right up, you can just see some detail in the image on the left.
Better still, you can take it into a program like Photoshop and stretch the curves (right). Pretty poor result, huh?
But what it does prove is that your end-to-end process is working. At least largely. You've correctly identified a Meteor pass, you're receiving a Meteor signal, your command line tools are working, and you're generating an image. Remembering that we only get 2 passes a day, I found this extremely useful as a way to dial in my setup.
The biggest single problem I encountered with Meteor was the low signal strength compared to NOAA. Local QRM is problematic. My antenna is a home-brew V-dipole. It's not a perfect setup.
But I was pretty pleased, a few days later on a high pass, when this popped out of my script:
The image is fairly low-resolution here for web purpose; the original is much higher.
Lots of noise and dropout, but we're unquestionably making progress!
Persevering, again, it all felt a bit hit and miss:
I tried adding a Nooelec LANA at the antenna point, combined with a Nooelec Flamingo FM broadcast blocking filter. Sadly, as I half expected, it amplified the noise as well as the signal, and didn't noticeably improve the results.
Finally, I bit the bullet and ordered the Nooelec SAWbird+ NOAA LNA. This is a super narrow-band filter and amplifier; it cuts out everything within about 1 MHz of 137 MHz, and boosts signals in that region by up to 30 dB.
The results speak for themselves - this was the first decent pass after I installed it:
And the rectified version below:
When I first decided to decode Meteor, I thought it would be a wee bit harder than NOAA. It isn't. It's significantly trickier, and you're going to need a slightly better setup.
If my experience is anything to go by, you're also going to need a degree of patience and perseverance! I did feel towards the end that I was surviving on sheer bloody-minded determination to get one or two decent images.
It felt a bit like cheating to buy the SAWbird. My whole premise through these posts is to demonstrate what can be done with a small, lightweight radio setup while travelling. And to be honest, I'm not going to spend a lot of time working Meteor - I find it too frustrating for the results, and I can't guarantee in future Airbnbs I'll even be able to get a suitable antenna up.
But as a technical challenge it's definitely worthwhile. I've sworn at it, cursed at it, and banged my head on the table. But when those last good images emerged from the script, it was all worthwhile 😉
(Note: there is a lot of material online about this topic, most of it for Windows, and much of it of variable quality. Shout out to Daniel Vogelbacher whose article on the subject I found the most useful!)
Batch Processing Script
This is the script I use to decode the raw IQ files. Feel free to use or modify to your heart's content. Depending on your setup, it can easily take 10-15 minutes to complete.
# bash script to process Meteor M-N2 raw IQ files
# meteord [.raw file without extension] [sample rate - default 150000]
# Author: Marco Crawford @ https://www.jocksaway.com
echo "===Job started at $(date)"
# Set sample rate if none supplied
if [ $# -eq 1 ]; then
echo "===No sample rate specified - defaulting to 150,000"
# Check for input file and process if there
if test -f "$1.raw"; then
echo "===Attempting to transcode $1.raw to $1.wav at SR $SAMPLE_RATE..."
sox -t raw -e floating-point -b 32 -c 2 -r $SAMPLE_RATE $1.raw \
-t wav -e signed-integer -b 16 -c 2 -r $SAMPLE_RATE $1.wav
echo "===ABORTING: $1.raw not found."
# Next demodulate the wav file
if test -f "$1.wav"; then
echo "===Attempting to demodulate $1.wav to $1.s..."
meteor_demod -O 8 -f 128 -m qpsk -o $1.s -B -R 65000 $1.wav
echo "===ABORTING: $1.wav not found."
# Next decode the symbol file
if test -f "$1.s"; then
echo "===Attempting to decode $1.s to $1.bmp"
medet $1.s $1 -r 65 -g 65 -b 64
echo "===ABORTING: $1.s not found."
# Finally, generate a rectified bmp
if test -f "$1.bmp"; then
echo "===Attempting to rectify $1.bmp to $1-rectified.png..."
echo "===ABORTING: $1.bmp not found."
# Tidy up the intermediate files
echo "===Deleting intermediate files..."
# Finally display the image and script stats
if test -f "$1.bmp"; then
echo "===Displaying $1.bmp and $1-rectified.png..."
eog $1.bmp &
eog $1-rectified.png &
echo "===ABORTING: $1.bmp not found."
echo "===Job finished at $(date)"
If you enjoyed this article, I'd love you to share it! You can use the buttons below 👍🏻