P25 Phase 2 / TDMA

Support for P25 Phase 2 / TDMA voice decode was added to OP25 in the first quarter of 2014.

This initial release is in the form of several command line (CLI) utility programs which serve to divide the demodulation and decoding process into the following steps:

  • Complex signal capture and storage
  • Channel selection and decimation
  • Demodulation
  • TDMA demultiplexing and speech decoding


The op25 git repository should already be present somewhere on your machine assuming you installed op25 via pybombs. Otherwise you can make a fresh clone of it; it is currently located at

Then change to the top level directory of the repository

cd ...../op25

Switch to the proper branch (as of Aug 2014)

git checkout max-tx

Change to the apps directory

cd op25/gr-op25_repeater/apps

We use the rtl_sdr app which is included in the rtl-sdr package.

rtl_sdr  -s 2400000 -f 388500000  capture.bin

We don't need the entire 2.4 MHz band, so we select a 96 KHz wide slice of spectrum containing the desired channel

python util/  -i capture.bin -s 2400000 -r 96000 -g 10  -c 706300 -o capture-96k.dat

Demodulate the complex I/Q data to result in a file of symbols (dibits).

python util/ -i capture-96k.dat -a -6 -r dbit.dat

Extract and play audio in TDMA slot 1 [Note: the values for sysid, wacn, and nac must be changed to suit your site]

tdma/ -i dbit.dat -n 0x4a1 -s 0x4a2 -w 0xbee00 -t 1


  • When capturing signal data you shouldn't use the exact channel frequency as the capture frequency. This is so as to avoid "DC offset" or "zero IF" interference. A tuning offset of at least 50 KHz is recommended.
  • This tuning offset, plus or minus an additional device- and temperature-dependent frequency offset (sometimes known as "PPM") must be compensated when selecting the channel (-c 706300 in the example above). The offset frequency is used to tune the desired signal to zero IF. The general problem of obtaining proper tuning in the presence of frequency offset is one of the most common "troubles" reported to the GNU Radio mailing list; it's not an OP25-related issue.
  • Also, the CQPSK frequency tuning loop (Costas loop) used in OP25 requires a tuning error less than about 1,200 Hz, to avoid spurious phase-locking to offsets at frequencies of PI/2 away from the desired center frequency.
  • When capturing data the best frequency to tune is generally in the center of the band of frequencies utilized by the trunked system, in order to capture the largest possible number of system channels within the available bandwidth, which is equal to the capture rate (2.4 MHz in this example).
  • You must also know three parameters from the target trunked P25 system: NAC, System ID, and WACN. These values may easily be obtained by using the signal scope application ( Once the system trunking control channel has been properly acquired, click on the "Traffic" tab to display the trunked system data which includes these three values. The values are printed out in hexadecimal, make sure to include the "0x" at the beginning of each value when entering them on the command line.
  • Note that the application assumes and requires the input sampling rate to be set to 96,000.
  • Finally, the TDMA slot ID (either 0 or 1) must be specified when decoding. Voice activity may occur in either slot (0 or 1). You can try running the command twice, once each with slot ID 0 and 1, if you're not sure which slot to use.
  • As of this writing (July 2014) the changes have not been merged into the master branch. Use git checkout max-tx to select the proper branch in the op25 repository.

Updated by laforge over 1 year ago · 3 revisions

Add picture from clipboard (Maximum size: 48.8 MB)