HackRF Shell FM Receiver: Real Audio Output!

It has been a few months since the last report, but I have still been working on my Scheme FM receiver project here and there. With toddlers about, and other responsibilities, it can be hard to get in more than 30 minutes of work on it a week. Also, they are fond of pressing the computer reset button in the moments of my most intense concentration.

Several weeks were spent trying to figure out how to improve program performance, enough that I could actuallt process the data in real time. The main key there was understanding how to properly arrange the processing and the decimation, to reduce calculations required. But I learned a lot in the process about efficient use of Guile Scheme and C bindings — mainly figuring out different ways to reduce function calls, type checks, and type conversions.

After quite a lot of work creating bindings, I got the bandpass filter and the fm demodulation into the processing chain. However, the data being spit out after the demodulation was all garbage, though with some patterns here and there. It took many weeks of bug hunting and studying signal theory, to root out the errors, most of which were mishandling of data pointers, though there was also some fuzzyiness in my understanding of convolution, FIR filters, and FM demodulation that I had to work through.

I got through that, and was finally able to get some data out of the receiver that sounded like real FM radio sounds. However, the desired sounds were buried deeply in distortion and noise. With some further study, I realized that I needed another filter after the FM demodulation. That seems to be what they do in the GNU Radio WBFM block. Also, I learned that in real FM broadcast radio signals, there is a stereo channel (or rather, the L-R channel) inserted as side-bands around the mono channel (or rather, the L+R channel) so you have to filter that out (or do the additional stereo processing). I inserted another filter, in the process learning a bit about C macro procedures.

After this, I was able to receive understandable FM broadcast audio, from a local country/western station. However, the audio still has a noticeable amount of static. Adjusting the filter values does affect that, so I am in the process of trying out different values to see what works best. I think I also need to do something to reverse the high-frequency “pre-emphasis” which is used in FM broadcasting.

Amateur Radio Logbook 20200222

Worked 40 meter band on Feb 22 2020, calling CQ on 7.25 Mhz with IC-746PRO using multiband antenna from Hagelbarger lookout in Fairbanks. Made contact at 12:16 AKST with KL7EDK, who reported that my signal was “not coming in strong” but said I was S-5. Finished calling CQ about 45 minutes later but did not make any other contacts.

Tuning around the bands, I found what sounded like some kind of data transmission at 14.434.79 Mhz.

Eielson Ionosonde for 12:15 AKST showed almost no data except a blip of E-layer.

Amateur Radio Logbook 20200212 – 2m Propagation Testing Hagelbarger Lookout Fairbanks, AK

Hagelbarger Lookout – 2m Propogation Test

Start date and time: 2020-02-12 20:05 AKST
End date and time: 2020-02-12 20:30 AKST

Frequency: 146.52 Mhz, simplex

Primary station:
Hagelbarger Lookout, northern Fairbanks, AK, USA
Stationary Operation from mobile station
GMC Jimmy, 5/8 whip antenna, 75 Watts, ICOM IC-V8000


AL7N, 20W, Colinear Vertical
Airport Way & Market St
AL7Z reads KL1TL with all bars, full quieting

KL7AJ, North Pole residence, 50W
Homebrew Ground Plan
KL7AJ reads KL1TL at nearly full quieting

KL7EDK, Farmers Loop & Steese
10 Watt Quarter Wave
KL7EDK reads KL1TL at full quieting

KL4DA, North Pole, location Plack Rd, Northpole, near the Pipeline
6-10 Watts, Diamond X 50A, 30ft off the ground
KL4DA reports KL1TL perfectly clear
Later switched to Kenwood portable hand-held
Kenwood TH-D74 transmitting at 5 Watts
KL4DA reports KL1TL having slight background static

AD4BL, 14 Mile Chena Hot Springs Rd
Diamond X 50A, transmitting 50 Watts
AD4BL reports KL1TL at full quieting

Forgot to record return signal reports, but from memory all contacts
easy to understand with some very slight background
static. KL4DA’s portable had more crackling.

Ionosonde report for 8pm AKST (Eielson):


Amateur Radio Logbook 20200206

While I’m not sure if this will drive up my follower count, I want to start keeping an online log of data from amateur radio experiments, such as propagations tests. The idea is to make the data available to anybody who would find it useful, rather than just stored in my memory.

On KL7KC net meeting tonight, we did a secondary portion on “Farmer’s Loop” repeater, 146.300 +0.6 103.5 tone. My location is Glasgow drive, West of Fairbanks, AK, and the repeater is near Constitution drive north of Fairbanks. That is a distance of approximately five miles. Net control reported that my signal was strong and clear when I was transmitting on 75 W, 25 W, and 10 W power. I’m using a 5/8 whip mag antenna mounted on top of my GMC.

HackRF Shell: Fun with filters

I had added bindings earlier for pulling data from the HackRF, and then more recently a binding to liquid-dsp frequency demodulation. But in between the two, filtering will be needed. So, I added a binding for the firdespm_lowpass function from liquid-dsp. This function gives you the coefficients for a Finite Impulse Response (FIR) filter, using the Parks-McClellan algorithm.

I wanted to see something interesting from that before going to bed, so I threw together a scheme procedure to generate and then print out the coefficients:

;; -*- geiser-scheme-implementation: guile -*-

;; Copyright 2020 Christopher Howard

;; This program is free software: you can redistribute it and/or modify
;; it under the terms of the GNU General Public License as published by
;; the Free Software Foundation, either version 3 of the License, or
;; (at your option) any later version.

;; This program is distributed in the hope that it will be useful,
;; but WITHOUT ANY WARRANTY; without even the implied warranty of
;; GNU General Public License for more details.

;; You should have received a copy of the GNU General Public License
;; along with this program.  If not, see <https://www.gnu.org/licenses/>.

(define-module (sdr filters)
  #:export (print-firdespm-lowpass-coefficients))

(use-modules (rnrs bytevectors)
             (sdr liquid-dsp))

(define (print-firdespm-lowpass-coefficients filter-len
  (let ((output-bv (make-bytevector (* 4 filter-len))))
    (firdespm-lowpass filter-len
    (let lp ((coeff 0))
      (when (< coeff filter-len)
          (bytevector-ieee-single-ref output-bv (* 4 coeff) (native-endianness))))
        (display "\n")
        (lp (1+ coeff))))))

Then I dumped some coefficients to a file:

(with-output-to-file "out.csv"
  (lambda () (print-firdespm-lowpass-coefficients 201 0.2 60.0 0)))

Plotting out the coefficients, I got this visual:

I don’t really know enough yet to be sure if those are sane results or not, but it looks pretty. I was hoping to pick up a DSP book from the library sometime this week and dive more into the details of FIR filters.


No, I am not calling down an imprecation on radio technology. Rather, I want to highlight a great free software streaming radio system that uses a Curses-based interface:

Curseradio allows you to browse streaming radio stations listed in the opml.radiotime.com index. There is a large listing, and no proprietary software is required to view or to listen to the stations. Use arrow keys to select a station, “enter key” to start streaming, the “q” key to quit, and “k” to stop the streaming without quitting (i.e., pause).

In Guix, the command is “guix package -i curseradio” to install it. Note that a few days ago I had Guix fix a bug that was preventing the streaming from starting (a command path issue) so you may need to update your Guix channel, or cherry-pick Guix commit 8d8c6bf.

HackRF Shell Update, Explanations

What is the (current) goal of the HackRF Shell project?

I aim to provide a free software program which sets up a Guile Scheme shell, allowing lisp-style control of the HackRF Software Defined Radio (SDR). The shell will provide procedures for (1) controlling the HackRF, including pulling from and pushing data to the radio, (2) Digital Signal Processing (DSP) e.g., frequency modulation, and (3) some i/o interfaces, specifically to the file system and to PulseAudio.

Why does this project exist?

Partly to help me learn about SDR and DSP. Also, I want to be able to code applications for HackRF SDR in Scheme, rather than in Python (Gnu Radio).

Wouldn’t it be better to use Guile FFI than embedding Guile in a C program?

Erm, well, maybe. But the embedded approach seems easy to understand, develop, and troubleshoot.

Shouldn’t you make something modular to work with any SDR?

I wanted to focus on getting somewhere practical with the SDR I have and the code I already wrote. But I believe it would be possible to expand the shell by adding or swapping in osmocom bindings instead of just the libhackrf bindings.

What have you done so far?

  • Created the C program with libhackrf bindings
  • Set up autotools files for development
  • Created Guix package definitions for HackRF Shell as well as the hackrf and liquid-dsp libraries.

What are you working on now?

Adding liquid-dsp bindings.

Where is the code?

git clone git://git.librehacker.com/pub/git/hackrf-rkt.git

Why has it taken you so long to make progress on this project?

  • Toddlers
  • Moving to a new apartment.
  • A job with no PTO.

What makes Guix such an awesome development environment?

Once you’ve made package definitions, which isn’t very hard, you can set up your development environment (exposed packages and environment variables) quite easily. Right now, for HackRF I simple cd into my source code and run

guix environment hackrfshell --ad-hoc liquid-dsp

The I run ./configure, make, etc. In the next iteration of the hackrfshell package definition, I will add liquid-dsp as a dependency, so then it would just be guix environment hackrfshell.

Not all my package definitions have made it into the official Guix git repository yet, but I’ve added them to my local Guix channel for the same effect.

Also because of Guix’s functional package management approach, I can use any verions of libhackrf, etc. I want, and not have to worry about wrestling with base system dependencies.