
Here I have a recording of FM decoded audio from a certain Motorola radio. In it you can see a continuous series of level changes, even when there is no audio (the fuzzy bits). This is the DCS (or generically CDCSS) used as a requirement to keep the squelch open. You can also see a continuous tone at the end of the transmission, just before the noise burst. This continuous tone is the squelch tail elimination (STE) which when the receiving radio hears, it silences the speaker output before the noise burst that happens just before the squelch cuts off.

Cutting the audio file down to a portion of just DCS tone looks like this. From here you can see that the bitstream is offset from zero so we want to use Audacity to normalize this, as well as amplify the signal a bit. After applying the Normalize effect with remove DC offset and normalize maximum aplitude, we get a signal which looks like this.

Now we want to extract the actual bits from the stream so we can decode them into a DCS code for radio operation. In order to make sure we get the bit spacing correct, we want to add a second channel with a continuous square wave at 134.4Hz. We add a new track with a square wave by using Generate->Tone, set the waveform to square, and set the frequency to 134.4Hz. We’ll also zoom in again, as DCS only uses a repeated bitstream 23 bits long.

From here you want to pick a transition of the square wave and transcribe whether the sampled audio is above or below the zero line. Taking the low to high transition, we get the bit series:
10000001110001101111100100000011100011011111001 ...
Before continuing we need a bit more information about how DCS’s
bitstream is decoded and encoded. DCS is encoded in a Golay code,
which is an error correcting data encoding. A particular DCS code is
represented as a 3 digit octal code, which translates to 9 bits of
data. This data is encoded in a Golay(23,12) code, which contains 12
bits of data and 11 check bits used for error correcting. Since only 9
bits are actually used for DCS, the first 3 bits are the fixed
sequence 100. However DCS actually transmits the Golay code in
LSB order, which means that this, and the data must be reversed. With
this information we can reverse the bistream, split it into words, and
split it into data and check bits. This gives us a Golay word that
looks like this:
100111110110 00111000000
----data---- ---check---
Stripping the initial 100 we get the data to be 111110110
or in octal, 766. But wait! That isn’t a valid DCS tone. Well it
turns out that Golay codes have interesting properties, meaning that a
single Golay code can be decoded into multiple different data values
depending on where the start bit is considered. DCS doesn’t have these
alternative rotations as possible options to help prevent inadvertent
conflicts. You can also invert the code and rotate it again to get
different values (this is where ‘inverted’ DCS comes from). I’m not
going to go into this in too much detail, but
this site goes into much
more detail (and has very helpful tables so you don’t actually have to
do the next step).
In order to find the real code, we now have to rotate the entire code
(including the check bits) to find other instances of the bit
sequence 100. We find
100011100000 01001111101
----data---- ---check---
and
100000010011 11101100011
----data---- ---check---
The first of which is 340 in octal, again not a valid DCS
option, but the second is 023, one of the most common DCS
choices (easiest to scroll to). I recommend just trying this one
before manually decoding it like I did…
I’m not going to cover the check bits in this post, but I found this very helpful.