Disclaimer: Before this project started, I have never worked on building an MFSK decoder. I am by no means an expert in this field. If anyone has improvements/ideas/concerns, please send me an e-mail, or submit a pull request on the GitHub repository.

In this post, I want to explain how the XPB decoder I built on top of Rivet works and state some of the concerns I have.

---

**The Baud rate & 121.56 samples per symbol**---

Rivet, in soundcard input mode, uses an audio sample rate of 8000 Hz. Combine this with the odd XPB Baud rate of 65.79 Baud and you get approx. 121.59 samples per symbol (SpS).

Obviously, we only want a decoder to decode each symbol once, using correct timing, and not decoding two symbols overlapping (results in another random symbol being decoded or some symbols being left out and others duplicated).

If the SpS rate wasn't as weird, let's say e.g., 200, we would just decode a symbol every 200 samples. The problem with 121.59 is that we cannot decode or wait fractions of samples.

So, if we only only chose one of two options (121 or 122), we would deviate from the ideal pattern by one full symbol at either ~206 symbols (decode every 121 samples) or ~296 symbols (decode every 122 samples). If we used a decoding pattern constantly switching between waiting 121 and 122 samples, we would be far better off, but still be one symbol off the ideal path at approximately 1352 symbols decoded.

The way I implemented a fix to this problem is by using a 121, 122 pattern as just described, but also let the decoder calculate the deviation we get from the ideal path at every step it takes. As soon as it hits -1 sample, the decoder takes a step of 123 samples, which adjusts the deviation so that we are back at the ideal path (approximately).

See this gallery for some charts visualizing the different deviations:

https://imgur.com/a/g90yuO5--

**Detecting a message start & jumping to the main routine**--

Different to XPA, XPA2, and most other MFSK modes, XPB does not use any sync tones. This, of course, makes it a lot harder to detect when a message starts.

The way I addressed this is that when the decoder is ready for a message start, it does an FFT of the last 100 samples of audio every sample. As soon as it decoded the starting symbol (usually "8" but can be user controlled) a defined amount of times (=> starting offset), it jumps to the main routine, using the decoding pattern explained previously. Here is where the user comes into place. If the starting offset is not set correctly, symbols might overlap and/or wrong symbols might be decoded. More of this is explained at

https://github.com/ZapdoZ/RivetZ/blob/master/README_XPB.MD.

--

**FFT Size of 100**--

To decode a symbol, the decoder uses the last 100 samples of audio it got and gets the frequency of them by performing an FFT.

One thing I am personally not sure about is if the FFT size of 100 could be replaced by something better. The problems I met with other FFTs are:

- FFT64 is too imprecise.
- FFT128 always takes a few samples from other symbols (since it's longer than 121.59), therefore decoding falsely.

The main concern here is that even though I use an FFT of 100, which is more precise than an FFT of 64, I still must set the error allowance (how much an FFT determined frequency can deviate from the frequency norm of a symbol) all the way up to

**+/- 86 Hz** (the theoretical maximum is 87.5, everything above that would cause overlapping) to prevent UNIDs from appearing.

--

**Decoding**--

XPB utilizes 16 different symbols, so I implemented hexadecimal decoding (0-9, A-F), in which the lowest symbol (540 Hz) is 0 and the highest symbol (3165 Hz) is F. Binary or decimal could of course be possible too, but I think in this case they would be hard to read and confusing.

--

**Message endings**--

Another problem is that we do not know how messages end (we

*might* be able to figure out if we can get enough decodes and they follow a pattern). That is why, when a message is over, the decoder does not stop decoding, because it simply does not know that the message is over. So, when the message is over and UNIDs start appearing, please freeze the screen or disable the soundcard input, otherwise you cannot copy the message content!

--

**Get the decoder**--

You can download the latest release of RivetZ (my fork of Rivet) here:

https://github.com/ZapdoZ/RivetZ/releases. It includes the XPB decoder as a selectable mode.

~ZapdoZ