So the quest to understand demodulation continues. My friend insom [suggested](https://tiny.tilde.website/@insom/111675902270293391) [looking](https://tiny.tilde.website/@insom/111675908217622845) at the zero crossing method, and looking at old implementations of similar protocols (like Kansas City Standard). Looked into [FT8](https://en.wikipedia.org/wiki/FT8), which is [8 frequency FSK](https://wsjt.sourceforge.io/FT4_FT8_QEX.pdf). I thought zero crossing would struggle multiple frequencies, but a comment in the linked forum thread made me think it worked poorly for multiple frequencies, or oddly spaced frequencies. Maybe I can fix this by shifting the signal around, or actually understanding zero crossing. Here's what I think it is: you count the time it takes for each half of a wave form to cross zero (ie how long is the wave above or below zero). You can also just count the number of samples since the last 0 and use the sample rate to determine how long that was. From that you can calculate the frequency by taking the inverse of the period. If you pool the guesses together, you can ignore some noise? A good experiment for this would be to take a clean signal and see if I can reconstruct it using this method. It's only a few lines of numpy. I also want to look into Phase Locked Loops. I think if I knew how long each symbol was, and where they were (ie the phase), I could run an FFT (or [Goertzel](https://en.wikipedia.org/wiki/Goertzel_algorithm)) on just that sample and see which frequency was present to decide which bit. I did come across this [Bell Systems Technical Journal article from 1968 on the topic](https://ia804705.us.archive.org/17/items/bstj47-10-2207/bstj47-10-2207.pdf), which I feel would be fun to read for history's sake. Some googling led me to the [syncronization chapter of PySDR](https://pysdr.org/content/sync.html), which I wish I'd realized earlier.