Building an AM Transmitter with HackRF One

There’s something quaint and old fashioned about AM radio. The muffled drifting in an out as you drive down the road, the cacophany of noise attacking your ears attempting to listen at night and the defening sound of passing under power lines or hearing a nearby lightning strike. What’s not to love?

The technology may be old but that doesn’t mean we can’t add a modern twist – AM from a software defined radio. We’re using the HackRF with GNURadio on Ubuntu, much like the FM transmitter we made earlier.

On that note, let’s have a look at the block diagram:

AM transmitter block diagram
Back to the future with AM radio.

Thankfully, once we break the steps down, the whole diagram isn’t too complicated. We’re only intending to modulate the carrier by adjusting the amplitude based on the audio signal.

Generating said audio signal is stage one. We take a FIFO (First In First Out) buffer file source. To fill said buffer, we’re decoding a web stream into a mono feed of samples. The mpg123 command can help here:

mpg123 -r48000 -m -s > solid.fifo

So long as the stream is mono and the sample rate matches (48kHz here), we should be good to go. While there are standards for transmitting stereo and even digitally on LW/MW frequencies, pretty much everything you come across on the dial in the UK is mono.

Our next step is a short integer to floating point conversion, followed by a downscaling into the -1 to +1 range. We get more headroom to work with (even though we shouldn’t use it) and scale correctly for later stages in the chain.

The final audio fettling step is a low pass filter tuned to 5kHz. This is a rough attempt to match the incoming audio to the frequency response of AM transmission on MW.

The Float to Complex stage is where the modulation magic happens. We’re actually using a tool better suited to Quadrature Amplitude Modulation (QAM), as used on modern digital systems such as WiFi, DAB, DVB, cable, satellite, fiber, etc.

QAM actually makes use of two carriers (think sine waves), 90 degrees out of phase. Both the phase and amplitude are tweaked in order to convey a wide range of symbols (block of bits).

QAM16 demonstration
An example of digital QAM in action, thanks to Chris Watts on Wikipedia.

Our case is the much simpler Amplitude modulation. We’re only adjusting the amplitude, we’re not fixed to discrete values and only have single carrier (we don’t need a pilot to measure phase and amplitude from).

Amplitude Modulation
An example of AM and FM modulation for a simple sine wave, thanks to Berserkerus on Wikipedia.

So, back to that Float to Complex block. It takes two inputs – the real and imaginary parts of a complex number. In our case, it’s best thinking of complex numbers in the polar co-ordinates system. You end up with amplitude (real) and phase (imaginary) parts of a complex number.

Feed our audio in as the real part (amplitude) and supply a constant as the imaginary (phase) and you’ve got amplitude modulation. Our proof comes later in the chain where we attach a constellation sink:

AM constellation display
That’s an awfully straight looking line.

Unlike the example animation above, we can see a straight line as the phase never changes. Only the amplitude changes, resulting in the samples spreading along the range -1 to +1.

If we want to get this transmitter on air, we need the Rational Resampler to upconvert from the 48kHz audio input sample rate to the 2MHz preferred by the HackRF One. We also want to use the osmocom Sink to tell GNURadio to dump out to the HackRF.

And on that note, there’s a gotcha. While the HackRF does claim to work down to 1MHz, I struggled to get anything working on the MW band. I had to use the VHF (FM) band and a scanner or second Software Defined Radio to pick up the signal.

That said, it does work and you can pick up that sweet old timey sounding audio on your tuner. If you want to give it a shot, I’ve attached the GNURadio config file here.

Next stop – QAM and some digital OFDM action.

You may also like...

1 Response

  1. Bruno says:

    Nice, thanks for sharing!