Keyboard Sounds

Short audio sample of typing on my Keychron K2v2 with Boba U4T switches, and MA Blue Cat keycaps.

(Youtube mirror)

I’m way too old for newfangled mech keyboards. This setup is pleasant enough to type on and does sound quite nice to me. But overall is too tactile for my taste.

I also did not realise the Keychron had dropped any future support of remapping the keys on their wireless models when I purchased the K2v2 which was quite disappointing.

Posted on

FM Frequencies

I’ve been really bored recently. So I’ve been looking to see how many FM stations I could find.

Equipment is AirSpy HF+ Discovery, SDRSharp, and a Discone Antenna mounted ~2m above the ground.

The websites FM Scan and VHF Propagation Map have been very useful for identifying stations, and finding good times to listen.

Furthest station was ABC Classic in Griffith NSW. Bit over 400KM away.

Updated 2021-09-22: Added a couple of new entries, included basic signal quality, and updated code.

Frequency Station Name Signal
87.6 Mhz Surf FM Medium
87.8 Mhz Kiss FM Medium
88 Mhz DCFM 88.0 Low
88.1 Mhz 3MFM Medium
88.3 Mhz Southern FM Medium
88.5 Mhz ABC Northen Tasmania DX
88.6 Mhz Plenty Valley FM Medium
88.7 Mhz Vision Radio Bendigo Very low
88.9 Mhz WynFM Medium
89 Mhz Radio Bayside Low
89.1 Mhz 3MFM Medium
89.3 Mhz Kix Country Radio Medium
89.5 Mhz Very low
89.7 Mhz ABC Radio National Willis Hill Tas DX
89.9 Mhz Light899 High
90.3 Mhz TripleJ Low
90.7 Mhz SYN FM High
90.9 Mhz TripleJ Tasmania DX
91.1 Mhz ABC Central Victoria Low
91.3 Mhz ABC News Radio Warrnambool DX
91.5 Mhz Smooth FM High
91.7 Mhz ABC Northern Tasmania DX
91.9 Mhz SEN Track Low
92.1 Mhz ABC Classic Warrnambool Very low
92.3 Mhz 3ZZZ High
92.5 Mhz Radio National Somwhere Medium
92.7 Mhz ANC Classic Bendigo Medium
92.9 Mhz Low
93.1 Mhz SBSRadio High
93.3 Mhz ABC Classic DX
93.5 Mhz Vision Australia Radio High
93.7 Mhz Very low
93.9 Mhz Bay939 Medium
94.1 Mhz 3WBC Medium
94.3 Mhz TripleM Gippsland High
94.5 Mhz Very low
94.7 Mhz The Pulse Medium
94.9 Mhz Joy94.9 High
95.1 Mhz ABC News Radio High
95.3 Mhz Triple M Goulburn Valley DX
95.5 Mhz K-ROCK Medium
95.7 Mhz Golden Days Radio Medium
96.1 Mhz ABC Radio National Medium
96.3 Mhz 96three Medium
96.5 Mhz Inner FM Medium
96.7 Mhz Triple J Medium
96.9 Mhz Medium
97.1 Mhz 3MDR High
97.3 Mhz ABC Clasic Griffith NSW Low
97.7 Mhz 3SER Casey Radio High
97.9 Mhz 979fm Medium
98.1 Mhz Radio Eastern FM High
98.3 Mhz RPP FM High
98.5 Mhz Apple 98.5 FM Medium
98.7 Mhz RPP FM High
98.9 Mhz Very low
99.1 Mhz Yarra Valley FM Low
99.3 Mhz 3NRG Medium
99.5 Mhz TRFM Medium
99.7 Mhz ABC Radio National Very low
100.1 Mhz Vision Australia Radio Shepparton DX
100.3 Mhz Nova100 High
100.5 Mhz Very low
100.7 Mhz ABC Gippsland High
101.1 Mhz KIIS 101.1 High
101.5 Mhz ABC Classic High
101.7 Mhz ABC Radio National Warrnambool DX
101.9 Mhz The Fox High
102.1 Mhz ABC Mildura Swan Hill / Goschen Very low
102.3 Mhz 3BA Medium
102.7 Mhz Triple R High
103.1 Mhz Power FM Medium
103.3 Mhz DX
103.5 Mhz 3MBS High
103.7 Mhz ABC Classic Goschen / Swam Hill DX
103.9 Mhz Life FM Gippsland Medium
104.3 Mhz Gold 104.3 High
104.7 Mhz Very low
105.1 Mhz Triple M High
105.5 Mhz ABC Classic FM Ballarat Low
105.9 Mhz ABC Classic FM High
106.3 Mhz Flow FM Medium
106.5 Mhz Very low
106.7 Mhz PBS High
106.9 Mhz Very low
107.1 Mhz Triple J Low
107.5 Mhz Triple J High
107.9 Mhz ABC Ballarat Low

Note: All stations were positively identified.

I need a bigger backyard so I can put up a big FM antenna…

Some Code too!

Wow, it’s been a long time since I wrote any code. First program in Deno/Typescript to help convert the SDRSharp frequencies file to a markdown table.

// I'm too stupid to use this library
// import { parse } from "";

// So let's pretend the xml might be terabytes in size and use a SAX library
import { SAXParser } from '';

class SignalQuality {
    protected _snr: number = 0;
    protected _isDx: boolean = false;

    set snr(value: number) {
        this._snr = value;

    get snr() : number {
        return this._snr;

    set isDx(value: boolean) {
        this._isDx = value;
    get isDx() : boolean {
        return this._isDx;

    protected textMap() : [string, string] {
        if(this._isDx) {
            return ['DX', 'orangered'];
        else if(this._snr < 5)
            return ['Very low', 'grey'];        
        else if(this._snr < 10)
            return ['Low', 'grey'];        
        else if(this._snr < 30)
            return ['Medium', '#ddd'];        
            return ['High', 'green'];        

    public formattedText() : string {    
        return this.textMap()[0];

    public formattedTextColor() : string {
        return this.textMap()[1];

class MemoryEntry {
    public name: string = '';
    public frequency: number = 0;
    public notes: string = '';
    public signal: SignalQuality = new SignalQuality();

    public formattedFrequency() : string {
        return (this.frequency / (1000 * 1000)) + ' Mhz';

async function parseFrequenciesXml(filename: string) : Promise<MemoryEntry[]>
    let entries = [] as MemoryEntry[];
    let currentEntry: MemoryEntry;

    let currentElement = {
        Name: false,
        Frequency: false,
        extraSNR: false,
        extraDX: false,
        extraNotes: false
    } as { [key: string]: boolean; };

    const parser = new SAXParser();

    parser.on('start_element', (el) => {
        if(el.qName == 'MemoryEntry') {
            currentEntry = new MemoryEntry();
        else {
            currentElement[el.qName] = true;
    }).on('end_element', (el) => {
        if(el.qName == 'MemoryEntry') {
        else {
            currentElement[el.qName] = false;
    }).on('text', (s) => {
        if(currentElement['Name']) {
   = s;
        else if(currentElement['Frequency']) {
            currentEntry.frequency = Number(s);
        if(currentElement['extraSNR']) {
            currentEntry.signal.snr = Number(s);
        if(currentElement['extraDX']) {
            currentEntry.signal.isDx = (s === 'true')
        if(currentElement['extraNotes']) {
            currentEntry.notes = s;

    // run parser, input source is Deno.Reader or Uint8Array or string
    const reader = await;
    await parser.parse(reader);

    return entries;

let filename = "./frequencies.xml";

if(Deno.args.length == 1) {
    filename = Deno.args[0];

console.log(`Reading from ${filename}`);

const desc1 = { name: "read", path: filename } as const;
const status1 = await Deno.permissions.request(desc1);

let entries = await parseFrequenciesXml(filename);

console.log("| Frequency | Station Name | Signal |");

for(let entry of entries) {
    console.log(`| ${entry.formattedFrequency()} | ${} |  <span style="color: ${entry.signal.formattedTextColor()}">${entry.signal.formattedText()}</span> |`);

Finally, this is the XSD I used to export my Excel spreadsheet into a XML for both SDRSharp and the above “program”.

<?xml version="1.0" encoding="UTF-8"?>
<xs:schema xmlns:xs="">
    <xs:element name="ArrayOfMemoryEntry">
                <xs:element ref="MemoryEntry" minOccurs="0" maxOccurs="unbounded"/>
    <xs:element name="MemoryEntry">
                <xs:element name="IsFavourite" type="xs:string"/>
                <xs:element name="Name" type="xs:string"/>
                <xs:element name="GroupName" type="xs:string"/>
                <xs:element name="Frequency" type="xs:integer"/>
                <xs:element name="DetectorType" type="xs:string"/>
                <xs:element name="Shift" type="xs:integer"/>
                <xs:element name="FilterBandwidth" type="xs:integer"/>
                <xs:element name="extraID" type="xs:string"/>
                <xs:element name="extraSNR" type="xs:integer"/>
                <xs:element name="extraDX" type="xs:integer"/>
                <xs:element name="extraNotes" type="xs:string"/>

Posted on


Last week the ISS was transmitting SSTV images. So I setup MMSSTV, and my FT818 with a new colinear antenna to see if I could receive any images.

It took a couple of days before I realised you can receive signals from the ISS even if the ISS isn’t “visible”, so I ended up leaving the radio on for the rest of the week. I actually received 14 images on the 27th (UTC) over 7 passes (!).

I was able to receive 11 of the 12 images in acceptable quality. Interestingly there must be some funny relationship between the time to send the complete 12 images and and the time is takes for the ISS to orbit the earth as I received a lot of some images, and none or very limited of others.

Image Number Times Received
1 0
2 1
3 3
4 5
5 5
6 8
7 6
8 8
9 5
10 3
11 2
12 1

Overall was good fun, even with a non-optimal high gain colinear.

All images

Posted on

HF is sometimes Fun

That signal is actually pretty cool…

I think it’s JORN an OTHR, but it only sort of matches up.

Sometimes there was a preamble before it started, and then it would jump around frequencies a little.

They weren’t evenly spaced, the lowest I was around 6.9753 Mhz to the highest 6.9576Mhz (USB).

Around 10s between bursts too.

Don’t really know what is going on, but this is what I saved:

Recording of a single burst (USB).

Update 2021-06-27: The signal is likely from US Navy, not JORN.

Posted on

HF is not Fun

I’ve done almost nothing with HF for a while. I’m still demoralized by all the interference.

Turns out the what I was receiving wasn’t related to power supply… Or anything else I can track down.

This is what I receive on 40m with a Discone (VHF/UHF) and a Airspy HF+ Discovery.

Can just see FT8 at 7040Khz. And there is a cool looking signal at 6950Khz too.

Finally got a laptop last week. If I can replicate the interference with a small antenna I might be able to get an idea where it’s coming from.

Posted on

More HF Radio

A little more work on my magnetic loop antenna.

I switched from using a Wifi stepper to a little high torque 12v DC motor + gearbox. I really liked the Wifi Stepper, it was painless to setup and use. It was exactly what (I thought) I wanted. Unfortunately I couldn’t get enough torque at low RPM with the little steppers I had. My variable capacitor has much to large a range, and needs very fine adjustments.

I don’t know how much torque the DC motor + gearbox actually has, but it feels like a lot. Another bonus was that the motor, gearbox, and a nice PWM controller was $30 AUD from Banggood.

For testing with my SDR I also switched to using a short coax cable and a long (powered) USB cable. I don’t think I’ve seen such a clean FT8 waterfall on my PC before. There is still some RF (right next to 7.074) but it’s night and day really.

Still, no idea if I can actually hear any better, but it certainly looks clearer.

My next plan is to switch to a shielded coupling loop. Right now, it’s just a few strands of copper wire twisted together in a rough loop. I found a nice piece of cable to use a while ago, but my soldering iron couldn’t heat the large solid conductor. I bought a Chinese T12 solder iron from Banggood that should have plenty of power.

For my other noisy project, I’m pretty sure it’s USB switch mode noise. Yay.

Posted on

Noisy Waterfall

New toy, cheap antenna, and an expensive power supply.

(1.5MB png. Noise doesn’t compress well)

Viewing the whole 0-30mhz shows some, ugh, noise.

Posted on

Necrodancer PB

I said this was meant to be a place where I could look back on. So, here’s my new Necrodancer Cadence PB of 10:40.84 from 2021-01-14.

Something like 1:20 faster than my last run.

I got an amazing Dead Ringer quick kill (without knowing what I was doing, it just somehow worked) and then Boots of Leaping made a very fast Necrodancer kill too. It was a very lucky run.

I wish the replays didn’t always desync.

Posted on

Random Photos

More random stuff. First is Aura Vale Lake Park and the second is Kilcunda Surf Beach.

Posted on

Mordialloc Pier

Just a couple of random pictures from Mordialloc pier.

I need to sort out some sort of work flow for posts like this…

Posted on