NXDN SACCH Decoding

Status
Not open for further replies.

blackmore90

Member
Joined
Jan 9, 2018
Messages
13
Hi, I am currently writing a C/C++ code to decode voice and control channels of an NXDN4800 trunked system. I have successfully decoded sound frames but i am having problems on obtaining call information, namely SACCH decoding. I get RTCH voice frames with full VCH(4x72 bits) without a problem but when i try to decode 60 bit SACCH fields i end up with CRC-6 and tail bits mismatch and a wrong SF value in the SR field. Therefore i cannot collect the consecutive layer-3 data and properly construct the layer-3 VCALL messages which will provide me the call info.

To be more clear after this short story, I share some files and technical information below:

The code applies the routine given in the NXDN standard document (TS 1-A Version 1.3) to each 60-bit SACCH frame, namely
Deinterleaving->Depuncturing->Convolutional Decoding->Tail Bit Removal->CRC-6 Checking->Decoding SR Field->Parsing 18-bit L3 Data.

The program runs with a bit file input which is formatted as one bit per byte. I have attached this file.

After finding the SYNC pattern: [1,1,0,0,1,1,0,1,1,1,1,1,0,1,0,1,1,0,0,1] with 3-bit error tolerance, 16-bit LICH decoding is performed. According to standard document LICH decoding procedure should be Descrambling->Dibit/Bit conversion->Parity Check->7 bit control data. However, i believe that the NXDN4800 system that i work on does not have any scrambler. Also, i need to flip some bits of the 16-bit LICH to successfully get the voice frames. Here is the code snippet of the bit flipper:

for (int i = 0; i < 16; i++) {
if (i == 0 || i == 8 || i == 14) {
lich = 0;
}
else if (i == 2 || i == 4 || i == 6
|| i == 10 || i == 12) {
lich = 1;
}
}

After this bit flipping and dibit-bit conversion, I sum first 4 bits with the last parity bit and successfully get even sum with a high probability. RF channel type is almost [0,1] (RTCH) in every frame and functional channel type is [1,0] (SACCH superframe structure). Steal flag is [1,1] which corresponds to no steal. In this case i successfully get voice frames.

After decoding LICH, decoding of 60-bit SACCH frames takes place. The problems i have defined in the beginning occurs in this step.

I can provide the codes of SACCH decoder blocks if needed.

I am stuck at this step and really need some ideas. I would be very happy if you would give an idea on this problem. Thank you very much.
 

Attachments

  • nxdn_input.zip
    36.4 KB · Views: 79
Last edited:

EricCottrell

Member
Premium Subscriber
Joined
Nov 8, 2002
Messages
2,413
Location
Boston, Ma
Hello,

I would be very suspicious if you have to modify bits to get it to work. You are likely not decoding correctly or not taking something in consideration. Different LICHs are used based on the type of system with multiple ones carrying voice.

I suspect that you are trying to decode an Icom IDAS trunked system, which is Trunking Type-D. The SACCH is used as the "control channel". The 1-A part of the specifications deals with Conventional and Trunking Type-C. Trunking Type-D is specified in Part 1-E and various things are different. As examples, the LICH is specified in Part 1-E 5.2.2 and the SCCH uses a CRC-7 code as specified in Part 1-E 4.5.1.1.

73 Eric
 

slicerwizard

Member
Joined
Sep 19, 2002
Messages
7,643
Location
Toronto, Ontario
I assume the attached file is raw decoded bits. I converted it to a wav file and fed it to the latest DSD+ FL. It decodes as voice traffic on a NEXEDGE trunking system (RAN=1), but with many, many errors. Very little SACCH data is decoded and the voice is very distorted, but I can tell that it's not English - maybe French, but not clear enough to be sure. I'd say that the fact that anything decoded is a clear indication that the system uses standard NXDN whitening.

It looks like your symbol decoder is not working very well and many decoded bits are wrong. That would explain why CRC checks are failing. Or maybe I messed up the wav file, but one idle message decoded perfectly, so I don't think the problem is on my end.

Code:
Sync:-NXDN48 TB DATA   ERR4  VCall  Group  TG=4001  RID=4100
                       ERR7  TX_REL_EX       Group Call Tgt=4001 Src=4100  TX OK
Sync:-NXDN48 TB DATA   ERR4  IDLE
Sync:-NXDN48 TB DATA   ERR3  VCall  Group  TG=4001  RID=4100
Sync:-NXDN48 TB DATA         IDLE
Sync:-NXDN48 TB DATA   ERR3  VCall  Group  TG=4001  RID=4100
Sync:-NXDN48 TB DATA   ERR3  TX_REL_EX       Group Call Tgt=4001 Src=4062  TX OK
Sync:-NXDN48 TB DATA   ERR3  TX_REL_EX       Group Call Tgt=4001 Src=4062  TX OK
Sync:-NXDN48 TB DATA   ERR3  TX_REL_EX       Group Call Tgt=4001 Src=4062  TX OK
Sync:-NXDN48 TB DATA   ERR2  TX_REL_EX       Group Call Tgt=4001 Src=4062  TX OK
Sync:-NXDN48 TB DATA   ERR8  TX_REL_EX       Group Call Tgt=4001 Src=4062  TX OK
                       ERR2  TX_REL_EX       Group Call Tgt=4001 Src=4062  TX OK
Sync:-NXDN48 TB DATA   ERR6  TX_REL_EX       Group Call Tgt=4001 Src=4062  TX OK
                       ERR6  TX_REL_EX       Group Call Tgt=4001 Src=4062  TX OK
Sync:-NXDN48 TB DATA   ERR4  VCall  Group  TG=4001  RID=4100
Sync:-NXDN48 TB DATA   ERR4  IDLE
Sync:-NXDN48 TB DATA   ERR3  VCall  Group  TG=4001  RID=4100
Sync:-NXDN48 TB DATA         IDLE
Sync:-NXDN48 TB DATA   ERR3  TX_REL_EX       Group Call Tgt=4001 Src=4139  TX OK
                       ERR8  VCall  Group  TG=4001  RID=4062
Sync:-NXDN48 TB DATA   ERR3  VCall  Group  TG=4001  RID=4100
Sync:-NXDN48 TB DATA   ERR3  TX_REL_EX       Group Call Tgt=4001 Src=4062  TX OK
Sync:-NXDN48 TB DATA   ERR3  TX_REL_EX       Group Call Tgt=4001 Src=4062  TX OK
Sync:-NXDN48 TB DATA   ERR3  TX_REL_EX       Group Call Tgt=4001 Src=4062  TX OK
Sync:-NXDN48 TB DATA   ERR3  TX_REL_EX       Group Call Tgt=4001 Src=4062  TX OK
Sync:-NXDN48 TB DATA   ERR1  TX_REL_EX       Group Call Tgt=4001 Src=4062  TX OK
Sync:-NXDN48 TB DATA   ERR4  VCall  Group  TG=4001  RID=4100
Sync:-NXDN48 TB DATA   ERR4  TX_REL_EX       Group Call Tgt=4001 Src=4100  TX OK
Sync:-NXDN48 TB DATA   ERR4  IDLE
That is the only link control data that decoded properly out of what I believe is a minute's worth of data, so somebody is messing up.

So my guess is that it's not working for you because you have bad symbol decoding plus you're not removing the whitening from the raw SACCH symbols?
 

blackmore90

Member
Joined
Jan 9, 2018
Messages
13
Thank you very much for your interest and responses.

Actually symbol decoder is written by our project leader. I will report him the results provided by slicerwizard. We will try to ensure that everything works fine by the raw bits decoder.

I'd say that the fact that anything decoded is a clear indication that the system uses standard NXDN whitening.
By saying standard NXDN whitening, do you mean scrambling? I could not find it on the standards document. Can i remove this effect through the raw input bits or do i have to do it on the raw symbols?

Actually, there is much to learn in NXDN for me. The sound belongs to an airport in my country and it is neither English nor French :)

Thank you very much again.
 

slicerwizard

Member
Joined
Sep 19, 2002
Messages
7,643
Location
Toronto, Ontario
By saying standard NXDN whitening, do you mean scrambling? I could not find it on the standards document.
Yes, the NXDN scrambling is just a way to avoid having long runs of identical symbols going over the air.


Can i remove this effect through the raw input bits or do i have to do it on the raw symbols?
The NXDN docs say that symbols are multiplied by +1 or -1. I'm guessing that means the symbols -3 -1 +1 +3 would be changed to +3 +1 -1 -3. That's the same as changing 11 10 00 01 to 01 00 10 11. So you either change the sign of the symbols or flip the first bit in a pair. At least that's how I read it.
 

blackmore90

Member
Joined
Jan 9, 2018
Messages
13
Ok, now we have checked the demodulator and realized that signal belonging to the attached bit file has deep fading in various moments so it is normal to have errors. I am sorry about that.


I have captured a signal with better conditions and applied the procedure that slicerwizard addressed. I have XORed the scrambler output with only first bit in a pair and now bingo! CRC-6 is matching.


I have uploaded the new bit file. I need to validate my results, namely check the src and dst unit ID's. I do not know how you feed the bit file into DSD+. I would be very happy if you tell me how to do it or provide a list similar to above.

Thank you very very much
 

Attachments

  • nxdn_bits.zip
    7.3 KB · Views: 35

slicerwizard

Member
Joined
Sep 19, 2002
Messages
7,643
Location
Toronto, Ontario
I do not know how you feed the bit file into DSD+. I would be very happy if you tell me how to do it or provide a list similar to above.
I just took each pair of bits and converted them to larger 16 bit integers:

00 ---> 5000
01 ---> 0
10 ---> 10000
11 ---> 15000

I wrote each symbol value to a file 40 times to simulate 2400 symbols per second at a 96 kHz sampling rate.

So 2 bits from your file ---> 80 bytes (40 signed 16 bit integers) in the new file.

I loaded the file into an audio editor as raw signed 16 bit mono 96 kHz audio and saved it as a wav file. Any decent editor, like Audacity, should do that. Then I fed the wav file to DSD+.
 

blackmore90

Member
Joined
Jan 9, 2018
Messages
13
thank you very much, slicerwizard. you helped me a lot. now i can get the correct src and dst ids.

i know that i have requested too much information but in order to finish the control channel decoding, i need to have call start and call end packets. now i am working on to obtain TX_REL_EX packet. std docs say that FACCH1 has interleaving between two functional channels, namely two 144-bit FACCHs as i understand. What does interleaving between functional channels mean? Continuation of interleaving through these channels?

best regards
 

slicerwizard

Member
Joined
Sep 19, 2002
Messages
7,643
Location
Toronto, Ontario
I'm looking at NXDN TS 1-A Version 2.0 (September 2016)


The NXDN docs indicate that an OTA FACCH1 block is 144 bits. (pg39)

Also, "FACCH1 is separated into two channels from one information data." (pg52)

Also, 80 payload bits are encoded as 144 OTA bits. (pg53)

So each FACCH1 block gives you a 10 byte message.

And complete FACCH1 messages are 10 bytes. (pg93)

The diagrams (pg53, etc.) show two FACCH1 blocks being sent back to back, so two messages are encoded?

I'm guessing that "interleaving between functional channels" and "FACCH1 is separated into two channels from one information data." just means that there are two FACCH1 messages in a row in the same NXDN frame.

The English in those docs is not good. Not good at all...
 

blackmore90

Member
Joined
Jan 9, 2018
Messages
13
I'm guessing that "interleaving between functional channels" and "FACCH1 is separated into two channels from one information data." just means that there are two FACCH1 messages in a row in the same NXDN frame.
This is exactly what i thought. Two FACCH1 messages in the same frame. However I haven't been able to receive the TX_REL_EX packets in both files i have attached here. CRC12 is OK in only some portion of frames but they contain VCALL_ASSGN_DUP which is useless for me:D. Rest have CRC errors mostly when both channels are FACCH1. Also, DSD+ 1.101 is not showing the TX_REL_EX packets that you posted here. Set up the verbose but it did not work, only VCalls show up :) Still working hard on these frames to develop something useful :)

The English in those docs is not good. Not good at all...
I really agree with you. It is much pain to understand something from those vague definitions.

Thank you very much
Best regards
 

EricCottrell

Member
Premium Subscriber
Joined
Nov 8, 2002
Messages
2,413
Location
Boston, Ma
Hello,

I use the itpp library to do the punctured convolutional code decoding.
Welcome to IT++!

You need to look at the lich to see how you decode the facch as there are two formats. One format has two 144 bit frames that end up being two 80 bit messages. Most of the time the second message is a repeat of the first or idle. The other format combines the two into a single 160 bit message.

73 Eric
 

blackmore90

Member
Joined
Jan 9, 2018
Messages
13
Hello,

I use the itpp library to do the punctured convolutional code decoding.
Welcome to IT++!

You need to look at the lich to see how you decode the facch as there are two formats. One format has two 144 bit frames that end up being two 80 bit messages. Most of the time the second message is a repeat of the first or idle. The other format combines the two into a single 160 bit message.

73 Eric

Hi Eric,
Thank you for the suggestion on convolutional decoding. We have designed a convolutional decoder and it seems working well as I have validated source and destination unit ID's after SACCH decoding, but i can use these libraries to make sure that everything by the L3 data works very well.

Also, thank you very much for the FACCH1 repetition information. The other format is FACCH2, isn't it?
If so, it seems there is no FACCH2 in the bit files i have posted here, at least that's what my program tells. I am taking the RF channel types and functional channel types into consideration when decoding. I only see FACCH1 frames as FACCH and CRC-12 is matching for only some portion of them.

Still working on to obtain TX_REL_EX,
Thank you very much.
 

blackmore90

Member
Joined
Jan 9, 2018
Messages
13
I guess it's a fastlane thing.

Yes, probably that's why I cannot see the TX_REL_EX messages, then the bit files probably contain TX_REL_EX messages, which I have not been able to get. Maybe I need to take Eric's advice and try those libraries. I don't know. Just experimenting :)
 

blackmore90

Member
Joined
Jan 9, 2018
Messages
13
Hello,

I use the itpp library to do the punctured convolutional code decoding.
Welcome to IT++!

You need to look at the lich to see how you decode the facch as there are two formats. One format has two 144 bit frames that end up being two 80 bit messages. Most of the time the second message is a repeat of the first or idle. The other format combines the two into a single 160 bit message.

73 Eric

Hi Eric,
First of all, thank you very much for the it++ suggestion. We have written a punctured convolutional decoder and actually it seems working fine because I have validated the src and dst unit IDs after SACCH decoding, which incorporates the same convolutional decoder as FACCH1. However, to ensure maximum safety, i can try that library. At the end i will make sure that everything works fine by the L3 message parsing.

And thank you for the FACCH repetition/idle information. I will check this in my input data. Is the other format which incorporates single 160 bit message refers to FACCH2? Actually my program takes LICH into consideration. I don't see any FACCH2 frames, only FACCH1's as FACCH. There are also full slot FACCH1 frames. However, some of them fail at CRC12 stage, the rest result in useless VCALL_ASSGN_DUP messages. Interestingly, most full slot FACCH1 frames fail at CRC12 stage. Half slots FACCH1s are much better. My program applies descrambling to both 144-bit FACCH1 frames whether the FACCH mode is full or half slot. Also, depunctured convolutional decoding is applied individually on 144-bit frames.

I have attached the bit view image of the second bit file as 384-bit frames. Through the end, full slot FACCH1 pattern can be clearly seen. Maybe this would help you give me an idea.

Apart from it++, i am going to test every block at input and output. I don't have a plan-B right now.

Many thanks for helping me along.
Best regards
 

Attachments

  • nxdn_bits.jpg
    nxdn_bits.jpg
    104.6 KB · Views: 582

blackmore90

Member
Joined
Jan 9, 2018
Messages
13
I am sorry for the redundant message here. Please don't consider the first message, since last one is updated version of it.
 

EricCottrell

Member
Premium Subscriber
Joined
Nov 8, 2002
Messages
2,413
Location
Boston, Ma
Hello,

It took a bit of work to get the itpp library to work because it uses a soft decision format where 0 = 1 and 1 = -1. Here is a code snippet that uses several datatypes from the library

Code:
#include <itpp/itcomm.h>

using namespace itpp;

static int initFlag = 0;
static Punctured_Convolutional_Code pcc;
static ivec generator(2);
static bmat puncture_matrix = "1 1;0 1";

void
processNXDNFacch1 (dsd_opts * opts, dsd_state * state, short chType, char facch1[144])
{
  long long ll;
  char tmpStr[81];
  int i, j;
  vec input(144);
  bvec output(92);
  short msgType;
  if(initFlag == 0)
  {
    generator(0)=023;
    generator(1)=035;
    pcc.set_generator_polynomials(generator, 5);
    pcc.set_method(Tail);
    pcc.set_puncture_matrix(puncture_matrix);
    pcc.set_truncation_length(20);
    initFlag = 1;
  }
  pcc.reset();
    // Convert to itpp soft decision mapping (0 = 1 and 1 = -1)
    for(unsigned int i=0; i<144; i++) {
        input[i] = (facch1[i])?-1.0:1.0;
    }
    pcc.decode_tail(input, output);
    fac_str_valid = 0;
    initCRC12();
    for(i = 0; i < 92; i++)
    {
      doCRC12((output[i])?1:0);
    }
    if(getCRC12() != 0)
      return;

If you look at Table 5.2-2 LICH Settings in Part 1-A of the specification you can see that the LICH is used to indicate if the contents have two voice frames, a voice frame and a facch1 frame, two facch1 frames, udch frame, or a facch2 frame. I also noticed the messages you want are likely contained in the facch2 frame, which it appears you are not decoding. The data is extracted from a facch2 frame like it is two facch1 frames and the 80 bits from the second frame are concatenated to the first 80 bits.

73 Eric
 

slicerwizard

Member
Joined
Sep 19, 2002
Messages
7,643
Location
Toronto, Ontario
We have written a punctured convolutional decoder and actually it seems working fine because I have validated the src and dst unit IDs after SACCH decoding, which incorporates the same convolutional decoder as FACCH1. However, to ensure maximum safety, i can try that library. At the end i will make sure that everything works fine by the L3 message parsing.
You can easily test your decoding chain by generating your own random data and encoding it. The encoding steps - CRC, tail bits, LFSR, puncturing, interleaving - are all simple to implement. Random payload data run through an encoder and decoder should be identical at both ends. You should then introduce some random bit flips between the encoder and decoder stages; you should still get the correct payload and CRC checks on the decoder side.
 

blackmore90

Member
Joined
Jan 9, 2018
Messages
13
Eric, thank you for the code snippet, i have started to replace my conv decoder. I use MS Visual Studio 2015 and building those it++ libraries on windows is a bit knotty. Do you use Cygwin or MinGW for building?

Yesterday, i fixed a bug in the software and i have succeeded to get only one healthy TX_REL_EX from full slot FACCH1 which was in the second bit file. One step forward, however, i need to have them in the first bit file as DSD+FL grabs many TX_REL_EX.

I don't see any LICH output as [0,1,0,1,0,0,1,0]. All goes like [0,1,1,0,...] or [0,1,0,0,...] which are SACCH frames, not UDCH. If DSD+FL grabs TX_REL_EX from FACCH2 packets, then my descrambling is erroneous. However, i have voice frames and VCALL packets successfully so i think descrambler is working fine.

slicerwizard, thank you for the suggestion on testing. I compared each block's output with MATLAB results and i can get the data without problem, each block seem to work fine but i guess my blocks slightly differ from the standard, i am missing a point.

I am still working hard and testing each block to detect the problem.
Many thanks and best regards.
 

G4KLX

Newbie
Joined
Jan 23, 2018
Messages
3
I'm working on decoding the SACCH for the MMDVM project. I have the LICH decoding correctly after I realised that the scrambler was per symbol and not per bit.

I'd be interested in your CRC algorithm for the six-bit CRC, as well as any gotchas on decoding the SACCH. I don't expect to see an FACCH2 unless I send data, I get the impression from the documentation that the FACCH2 works as a header for a bunch of UDCH blocks.

For voice I only expect to see SACCH and FACCH1 as well as audio blocks.
 
Status
Not open for further replies.
Top