Yaesu System Fusion (YSF) is a radio system designed and implemented by Yaesu. At its core, it tries to merge traditional FM with a digital voice mode. This project's aim is to investigate the digital aspect of YSF and to provide decoding tools. In order to meet this goal, GNU Radio is employed to do most of the tricky things outlined in the technical specifications of the system. This work is based on revision 1.01 of the manual. Due to the proprietary nature of those specifications, Yaesu can amend and change things as they wish. They have done so in the past. Currently, you can probably download revision 1.02 or newer from the Yaesu page, but 1.01 is not available anymore and therefore hosted locally. People reading this should probably be mildly concerned about the consequences of the choice made by Yaesu.
Please note that this is not a software package that you can download and simply tune into YSF signals without putting some effort. This is merely a proof of concept that demonstrates that it is possible to build a receiver for YSF. Insights gained from this work might be used to add YSF support to e.g. DSD, but this project is not a scanner application per se. Also note that this is not a finished product. For example, the current code misses several opportunities to apply forward error correction (FEC), the quality of the audio output is therefore reduced heavily. Check the issues page on github for an overview of what you can expect. I gladly accept pull-requests :-). mbelib is required to turn the AMBE frames into something that you can hear. This might have legal implications for you, please be aware of that.
Here is an early recording (direct link) of what I got out of the system while transmitting with an FT1D. Reception was done with a HackRF One, although one of those cheap RTL SDR dongles works just as well.
If you want to give it a try yourself, have a look at the Getting Started page. Again, this is some experimental stuff that I am sharing with other curious amateurs and not a "download, run and forget" kind of program.
Before I dig into the details of this work, let me say thank you to the amazing GNU Radio community who not only came up with a great software framework, but also provided me with a lot of help when things were not working the way I expected them to work. Johnathan Corgan in particular shared a lot of the insights he gained while working on C4FM for the past few years. Sylvain Munaut helped me a lot in figuring out how VW mode works. I learned a lot of mathematical tricks from him and surely, I would not have been able to pull this off without his help. Thanks to him, I learned more about Galois Fields than at University. Raffaello Di Martino (IZ0QWM) provided me with a vast amount of sample data. David Rickett (VA7EEX) allowed me to use his PiDV remotely to create correct AMBE frames and to validate the ones generated by this project. Both of this has proven to be extremely helpful.
This section briefly outlines the
ysf_rx.grc flowgraph found in the
directory of the project. The flowgraph corresponds to commit
6830db0, although I will update this page as things progress. The
full flowgraph can be seen here, I will split it into
several parts to make this discussion easier to follow.
The quadrature signal is captured by hardware (osmocom Source) or replayed through a file source and fed into a frequency xlating FIR filter, where it is filtered, shifted to DC and down-sampled. The filtering is necessary to prevent aliasing. The frequency shift is done because some SDRs have a considerable spike at DC that is in the way. An easy way to get around that is to set the hardware up such that the signal for interest is offset. For example, one can set a center frequency of 432 MHz and transmit at 432.5 MHz. The frequency has then to be translated downwards by 500 kHz. The quadrature signal is then demodulated before it is fed into the polyphase clock sync block. This block applies the root-raised cosine (RRC) filter and outputs dibits at a symbol rate of 4.8 kHz. Note that the equation for the RRC filter is completely wrong and doesn't even make sense, but the symbol rate and the roll-off given are correct.
The signal from the clock recovery block is sliced into the four levels that
are inherent to C4FM. They are then remapped to the dibits defined in Table 3-1
of the Yaesu spec. The YSF Deframer is my first custom block. It waits for the
0xd471c9634d which marks the beginning of every packet.
The subsequent 200 bits are sent to the top output stream. Those are the FICH
header which contains information on the payload-content and -structure. The
subsequent 720 payload-bits are then temporarily stored inside the deframer.
The FICH header is decoded according to Figure 4-26 of the Yaesu spec. The sequence of blocks needed for this is very similar to the payload decoding outlined in the next section. Note however that in the flowchart shown above, Golay decoding is not performed. Instead, the first 12 bits are kept and the remainder is thrown away. I can get away with this because the first block of the Golay-matrix is identity, but eventually I will have to do this properly. After decoding, the FICH header hits the YSF FICH Sink, the second custom block. This block parses the FICH header and sends back a message to the deframer, telling it what is contained in the payload. The deframer pulls apart the payload according to those instructions and distributes it into the three payload streams.
This part of the flowgraph takes care of turning the dibits into the packets expected by the data sink. This is used to display call signs, messages and other information. Depending on type and mode, this kind of data can be transferred in different ways. The top path implements the decoding shown in Figure 4-30 of the specification, the bottom path implements the decoding shown in Figure 4-31 of the spec. The two decodings only differ by their respective parameters. In a nutshell, the dibits are de-interleaved and then, forward error correction is applied by the Viterbi algorithm following a Trellis Convolutional Code. This step turns the dibits into a stream of bits where bit-errors are hopefully corrected by the FEC. Lastly, a fixed sequence from a scrambler is XORed with the bit-stream before the data is displayed in the DCH Sink. The de-scrambling is done manually due to a bug in GNU Radio. It is important to note that the scrambler is part of the system in order to have a randomly distributed stream of data, since long sequences of the same bit would violate some theoretical assumptions of the techniques that make this system robust towards bit-errors. It is not there to conceal the meaning of the transmission.
Similarly, this is an implementation of Figures 4-32 and 4-23 of the Yaesu spec, to decode DN voice and VW voice, respectively. The former is quite similar to the approach discussed in the previous section. The custom V/D2 VCH Decoder block undoes the weird bit triplication introduced in step 3 of the figure. The output of this block is an AMBE frame. Those AMBE frames enter another custom block, the mbelib Conversion Block. This block calls mbelib and retrieves the synthesized speech, which is normalized in amplitude by an AGC and sent to the speaker.
The bottom branch is considerably simpler: The dibits are converted into bits by unpacking, then de-interleaved according to a pattern that was not easy to figure out, as it is not documented by Yaesu. The standard AMBE scrambler is then (still inside the same block) applied to the frame, which is handed to the mbelib Conversion Block as before. IMBE is used here since the rate used in VW mode is supposed to be backwards compatible with an IMBE rate that is luckily supported by mbelib.