hz.tools/fm: analog fm radio modulator and demodulator

Paul Tagliamonte 2023-02-22 project

The hz.tools/fm package contains a demodulator for FM analog radio. This code is a bit old, so it has a lot of room for cleanup, but it’ll do a very basic demodulation of IQ to audio.

The git repos can be found at github.com/hztools/go-fm, and is importable as hz.tools/fm.

The hz.tools/fm package contains a modulator, which has been tested “on the air” and with some of my handheld radios. This code is a bit old, since the hz.tools/fm code is effectively the first IQ processing code I’d ever written, but it still runs and I run it from time to time.

    // Basic sketch for playing FM radio using a reader stream from
    // an SDR or other IQ stream.

    bandwidth := 150*rf.KHz
    reader, err = stream.ConvertReader(reader, sdr.SampleFormatC64)
    if err != nil {
        ...
    }
    demod, err := fm.Demodulate(reader, fm.DemodulatorConfig{
        Deviation:       bandwidth / 2,
        Downsample:      8, // some value here depending on sample rate
        Planner:         fftw.Plan,
    })
    if err != nil {
        ...
    }
    speaker, err := pulseaudio.NewWriter(pulseaudio.Config{
        Format:     pulseaudio.SampleFormatFloat32NE,
        Rate:       demod.SampleRate(),
        AppName:    "rf",
        StreamName: "fm",
        Channels:   1,
        SinkName:   "",
    })
    if err != nil {
        ...
    }

    buf := make([]float32, 1024*64)
    for {
        i, err := demod.Read(buf)
        if err != nil {
            ...
        }
        if i == 0 {
            panic("...")
        }
        if err := speaker.Write(buf[:i]); err != nil {
            ...
        }
    }