#ifndef __LDPC_H__ #define __LDPC_H__ #include #include #include #include #include "bitcount.h" #ifndef __AVR__ // #include #include #endif #ifdef __AVR__ #include #endif // extern const uint32_t LDPC_ParityGen_n208k160[48][5]; // extern const uint32_t LDPC_ParityCheck_n208k160[48][7]; // extern const uint8_t LDPC_ParityCheckIndex_n208k160[48][24]; // extern const uint8_t LDPC_BitWeight_n208k160[208]; #ifdef WITH_PPM extern const uint32_t LDPC_ParityGen_n354k160[194][5]; extern const uint32_t LDPC_ParityCheck_n354k160[194][12]; #endif #ifdef __AVR__ // encode Parity from Data: Data is 5x 32-bit words = 160 bits, Parity is 1.5x 32-bit word = 48 bits void LDPC_Encode(const uint32_t *Data, uint32_t *Parity, const uint32_t ParityGen[48][5]); void LDPC_Encode(const uint32_t *Data, uint32_t *Parity); // encode Parity from Data: Data is 20 bytes = 160 bits, Parity is 6 bytes = 48 bits void LDPC_Encode(const uint8_t *Data, uint8_t *Parity, const uint32_t ParityGen[48][5]); void LDPC_Encode(const uint8_t *Data, uint8_t *Parity); void LDPC_Encode( uint8_t *Data); // check Data against Parity (run 48 parity checks) - return number of failed checks uint8_t LDPC_Check(const uint8_t *Data); // 20 data bytes followed by 6 parity bytes uint8_t LDPC_Check(const uint32_t *Packet); #else // if not 8-bit AVR void LDPC_Encode(const uint8_t *Data, uint8_t *Parity, const uint32_t ParityGen[48][5]); void LDPC_Encode(const uint8_t *Data, uint8_t *Parity); void LDPC_Encode( uint8_t *Data); // encode Parity from Data: Data is 5x 32-bit words = 160 bits, Parity is 1.5x 32-bit word = 48 bits // void LDPC_Encode(const uint32_t *Data, uint32_t *Parity, const uint32_t ParityGen[48][5]); // void LDPC_Encode(const uint32_t *Data, uint32_t *Parity, uint8_t DataWords, uint8_t Checks, const uint32_t *ParityGen); // inline void LDPC_Encode(const uint32_t *Data, uint32_t *Parity) { LDPC_Encode(Data, Parity, 5, 48, (uint32_t *)LDPC_ParityGen_n208k160); } // inline void LDPC_Encode( uint32_t *Data) { LDPC_Encode(Data, Data+5, 5, 48, (uint32_t *)LDPC_ParityGen_n208k160); } // inline void LDPC_Encode_n394k160(const uint32_t *Data, uint32_t *Parity) { LDPC_Encode(Data, Parity, 5, 194, (uint32_t *)LDPC_ParityGen_n354k160); } // inline void LDPC_Encode_n394k160( uint32_t *Data) { LDPC_Encode(Data, Data+5, 5, 194, (uint32_t *)LDPC_ParityGen_n354k160); } void LDPC_Encode(const uint32_t *Data, uint32_t *Parity); void LDPC_Encode( uint32_t *Data); #ifdef WITH_PPM void LDPC_Encode_n354k160(const uint32_t *Data, uint32_t *Parity); void LDPC_Encode_n354k160( uint32_t *Data); #endif // check Data against Parity (run 48 parity checks) - return number of failed checks uint8_t LDPC_Check(const uint32_t *Data, const uint32_t *Parity); // Data and Parity are 32-bit words uint8_t LDPC_Check(const uint32_t *Data); uint8_t LDPC_Check(const uint8_t *Data); // 20 data bytes followed by 6 parity bytes #ifdef WITH_PPM uint8_t LDPC_Check_n354k160(const uint32_t *Data, const uint32_t *Parity); // Data and Parity are 32-bit words uint8_t LDPC_Check_n354k160(const uint32_t *Data); #endif #endif // __AVR__ #ifndef __AVR__ extern const uint8_t LDPC_ParityCheckIndex_n208k160[48][24]; class LDPC_Decoder { public: const static uint8_t UserBits = 160; // 5 32-bit bits = 20 bytes const static uint8_t UserWords = UserBits/32; const static uint8_t ParityBits = 48; // 6 bytes (total packet is 26 bytes) const static uint8_t CodeBits = UserBits+ParityBits; // 160+48 = 208 code bits = 26 bytes const static uint8_t CodeBytes = (CodeBits+ 7)/ 8; // const static uint8_t CodeWords = (CodeBits+31)/32; // const static uint8_t MaxCheckWeight = 24; // const static uint8_t MaxBitWeight = 8; public: int16_t InpBit[CodeBits]; // a-priori bits int16_t ExtBit[CodeBits]; // extrinsic inf. int16_t OutBit[CodeBits]; // a-posteriori bits void Input(const uint8_t *Data, const uint8_t *Err) { uint8_t Mask=1; uint8_t Idx=0; uint8_t DataByte=0; uint8_t ErrByte=0; for(uint8_t Bit=0; Bit32767) Inp=32767; else if(Inp<(-32767)) Inp=(-32767); OutBit[Bit] = InpBit[Bit] = Inp; ExtBit[Bit]=0; } } void Output(uint32_t Data[CodeWords]) { uint32_t Mask=1; uint8_t Idx=0; uint32_t Word=0; for(uint8_t Bit=0; Bit0) Word|=Mask; Mask<<=1; if(Mask==0) { Data[Idx++]=Word; Word=0; Mask=1; } } if(Mask>1) Data[Idx++]=Word; } void Output(uint8_t Data[CodeBytes]) { uint8_t Mask=1; uint8_t Idx=0; uint8_t Byte=0; for(uint8_t Bit=0; Bit0) Byte|=Mask; Mask<<=1; if(Mask==0) { Data[Idx++]=Byte; Byte=0; Mask=1; } } if(Mask>1) Data[Idx++]=Byte; } int8_t ProcessChecks(void) { for(uint8_t Bit=0; Bit>1); } return Count; } int16_t ProcessCheck(uint8_t Row) { int16_t MinAmpl=32767; uint8_t MinBit=0; int16_t MinAmpl2=MinAmpl; uint32_t Word=0; uint32_t Mask=1; const uint8_t *CheckIndex = LDPC_ParityCheckIndex_n208k160[Row]; uint8_t CheckWeight = *CheckIndex++; for(uint8_t Bit=0; Bit0) Word|=Mask; Mask<<=1; if(Ampl<0) Ampl=(-Ampl); if(Ampl class LDPC_FloatDecoder { public: const static int MaxCodeBits=512; const static int MaxParityBits=256; const static int MaxParityWeight=32; // int CodeBits; // number of code bits int ParityBits; // number of parity bits uint16_t ParityCheckIndex[MaxParityBits][MaxParityWeight]; // list of 1's in the ParityCheck matrix uint8_t ParityCheckRowWeight[MaxParityBits]; // number of 1's in ParityCheck rows uint8_t ParityCheckColWeight[MaxCodeBits]; // number of 1's in ParityCheck columns Float InpBit[MaxCodeBits]; // a-priori bits Float ExtBit[MaxCodeBits]; // extrinsic inf. Float OutBit[MaxCodeBits]; // a-posteriori bits Float Feedback; public: LDPC_FloatDecoder() { CodeBits=0; ParityBits=0; Feedback=0.33; } void Clear(void) { for(int Bit=0; BitMaxCodeBits) return -1; CodeBits=NewCodeBits; if(ParityBits>MaxParityBits) return -1; ParityBits=NewParityBits; for(int Bit=0; Bit0) Word|=Mask; Mask<<=1; if(Mask==0) { Data[Idx++]=Word; Word=0; Mask=1; } } if(Mask>1) Data[Idx++]=Word; } void Output(uint8_t *Data) // format decoded bits as a series of bytes { uint8_t Mask=1; int Idx=0; uint8_t Byte=0; for(int Bit=0; Bit0) Byte|=Mask; Mask<<=1; if(Mask==0) { Data[Idx++]=Byte; Byte=0; Mask=1; } } if(Mask>1) Data[Idx++]=Byte; } int ProcessChecks(void) { for(int Bit=0; Bit::max(); int MinBit=0; Float MinAmpl2=MinAmpl; // look for 1st and 2nd smallest LL uint32_t Word=0; uint32_t Mask=1; const uint16_t *CheckIndex = ParityCheckIndex[Row]; // indeces of bits in this parity check int CheckWeight = ParityCheckRowWeight[Row]; // number of bits in this parity check for(int Bit=0; Bit0) Word|=Mask; // store hard bits in the Word Mask<<=1; if(Ampl<0) Ampl=(-Ampl); // strip the LL sign if(Ampl0; bool Out=OutBit[Idx]>0; if(Inp!=Out) Count++; } return Count; } } ; #ifdef WITH_PPM template class OGN_PPM_Decoder { public: static const int DataBits = 32*5; // 5 words = 160 data bits = OGN packet static const int ParityBits = 194; // 194 parity bits (Gallager code) static const int CodeBits = DataBits+ParityBits; // 354 total bits per Gallager code block static const int BitsPerSymbol = 6; // 6 bits per symbol for PPM modulation static const int PulsesPerSlot = 1< LDPC_Decoder; // inner LDPC code decoder Float InpSymb[CodeSymbols][PulsesPerSlot]; // input from the demodulator Float ExtSymb[CodeSymbols][PulsesPerSlot]; // output from the LDPC decoder Float OutSymb[CodeSymbols][PulsesPerSlot]; // input x extrinsic inf. public: OGN_PPM_Decoder() { LDPC_Decoder.Configure(CodeBits, ParityBits, (uint32_t *)LDPC_ParityCheck_n354k160); Clear(); } void Clear(void) { for(int Symb=0; Symb=CodeSymbols) || (Symbol>=PulsesPerSlot) ) return; InpSymb[Slot][Symbol]+=Power; } int Process(int Loops=48) { LDPC_Decoder.Clear(); for(int Symb=0; Symb>=1; } } } int CheckErr=0; for( int Loop=0; Loop %3d\n", Loop, CheckErr); if(CheckErr==0) break; } return CheckErr; } static uint8_t Gray(uint8_t Binary) { return Binary ^ (Binary>>1); } static uint8_t Binary(uint8_t Gray) { Gray = Gray ^ (Gray >> 4); Gray = Gray ^ (Gray >> 2); Gray = Gray ^ (Gray >> 1); return Gray; } void NormExtSymb(Float Norm=1.0) { for(int Symb=0; Symb