Starting to add code for a potential "QRA65" mode.

git-svn-id: svn+ssh://svn.code.sf.net/p/wsjt/wsjt/branches/wsjtx@6788 ab8295b8-cf94-4d9e-aec4-7959e3be5d79
This commit is contained in:
Joe Taylor 2016-06-21 15:07:24 +00:00
parent 431e7ad719
commit 14f03dca53
21 changed files with 4683 additions and 0 deletions

436
lib/qra/qra65/main.c Normal file
View File

@ -0,0 +1,436 @@
// main.c
// QRA65 mode encode/decode test
//
// (c) 2016 - Nico Palermo, IV3NWV
//
// Thanks to Andrea Montefusco IW0HDV for his help on adapting the sources
// to OSs other than MS Windows
//
// ------------------------------------------------------------------------------
// This file is part of the qracodes project, a Forward Error Control
// encoding/decoding package based on Q-ary RA (Repeat and Accumulate) LDPC codes.
//
// Files in this package:
// main.c - this file
// qra65.c/.h - qra65 mode encode/decoding functions
//
// ..\qracodes\normrnd.c/.h - random gaussian number generator
// ..\qracodes\npfwht.c/.h - Fast Walsh-Hadamard Transforms
// ..\qracodes\pdmath.c/.h - Elementary math on probability distributions
// ..\qracodes\qra12_63_64_irr_b.c/.h - Tables for a QRA(12,63) irregular RA code over GF(64)
// ..\qracodes\qra13_64_64_irr_e.c/.h - Tables for a QRA(13,64) irregular RA code " "
// ..\qracodes\qracodes.c/.h - QRA codes encoding/decoding functions
//
// -------------------------------------------------------------------------------
//
// qracodes is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
// qracodes is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
// You should have received a copy of the GNU General Public License
// along with qracodes source distribution.
// If not, see <http://www.gnu.org/licenses/>.
// -----------------------------------------------------------------------------
// The code used by the QRA65 mode is the code:
// QRA13_64_64_IRR_E: K=13 N=64 Q=64 irregular QRA code (defined in qra13_64_64_irr_e.h /.c)
// This code has been designed to include a CRC as the 13th information symbol
// and improve the code UER (Undetected Error Rate).
// The CRC symbol is not sent along the channel (the codes are punctured) and the
// resulting code is still a (12,63) code with an effective code rate of R = 12/63.
// ------------------------------------------------------------------------------
// OS dependent defines and includes --------------------------------------------
#if _WIN32 // note the underscore: without it, it's not msdn official!
// Windows (x64 and x86)
#include <windows.h> // required only for GetTickCount(...)
#include <process.h> // _beginthread
#endif
#if __linux__
#include <unistd.h>
#include <time.h>
unsigned GetTickCount(void) {
struct timespec ts;
unsigned theTick = 0U;
clock_gettime( CLOCK_REALTIME, &ts );
theTick = ts.tv_nsec / 1000000;
theTick += ts.tv_sec * 1000;
return theTick;
}
#endif
#if __APPLE__
#endif
#include <stdlib.h>
#include <stdio.h>
#include "qra65.h"
#include "..\qracodes\normrnd.h" // gaussian numbers generator
// -----------------------------------------------------------------------------------
// channel types
#define CHANNEL_AWGN 0
#define CHANNEL_RAYLEIGH 1
void printwordd(char *msg, int *x, int size)
{
int k;
printf("\n%s ",msg);
for (k=0;k<size;k++)
printf("%2d ",x[k]);
printf("\n");
}
void printwordh(char *msg, int *x, int size)
{
int k;
printf("\n%s ",msg);
for (k=0;k<size;k++)
printf("%02hx ",x[k]);
printf("\n");
}
#define NSAMPLES (QRA65_N*QRA65_M)
static float rp[NSAMPLES];
static float rq[NSAMPLES];
static float chp[NSAMPLES];
static float chq[NSAMPLES];
static float r[NSAMPLES];
float *mfskchannel(int *x, int channel_type, float EbNodB)
{
// simulate a MFSK channel (AWGN or Rayleigh)
// x is a pointer to the transmitted codeword (an array of QRA65_N integers in the range 0..63)
//
// the function returns the received symbol energies (squared amplitudes)
// as an array of (QRA65_M*QRA65_N) float numbers
// the first QRA65_M entries of this array are the energies of the first symbol in the codeword
// the second QRA65_M entries are those of the second symbol
// and so on up to the last codeword symbol
const float No = 1.0f; // noise spectral density
const float sigma = (float)sqrt(No/2.0f); // std dev of noise I/Q components
const float sigmach = (float)sqrt(1/2.0f); // std dev of channel I/Q gains
const float R = 1.0f*QRA65_K/QRA65_N;
float EbNo = (float)pow(10,EbNodB/10);
float EsNo = 1.0f*QRA65_m*R*EbNo;
float Es = EsNo*No;
float A = (float)sqrt(Es);
int k;
normrnd_s(rp,NSAMPLES,0,sigma);
normrnd_s(rq,NSAMPLES,0,sigma);
if (channel_type == CHANNEL_AWGN)
for (k=0;k<QRA65_N;k++)
rp[k*QRA65_M+x[k]]+=A;
else
if (channel_type == CHANNEL_RAYLEIGH) {
normrnd_s(chp,QRA65_N,0,sigmach);
normrnd_s(chq,QRA65_N,0,sigmach);
for (k=0;k<QRA65_N;k++) {
rp[k*QRA65_M+x[k]]+=A*chp[k];
rq[k*QRA65_M+x[k]]+=A*chq[k];
}
}
else {
return 0; // unknown channel type
}
// compute the squares of the amplitudes of the received samples
for (k=0;k<NSAMPLES;k++)
r[k] = rp[k]*rp[k] + rq[k]*rq[k];
return r;
}
// These defines are some packed fields as computed by JT65
#define CALL_IV3NWV 0x7F85AE7
#define CALL_K1JT 0xF70DDD7
#define GRID_JN66 0x3AE4 // JN66
#define GRID_73 0x7ED0 // 73
char decode_type[6][32] = {
"[? ? ?] AP0",
"[CQ ? ?] AP27",
"[CQ ? ] AP44",
"[CALL ? ?] AP29",
"[CALL ? ] AP45",
"[CALL CALL ?] AP57"
};
int test_proc_1(int channel_type, float EbNodB, int mode)
{
// Here we simulate the following (dummy) QSO:
//
// 1) CQ IV3NWV
// 2) IV3NWV K1JT
// 3) K1JT IV3NWV 73
// 4) IV3NWV K1JT 73
//
// No message repetition is attempted
// The QSO is counted as successfull if IV3NWV received the last message
// When mode=QRA_AUTOAP each decoder attempts to decode the message sent
// by the other station using the a-priori information derived by what
// has been already decoded in a previous phase of the QSO if
// decoding with no a-priori information has not been successful.
// I.e. at step 1) K1JT's decoder first attempts to decode msgs of type [? ? ?] and if this
// attempt fails, it attempts to decode [CQ/QRZ ? ?] or [[CQ/QRZ ?] msgs
// At step 2) if IV3NWV's decoder is unable to decode K1JT's without AP it attempts to decode
// messages of the type [IV3NWV ? ?] and [IV3NWV ?].
// At step 3) K1JT's decoder attempts to decode [? ? ?] and [K1JT IV3NWV ?] (this last decode
// type has been enabled by K1JT's encoder at step 2)
// At step 4) IV3NWV's decoder attempts to decode [? ? ?] and [IV3NWV K1JT ?] (this last decode
// type has been enabled by IV3NWV's encoder at step 3)
// At each step the simulation reports if a decode was successful.
// In this case it also reports the type of decode (see table decode_type above)
// When mode=QRA_NOAP, only [? ? ?] decodes are attempted and no a-priori information
// is used by the decoder
// The function returns 0 if all of the four messages have been decoded by their recipients
// (with no retries) and -1 if any of them could not be decoded
int x[QRA65_K], xdec[QRA65_K];
int y[QRA65_N];
float *r;
int rc;
// each simulated station must use its own codec
// as it might work with different a-priori information
qra65codec *codec_iv3nwv = qra65_init(mode,CALL_IV3NWV); // codec for IV3NWV
qra65codec *codec_k1jt = qra65_init(mode,CALL_K1JT); // codec for K1JT
// IV3NWV makes a CQ call (with no grid)
printf("IV3NWV tx: CQ IV3NWV\n");
encodemsg_jt65(x,CALL_CQ,CALL_IV3NWV,GRID_BLANK);
qra65_encode(codec_iv3nwv, y, x);
r = mfskchannel(y,channel_type,EbNodB);
// K1JT attempts to decode
rc = qra65_decode(codec_k1jt, xdec,r);
if (rc>=0) { // decoded
printf("K1JT rx: received with apcode=%d %s\n",rc, decode_type[rc]);
// K1JT replies to IV3NWV (with no grid)
printf("K1JT tx: IV3NWV K1JT\n");
encodemsg_jt65(x,CALL_IV3NWV,CALL_K1JT, GRID_BLANK);
qra65_encode(codec_k1jt, y, x);
r = mfskchannel(y,channel_type,EbNodB);
// IV3NWV attempts to decode
rc = qra65_decode(codec_iv3nwv, xdec,r);
if (rc>=0) { // decoded
printf("IV3NWV rx: received with apcode=%d %s\n",rc, decode_type[rc]);
// IV3NWV replies to K1JT with a 73
printf("IV3NWV tx: K1JT IV3NWV 73\n");
encodemsg_jt65(x,CALL_K1JT,CALL_IV3NWV, GRID_73);
qra65_encode(codec_iv3nwv, y, x);
r = mfskchannel(y,channel_type,EbNodB);
// K1JT attempts to decode
rc = qra65_decode(codec_k1jt, xdec,r);
if (rc>=0) { // decoded
printf("K1JT rx: received with apcode=%d %s\n",rc, decode_type[rc]);
// K1JT replies to IV3NWV with a 73
printf("K1JT tx: IV3NWV K1JT 73\n");
encodemsg_jt65(x,CALL_IV3NWV,CALL_K1JT, GRID_73);
qra65_encode(codec_k1jt, y, x);
r = mfskchannel(y,channel_type,EbNodB);
// IV3NWV attempts to decode
rc = qra65_decode(codec_iv3nwv, xdec,r);
if (rc>=0) { // decoded
printf("IV3NWV rx: received with apcode=%d %s\n",rc, decode_type[rc]);
return 0;
}
}
}
}
printf("the other party did not decode\n");
return -1;
}
int test_proc_2(int channel_type, float EbNodB, int mode)
{
// Here we simulate the decoder of K1JT after K1JT has sent a msg [IV3NWV K1JT]
// and IV3NWV sends him the msg [K1JT IV3NWV JN66]
// If mode=QRA_NOAP, K1JT decoder attempts to decode only msgs of type [? ? ?].
// If mode=QRA_AUTOP, K1JT decoder will attempt to decode also the msgs [K1JT IV3NWV] and
// [K1JT IV3NWV ?].
// In the case a decode is successful the return code of the qra65_decode function
// indicates the amount of a-priori information required to decode the received message
// accordingly to this table:
// rc=0 [? ? ?] AP0
// rc=1 [CQ ? ?] AP27
// rc=2 [CQ ? ] AP44
// rc=3 [CALL ? ?] AP29
// rc=4 [CALL ? ] AP45
// rc=5 [CALL CALL ?] AP57
// The return code is <0 when decoding is unsuccessful
// This test simulates the situation ntx times and reports how many times
// a particular type decode among the above 6 cases succeded.
int x[QRA65_K], xdec[QRA65_K];
int y[QRA65_N];
float *r;
int rc,k;
int ndecok[6] = { 0, 0, 0, 0, 0, 0};
int ntx = 100,ndec=0;
qra65codec *codec_iv3nwv = qra65_init(mode,CALL_IV3NWV); // codec for IV3NWV
qra65codec *codec_k1jt = qra65_init(mode,CALL_K1JT); // codec for K1JT
// this will enable k1jt's decoder to look for iv3nwv calls
encodemsg_jt65(x,CALL_IV3NWV,CALL_K1JT,GRID_BLANK);
qra65_encode(codec_k1jt, y, x);
printf("K1JT tx: IV3NWV K1JT\n");
// iv3nwv reply to k1jt
printf("IV3NWV tx: K1JT IV3NWV JN66\n");
encodemsg_jt65(x,CALL_K1JT,CALL_IV3NWV,GRID_JN66);
qra65_encode(codec_iv3nwv, y, x);
printf("Simulating decodes by K1JT up to AP56 ...");
for (k=0;k<ntx;k++) {
printf(".");
r = mfskchannel(y,channel_type,EbNodB);
rc = qra65_decode(codec_k1jt, xdec,r);
if (rc>=0)
ndecok[rc]++;
}
printf("\n");
printf("Transimtted:%d - Decoded:\n",ntx);
for (k=0;k<6;k++) {
printf("%3d with %s\n",ndecok[k],decode_type[k]);
ndec += ndecok[k];
}
printf("Total: %d/%d\n",ndec,ntx);
printf("\n");
return 0;
}
void syntax(void)
{
printf("\nQRA65 Mode Tests\n");
printf("2016, Nico Palermo - IV3NWV\n\n");
printf("---------------------------\n\n");
printf("Syntax: qra65 [-s<snrdb>] [-c<channel>] [-a<ap-type>] [-t<testtype>] [-h]\n");
printf("Options: \n");
printf(" -s<snrdb> : set simulation SNR in 2500 Hz BW (default:-27.5 dB)\n");
printf(" -c<channel> : set channel type 0=AWGN (default) 1=Rayleigh\n");
printf(" -a<ap-type> : set decode type 0=NO_AP 1=AUTO_AP (default)\n");
printf(" -t<testtype>: 0=simulate seq of msgs between IV3NWV and K1JT (default)\n");
printf(" 1=simulate K1JT receiving K1JT IV3NWV JN66\n");
printf(" -h: this help\n");
}
int main(int argc, char* argv[])
{
int k, rc, nok=0;
float SNRdB = -27.5f;
unsigned int channel = CHANNEL_AWGN;
unsigned int mode = QRA_AUTOAP;
unsigned int testtype=0;
int nqso = 100;
float EbNodB;
// parse command line
while(--argc) {
argv++;
if (strncmp(*argv,"-h",2)==0) {
syntax();
return 0;
}
else
if (strncmp(*argv,"-a",2)==0) {
mode = (unsigned int)atoi((*argv)+2);
if (mode>1) {
printf("Invalid decoding mode\n");
syntax();
return -1;
}
}
else
if (strncmp(*argv,"-s",2)==0) {
SNRdB = (float)atof((*argv)+2);
if (SNRdB>0 || SNRdB<-40) {
printf("SNR should be in the range [-40..0]\n");
syntax();
return -1;
}
}
else
if (strncmp(*argv,"-t",2)==0) {
testtype = (unsigned int)atoi((*argv)+2);
if (testtype>1) {
printf("Invalid test type\n");
syntax();
return -1;
}
}
else
if (strncmp(*argv,"-c",2)==0) {
channel = (unsigned int)atoi((*argv)+2);
if (channel>CHANNEL_RAYLEIGH) {
printf("Invalid channel type\n");
syntax();
return -1;
}
}
else {
printf("Invalid option\n");
syntax();
return -1;
}
}
EbNodB = SNRdB+29.1f;
if (testtype==0) {
for (k=0;k<nqso;k++) {
printf("\n\n------------------------\n");
rc = test_proc_1(channel, EbNodB, mode);
if (rc==0)
nok++;
}
printf("\n\n%d/%d QSOs to end without repetitions\n",nok,nqso);
}
else
test_proc_2(channel, EbNodB, mode);
printf("SNR = %.1fdB channel=%s ap-mode=%s\n\n",
SNRdB,
channel==CHANNEL_AWGN?"AWGN":"RAYLEIGH",
mode==QRA_NOAP?"NO_AP":"AUTO_AP"
);
return 0;
}

344
lib/qra/qra65/qra65.c Normal file
View File

@ -0,0 +1,344 @@
// qra65.c
// Encoding/decoding functions for the QRA65 mode
//
// (c) 2016 - Nico Palermo, IV3NWV
//
// -------------------------------------------------------------------------------
//
// qracodes is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
// qracodes is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
// You should have received a copy of the GNU General Public License
// along with qracodes source distribution.
// If not, see <http://www.gnu.org/licenses/>.
// -----------------------------------------------------------------------------
// Code used in this sowftware release:
// QRA13_64_64_IRR_E: K=13 N=64 Q=64 irregular QRA code (defined in qra13_64_64_irr_e.h /.c)
// Codes with K=13 are designed to include a CRC as the 13th information symbol
// and improve the code UER (Undetected Error Rate).
// The CRC symbol is not sent along the channel (the codes are punctured) and the
// resulting code is a (12,63) code
// ------------------------------------------------------------------------------
#include <stdlib.h>
#include <math.h>
#include "qra65.h"
#include "..\qracodes\qracodes.h"
#include "..\qracodes\qra13_64_64_irr_e.h"
#include "..\qracodes\pdmath.h"
// Code parameters of the QRA65 mode
#define QRA65_CODE qra_13_64_64_irr_e
#define QRA65_NMSG 218 // this must much the value indicated in QRA65_CODE.NMSG
#define QRA65_KC (QRA65_K+1) // information symbols crc included (as defined in the code)
#define QRA65_NC (QRA65_N+1) // codeword length (as defined in the code)
#define QRA65_NITER 100 // max number of iterations per decode
// static functions declarations -------------------------------------------------
static int calc_crc6(const int *x, int sz);
static void ix_mask(float *dst, const float *src, const int *mask, const int *x);
static int qra65_do_decode(int *x, const float *pix, const int *ap_mask, const int *ap_x);
// a-priori information masks for fields in jt65-like msgs -----------------------
#define MASK_CQQRZ 0xFFFFFFC // CQ/QRZ calls common bits
#define MASK_CALL1 0xFFFFFFF
#define MASK_CALL2 0xFFFFFFF
#define MASK_GRIDFULL 0xFFFF
#define MASK_GRIDBIT 0x8000 // b[15] is 0 for all the messages which are not text
// -------------------------------------------------------------------------------
qra65codec *qra65_init(int flags, const int mycall)
{
// Eb/No value for which we optimize the decoder metric
const float EbNodBMetric = 2.8f;
const float EbNoMetric = (float)pow(10,EbNodBMetric/10);
const float R = 1.0f*(QRA65_KC)/(QRA65_NC);
qra65codec *pcodec = (qra65codec*)malloc(sizeof(qra65codec));
if (!pcodec)
return 0; // can't allocate memory
pcodec->decEsNoMetric = 1.0f*QRA65_m*R*EbNoMetric;
pcodec->apflags = flags;
if (flags!=QRA_AUTOAP)
return pcodec;
// initialize messages and mask for decoding with a-priori information
pcodec->apmycall = mycall;
pcodec->apsrccall = 0;
// encode CQ/QRZ messages and masks
// NOTE: Here we handle only CQ and QRZ msgs
// 'CQ nnn', 'CQ DX' and 'DE' msgs
// will be handled by the decoder as messages with no a-priori knowledge
encodemsg_jt65(pcodec->apmsg_cqqrz, CALL_CQ, 0, GRID_BLANK);
encodemsg_jt65(pcodec->apmask_cqqrz, MASK_CQQRZ,0, MASK_GRIDBIT); // AP27 (26+1)
encodemsg_jt65(pcodec->apmask_cqqrz_ooo, MASK_CQQRZ,0, MASK_GRIDFULL); // AP42 (26+16)
// encode [mycall ? x] messages and set masks
encodemsg_jt65(pcodec->apmsg_call1, mycall, 0, GRID_BLANK);
encodemsg_jt65(pcodec->apmask_call1, MASK_CALL1, 0, MASK_GRIDBIT); // AP29 (28+1)
encodemsg_jt65(pcodec->apmask_call1_ooo, MASK_CALL1, 0, MASK_GRIDFULL); // AP44 (28+16)
// set mask for [mycall srccall ?] messages
encodemsg_jt65(pcodec->apmask_call1_call2,MASK_CALL1, MASK_CALL2, MASK_GRIDBIT); // AP56 (28+28)
return pcodec;
}
void qra65_encode(qra65codec *pcodec, int *y, const int *x)
{
int encx[QRA65_KC]; // encoder input buffer
int ency[QRA65_NC]; // encoder output buffer
int call1,call2,grid;
memcpy(encx,x,QRA65_K*sizeof(int)); // copy input to the encoder buffer
encx[QRA65_K]=calc_crc6(encx,QRA65_K); // compute and add the crc symbol
qra_encode(&QRA65_CODE, ency, encx); // encode msg+crc using the given QRA code
// copy codeword to output puncturing the crc symbol
memcpy(y,ency,QRA65_K*sizeof(int)); // copy the information symbols
memcpy(y+QRA65_K,ency+QRA65_KC,QRA65_C*sizeof(int)); // copy the parity check symbols
if (pcodec->apflags!=QRA_AUTOAP)
return;
// look if the msg sent is a std type message (bit15 of grid field = 0)
if ((x[9]&0x80)==1)
return; // no, it's a text message
// it's a [call1 call2 grid] message
// we assume that call2 is our call (but we don't check it)
// call1 the station callsign we are calling or indicates a general call (CQ/QRZ/etc..)
decodemsg_jt65(&call1,&call2,&grid,x);
if ((call1>=CALL_CQ && call1<=CALL_CQ999) || call1==CALL_CQDX || call1==CALL_DE) {
// we are making a general call, so we still don't know who can reply us (srccall)
// reset apsrccall to 0 so that the decoder won't look for [mycall srccall ?] msgs
pcodec->apsrccall = 0;
}
else {
// we are replying someone named call1
// set apmsg_call1_call2 so that the decoder will attempt to decode [mycall call1 ?] msgs
pcodec->apsrccall = call1;
encodemsg_jt65(pcodec->apmsg_call1_call2, pcodec->apmycall, pcodec->apsrccall, 0);
}
}
int qra65_decode(qra65codec *pcodec, int *x, const float *rxen)
{
uint k;
float *srctmp, *dsttmp;
float ix[QRA65_NC*QRA65_M]; // (depunctured) intrisic information to the decoder
int rc;
// sanity check
if (QRA65_NMSG!=QRA65_CODE.NMSG)
return -16; // QRA65_NMSG define is wrong
// compute symbols intrinsic probabilities from received energy observations
qra_mfskbesselmetric(ix, rxen, QRA65_m, QRA65_N,pcodec->decEsNoMetric);
// de-puncture observations adding a uniform distribution for the crc symbol ----------
// move check symbols distributions one symbol towards the end
dsttmp = PD_ROWADDR(ix,QRA65_M, QRA65_NC-1); // point to the last symbol prob dist
srctmp = dsttmp-QRA65_M; // source is the previous pd
for (k=0;k<QRA65_C;k++) {
pd_init(dsttmp,srctmp,QRA65_M);
dsttmp -=QRA65_M;
srctmp -=QRA65_M;
}
// init crc prob to a uniform distribution
pd_init(dsttmp,pd_uniform(QRA65_m),QRA65_M);
// attempt to decode without a-priori --------------------------------------------------
rc = qra65_do_decode(x, ix, NULL, NULL);
if (rc>=0) return 0; // successfull decode with 0 ap
if (pcodec->apflags!=QRA_AUTOAP) return rc; // rc<0 = unsuccessful decode
// attempt to decode CQ calls
rc = qra65_do_decode(x, ix, pcodec->apmask_cqqrz, pcodec->apmsg_cqqrz); // 27 bit AP
if (rc>=0) return 1; // decoded [cq/qrz ? ?]
rc = qra65_do_decode(x, ix, pcodec->apmask_cqqrz_ooo, pcodec->apmsg_cqqrz); // 44 bit AP
if (rc>=0) return 2; // decoded [cq ? ooo]
// attempt to decode calls directed to us (mycall)
rc = qra65_do_decode(x, ix, pcodec->apmask_call1, pcodec->apmsg_call1); // 29 bit AP
if (rc>=0) return 3; // decoded [mycall ? ?]
rc = qra65_do_decode(x, ix, pcodec->apmask_call1_ooo, pcodec->apmsg_call1); // 45 bit AP
if (rc>=0) return 4; // decoded [mycall ? ooo]
// if apsrccall is set attempt to decode [mycall srccall ?] msgs
if (pcodec->apsrccall==0) return rc; // nothing more to do
rc = qra65_do_decode(x, ix, pcodec->apmask_call1_call2, pcodec->apmsg_call1_call2); // 57 bit AP
if (rc>=0) return 5; // decoded [mycall srccall ?]
return rc;
}
// static functions definitions ----------------------------------------------------------------
// decode with given a-priori information
static int qra65_do_decode(int *x, const float *pix, const int *ap_mask, const int *ap_x)
{
int rc;
const float *ixsrc;
float ix_masked[QRA65_NC*QRA65_M]; // (masked) intrinsic information to the decoder
float ex[QRA65_NC*QRA65_M]; // extrinsic information from the decoder
float v2cmsg[QRA65_NMSG*QRA65_M]; // buffers for the decoder messages
float c2vmsg[QRA65_NMSG*QRA65_M];
int xdec[QRA65_KC];
if (ap_mask==NULL) { // no a-priori information
ixsrc = pix; // intrinsic source is what passed as argument
}
else { // a-priori information provided
// mask channel observations with a-priori
ix_mask(ix_masked,pix,ap_mask,ap_x);
ixsrc = ix_masked; // intrinsic source is the masked version
}
// run the decoding algorithm
rc = qra_extrinsic(&QRA65_CODE,ex,ixsrc,QRA65_NITER,v2cmsg,c2vmsg);
if (rc<0)
return -1; // no convergence in given iterations
// decode
qra_mapdecode(&QRA65_CODE,xdec,ex,ixsrc);
// verify crc
if (calc_crc6(xdec,QRA65_K)!=xdec[QRA65_K]) // crc doesn't match (detected error)
return -2; // decoding was succesfull but crc doesn't match
// success. copy decoded message to output buffer
memcpy(x,xdec,QRA65_K*sizeof(int));
return 0;
}
// crc functions -------------------------------------------------------------------------------
// crc-6 generator polynomial
// g(x) = x^6 + a5*x^5 + ... + a1*x + a0
// g(x) = x^6 + x + 1
#define CRC6_GEN_POL 0x30 // MSB=a0 LSB=a5
// g(x) = x^6 + x^2 + x + 1 (as suggested by Joe. See: https://users.ece.cmu.edu/~koopman/crc/)
// #define CRC6_GEN_POL 0x38 // MSB=a0 LSB=a5. Simulation results are similar
static int calc_crc6(const int *x, int sz)
{
// todo: compute it faster using a look up table
int k,j,t,sr = 0;
for (k=0;k<sz;k++) {
t = x[k];
for (j=0;j<6;j++) {
if ((t^sr)&0x01)
sr = (sr>>1) ^ CRC6_GEN_POL;
else
sr = (sr>>1);
t>>=1;
}
}
return sr;
}
static void ix_mask(float *dst, const float *src, const int *mask, const int *x)
{
// mask intrinsic information (channel observations) with a priori knowledge
uint k,kk, smask;
float *row;
memcpy(dst,src,(QRA65_NC*QRA65_M)*sizeof(float));
for (k=0;k<QRA65_K;k++) { // we can mask only information symbols distrib
smask = mask[k];
row = PD_ROWADDR(dst,QRA65_M,k);
if (smask) {
for (kk=0;kk<QRA65_M;kk++)
if (((kk^x[k])&smask)!=0)
*(row+kk) = 0.f;
pd_norm(row,QRA65_m);
}
}
}
// encode/decode msgs as done in JT65
void encodemsg_jt65(int *y, const int call1, const int call2, const int grid)
{
y[0]= (call1>>22)&0x3F;
y[1]= (call1>>16)&0x3F;
y[2]= (call1>>10)&0x3F;
y[3]= (call1>>4)&0x3F;
y[4]= (call1<<2)&0x3F;
y[4] |= (call2>>26)&0x3F;
y[5]= (call2>>20)&0x3F;
y[6]= (call2>>14)&0x3F;
y[7]= (call2>>8)&0x3F;
y[8]= (call2>>2)&0x3F;
y[9]= (call2<<4)&0x3F;
y[9] |= (grid>>12)&0x3F;
y[10]= (grid>>6)&0x3F;
y[11]= (grid)&0x3F;
}
void decodemsg_jt65(int *call1, int *call2, int *grid, const int *x)
{
int nc1, nc2, ng;
nc1 = x[4]>>2;
nc1 |= x[3]<<4;
nc1 |= x[2]<<10;
nc1 |= x[1]<<16;
nc1 |= x[0]<<22;
nc2 = x[9]>>4;
nc2 |= x[8]<<2;
nc2 |= x[7]<<8;
nc2 |= x[6]<<14;
nc2 |= x[5]<<20;
nc2 |= (x[4]&0x03)<<26;
ng = x[11];
ng |= x[10]<<6;
ng |= (x[9]&0x0F)<<12;
*call1 = nc1;
*call2 = nc2;
*grid = ng;
}

123
lib/qra/qra65/qra65.h Normal file
View File

@ -0,0 +1,123 @@
// qra65.h
// Encoding/decoding functions for the QRA65 mode
//
// (c) 2016 - Nico Palermo, IV3NWV
// ------------------------------------------------------------------------------
// This file is part of the qracodes project, a Forward Error Control
// encoding/decoding package based on Q-ary RA (Repeat and Accumulate) LDPC codes.
//
// qracodes is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
// qracodes is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
// You should have received a copy of the GNU General Public License
// along with qracodes source distribution.
// If not, see <http://www.gnu.org/licenses/>.
#ifndef _qra65_h_
#define _qra65_h_
// qra65_init(...) initialization flags
#define QRA_NOAP 0 // don't use a-priori knowledge
#define QRA_AUTOAP 1 // use auto a-priori knowledge
// QRA code parameters
#define QRA65_K 12 // information symbols
#define QRA65_N 63 // codeword length
#define QRA65_C 51 // (number of parity checks C=(N-K))
#define QRA65_M 64 // code alphabet size
#define QRA65_m 6 // bits per symbol
// packed predefined callsigns and fields as defined in JT65
#define CALL_CQ 0xFA08319
#define CALL_QRZ 0xFA0831A
#define CALL_CQ000 0xFA0831B
#define CALL_CQ999 0xFA08702
#define CALL_CQDX 0x5624C39
#define CALL_DE 0xFF641D1
#define GRID_BLANK 0x7E91
typedef struct {
float decEsNoMetric;
int apflags;
int apmycall;
int apsrccall;
int apmsg_cqqrz[12]; // [cq/qrz ? blank]
int apmsg_call1[12]; // [mycall ? blank]
int apmsg_call1_call2[12]; // [mycall srccall ?]
int apmask_cqqrz[12];
int apmask_cqqrz_ooo[12];
int apmask_call1[12];
int apmask_call1_ooo[12];
int apmask_call1_call2[12];
} qra65codec;
#ifdef __cplusplus
extern "C" {
#endif
qra65codec *qra65_init(int flags, const int mycall);
// QRA65 mode initialization function
// arguments:
// flags: set the decoder mode
// When flags = QRA_NOAP no a-priori information will be used by the decoder
// When flags = QRA_AUTOAP the decoder will attempt to decode with the amount
// of available a-priori information
// mycall: 28-bit packed callsign of the user (as computed by JT65)
// returns:
// Pointer to the qra65codec data structure allocated and inizialized by the function
// this handle should be passed to the encoding/decoding functions
//
// 0 if unsuccessful (can't allocate memory)
// -------------------------------------------------------------------------------------------
void qra65_encode(qra65codec *pcodec, int *y, const int *x);
// QRA65 mode encoder
// arguments:
// pcodec = pointer to a qra65codec data structure as returned by qra65_init
// x = pointer to the message to encode
// x must point to an array of integers (i.e. defined as int x[12])
// y = pointer to the encoded message
// y must point to an array of integers of lenght 63 (i.e. defined as int y[63])
// -------------------------------------------------------------------------------------------
int qra65_decode(qra65codec *pcodec, int *x, const float *r);
// QRA65 mode decoder
// arguments:
// pcodec = pointer to a qra65codec data structure as returned by qra65_init
// x = pointer to the array of integers where the decoded message will be stored
// x must point to an array of integers (i.e. defined as int x[12])
// r = pointer to the received symbols energies (squared amplitudes)
// r must point to an array of QRA65_M*QRA65_N (=64*63=4032) float numbers.
// The first QRA_M entries should be the energies of the first symbol in the codeword
// The last QRA_M entries should be the energies of the last symbol in the codeword
//
// return code:
//
// The return code is <0 when decoding is unsuccessful
// -16 indicates that the definition of QRA65_NMSG does not match what required by the code
// If the decoding process is successfull the return code is accordingly to the following table
// rc=0 [? ? ?] AP0 (decoding with no a-priori)
// rc=1 [CQ ? ?] AP27
// rc=2 [CQ ? ] AP44
// rc=3 [CALL ? ?] AP29
// rc=4 [CALL ? ] AP45
// rc=5 [CALL CALL ?] AP57
// return codes in the range 1-5 indicate the amount of a-priori information which was required
// to decode the received message and are possible only when the QRA_AUTOAP mode has been enabled.
// -------------------------------------------------------------------------------------------
// encode/decode std msgs in 12 symbols as done in jt65
void encodemsg_jt65(int *y, const int call1, const int call2, const int grid);
void decodemsg_jt65(int *call1, int *call2, int *grid, const int *x);
#ifdef __cplusplus
}
#endif
#endif // _qra65_h_

245
lib/qra/qra65/qra65.vcproj Normal file
View File

@ -0,0 +1,245 @@
<?xml version="1.0" encoding="Windows-1252"?>
<VisualStudioProject
ProjectType="Visual C++"
Version="9,00"
Name="qra65"
ProjectGUID="{65A5CBA9-DD44-4973-9552-E6E16FD6E2AD}"
RootNamespace="qra65"
TargetFrameworkVersion="196613"
>
<Platforms>
<Platform
Name="Win32"
/>
</Platforms>
<ToolFiles>
</ToolFiles>
<Configurations>
<Configuration
Name="Debug|Win32"
OutputDirectory="$(SolutionDir)$(ConfigurationName)"
IntermediateDirectory="$(ConfigurationName)"
ConfigurationType="1"
CharacterSet="2"
>
<Tool
Name="VCPreBuildEventTool"
/>
<Tool
Name="VCCustomBuildTool"
/>
<Tool
Name="VCXMLDataGeneratorTool"
/>
<Tool
Name="VCWebServiceProxyGeneratorTool"
/>
<Tool
Name="VCMIDLTool"
/>
<Tool
Name="VCCLCompilerTool"
Optimization="0"
MinimalRebuild="true"
BasicRuntimeChecks="3"
RuntimeLibrary="3"
WarningLevel="3"
DebugInformationFormat="4"
/>
<Tool
Name="VCManagedResourceCompilerTool"
/>
<Tool
Name="VCResourceCompilerTool"
/>
<Tool
Name="VCPreLinkEventTool"
/>
<Tool
Name="VCLinkerTool"
GenerateDebugInformation="true"
TargetMachine="1"
/>
<Tool
Name="VCALinkTool"
/>
<Tool
Name="VCManifestTool"
/>
<Tool
Name="VCXDCMakeTool"
/>
<Tool
Name="VCBscMakeTool"
/>
<Tool
Name="VCFxCopTool"
/>
<Tool
Name="VCAppVerifierTool"
/>
<Tool
Name="VCPostBuildEventTool"
/>
</Configuration>
<Configuration
Name="Release|Win32"
OutputDirectory="$(SolutionDir)$(ConfigurationName)"
IntermediateDirectory="$(ConfigurationName)"
ConfigurationType="1"
UseOfMFC="0"
CharacterSet="0"
WholeProgramOptimization="1"
>
<Tool
Name="VCPreBuildEventTool"
/>
<Tool
Name="VCCustomBuildTool"
/>
<Tool
Name="VCXMLDataGeneratorTool"
/>
<Tool
Name="VCWebServiceProxyGeneratorTool"
/>
<Tool
Name="VCMIDLTool"
/>
<Tool
Name="VCCLCompilerTool"
Optimization="3"
EnableIntrinsicFunctions="true"
FavorSizeOrSpeed="1"
OmitFramePointers="true"
EnableFiberSafeOptimizations="true"
PreprocessorDefinitions="WIN32;NDEBUG;_CONSOLE"
ExceptionHandling="0"
RuntimeLibrary="2"
StructMemberAlignment="4"
BufferSecurityCheck="false"
EnableFunctionLevelLinking="true"
EnableEnhancedInstructionSet="2"
FloatingPointModel="2"
WarningLevel="3"
DebugInformationFormat="3"
/>
<Tool
Name="VCManagedResourceCompilerTool"
/>
<Tool
Name="VCResourceCompilerTool"
/>
<Tool
Name="VCPreLinkEventTool"
/>
<Tool
Name="VCLinkerTool"
LinkIncremental="1"
GenerateManifest="true"
GenerateDebugInformation="false"
SubSystem="1"
OptimizeReferences="2"
EnableCOMDATFolding="2"
TargetMachine="1"
/>
<Tool
Name="VCALinkTool"
/>
<Tool
Name="VCManifestTool"
/>
<Tool
Name="VCXDCMakeTool"
/>
<Tool
Name="VCBscMakeTool"
/>
<Tool
Name="VCFxCopTool"
/>
<Tool
Name="VCAppVerifierTool"
/>
<Tool
Name="VCPostBuildEventTool"
/>
</Configuration>
</Configurations>
<References>
</References>
<Files>
<Filter
Name="Source Files"
Filter="cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx"
UniqueIdentifier="{4FC737F1-C7A5-4376-A066-2A32D752A2FF}"
>
<File
RelativePath=".\main.c"
>
</File>
<File
RelativePath="..\qracodes\normrnd.c"
>
</File>
<File
RelativePath="..\qracodes\npfwht.c"
>
</File>
<File
RelativePath="..\qracodes\pdmath.c"
>
</File>
<File
RelativePath="..\qracodes\qra13_64_64_irr_e.c"
>
</File>
<File
RelativePath=".\qra65.c"
>
</File>
<File
RelativePath="..\qracodes\qracodes.c"
>
</File>
</Filter>
<Filter
Name="Header Files"
Filter="h;hpp;hxx;hm;inl;inc;xsd"
UniqueIdentifier="{93995380-89BD-4b04-88EB-625FBE52EBFB}"
>
<File
RelativePath="..\qracodes\normrnd.h"
>
</File>
<File
RelativePath="..\qracodes\npfwht.h"
>
</File>
<File
RelativePath="..\qracodes\pdmath.h"
>
</File>
<File
RelativePath="..\qracodes\qra13_64_64_irr_e.h"
>
</File>
<File
RelativePath=".\qra65.h"
>
</File>
<File
RelativePath="..\qracodes\qracodes.h"
>
</File>
</Filter>
<Filter
Name="Resource Files"
Filter="rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav"
UniqueIdentifier="{67DA6AB6-F800-4c08-8B7A-83BB121AAD01}"
>
</Filter>
</Files>
<Globals>
</Globals>
</VisualStudioProject>

View File

@ -0,0 +1,7 @@
# Eb/No Values to be used during the code simulation
# Each line of this file indicates the Eb/No value to be simulated (in dB)
# and the number of errors to be detected by the decoder
0.6 10000
1.1 10000
1.6 10000
2.1 10000

View File

@ -0,0 +1,15 @@
# Eb/No Values to be used during the code simulation
# Each line of this file indicates the Eb/No value to be simulated (in dB)
# and the number of errors to be detected by the decoder
1.1 1000
1.6 1000
2.1 1000
2.6 1000
3.1 1000
3.6 1000
4.1 1000
4.6 1000
5.1 500
5.6 200
6.1 100
6.6 50

View File

@ -0,0 +1,11 @@
# Eb/No Values to be used during the code simulation
# Each line of this file indicates the Eb/No value to be simulated (in dB)
# and the number of errors to be detected by the decoder
1.1 500
1.6 500
2.1 500
2.6 500
3.1 500
3.6 500
4.1 200
4.6 50

687
lib/qra/qracodes/main.c Normal file
View File

@ -0,0 +1,687 @@
// main.c
// Word Error Rate test example for Q-ary RA codes over GF(64)
//
// (c) 2016 - Nico Palermo, IV3NWV
//
// Thanks to Andrea Montefusco IW0HDV for his help on adapting the sources
// to OSs other than MS Windows
//
// ------------------------------------------------------------------------------
// This file is part of the qracodes project, a Forward Error Control
// encoding/decoding package based on Q-ary RA (Repeat and Accumulate) LDPC codes.
//
// Files in this package:
// main.c - this file
// normrnd.c/.h - random gaussian number generator
// npfwht.c/.h - Fast Walsh-Hadamard Transforms
// pdmath.c/.h - Elementary math on probability distributions
// qra12_63_64_irr_b.c/.h - Tables for a QRA(12,63) irregular RA code over GF(64)
// qra13_64_64_irr_e.c/.h - Tables for a QRA(13,64) irregular RA code " "
// qracodes.c/.h - QRA codes encoding/decoding functions
//
// -------------------------------------------------------------------------------
//
// qracodes is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
// qracodes is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
// You should have received a copy of the GNU General Public License
// along with qracodes source distribution.
// If not, see <http://www.gnu.org/licenses/>.
// -----------------------------------------------------------------------------
// Two codes are available for simulations in this sowftware release:
// QRA12_63_64_IRR_B: K=12 N=63 Q=64 irregular QRA code (defined in qra12_63_64_irr_b.h /.c)
// QRA13_64_64_IRR_E: K=13 N=64 Q=64 irregular QRA code (defined in qra13_64_64_irr_b.h /.c)
// Codes with K=13 are designed to include a CRC as the 13th information symbol
// and improve the code UER (Undetected Error Rate).
// The CRC symbol is not sent along the channel (the codes are punctured) and the
// resulting code is still a (12,63) code with an effective code rate of R = 12/63.
// ------------------------------------------------------------------------------
// OS dependent defines and includes --------------------------------------------
#if _WIN32 // note the underscore: without it, it's not msdn official!
// Windows (x64 and x86)
#include <windows.h> // required only for GetTickCount(...)
#include <process.h> // _beginthread
#endif
#if __linux__
#include <unistd.h>
#include <time.h>
unsigned GetTickCount(void) {
struct timespec ts;
unsigned theTick = 0U;
clock_gettime( CLOCK_REALTIME, &ts );
theTick = ts.tv_nsec / 1000000;
theTick += ts.tv_sec * 1000;
return theTick;
}
#endif
#if __APPLE__
#endif
#include <stdlib.h>
#include <stdio.h>
#include "qracodes.h"
#include "normrnd.h" // gaussian numbers generator
#include "pdmath.h" // operations on probability distributions
// defined codes
#include "qra12_63_64_irr_b.h"
#include "qra13_64_64_irr_e.h"
// -----------------------------------------------------------------------------------
#define NTHREADS_MAX 24
// channel types
#define CHANNEL_AWGN 0
#define CHANNEL_RAYLEIGH 1
// amount of a-priori information provided to the decoder
#define AP_NONE 0
#define AP_28 1
#define AP_44 2
#define AP_56 3
const char ap_str[4][16] = {
"None",
"28 bit",
"44 bit",
"56 bit"
};
const char fnameout_pfx[2][64] = {
"wer-awgn-",
"wer-rayleigh-"
};
const char fnameout_sfx[4][64] = {
"-ap00.txt",
"-ap28.txt",
"-ap44.txt",
"-ap56.txt"
};
const uint ap_masks_jt65[4][13] = {
// Each row must be 13 entries long (to handle puntc. codes 13,64)
// The mask of 13th symbol (crc) is alway initializated to 0
// AP0 - no a-priori knowledge
{ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},
// AP28 - 1st field known [cq ? ?] or [dst ? ?]
{0x3F,0x3F,0x3F,0x3F,0x3C, 0, 0, 0, 0, 0, 0, 0},
// AP44 - 1st and 3rd fields known [cq ? 0] or [dst ? 0]
{0x3F,0x3F,0x3F,0x3F,0x3C, 0, 0, 0, 0,0x0F,0x3F,0x3F},
// AP56 - 1st and 2nd fields known [dst src ?]
{0x3F,0x3F,0x3F,0x3F,0x3F,0x3F,0x3F,0x3F,0x3F,0x30, 0, 0}
};
void ix_mask(const qracode *pcode, float *r, const int *mask, const int *x);
void printword(char *msg, int *x, int size)
{
int k;
printf("\n%s ",msg);
for (k=0;k<size;k++)
printf("%02hx ",x[k]);
printf("\n");
}
typedef struct {
int channel_type;
float EbNodB;
volatile int nt;
volatile int nerrs;
volatile int nerrsu;
volatile int stop;
volatile int done;
int ap_index; // index to the a priori knowledge mask
const qracode *pcode; // pointer to the code descriptor
uint *x; //[qra_K]; input message buffer
uint *y, *ydec; //[qra_N]; encoded/decoded codewords buffers
float *qra_v2cmsg; //[qra_NMSG*qra_M]; MP decoder v->c msg buffer
float *qra_c2vmsg; //[qra_NMSG*qra_M]; MP decoder c->v msg buffer
float *rp; // [qra_N*qra_M]; received samples (real component) buffer
float *rq; // [qra_N*qra_M]; received samples (imag component) buffer
float *chp; //[qra_N]; channel gains (real component) buffer
float *chq; //[qra_N]; channel gains (imag component) buffer
float *r; //[qra_N*qra_M]; received samples (amplitude) buffer
float *ix; // [qra_N*qra_M]; // intrinsic information to the MP algorithm
float *ex; // [qra_N*qra_M]; // extrinsic information from the MP algorithm
} wer_test_ds;
typedef void( __cdecl *pwer_test_thread)(wer_test_ds*);
// crc-6 generator polynomial
// g(x) = x^6 + a5*x^5 + ... + a1*x + a0
// g(x) = x^6 + x + 1
#define CRC6_GEN_POL 0x30 // MSB=a0 LSB=a5
// g(x) = x^6 + x^2 + x + 1 (as suggested by Joe. See: https://users.ece.cmu.edu/~koopman/crc/)
// #define CRC6_GEN_POL 0x38 // MSB=a0 LSB=a5. Simulation results are similar
int calc_crc6(int *x, int sz)
{
int k,j,t,sr = 0;
for (k=0;k<sz;k++) {
t = x[k];
for (j=0;j<6;j++) {
if ((t^sr)&0x01)
sr = (sr>>1) ^ CRC6_GEN_POL;
else
sr = (sr>>1);
t>>=1;
}
}
return sr;
}
void wer_test_thread(wer_test_ds *pdata)
{
const qracode *pcode=pdata->pcode;
const uint qra_K = pcode->K;
const uint qra_N = pcode->N;
const uint qra_M = pcode->M;
const uint qra_m = pcode->m;
const uint NSAMPLES = pcode->N*pcode->M;
const float No = 1.0f; // noise spectral density
const float sigma = (float)sqrt(No/2.0f); // std dev of noise I/Q components
const float sigmach = (float)sqrt(1/2.0f); // std dev of channel I/Q gains
// Eb/No value for which we optimize the bessel metric
const float EbNodBMetric = 2.8f;
const float EbNoMetric = (float)pow(10,EbNodBMetric/10);
uint k,t,j,diff;
float R;
float EsNoMetric;
float EbNo, EsNo, Es, A;
int channel_type, code_type;
int nt=0; // transmitted codewords
int nerrs = 0; // total number of errors
int nerrsu = 0; // number of undetected errors
int rc;
// inizialize pointer to required buffers
uint *x=pdata->x; // message buffer
uint *y=pdata->y, *ydec=pdata->ydec; // encoded/decoded codeword buffers
float *qra_v2cmsg=pdata->qra_v2cmsg; // table of the v->c messages
float *qra_c2vmsg=pdata->qra_c2vmsg; // table of the c->v messages
float *rp=pdata->rp; // received samples (real component)
float *rq=pdata->rq; // received samples (imag component)
float *chp=pdata->chp; // channel gains (real component)
float *chq=pdata->chq; // channel gains (imag component)
float *r=pdata->r; // received samples amplitudes
float *ix=pdata->ix; // intrinsic information to the MP algorithm
float *ex=pdata->ex; // extrinsic information from the MP algorithm
channel_type = pdata->channel_type;
code_type = pcode->type;
// define the (true) code rate accordingly to the code type
switch(code_type) {
case QRATYPE_CRC:
R = 1.0f*(qra_K-1)/qra_N;
break;
case QRATYPE_CRCPUNCTURED:
R = 1.0f*(qra_K-1)/(qra_N-1);
break;
case QRATYPE_NORMAL:
default:
R = 1.0f*(qra_K)/(qra_N);
}
EsNoMetric = 1.0f*qra_m*R*EbNoMetric;
EbNo = (float)pow(10,pdata->EbNodB/10);
EsNo = 1.0f*qra_m*R*EbNo;
Es = EsNo*No;
A = (float)sqrt(Es);
// encode the input
if (code_type==QRATYPE_CRC || code_type==QRATYPE_CRCPUNCTURED) {
// compute the information message symbol check as the (negated) xor of all the
// information message symbols
for (k=0;k<(qra_K-1);k++)
x[k]=k%qra_M;
x[k]=calc_crc6(x,qra_K-1);
}
else
for (k=0;k<qra_K;k++)
x[k]=k%qra_M;
qra_encode(pcode,y,x);
while (pdata->stop==0) {
// simulate the channel
// NOTE: in the case that the code is punctured, for simplicity
// we compute the channel outputs and the metric also for the crc symbol
// then we ignore its observation.
normrnd_s(rp,NSAMPLES,0,sigma);
normrnd_s(rq,NSAMPLES,0,sigma);
if (channel_type == CHANNEL_AWGN) {
for (k=0;k<qra_N;k++)
rp[k*qra_M+y[k]]+=A;
}
else if (channel_type == CHANNEL_RAYLEIGH) {
normrnd_s(chp,qra_N,0,sigmach);
normrnd_s(chq,qra_N,0,sigmach);
for (k=0;k<qra_N;k++) {
rp[k*qra_M+y[k]]+=A*chp[k];
rq[k*qra_M+y[k]]+=A*chq[k];
}
}
else {
pdata->done = 1;
return; // unknown channel type
}
// compute the squares of the amplitudes of the received samples
for (k=0;k<NSAMPLES;k++)
r[k] = rp[k]*rp[k] + rq[k]*rq[k];
// compute the intrinsic symbols probabilities
qra_mfskbesselmetric(ix,r,pcode->m,pcode->N,EsNoMetric);
if (code_type==QRATYPE_CRCPUNCTURED) {
// ignore observations of the CRC symbol as it is not actually sent
// over the channel
pd_init(PD_ROWADDR(ix,qra_M,qra_K),pd_uniform(qra_m),qra_M);
}
if (pdata->ap_index!=0)
// mask channel observations with a priori knowledge
ix_mask(pcode,ix,ap_masks_jt65[pdata->ap_index],x);
// compute the extrinsic symbols probabilities with the message-passing algorithm
// stop if extrinsic information does not converges to 1 within the given number of iterations
rc = qra_extrinsic(pcode,ex,ix,100,qra_v2cmsg,qra_c2vmsg);
if (rc>=0) { // the MP algorithm converged to Iex~1 in rc iterations
// decode the codeword
qra_mapdecode(pcode,ydec,ex,ix);
// look for undetected errors
if (code_type==QRATYPE_CRC || code_type==QRATYPE_CRCPUNCTURED) {
j = 0; diff = 0;
for (k=0;k<(qra_K-1);k++)
diff |= (ydec[k]!=x[k]);
t = calc_crc6(ydec,qra_K-1);
if (t!=ydec[k]) // error detected - crc doesn't matches
nerrs += 1;
else
if (diff) { // decoded message is not equal to the transmitted one but
// the crc test passed
// add as undetected error
nerrsu += 1;
nerrs += 1;
// uncomment to see what the undetected error pattern looks like
//printword("U", ydec);
}
}
else
for (k=0;k<qra_K;k++)
if (ydec[k]!=x[k]) { // decoded msg differs from the transmitted one
nerrsu += 1; // it's a false decode
nerrs += 1;
// uncomment to see what the undetected error pattern looks like
// printword("U", ydec);
break;
}
}
else // failed to converge to a solution within the given number of iterations
nerrs++;
nt = nt+1;
pdata->nt=nt;
pdata->nerrs=nerrs;
pdata->nerrsu=nerrsu;
}
pdata->done=1;
_endthread();
}
void ix_mask(const qracode *pcode, float *r, const int *mask, const int *x)
{
// mask intrinsic information (channel observations) with a priori knowledge
uint k,kk, smask;
const uint qra_K=pcode->K;
const uint qra_M=pcode->M;
const uint qra_m=pcode->m;
for (k=0;k<qra_K;k++) {
smask = mask[k];
if (smask) {
for (kk=0;kk<qra_M;kk++)
if (((kk^x[k])&smask)!=0)
*(PD_ROWADDR(r,qra_M,k)+kk) = 0.f;
pd_norm(PD_ROWADDR(r,qra_M,k),qra_m);
}
}
}
int wer_test_proc(const qracode *pcode, uint nthreads, int chtype, uint ap_index, float *EbNodB, uint *nerrstgt, uint nitems)
{
uint k,nn,j,nt,nerrs,nerrsu,nd;
uint cini,cend;
char fnameout[128];
FILE *fout;
wer_test_ds wt[NTHREADS_MAX];
float pe,avgt;
nn = sizeof(EbNodB)/sizeof(float); // size of the EbNo array to test
if (nthreads>NTHREADS_MAX) {
printf("Error: nthreads should be <=%d\n",NTHREADS_MAX);
return -1;
}
sprintf(fnameout,"%s%s%s",
fnameout_pfx[chtype],
pcode->name,
fnameout_sfx[ap_index]);
fout = fopen(fnameout,"w");
fprintf(fout,"# Channel (0=AWGN,1=Rayleigh), Eb/No (dB), Transmitted codewords, Errors, Undetected Errors, Avg dec. time (ms), WER\n");
printf("\nTesting the code %s over the %s channel\nSimulation data will be saved to %s\n",
pcode->name,
chtype==CHANNEL_AWGN?"AWGN":"Rayleigh",
fnameout);
fflush (stdout);
// init fixed thread parameters and preallocate buffers
for (j=0;j<nthreads;j++) {
wt[j].channel_type=chtype;
wt[j].ap_index = ap_index;
wt[j].pcode = pcode;
wt[j].x = (uint*)malloc(pcode->K*sizeof(uint));
wt[j].y = (uint*)malloc(pcode->N*sizeof(uint));
wt[j].ydec = (uint*)malloc(pcode->N*sizeof(uint));
wt[j].qra_v2cmsg = (float*)malloc(pcode->NMSG*pcode->M*sizeof(float));
wt[j].qra_c2vmsg = (float*)malloc(pcode->NMSG*pcode->M*sizeof(float));
wt[j].rp = (float*)malloc(pcode->N*pcode->M*sizeof(float));
wt[j].rq = (float*)malloc(pcode->N*pcode->M*sizeof(float));
wt[j].chp = (float*)malloc(pcode->N*sizeof(float));
wt[j].chq = (float*)malloc(pcode->N*sizeof(float));
wt[j].r = (float*)malloc(pcode->N*pcode->M*sizeof(float));
wt[j].ix = (float*)malloc(pcode->N*pcode->M*sizeof(float));
wt[j].ex = (float*)malloc(pcode->N*pcode->M*sizeof(float));
}
for (k=0;k<nitems;k++) {
printf("\nTesting at Eb/No=%4.1f dB...",EbNodB[k]);
fflush (stdout);
for (j=0;j<nthreads;j++) {
wt[j].EbNodB=EbNodB[k];
wt[j].nt=0;
wt[j].nerrs=0;
wt[j].nerrsu=0;
wt[j].done = 0;
wt[j].stop = 0;
_beginthread((void*)(void*)wer_test_thread,0,&wt[j]);
}
nd = 0;
cini = GetTickCount();
while (1) {
// count errors
nerrs = 0;
for (j=0;j<nthreads;j++)
nerrs += wt[j].nerrs;
// stop the working threads
// if number of errors reached at this Eb/No value
if (nerrs>=nerrstgt[k]) {
for (j=0;j<nthreads;j++)
wt[j].stop = 1;
break;
}
else { // continue with the simulation
Sleep(2);
nd = (nd+1)%100;
if (nd==0) {
printf(".");
fflush (stdout);
}
}
}
cend = GetTickCount();
// wait for the working threads to exit
for (j=0;j<nthreads;j++)
while(wt[j].done==0)
Sleep(1);
printf("\n");
fflush (stdout);
// compute the total number of transmitted codewords
// the total number of errors and the total number of undetected errors
nt = 0;
nerrs =0;
nerrsu = 0;
for (j=0;j<nthreads;j++) {
nt += wt[j].nt;
nerrs += wt[j].nerrs;
nerrsu += wt[j].nerrsu;
}
pe = 1.0f*nerrs/nt; // word error rate
avgt = 1.0f*(cend-cini)/nt; // average time per decode (ms)
printf("Elapsed Time=%6.1fs (%5.2fms/word)\nTransmitted=%8d - Errors=%6d - Undetected=%3d - WER=%.2e\n",
0.001f*(cend-cini),
avgt, nt, nerrs, nerrsu, pe);
fflush (stdout);
// save simulation data to output file
fprintf(fout,"%01d %.2f %d %d %d %.2f %.2e\n",
chtype,
EbNodB[k],
nt,
nerrs,
nerrsu,
avgt,
pe);
}
fclose(fout);
return 0;
}
const qracode *codetotest[] = {
&qra_12_63_64_irr_b,
&qra_13_64_64_irr_e
};
void syntax(void)
{
printf("\nQ-ary Repeat-Accumulate Code Word Error Rate Simulator\n");
printf("2016, Nico Palermo - IV3NWV\n\n");
printf("Syntax: qracodes [-q<code_index>] [-t<threads>] [-c<ch_type>] [-a<ap_index>] [-f<fnamein>[-h]\n");
printf("Options: \n");
printf(" -q<code_index>: code to simulate. 0=qra_12_63_64_irr_b\n");
printf(" 1=qra_13_64_64_irr_e (default)\n");
printf(" -t<threads> : number of threads to be used for the simulation [1..24]\n");
printf(" (default=8)\n");
printf(" -c<ch_type> : channel_type. 0=AWGN 1=Rayleigh \n");
printf(" (default=AWGN)\n");
printf(" -a<ap_index> : amount of a-priori information provided to decoder. \n");
printf(" 0= No a-priori (default)\n");
printf(" 1= 28 bit \n");
printf(" 2= 44 bit \n");
printf(" 3= 56 bit \n");
printf(" -f<fnamein> : name of the file containing the Eb/No values to be simulated\n");
printf(" (default=ebnovalues.txt)\n");
printf(" This file should contain lines in this format:\n");
printf(" # Eb/No(dB) Target Errors\n");
printf(" 0.1 5000\n");
printf(" 0.6 5000\n");
printf(" 1.1 1000\n");
printf(" 1.6 1000\n");
printf(" ...\n");
printf(" (lines beginning with a # are treated as comments\n\n");
}
#define SIM_POINTS_MAX 20
int main(int argc, char* argv[])
{
float EbNodB[SIM_POINTS_MAX];
uint nerrstgt[SIM_POINTS_MAX];
FILE *fin;
char fnamein[128]= "ebnovalues.txt";
char buf[128];
uint nitems = 0;
uint code_idx = 1;
uint nthreads = 8;
uint ch_type = CHANNEL_AWGN;
uint ap_index = AP_NONE;
// parse command line
while(--argc) {
argv++;
if (strncmp(*argv,"-h",2)==0) {
syntax();
return 0;
}
else
if (strncmp(*argv,"-q",2)==0) {
code_idx = (uint)atoi((*argv)+2);
if (code_idx>1) {
printf("Invalid code index\n");
syntax();
return -1;
}
}
else
if (strncmp(*argv,"-t",2)==0) {
nthreads = (uint)atoi((*argv)+2);
if (nthreads>NTHREADS_MAX) {
printf("Invalid number of threads\n");
syntax();
return -1;
}
}
else
if (strncmp(*argv,"-c",2)==0) {
ch_type = (uint)atoi((*argv)+2);
if (ch_type>CHANNEL_RAYLEIGH) {
printf("Invalid channel type\n");
syntax();
return -1;
}
}
else
if (strncmp(*argv,"-a",2)==0) {
ap_index = (uint)atoi((*argv)+2);
if (ap_index>AP_56) {
printf("Invalid a-priori information index\n");
syntax();
return -1;
}
}
else
if (strncmp(*argv,"-f",2)==0) {
strncpy(fnamein,(*argv)+2,127);
}
else
if (strncmp(*argv,"-h",2)==0) {
syntax();
return -1;
}
else {
printf("Invalid option\n");
syntax();
return -1;
}
}
// parse points to be simulated from the input file
fin = fopen(fnamein,"r");
if (!fin) {
printf("Can't open file: %s\n",fnamein);
syntax();
}
while (fgets(buf,128,fin)!=0)
if (*buf=='#' || *buf=='\n' )
continue;
else
if (nitems==SIM_POINTS_MAX)
break;
else
if (sscanf(buf,"%f %u",&EbNodB[nitems],&nerrstgt[nitems])!=2) {
printf("Invalid input file format\n");
syntax();
return -1;
}
else
nitems++;
fclose(fin);
if (nitems==0) {
printf("No Eb/No point specified in file %s\n",fnamein);
syntax();
return -1;
}
printf("\nQ-ary Repeat-Accumulate Code Word Error Rate Simulator\n");
printf("2016, Nico Palermo - IV3NWV\n\n");
printf("Nthreads = %d\n",nthreads);
printf("Channel = %s\n",ch_type==CHANNEL_AWGN?"AWGN":"Rayleigh");
printf("Codename = %s\n",codetotest[code_idx]->name);
printf("A-priori = %s\n",ap_str[ap_index]);
printf("Eb/No input file = %s\n\n",fnamein);
wer_test_proc(codetotest[code_idx], nthreads, ch_type, ap_index, EbNodB, nerrstgt, nitems);
return 0;
}

View File

@ -0,0 +1,83 @@
// normrnd.c
// functions to generate gaussian distributed numbers
//
// (c) 2016 - Nico Palermo, IV3NWV - Microtelecom Srl, Italy
//
// Credits to Andrea Montefusco - IW0HDV for his help on adapting the sources
// to OSs other than MS Windows
//
// ------------------------------------------------------------------------------
// This file is part of the qracodes project, a Forward Error Control
// encoding/decoding package based on Q-ary RA (Repeat and Accumulate) LDPC codes.
//
// qracodes is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
// qracodes is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
// You should have received a copy of the GNU General Public License
// along with qracodes source distribution.
// If not, see <http://www.gnu.org/licenses/>.
#include "normrnd.h"
#if _WIN32 // note the underscore: without it, it's not msdn official!
// Windows (x64 and x86)
#include <windows.h> // required only for GetTickCount(...)
#elif __unix__ // all unices, not all compilers
#define rand_s rand_r
#include <stdlib.h>
#include <limits.h> // for UINT_MAX
// Unix
#elif __linux__
// linux
#elif __APPLE__
// Mac OS, not sure if this is covered by __posix__ and/or __unix__ though...
#endif
// use MS rand_s(...) function
void normrnd_s(float *dst, int nitems, float mean, float stdev)
{
unsigned int r;
float phi=0, u=0;
int set = 0;
while (nitems--)
if (set==1) {
*dst++ = (float)sin(phi)*u*stdev+mean;
set = 0;
}
else {
rand_s(&r); phi = (M_2PI/(1.0f+UINT_MAX))*r;
rand_s(&r); u = (float)sqrt(-2.0f* log( (1.0f/(1.0f+UINT_MAX))*(1.0f+r) ) );
*dst++ = (float)cos(phi)*u*stdev+mean;
set=1;
}
}
// use MS rand() function
void normrnd(float *dst, int nitems, float mean, float stdev)
{
float phi=0, u=0;
int set = 0;
while (nitems--)
if (set==1) {
*dst++ = (float)sin(phi)*u*stdev+mean;
set = 0;
}
else {
phi = (M_2PI/(1.0f+RAND_MAX))*rand();
u = (float)sqrt(-2.0f* log( (1.0f/(1.0f+RAND_MAX))*(1.0f+rand()) ) );
*dst++ = (float)cos(phi)*u*stdev+mean;
set=1;
}
}

View File

@ -0,0 +1,49 @@
// normrnd.h
// Functions to generate gaussian distributed numbers
//
// (c) 2016 - Nico Palermo, IV3NWV - Microtelecom Srl, Italy
// ------------------------------------------------------------------------------
// This file is part of the qracodes project, a Forward Error Control
// encoding/decoding package based on Q-ary RA (Repeat and Accumulate) LDPC codes.
//
// qracodes is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
// qracodes is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
// You should have received a copy of the GNU General Public License
// along with qracodes source distribution.
// If not, see <http://www.gnu.org/licenses/>.
#ifndef _normrnd_h_
#define _normrnd_h_
#define _CRT_RAND_S
#include <stdlib.h>
#define _USE_MATH_DEFINES
#include <math.h>
#define M_2PI (2.0f*(float)M_PI)
#ifdef __cplusplus
extern "C" {
#endif
void normrnd_s(float *dst, int nitems, float mean, float stdev);
// generate a random array of numbers with a gaussian distribution of given mean and stdev
// use MS rand_s(...) function
void normrnd(float *dst, int nitems, float mean, float stdev);
// generate a random array of numbers with a gaussian distribution of given mean and stdev
// use MS rand() function
#ifdef __cplusplus
}
#endif
#endif // _normrnd_h_

216
lib/qra/qracodes/npfwht.c Normal file
View File

@ -0,0 +1,216 @@
// npfwht.c
// Basic implementation of the Fast Walsh-Hadamard Transforms
//
// (c) 2016 - Nico Palermo, IV3NWV - Microtelecom Srl, Italy
// ------------------------------------------------------------------------------
// This file is part of the qracodes project, a Forward Error Control
// encoding/decoding package based on Q-ary RA (repeat and accumulate) LDPC codes.
//
// qracodes is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
// qracodes is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
// You should have received a copy of the GNU General Public License
// along with qracodes source distribution.
// If not, see <http://www.gnu.org/licenses/>.
#include "npfwht.h"
#define WHBFY(dst,src,base,offs,dist) { dst[base+offs]=src[base+offs]+src[base+offs+dist]; dst[base+offs+dist]=src[base+offs]-src[base+offs+dist]; }
typedef void (*pnp_fwht)(float*,float*);
static void np_fwht2(float *dst, float *src);
static void np_fwht1(float *dst, float *src);
static void np_fwht2(float *dst, float *src);
static void np_fwht4(float *dst, float *src);
static void np_fwht8(float *dst, float *src);
static void np_fwht16(float *dst, float *src);
static void np_fwht32(float *dst, float *src);
static void np_fwht64(float *dst, float *src);
static pnp_fwht np_fwht_tab[7] = {
np_fwht1,
np_fwht2,
np_fwht4,
np_fwht8,
np_fwht16,
np_fwht32,
np_fwht64
};
void np_fwht(int nlogdim, float *dst, float *src)
{
np_fwht_tab[nlogdim](dst,src);
}
static void np_fwht1(float *dst, float *src)
{
dst[0] = src[0];
}
static void np_fwht2(float *dst, float *src)
{
float t[2];
WHBFY(t,src,0,0,1);
dst[0]= t[0];
dst[1]= t[1];
}
static void np_fwht4(float *dst, float *src)
{
float t[4];
// group 1
WHBFY(t,src,0,0,2); WHBFY(t,src,0,1,2);
// group 2
WHBFY(dst,t,0,0,1); WHBFY(dst,t,2,0,1);
};
static void np_fwht8(float *dst, float *src)
{
float t[16];
float *t1=t, *t2=t+8;
// group 1
WHBFY(t1,src,0,0,4); WHBFY(t1,src,0,1,4); WHBFY(t1,src,0,2,4); WHBFY(t1,src,0,3,4);
// group 2
WHBFY(t2,t1,0,0,2); WHBFY(t2,t1,0,1,2); WHBFY(t2,t1,4,0,2); WHBFY(t2,t1,4,1,2);
// group 3
WHBFY(dst,t2,0,0,1); WHBFY(dst,t2,2,0,1); WHBFY(dst,t2,4,0,1); WHBFY(dst,t2,6,0,1);
};
static void np_fwht16(float *dst, float *src)
{
float t[32];
float *t1=t, *t2=t+16;
// group 1
WHBFY(t1,src,0,0,8); WHBFY(t1,src,0,1,8); WHBFY(t1,src,0,2,8); WHBFY(t1,src,0,3,8);
WHBFY(t1,src,0,4,8); WHBFY(t1,src,0,5,8); WHBFY(t1,src,0,6,8); WHBFY(t1,src,0,7,8);
// group 2
WHBFY(t2,t1,0,0,4); WHBFY(t2,t1,0,1,4); WHBFY(t2,t1,0,2,4); WHBFY(t2,t1,0,3,4);
WHBFY(t2,t1,8,0,4); WHBFY(t2,t1,8,1,4); WHBFY(t2,t1,8,2,4); WHBFY(t2,t1,8,3,4);
// group 3
WHBFY(t1,t2,0,0,2); WHBFY(t1,t2,0,1,2); WHBFY(t1,t2,4,0,2); WHBFY(t1,t2,4,1,2);
WHBFY(t1,t2,8,0,2); WHBFY(t1,t2,8,1,2); WHBFY(t1,t2,12,0,2); WHBFY(t1,t2,12,1,2);
// group 4
WHBFY(dst,t1,0,0,1); WHBFY(dst,t1,2,0,1); WHBFY(dst,t1,4,0,1); WHBFY(dst,t1,6,0,1);
WHBFY(dst,t1,8,0,1); WHBFY(dst,t1,10,0,1); WHBFY(dst,t1,12,0,1); WHBFY(dst,t1,14,0,1);
}
static void np_fwht32(float *dst, float *src)
{
float t[64];
float *t1=t, *t2=t+32;
// group 1
WHBFY(t1,src,0,0,16); WHBFY(t1,src,0,1,16); WHBFY(t1,src,0,2,16); WHBFY(t1,src,0,3,16);
WHBFY(t1,src,0,4,16); WHBFY(t1,src,0,5,16); WHBFY(t1,src,0,6,16); WHBFY(t1,src,0,7,16);
WHBFY(t1,src,0,8,16); WHBFY(t1,src,0,9,16); WHBFY(t1,src,0,10,16); WHBFY(t1,src,0,11,16);
WHBFY(t1,src,0,12,16); WHBFY(t1,src,0,13,16); WHBFY(t1,src,0,14,16); WHBFY(t1,src,0,15,16);
// group 2
WHBFY(t2,t1,0,0,8); WHBFY(t2,t1,0,1,8); WHBFY(t2,t1,0,2,8); WHBFY(t2,t1,0,3,8);
WHBFY(t2,t1,0,4,8); WHBFY(t2,t1,0,5,8); WHBFY(t2,t1,0,6,8); WHBFY(t2,t1,0,7,8);
WHBFY(t2,t1,16,0,8); WHBFY(t2,t1,16,1,8); WHBFY(t2,t1,16,2,8); WHBFY(t2,t1,16,3,8);
WHBFY(t2,t1,16,4,8); WHBFY(t2,t1,16,5,8); WHBFY(t2,t1,16,6,8); WHBFY(t2,t1,16,7,8);
// group 3
WHBFY(t1,t2,0,0,4); WHBFY(t1,t2,0,1,4); WHBFY(t1,t2,0,2,4); WHBFY(t1,t2,0,3,4);
WHBFY(t1,t2,8,0,4); WHBFY(t1,t2,8,1,4); WHBFY(t1,t2,8,2,4); WHBFY(t1,t2,8,3,4);
WHBFY(t1,t2,16,0,4); WHBFY(t1,t2,16,1,4); WHBFY(t1,t2,16,2,4); WHBFY(t1,t2,16,3,4);
WHBFY(t1,t2,24,0,4); WHBFY(t1,t2,24,1,4); WHBFY(t1,t2,24,2,4); WHBFY(t1,t2,24,3,4);
// group 4
WHBFY(t2,t1,0,0,2); WHBFY(t2,t1,0,1,2); WHBFY(t2,t1,4,0,2); WHBFY(t2,t1,4,1,2);
WHBFY(t2,t1,8,0,2); WHBFY(t2,t1,8,1,2); WHBFY(t2,t1,12,0,2); WHBFY(t2,t1,12,1,2);
WHBFY(t2,t1,16,0,2); WHBFY(t2,t1,16,1,2); WHBFY(t2,t1,20,0,2); WHBFY(t2,t1,20,1,2);
WHBFY(t2,t1,24,0,2); WHBFY(t2,t1,24,1,2); WHBFY(t2,t1,28,0,2); WHBFY(t2,t1,28,1,2);
// group 5
WHBFY(dst,t2,0,0,1); WHBFY(dst,t2,2,0,1); WHBFY(dst,t2,4,0,1); WHBFY(dst,t2,6,0,1);
WHBFY(dst,t2,8,0,1); WHBFY(dst,t2,10,0,1); WHBFY(dst,t2,12,0,1); WHBFY(dst,t2,14,0,1);
WHBFY(dst,t2,16,0,1); WHBFY(dst,t2,18,0,1); WHBFY(dst,t2,20,0,1); WHBFY(dst,t2,22,0,1);
WHBFY(dst,t2,24,0,1); WHBFY(dst,t2,26,0,1); WHBFY(dst,t2,28,0,1); WHBFY(dst,t2,30,0,1);
}
static void np_fwht64(float *dst, float *src)
{
float t[128];
float *t1=t, *t2=t+64;
// group 1
WHBFY(t1,src,0,0,32); WHBFY(t1,src,0,1,32); WHBFY(t1,src,0,2,32); WHBFY(t1,src,0,3,32);
WHBFY(t1,src,0,4,32); WHBFY(t1,src,0,5,32); WHBFY(t1,src,0,6,32); WHBFY(t1,src,0,7,32);
WHBFY(t1,src,0,8,32); WHBFY(t1,src,0,9,32); WHBFY(t1,src,0,10,32); WHBFY(t1,src,0,11,32);
WHBFY(t1,src,0,12,32); WHBFY(t1,src,0,13,32); WHBFY(t1,src,0,14,32); WHBFY(t1,src,0,15,32);
WHBFY(t1,src,0,16,32); WHBFY(t1,src,0,17,32); WHBFY(t1,src,0,18,32); WHBFY(t1,src,0,19,32);
WHBFY(t1,src,0,20,32); WHBFY(t1,src,0,21,32); WHBFY(t1,src,0,22,32); WHBFY(t1,src,0,23,32);
WHBFY(t1,src,0,24,32); WHBFY(t1,src,0,25,32); WHBFY(t1,src,0,26,32); WHBFY(t1,src,0,27,32);
WHBFY(t1,src,0,28,32); WHBFY(t1,src,0,29,32); WHBFY(t1,src,0,30,32); WHBFY(t1,src,0,31,32);
// group 2
WHBFY(t2,t1,0,0,16); WHBFY(t2,t1,0,1,16); WHBFY(t2,t1,0,2,16); WHBFY(t2,t1,0,3,16);
WHBFY(t2,t1,0,4,16); WHBFY(t2,t1,0,5,16); WHBFY(t2,t1,0,6,16); WHBFY(t2,t1,0,7,16);
WHBFY(t2,t1,0,8,16); WHBFY(t2,t1,0,9,16); WHBFY(t2,t1,0,10,16); WHBFY(t2,t1,0,11,16);
WHBFY(t2,t1,0,12,16); WHBFY(t2,t1,0,13,16); WHBFY(t2,t1,0,14,16); WHBFY(t2,t1,0,15,16);
WHBFY(t2,t1,32,0,16); WHBFY(t2,t1,32,1,16); WHBFY(t2,t1,32,2,16); WHBFY(t2,t1,32,3,16);
WHBFY(t2,t1,32,4,16); WHBFY(t2,t1,32,5,16); WHBFY(t2,t1,32,6,16); WHBFY(t2,t1,32,7,16);
WHBFY(t2,t1,32,8,16); WHBFY(t2,t1,32,9,16); WHBFY(t2,t1,32,10,16); WHBFY(t2,t1,32,11,16);
WHBFY(t2,t1,32,12,16); WHBFY(t2,t1,32,13,16); WHBFY(t2,t1,32,14,16); WHBFY(t2,t1,32,15,16);
// group 3
WHBFY(t1,t2,0,0,8); WHBFY(t1,t2,0,1,8); WHBFY(t1,t2,0,2,8); WHBFY(t1,t2,0,3,8);
WHBFY(t1,t2,0,4,8); WHBFY(t1,t2,0,5,8); WHBFY(t1,t2,0,6,8); WHBFY(t1,t2,0,7,8);
WHBFY(t1,t2,16,0,8); WHBFY(t1,t2,16,1,8); WHBFY(t1,t2,16,2,8); WHBFY(t1,t2,16,3,8);
WHBFY(t1,t2,16,4,8); WHBFY(t1,t2,16,5,8); WHBFY(t1,t2,16,6,8); WHBFY(t1,t2,16,7,8);
WHBFY(t1,t2,32,0,8); WHBFY(t1,t2,32,1,8); WHBFY(t1,t2,32,2,8); WHBFY(t1,t2,32,3,8);
WHBFY(t1,t2,32,4,8); WHBFY(t1,t2,32,5,8); WHBFY(t1,t2,32,6,8); WHBFY(t1,t2,32,7,8);
WHBFY(t1,t2,48,0,8); WHBFY(t1,t2,48,1,8); WHBFY(t1,t2,48,2,8); WHBFY(t1,t2,48,3,8);
WHBFY(t1,t2,48,4,8); WHBFY(t1,t2,48,5,8); WHBFY(t1,t2,48,6,8); WHBFY(t1,t2,48,7,8);
// group 4
WHBFY(t2,t1,0,0,4); WHBFY(t2,t1,0,1,4); WHBFY(t2,t1,0,2,4); WHBFY(t2,t1,0,3,4);
WHBFY(t2,t1,8,0,4); WHBFY(t2,t1,8,1,4); WHBFY(t2,t1,8,2,4); WHBFY(t2,t1,8,3,4);
WHBFY(t2,t1,16,0,4); WHBFY(t2,t1,16,1,4); WHBFY(t2,t1,16,2,4); WHBFY(t2,t1,16,3,4);
WHBFY(t2,t1,24,0,4); WHBFY(t2,t1,24,1,4); WHBFY(t2,t1,24,2,4); WHBFY(t2,t1,24,3,4);
WHBFY(t2,t1,32,0,4); WHBFY(t2,t1,32,1,4); WHBFY(t2,t1,32,2,4); WHBFY(t2,t1,32,3,4);
WHBFY(t2,t1,40,0,4); WHBFY(t2,t1,40,1,4); WHBFY(t2,t1,40,2,4); WHBFY(t2,t1,40,3,4);
WHBFY(t2,t1,48,0,4); WHBFY(t2,t1,48,1,4); WHBFY(t2,t1,48,2,4); WHBFY(t2,t1,48,3,4);
WHBFY(t2,t1,56,0,4); WHBFY(t2,t1,56,1,4); WHBFY(t2,t1,56,2,4); WHBFY(t2,t1,56,3,4);
// group 5
WHBFY(t1,t2,0,0,2); WHBFY(t1,t2,0,1,2); WHBFY(t1,t2,4,0,2); WHBFY(t1,t2,4,1,2);
WHBFY(t1,t2,8,0,2); WHBFY(t1,t2,8,1,2); WHBFY(t1,t2,12,0,2); WHBFY(t1,t2,12,1,2);
WHBFY(t1,t2,16,0,2); WHBFY(t1,t2,16,1,2); WHBFY(t1,t2,20,0,2); WHBFY(t1,t2,20,1,2);
WHBFY(t1,t2,24,0,2); WHBFY(t1,t2,24,1,2); WHBFY(t1,t2,28,0,2); WHBFY(t1,t2,28,1,2);
WHBFY(t1,t2,32,0,2); WHBFY(t1,t2,32,1,2); WHBFY(t1,t2,36,0,2); WHBFY(t1,t2,36,1,2);
WHBFY(t1,t2,40,0,2); WHBFY(t1,t2,40,1,2); WHBFY(t1,t2,44,0,2); WHBFY(t1,t2,44,1,2);
WHBFY(t1,t2,48,0,2); WHBFY(t1,t2,48,1,2); WHBFY(t1,t2,52,0,2); WHBFY(t1,t2,52,1,2);
WHBFY(t1,t2,56,0,2); WHBFY(t1,t2,56,1,2); WHBFY(t1,t2,60,0,2); WHBFY(t1,t2,60,1,2);
// group 6
WHBFY(dst,t1,0,0,1); WHBFY(dst,t1,2,0,1); WHBFY(dst,t1,4,0,1); WHBFY(dst,t1,6,0,1);
WHBFY(dst,t1,8,0,1); WHBFY(dst,t1,10,0,1); WHBFY(dst,t1,12,0,1); WHBFY(dst,t1,14,0,1);
WHBFY(dst,t1,16,0,1); WHBFY(dst,t1,18,0,1); WHBFY(dst,t1,20,0,1); WHBFY(dst,t1,22,0,1);
WHBFY(dst,t1,24,0,1); WHBFY(dst,t1,26,0,1); WHBFY(dst,t1,28,0,1); WHBFY(dst,t1,30,0,1);
WHBFY(dst,t1,32,0,1); WHBFY(dst,t1,34,0,1); WHBFY(dst,t1,36,0,1); WHBFY(dst,t1,38,0,1);
WHBFY(dst,t1,40,0,1); WHBFY(dst,t1,42,0,1); WHBFY(dst,t1,44,0,1); WHBFY(dst,t1,46,0,1);
WHBFY(dst,t1,48,0,1); WHBFY(dst,t1,50,0,1); WHBFY(dst,t1,52,0,1); WHBFY(dst,t1,54,0,1);
WHBFY(dst,t1,56,0,1); WHBFY(dst,t1,58,0,1); WHBFY(dst,t1,60,0,1); WHBFY(dst,t1,62,0,1);
}

45
lib/qra/qracodes/npfwht.h Normal file
View File

@ -0,0 +1,45 @@
// np_fwht.h
// Basic implementation of the Fast Walsh-Hadamard Transforms
//
// (c) 2016 - Nico Palermo, IV3NWV - Microtelecom Srl, Italy
// ------------------------------------------------------------------------------
// This file is part of the qracodes project, a Forward Error Control
// encoding/decoding package based on Q-ary RA (repeat and accumulate) LDPC codes.
//
// qracodes is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
// qracodes is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
// You should have received a copy of the GNU General Public License
// along with qracodes source distribution.
// If not, see <http://www.gnu.org/licenses/>.
#ifndef _npfwht_h_
#define _npfwht_h_
#ifdef __cplusplus
extern "C" {
#endif
void np_fwht(int nlogdim, float *dst, float *src);
// Compute the Walsh-Hadamard transform of the given data up to a
// 64-dimensional transform
//
// Input parameters:
// nlogdim: log2 of the transform size. Must be in the range [0..6]
// src : pointer to the input data buffer.
// dst : pointer to the output data buffer.
//
// src and dst must point to preallocated data buffers of size 2^nlogdim*sizeof(float)
// src and dst buffers can overlap
#ifdef __cplusplus
}
#endif
#endif // _npfwht_

385
lib/qra/qracodes/pdmath.c Normal file
View File

@ -0,0 +1,385 @@
// pdmath.c
// Elementary math on probability distributions
//
// (c) 2016 - Nico Palermo, IV3NWV - Microtelecom Srl, Italy
// ------------------------------------------------------------------------------
// This file is part of the qracodes project, a Forward Error Control
// encoding/decoding package based on Q-ary RA (Repeat and Accumulate) LDPC codes.
//
// qracodes is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
// qracodes is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
// You should have received a copy of the GNU General Public License
// along with qracodes source distribution.
// If not, see <http://www.gnu.org/licenses/>.
#include "pdmath.h"
typedef const float *ppd_uniform;
typedef void (*ppd_imul)(float*,const float*);
typedef float (*ppd_norm)(float*);
// define vector size in function of its logarithm in base 2
static const int pd_log2dim[7] = {
1,2,4,8,16,32,64
};
// define uniform distributions of given size
static const float pd_uniform1[1] = {
1.
};
static const float pd_uniform2[2] = {
1./2., 1./2.
};
static const float pd_uniform4[4] = {
1./4., 1./4.,1./4., 1./4.
};
static const float pd_uniform8[8] = {
1./8., 1./8.,1./8., 1./8.,1./8., 1./8.,1./8., 1./8.
};
static const float pd_uniform16[16] = {
1./16., 1./16., 1./16., 1./16.,1./16., 1./16.,1./16., 1./16.,
1./16., 1./16., 1./16., 1./16.,1./16., 1./16.,1./16., 1./16.
};
static const float pd_uniform32[32] = {
1./32., 1./32., 1./32., 1./32.,1./32., 1./32.,1./32., 1./32.,
1./32., 1./32., 1./32., 1./32.,1./32., 1./32.,1./32., 1./32.,
1./32., 1./32., 1./32., 1./32.,1./32., 1./32.,1./32., 1./32.,
1./32., 1./32., 1./32., 1./32.,1./32., 1./32.,1./32., 1./32.
};
static const float pd_uniform64[64] = {
1./64., 1./64., 1./64., 1./64.,1./64., 1./64.,1./64., 1./64.,
1./64., 1./64., 1./64., 1./64.,1./64., 1./64.,1./64., 1./64.,
1./64., 1./64., 1./64., 1./64.,1./64., 1./64.,1./64., 1./64.,
1./64., 1./64., 1./64., 1./64.,1./64., 1./64.,1./64., 1./64.,
1./64., 1./64., 1./64., 1./64.,1./64., 1./64.,1./64., 1./64.,
1./64., 1./64., 1./64., 1./64.,1./64., 1./64.,1./64., 1./64.,
1./64., 1./64., 1./64., 1./64.,1./64., 1./64.,1./64., 1./64.,
1./64., 1./64., 1./64., 1./64.,1./64., 1./64.,1./64., 1./64.
};
static const ppd_uniform pd_uniform_tab[7] = {
pd_uniform1,
pd_uniform2,
pd_uniform4,
pd_uniform8,
pd_uniform16,
pd_uniform32,
pd_uniform64
};
// returns a pointer to the uniform distribution of the given logsize
const float *pd_uniform(int nlogdim)
{
return pd_uniform_tab[nlogdim];
}
// in-place multiplication functions
// compute dst = dst*src for any element of the distrib
static void pd_imul1(float *dst, const float *src)
{
dst[0] *= src[0];
}
static void pd_imul2(float *dst, const float *src)
{
dst[0] *= src[0]; dst[1] *= src[1];
}
static void pd_imul4(float *dst, const float *src)
{
dst[0] *= src[0]; dst[1] *= src[1];
dst[2] *= src[2]; dst[3] *= src[3];
}
static void pd_imul8(float *dst, const float *src)
{
dst[0] *= src[0]; dst[1] *= src[1]; dst[2] *= src[2]; dst[3] *= src[3];
dst[4] *= src[4]; dst[5] *= src[5]; dst[6] *= src[6]; dst[7] *= src[7];
}
static void pd_imul16(float *dst, const float *src)
{
dst[0] *= src[0]; dst[1] *= src[1]; dst[2] *= src[2]; dst[3] *= src[3];
dst[4] *= src[4]; dst[5] *= src[5]; dst[6] *= src[6]; dst[7] *= src[7];
dst[8] *= src[8]; dst[9] *= src[9]; dst[10]*= src[10]; dst[11]*= src[11];
dst[12]*= src[12]; dst[13]*= src[13]; dst[14]*= src[14]; dst[15]*= src[15];
}
static void pd_imul32(float *dst, const float *src)
{
pd_imul16(dst,src);
pd_imul16(dst+16,src+16);
}
static void pd_imul64(float *dst, const float *src)
{
pd_imul16(dst, src);
pd_imul16(dst+16, src+16);
pd_imul16(dst+32, src+32);
pd_imul16(dst+48, src+48);
}
static const ppd_imul pd_imul_tab[7] = {
pd_imul1,
pd_imul2,
pd_imul4,
pd_imul8,
pd_imul16,
pd_imul32,
pd_imul64
};
// in place multiplication
// compute dst = dst*src for any element of the distrib give their log2 size
// arguments must be pointers to array of floats of the given size
void pd_imul(float *dst, const float *src, int nlogdim)
{
pd_imul_tab[nlogdim](dst,src);
}
static float pd_norm1(float *ppd)
{
float t = ppd[0];
ppd[0] = 1.f;
return t;
}
static float pd_norm2(float *ppd)
{
float t,to;
t =ppd[0]; t +=ppd[1];
if (t<=0) {
pd_init(ppd,pd_uniform(1),pd_log2dim[1]);
return t;
}
to = t;
t = 1.f/t;
ppd[0] *=t; ppd[1] *=t;
return to;
}
static float pd_norm4(float *ppd)
{
float t,to;
t =ppd[0]; t +=ppd[1]; t +=ppd[2]; t +=ppd[3];
if (t<=0) {
pd_init(ppd,pd_uniform(2),pd_log2dim[2]);
return t;
}
to = t;
t = 1.f/t;
ppd[0] *=t; ppd[1] *=t; ppd[2] *=t; ppd[3] *=t;
return to;
}
static float pd_norm8(float *ppd)
{
float t,to;
t =ppd[0]; t +=ppd[1]; t +=ppd[2]; t +=ppd[3];
t +=ppd[4]; t +=ppd[5]; t +=ppd[6]; t +=ppd[7];
if (t<=0) {
pd_init(ppd,pd_uniform(3),pd_log2dim[3]);
return t;
}
to = t;
t = 1.f/t;
ppd[0] *=t; ppd[1] *=t; ppd[2] *=t; ppd[3] *=t;
ppd[4] *=t; ppd[5] *=t; ppd[6] *=t; ppd[7] *=t;
return to;
}
static float pd_norm16(float *ppd)
{
float t,to;
t =ppd[0]; t +=ppd[1]; t +=ppd[2]; t +=ppd[3];
t +=ppd[4]; t +=ppd[5]; t +=ppd[6]; t +=ppd[7];
t +=ppd[8]; t +=ppd[9]; t +=ppd[10]; t +=ppd[11];
t +=ppd[12]; t +=ppd[13]; t +=ppd[14]; t +=ppd[15];
if (t<=0) {
pd_init(ppd,pd_uniform(4),pd_log2dim[4]);
return t;
}
to = t;
t = 1.f/t;
ppd[0] *=t; ppd[1] *=t; ppd[2] *=t; ppd[3] *=t;
ppd[4] *=t; ppd[5] *=t; ppd[6] *=t; ppd[7] *=t;
ppd[8] *=t; ppd[9] *=t; ppd[10] *=t; ppd[11] *=t;
ppd[12] *=t; ppd[13] *=t; ppd[14] *=t; ppd[15] *=t;
return to;
}
static float pd_norm32(float *ppd)
{
float t,to;
t =ppd[0]; t +=ppd[1]; t +=ppd[2]; t +=ppd[3];
t +=ppd[4]; t +=ppd[5]; t +=ppd[6]; t +=ppd[7];
t +=ppd[8]; t +=ppd[9]; t +=ppd[10]; t +=ppd[11];
t +=ppd[12]; t +=ppd[13]; t +=ppd[14]; t +=ppd[15];
t +=ppd[16]; t +=ppd[17]; t +=ppd[18]; t +=ppd[19];
t +=ppd[20]; t +=ppd[21]; t +=ppd[22]; t +=ppd[23];
t +=ppd[24]; t +=ppd[25]; t +=ppd[26]; t +=ppd[27];
t +=ppd[28]; t +=ppd[29]; t +=ppd[30]; t +=ppd[31];
if (t<=0) {
pd_init(ppd,pd_uniform(5),pd_log2dim[5]);
return t;
}
to = t;
t = 1.f/t;
ppd[0] *=t; ppd[1] *=t; ppd[2] *=t; ppd[3] *=t;
ppd[4] *=t; ppd[5] *=t; ppd[6] *=t; ppd[7] *=t;
ppd[8] *=t; ppd[9] *=t; ppd[10] *=t; ppd[11] *=t;
ppd[12] *=t; ppd[13] *=t; ppd[14] *=t; ppd[15] *=t;
ppd[16] *=t; ppd[17] *=t; ppd[18] *=t; ppd[19] *=t;
ppd[20] *=t; ppd[21] *=t; ppd[22] *=t; ppd[23] *=t;
ppd[24] *=t; ppd[25] *=t; ppd[26] *=t; ppd[27] *=t;
ppd[28] *=t; ppd[29] *=t; ppd[30] *=t; ppd[31] *=t;
return to;
}
static float pd_norm64(float *ppd)
{
float t,to;
t =ppd[0]; t +=ppd[1]; t +=ppd[2]; t +=ppd[3];
t +=ppd[4]; t +=ppd[5]; t +=ppd[6]; t +=ppd[7];
t +=ppd[8]; t +=ppd[9]; t +=ppd[10]; t +=ppd[11];
t +=ppd[12]; t +=ppd[13]; t +=ppd[14]; t +=ppd[15];
t +=ppd[16]; t +=ppd[17]; t +=ppd[18]; t +=ppd[19];
t +=ppd[20]; t +=ppd[21]; t +=ppd[22]; t +=ppd[23];
t +=ppd[24]; t +=ppd[25]; t +=ppd[26]; t +=ppd[27];
t +=ppd[28]; t +=ppd[29]; t +=ppd[30]; t +=ppd[31];
t +=ppd[32]; t +=ppd[33]; t +=ppd[34]; t +=ppd[35];
t +=ppd[36]; t +=ppd[37]; t +=ppd[38]; t +=ppd[39];
t +=ppd[40]; t +=ppd[41]; t +=ppd[42]; t +=ppd[43];
t +=ppd[44]; t +=ppd[45]; t +=ppd[46]; t +=ppd[47];
t +=ppd[48]; t +=ppd[49]; t +=ppd[50]; t +=ppd[51];
t +=ppd[52]; t +=ppd[53]; t +=ppd[54]; t +=ppd[55];
t +=ppd[56]; t +=ppd[57]; t +=ppd[58]; t +=ppd[59];
t +=ppd[60]; t +=ppd[61]; t +=ppd[62]; t +=ppd[63];
if (t<=0) {
pd_init(ppd,pd_uniform(6),pd_log2dim[6]);
return t;
}
to = t;
t = 1.0f/t;
ppd[0] *=t; ppd[1] *=t; ppd[2] *=t; ppd[3] *=t;
ppd[4] *=t; ppd[5] *=t; ppd[6] *=t; ppd[7] *=t;
ppd[8] *=t; ppd[9] *=t; ppd[10] *=t; ppd[11] *=t;
ppd[12] *=t; ppd[13] *=t; ppd[14] *=t; ppd[15] *=t;
ppd[16] *=t; ppd[17] *=t; ppd[18] *=t; ppd[19] *=t;
ppd[20] *=t; ppd[21] *=t; ppd[22] *=t; ppd[23] *=t;
ppd[24] *=t; ppd[25] *=t; ppd[26] *=t; ppd[27] *=t;
ppd[28] *=t; ppd[29] *=t; ppd[30] *=t; ppd[31] *=t;
ppd[32] *=t; ppd[33] *=t; ppd[34] *=t; ppd[35] *=t;
ppd[36] *=t; ppd[37] *=t; ppd[38] *=t; ppd[39] *=t;
ppd[40] *=t; ppd[41] *=t; ppd[42] *=t; ppd[43] *=t;
ppd[44] *=t; ppd[45] *=t; ppd[46] *=t; ppd[47] *=t;
ppd[48] *=t; ppd[49] *=t; ppd[50] *=t; ppd[51] *=t;
ppd[52] *=t; ppd[53] *=t; ppd[54] *=t; ppd[55] *=t;
ppd[56] *=t; ppd[57] *=t; ppd[58] *=t; ppd[59] *=t;
ppd[60] *=t; ppd[61] *=t; ppd[62] *=t; ppd[63] *=t;
return to;
}
static const ppd_norm pd_norm_tab[7] = {
pd_norm1,
pd_norm2,
pd_norm4,
pd_norm8,
pd_norm16,
pd_norm32,
pd_norm64
};
float pd_norm(float *pd, int nlogdim)
{
return pd_norm_tab[nlogdim](pd);
}
void pd_memset(float *dst, const float *src, int ndim, int nitems)
{
int size = PD_SIZE(ndim);
while(nitems--) {
memcpy(dst,src,size);
dst +=ndim;
}
}
void pd_fwdperm(float *dst, float *src, const unsigned int *perm, int ndim)
{
// TODO: non-loop implementation
while (ndim--)
dst[ndim] = src[perm[ndim]];
}
void pd_bwdperm(float *dst, float *src, const unsigned int *perm, int ndim)
{
// TODO: non-loop implementation
while (ndim--)
dst[perm[ndim]] = src[ndim];
}
float pd_max(float *src, int ndim)
{
// TODO: faster implementation
float cmax=0; // we assume that prob distributions are always positive
float cval;
while (ndim--) {
cval = src[ndim];
if (cval>=cmax) {
cmax = cval;
}
}
return cmax;
}
int pd_argmax(float *pmax, float *src, int ndim)
{
// TODO: faster implementation
float cmax=0; // we assume that prob distributions are always positive
float cval;
int idxmax=-1; // indicates that all pd elements are <0
while (ndim--) {
cval = src[ndim];
if (cval>=cmax) {
cmax = cval;
idxmax = ndim;
}
}
if (pmax)
*pmax = cmax;
return idxmax;
}

85
lib/qra/qracodes/pdmath.h Normal file
View File

@ -0,0 +1,85 @@
// pdmath.h
// Elementary math on probability distributions
//
// (c) 2016 - Nico Palermo, IV3NWV - Microtelecom Srl, Italy
// ------------------------------------------------------------------------------
// This file is part of the qracodes project, a Forward Error Control
// encoding/decoding package based on Q-ary RA (repeat and accumulate) LDPC codes.
//
// qracodes is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
// qracodes is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
// You should have received a copy of the GNU General Public License
// along with qracodes source distribution.
// If not, see <http://www.gnu.org/licenses/>.
#ifndef _pdmath_h_
#define _pdmath_h_
#include <memory.h>
#ifdef __cplusplus
extern "C" {
#endif
#define PD_NDIM(nlogdim) ((1<<(nlogdim))
#define PD_SIZE(ndim) ((ndim)*sizeof(float))
#define PD_ROWADDR(fp,ndim,idx) (fp+((ndim)*(idx)))
const float *pd_uniform(int nlogdim);
// Returns a pointer to a (constant) uniform distribution of the given log2 size
#define pd_init(dst,src,ndim) memcpy(dst,src,PD_SIZE(ndim))
// Distribution copy
void pd_memset(float *dst, const float *src, int ndim, int nitems);
// Copy the distribution pointed by src to the array of distributions dst
// src is a pointer to the input distribution (a vector of size ndim)
// dst is a pointer to a linear array of distributions (a vector of size ndim*nitems)
void pd_imul(float *dst, const float *src, int nlogdim);
// In place multiplication
// Compute dst = dst*src for any element of the distrib give their log2 size
// src and dst arguments must be pointers to array of floats of the given size
float pd_norm(float *pd, int nlogdim);
// In place normalizazion
// Normalizes the input vector so that the sum of its components are one
// pd must be a pointer to an array of floats of the given size.
// If the norm of the input vector is non-positive the vector components
// are replaced with a uniform distribution
// Returns the norm of the distribution prior to the normalization
void pd_fwdperm(float *dst, float *src, const unsigned int *perm, int ndim);
// Forward permutation of a distribution
// Computes dst[k] = src[perm[k]] for every element in the distribution
// perm must be a pointer to an array of integers of length ndim
void pd_bwdperm(float *dst, float *src, const unsigned int *perm, int ndim);
// Backward permutation of a distribution
// Computes dst[perm[k]] = src[k] for every element in the distribution
// perm must be a pointer to an array of integers of length ndim
float pd_max(float *src, int ndim);
// Return the maximum of the elements of the given distribution
// Assumes that the input vector is a probability distribution and that each element in the
// distribution is non negative
int pd_argmax(float *pmax, float *src, int ndim);
// Return the index of the maximum element of the given distribution
// The maximum is stored in the variable pointed by pmax if pmax is not null
// Same note of pd_max applies.
// Return -1 if all the elements in the distribution are negative
#ifdef __cplusplus
}
#endif
#endif // _pdmath_h_

View File

@ -0,0 +1,534 @@
// qra12_63_64_irr_b.c
// Encoding/Decoding tables for Q-ary RA code (12,63) over GF(64)
// Code Name: qra12_63_64_irr_b
// (12,63) RA Code over GF(64) - RF=333344455567
// (c) 2016 - Nico Palermo - IV3NWV - Microtelecom Srl, Italy
// This file is part of the qracodes project, a Forward Error Control
// encoding/decoding package based on Q-ary RA (Repeat and Accumulate) LDPC codes.
//
// qracodes is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
// qracodes is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with qracodes source distribution.
// If not, see <http://www.gnu.org/licenses/>.
#include "qra12_63_64_irr_b.h"
#define qra_K 12 // number of information symbols
#define qra_N 63 // codeword length in symbols
#define qra_m 6 // bits/symbol
#define qra_M 64 // Symbol alphabet cardinality
#define qra_a 1 // grouping factor
#define qra_NC 51 // number of check symbols (N-K)
// Defines used by the message passing decoder --------
#define qra_V 63 // number of variables in the code graph (N)
#define qra_C 115 // number of factors in the code graph (N +(N-K)+1)
#define qra_NMSG 217 // number of msgs in the code graph
#define qra_MAXVDEG 8 // maximum variable degree
#define qra_MAXCDEG 3 // maximum factor degree
#define qra_R 0.19048f // code rate (K/N)
#define CODE_NAME "qra_12_63_64_irr_b"
// table of the systematic symbols indexes in the accumulator chain
static const int qra_acc_input_idx[qra_NC+1] = {
3, 11, 0, 1, 7, 8, 6, 5, 10, 4,
11, 9, 0, 2, 6, 7, 8, 4, 11, 5,
10, 2, 1, 9, 3, 8, 4, 11, 5, 7,
10, 9, 6, 3, 11, 5, 8, 10, 0, 7,
9, 11, 4, 2, 10, 6, 8, 1, 9, 7,
11, 10
};
// table of the systematic symbols weight logarithms over GF(M)
static const unsigned int qra_acc_input_wlog[qra_NC+1] = {
39, 0, 34, 16, 25, 0, 34, 48, 19, 13,
29, 56, 0, 5, 39, 42, 31, 0, 10, 0,
57, 62, 33, 43, 0, 14, 22, 48, 28, 20,
5, 45, 16, 43, 17, 4, 32, 0, 31, 0,
0, 28, 57, 0, 18, 0, 60, 0, 10, 31,
57, 27
};
// table of the logarithms of the elements of GF(M) (log(0) never used)
static const int qra_log[qra_M] = {
-1, 0, 1, 6, 2, 12, 7, 26, 3, 32,
13, 35, 8, 48, 27, 18, 4, 24, 33, 16,
14, 52, 36, 54, 9, 45, 49, 38, 28, 41,
19, 56, 5, 62, 25, 11, 34, 31, 17, 47,
15, 23, 53, 51, 37, 44, 55, 40, 10, 61,
46, 30, 50, 22, 39, 43, 29, 60, 42, 21,
20, 59, 57, 58
};
// table of GF(M) elements given their logarithm
static const unsigned int qra_exp[qra_M-1] = {
1, 2, 4, 8, 16, 32, 3, 6, 12, 24,
48, 35, 5, 10, 20, 40, 19, 38, 15, 30,
60, 59, 53, 41, 17, 34, 7, 14, 28, 56,
51, 37, 9, 18, 36, 11, 22, 44, 27, 54,
47, 29, 58, 55, 45, 25, 50, 39, 13, 26,
52, 43, 21, 42, 23, 46, 31, 62, 63, 61,
57, 49, 33
};
// table of the messages weight logarithms over GF(M)
static const unsigned int qra_msgw[qra_NMSG] = {
0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 39, 0, 34, 16, 25, 0, 34,
48, 19, 13, 29, 56, 0, 5, 39, 42, 31,
0, 10, 0, 57, 62, 33, 43, 0, 14, 22,
48, 28, 20, 5, 45, 16, 43, 17, 4, 32,
0, 31, 0, 0, 28, 57, 0, 18, 0, 60,
0, 10, 31, 57, 27, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0
};
// table of the degrees of the variable nodes
static const unsigned int qra_vdeg[qra_V] = {
4, 4, 4, 4, 5, 5, 5, 6, 6, 6,
7, 8, 3, 3, 3, 3, 3, 3, 3, 3,
3, 3, 3, 3, 3, 3, 3, 3, 3, 3,
3, 3, 3, 3, 3, 3, 3, 3, 3, 3,
3, 3, 3, 3, 3, 3, 3, 3, 3, 3,
3, 3, 3, 3, 3, 3, 3, 3, 3, 3,
3, 3, 3
};
// table of the degrees of the factor nodes
static const unsigned int qra_cdeg[qra_C] = {
1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 2, 3, 3, 3, 3, 3, 3,
3, 3, 3, 3, 3, 3, 3, 3, 3, 3,
3, 3, 3, 3, 3, 3, 3, 3, 3, 3,
3, 3, 3, 3, 3, 3, 3, 3, 3, 3,
3, 3, 3, 3, 3, 3, 3, 3, 3, 3,
3, 3, 3, 3, 2
};
// table (uncompressed) of the v->c message indexes (-1=unused entry)
static const int qra_v2cmidx[qra_V*qra_MAXVDEG] = {
0, 65, 75, 101, -1, -1, -1, -1,
1, 66, 85, 110, -1, -1, -1, -1,
2, 76, 84, 106, -1, -1, -1, -1,
3, 63, 87, 96, -1, -1, -1, -1,
4, 72, 80, 89, 105, -1, -1, -1,
5, 70, 82, 91, 98, -1, -1, -1,
6, 69, 77, 95, 108, -1, -1, -1,
7, 67, 78, 92, 102, 112, -1, -1,
8, 68, 79, 88, 99, 109, -1, -1,
9, 74, 86, 94, 103, 111, -1, -1,
10, 71, 83, 93, 100, 107, 114, -1,
11, 64, 73, 81, 90, 97, 104, 113,
12, 115, 116, -1, -1, -1, -1, -1,
13, 117, 118, -1, -1, -1, -1, -1,
14, 119, 120, -1, -1, -1, -1, -1,
15, 121, 122, -1, -1, -1, -1, -1,
16, 123, 124, -1, -1, -1, -1, -1,
17, 125, 126, -1, -1, -1, -1, -1,
18, 127, 128, -1, -1, -1, -1, -1,
19, 129, 130, -1, -1, -1, -1, -1,
20, 131, 132, -1, -1, -1, -1, -1,
21, 133, 134, -1, -1, -1, -1, -1,
22, 135, 136, -1, -1, -1, -1, -1,
23, 137, 138, -1, -1, -1, -1, -1,
24, 139, 140, -1, -1, -1, -1, -1,
25, 141, 142, -1, -1, -1, -1, -1,
26, 143, 144, -1, -1, -1, -1, -1,
27, 145, 146, -1, -1, -1, -1, -1,
28, 147, 148, -1, -1, -1, -1, -1,
29, 149, 150, -1, -1, -1, -1, -1,
30, 151, 152, -1, -1, -1, -1, -1,
31, 153, 154, -1, -1, -1, -1, -1,
32, 155, 156, -1, -1, -1, -1, -1,
33, 157, 158, -1, -1, -1, -1, -1,
34, 159, 160, -1, -1, -1, -1, -1,
35, 161, 162, -1, -1, -1, -1, -1,
36, 163, 164, -1, -1, -1, -1, -1,
37, 165, 166, -1, -1, -1, -1, -1,
38, 167, 168, -1, -1, -1, -1, -1,
39, 169, 170, -1, -1, -1, -1, -1,
40, 171, 172, -1, -1, -1, -1, -1,
41, 173, 174, -1, -1, -1, -1, -1,
42, 175, 176, -1, -1, -1, -1, -1,
43, 177, 178, -1, -1, -1, -1, -1,
44, 179, 180, -1, -1, -1, -1, -1,
45, 181, 182, -1, -1, -1, -1, -1,
46, 183, 184, -1, -1, -1, -1, -1,
47, 185, 186, -1, -1, -1, -1, -1,
48, 187, 188, -1, -1, -1, -1, -1,
49, 189, 190, -1, -1, -1, -1, -1,
50, 191, 192, -1, -1, -1, -1, -1,
51, 193, 194, -1, -1, -1, -1, -1,
52, 195, 196, -1, -1, -1, -1, -1,
53, 197, 198, -1, -1, -1, -1, -1,
54, 199, 200, -1, -1, -1, -1, -1,
55, 201, 202, -1, -1, -1, -1, -1,
56, 203, 204, -1, -1, -1, -1, -1,
57, 205, 206, -1, -1, -1, -1, -1,
58, 207, 208, -1, -1, -1, -1, -1,
59, 209, 210, -1, -1, -1, -1, -1,
60, 211, 212, -1, -1, -1, -1, -1,
61, 213, 214, -1, -1, -1, -1, -1,
62, 215, 216, -1, -1, -1, -1, -1
};
// table (uncompressed) of the c->v message indexes (-1=unused entry)
static const int qra_c2vmidx[qra_C*qra_MAXCDEG] = {
0, -1, -1, 1, -1, -1, 2, -1, -1, 3, -1, -1,
4, -1, -1, 5, -1, -1, 6, -1, -1, 7, -1, -1,
8, -1, -1, 9, -1, -1, 10, -1, -1, 11, -1, -1,
12, -1, -1, 13, -1, -1, 14, -1, -1, 15, -1, -1,
16, -1, -1, 17, -1, -1, 18, -1, -1, 19, -1, -1,
20, -1, -1, 21, -1, -1, 22, -1, -1, 23, -1, -1,
24, -1, -1, 25, -1, -1, 26, -1, -1, 27, -1, -1,
28, -1, -1, 29, -1, -1, 30, -1, -1, 31, -1, -1,
32, -1, -1, 33, -1, -1, 34, -1, -1, 35, -1, -1,
36, -1, -1, 37, -1, -1, 38, -1, -1, 39, -1, -1,
40, -1, -1, 41, -1, -1, 42, -1, -1, 43, -1, -1,
44, -1, -1, 45, -1, -1, 46, -1, -1, 47, -1, -1,
48, -1, -1, 49, -1, -1, 50, -1, -1, 51, -1, -1,
52, -1, -1, 53, -1, -1, 54, -1, -1, 55, -1, -1,
56, -1, -1, 57, -1, -1, 58, -1, -1, 59, -1, -1,
60, -1, -1, 61, -1, -1, 62, -1, -1, 63, 115, -1,
64, 116, 117, 65, 118, 119, 66, 120, 121, 67, 122, 123,
68, 124, 125, 69, 126, 127, 70, 128, 129, 71, 130, 131,
72, 132, 133, 73, 134, 135, 74, 136, 137, 75, 138, 139,
76, 140, 141, 77, 142, 143, 78, 144, 145, 79, 146, 147,
80, 148, 149, 81, 150, 151, 82, 152, 153, 83, 154, 155,
84, 156, 157, 85, 158, 159, 86, 160, 161, 87, 162, 163,
88, 164, 165, 89, 166, 167, 90, 168, 169, 91, 170, 171,
92, 172, 173, 93, 174, 175, 94, 176, 177, 95, 178, 179,
96, 180, 181, 97, 182, 183, 98, 184, 185, 99, 186, 187,
100, 188, 189, 101, 190, 191, 102, 192, 193, 103, 194, 195,
104, 196, 197, 105, 198, 199, 106, 200, 201, 107, 202, 203,
108, 204, 205, 109, 206, 207, 110, 208, 209, 111, 210, 211,
112, 212, 213, 113, 214, 215, 114, 216, -1
};
// permutation matrix to compute Prob(x*alfa^logw)
static const unsigned int qra_pmat[qra_M*qra_M] = {
0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15,
16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47,
48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63,
0, 33, 1, 32, 2, 35, 3, 34, 4, 37, 5, 36, 6, 39, 7, 38,
8, 41, 9, 40, 10, 43, 11, 42, 12, 45, 13, 44, 14, 47, 15, 46,
16, 49, 17, 48, 18, 51, 19, 50, 20, 53, 21, 52, 22, 55, 23, 54,
24, 57, 25, 56, 26, 59, 27, 58, 28, 61, 29, 60, 30, 63, 31, 62,
0, 49, 33, 16, 1, 48, 32, 17, 2, 51, 35, 18, 3, 50, 34, 19,
4, 53, 37, 20, 5, 52, 36, 21, 6, 55, 39, 22, 7, 54, 38, 23,
8, 57, 41, 24, 9, 56, 40, 25, 10, 59, 43, 26, 11, 58, 42, 27,
12, 61, 45, 28, 13, 60, 44, 29, 14, 63, 47, 30, 15, 62, 46, 31,
0, 57, 49, 8, 33, 24, 16, 41, 1, 56, 48, 9, 32, 25, 17, 40,
2, 59, 51, 10, 35, 26, 18, 43, 3, 58, 50, 11, 34, 27, 19, 42,
4, 61, 53, 12, 37, 28, 20, 45, 5, 60, 52, 13, 36, 29, 21, 44,
6, 63, 55, 14, 39, 30, 22, 47, 7, 62, 54, 15, 38, 31, 23, 46,
0, 61, 57, 4, 49, 12, 8, 53, 33, 28, 24, 37, 16, 45, 41, 20,
1, 60, 56, 5, 48, 13, 9, 52, 32, 29, 25, 36, 17, 44, 40, 21,
2, 63, 59, 6, 51, 14, 10, 55, 35, 30, 26, 39, 18, 47, 43, 22,
3, 62, 58, 7, 50, 15, 11, 54, 34, 31, 27, 38, 19, 46, 42, 23,
0, 63, 61, 2, 57, 6, 4, 59, 49, 14, 12, 51, 8, 55, 53, 10,
33, 30, 28, 35, 24, 39, 37, 26, 16, 47, 45, 18, 41, 22, 20, 43,
1, 62, 60, 3, 56, 7, 5, 58, 48, 15, 13, 50, 9, 54, 52, 11,
32, 31, 29, 34, 25, 38, 36, 27, 17, 46, 44, 19, 40, 23, 21, 42,
0, 62, 63, 1, 61, 3, 2, 60, 57, 7, 6, 56, 4, 58, 59, 5,
49, 15, 14, 48, 12, 50, 51, 13, 8, 54, 55, 9, 53, 11, 10, 52,
33, 31, 30, 32, 28, 34, 35, 29, 24, 38, 39, 25, 37, 27, 26, 36,
16, 46, 47, 17, 45, 19, 18, 44, 41, 23, 22, 40, 20, 42, 43, 21,
0, 31, 62, 33, 63, 32, 1, 30, 61, 34, 3, 28, 2, 29, 60, 35,
57, 38, 7, 24, 6, 25, 56, 39, 4, 27, 58, 37, 59, 36, 5, 26,
49, 46, 15, 16, 14, 17, 48, 47, 12, 19, 50, 45, 51, 44, 13, 18,
8, 23, 54, 41, 55, 40, 9, 22, 53, 42, 11, 20, 10, 21, 52, 43,
0, 46, 31, 49, 62, 16, 33, 15, 63, 17, 32, 14, 1, 47, 30, 48,
61, 19, 34, 12, 3, 45, 28, 50, 2, 44, 29, 51, 60, 18, 35, 13,
57, 23, 38, 8, 7, 41, 24, 54, 6, 40, 25, 55, 56, 22, 39, 9,
4, 42, 27, 53, 58, 20, 37, 11, 59, 21, 36, 10, 5, 43, 26, 52,
0, 23, 46, 57, 31, 8, 49, 38, 62, 41, 16, 7, 33, 54, 15, 24,
63, 40, 17, 6, 32, 55, 14, 25, 1, 22, 47, 56, 30, 9, 48, 39,
61, 42, 19, 4, 34, 53, 12, 27, 3, 20, 45, 58, 28, 11, 50, 37,
2, 21, 44, 59, 29, 10, 51, 36, 60, 43, 18, 5, 35, 52, 13, 26,
0, 42, 23, 61, 46, 4, 57, 19, 31, 53, 8, 34, 49, 27, 38, 12,
62, 20, 41, 3, 16, 58, 7, 45, 33, 11, 54, 28, 15, 37, 24, 50,
63, 21, 40, 2, 17, 59, 6, 44, 32, 10, 55, 29, 14, 36, 25, 51,
1, 43, 22, 60, 47, 5, 56, 18, 30, 52, 9, 35, 48, 26, 39, 13,
0, 21, 42, 63, 23, 2, 61, 40, 46, 59, 4, 17, 57, 44, 19, 6,
31, 10, 53, 32, 8, 29, 34, 55, 49, 36, 27, 14, 38, 51, 12, 25,
62, 43, 20, 1, 41, 60, 3, 22, 16, 5, 58, 47, 7, 18, 45, 56,
33, 52, 11, 30, 54, 35, 28, 9, 15, 26, 37, 48, 24, 13, 50, 39,
0, 43, 21, 62, 42, 1, 63, 20, 23, 60, 2, 41, 61, 22, 40, 3,
46, 5, 59, 16, 4, 47, 17, 58, 57, 18, 44, 7, 19, 56, 6, 45,
31, 52, 10, 33, 53, 30, 32, 11, 8, 35, 29, 54, 34, 9, 55, 28,
49, 26, 36, 15, 27, 48, 14, 37, 38, 13, 51, 24, 12, 39, 25, 50,
0, 52, 43, 31, 21, 33, 62, 10, 42, 30, 1, 53, 63, 11, 20, 32,
23, 35, 60, 8, 2, 54, 41, 29, 61, 9, 22, 34, 40, 28, 3, 55,
46, 26, 5, 49, 59, 15, 16, 36, 4, 48, 47, 27, 17, 37, 58, 14,
57, 13, 18, 38, 44, 24, 7, 51, 19, 39, 56, 12, 6, 50, 45, 25,
0, 26, 52, 46, 43, 49, 31, 5, 21, 15, 33, 59, 62, 36, 10, 16,
42, 48, 30, 4, 1, 27, 53, 47, 63, 37, 11, 17, 20, 14, 32, 58,
23, 13, 35, 57, 60, 38, 8, 18, 2, 24, 54, 44, 41, 51, 29, 7,
61, 39, 9, 19, 22, 12, 34, 56, 40, 50, 28, 6, 3, 25, 55, 45,
0, 13, 26, 23, 52, 57, 46, 35, 43, 38, 49, 60, 31, 18, 5, 8,
21, 24, 15, 2, 33, 44, 59, 54, 62, 51, 36, 41, 10, 7, 16, 29,
42, 39, 48, 61, 30, 19, 4, 9, 1, 12, 27, 22, 53, 56, 47, 34,
63, 50, 37, 40, 11, 6, 17, 28, 20, 25, 14, 3, 32, 45, 58, 55,
0, 39, 13, 42, 26, 61, 23, 48, 52, 19, 57, 30, 46, 9, 35, 4,
43, 12, 38, 1, 49, 22, 60, 27, 31, 56, 18, 53, 5, 34, 8, 47,
21, 50, 24, 63, 15, 40, 2, 37, 33, 6, 44, 11, 59, 28, 54, 17,
62, 25, 51, 20, 36, 3, 41, 14, 10, 45, 7, 32, 16, 55, 29, 58,
0, 50, 39, 21, 13, 63, 42, 24, 26, 40, 61, 15, 23, 37, 48, 2,
52, 6, 19, 33, 57, 11, 30, 44, 46, 28, 9, 59, 35, 17, 4, 54,
43, 25, 12, 62, 38, 20, 1, 51, 49, 3, 22, 36, 60, 14, 27, 41,
31, 45, 56, 10, 18, 32, 53, 7, 5, 55, 34, 16, 8, 58, 47, 29,
0, 25, 50, 43, 39, 62, 21, 12, 13, 20, 63, 38, 42, 51, 24, 1,
26, 3, 40, 49, 61, 36, 15, 22, 23, 14, 37, 60, 48, 41, 2, 27,
52, 45, 6, 31, 19, 10, 33, 56, 57, 32, 11, 18, 30, 7, 44, 53,
46, 55, 28, 5, 9, 16, 59, 34, 35, 58, 17, 8, 4, 29, 54, 47,
0, 45, 25, 52, 50, 31, 43, 6, 39, 10, 62, 19, 21, 56, 12, 33,
13, 32, 20, 57, 63, 18, 38, 11, 42, 7, 51, 30, 24, 53, 1, 44,
26, 55, 3, 46, 40, 5, 49, 28, 61, 16, 36, 9, 15, 34, 22, 59,
23, 58, 14, 35, 37, 8, 60, 17, 48, 29, 41, 4, 2, 47, 27, 54,
0, 55, 45, 26, 25, 46, 52, 3, 50, 5, 31, 40, 43, 28, 6, 49,
39, 16, 10, 61, 62, 9, 19, 36, 21, 34, 56, 15, 12, 59, 33, 22,
13, 58, 32, 23, 20, 35, 57, 14, 63, 8, 18, 37, 38, 17, 11, 60,
42, 29, 7, 48, 51, 4, 30, 41, 24, 47, 53, 2, 1, 54, 44, 27,
0, 58, 55, 13, 45, 23, 26, 32, 25, 35, 46, 20, 52, 14, 3, 57,
50, 8, 5, 63, 31, 37, 40, 18, 43, 17, 28, 38, 6, 60, 49, 11,
39, 29, 16, 42, 10, 48, 61, 7, 62, 4, 9, 51, 19, 41, 36, 30,
21, 47, 34, 24, 56, 2, 15, 53, 12, 54, 59, 1, 33, 27, 22, 44,
0, 29, 58, 39, 55, 42, 13, 16, 45, 48, 23, 10, 26, 7, 32, 61,
25, 4, 35, 62, 46, 51, 20, 9, 52, 41, 14, 19, 3, 30, 57, 36,
50, 47, 8, 21, 5, 24, 63, 34, 31, 2, 37, 56, 40, 53, 18, 15,
43, 54, 17, 12, 28, 1, 38, 59, 6, 27, 60, 33, 49, 44, 11, 22,
0, 47, 29, 50, 58, 21, 39, 8, 55, 24, 42, 5, 13, 34, 16, 63,
45, 2, 48, 31, 23, 56, 10, 37, 26, 53, 7, 40, 32, 15, 61, 18,
25, 54, 4, 43, 35, 12, 62, 17, 46, 1, 51, 28, 20, 59, 9, 38,
52, 27, 41, 6, 14, 33, 19, 60, 3, 44, 30, 49, 57, 22, 36, 11,
0, 54, 47, 25, 29, 43, 50, 4, 58, 12, 21, 35, 39, 17, 8, 62,
55, 1, 24, 46, 42, 28, 5, 51, 13, 59, 34, 20, 16, 38, 63, 9,
45, 27, 2, 52, 48, 6, 31, 41, 23, 33, 56, 14, 10, 60, 37, 19,
26, 44, 53, 3, 7, 49, 40, 30, 32, 22, 15, 57, 61, 11, 18, 36,
0, 27, 54, 45, 47, 52, 25, 2, 29, 6, 43, 48, 50, 41, 4, 31,
58, 33, 12, 23, 21, 14, 35, 56, 39, 60, 17, 10, 8, 19, 62, 37,
55, 44, 1, 26, 24, 3, 46, 53, 42, 49, 28, 7, 5, 30, 51, 40,
13, 22, 59, 32, 34, 57, 20, 15, 16, 11, 38, 61, 63, 36, 9, 18,
0, 44, 27, 55, 54, 26, 45, 1, 47, 3, 52, 24, 25, 53, 2, 46,
29, 49, 6, 42, 43, 7, 48, 28, 50, 30, 41, 5, 4, 40, 31, 51,
58, 22, 33, 13, 12, 32, 23, 59, 21, 57, 14, 34, 35, 15, 56, 20,
39, 11, 60, 16, 17, 61, 10, 38, 8, 36, 19, 63, 62, 18, 37, 9,
0, 22, 44, 58, 27, 13, 55, 33, 54, 32, 26, 12, 45, 59, 1, 23,
47, 57, 3, 21, 52, 34, 24, 14, 25, 15, 53, 35, 2, 20, 46, 56,
29, 11, 49, 39, 6, 16, 42, 60, 43, 61, 7, 17, 48, 38, 28, 10,
50, 36, 30, 8, 41, 63, 5, 19, 4, 18, 40, 62, 31, 9, 51, 37,
0, 11, 22, 29, 44, 39, 58, 49, 27, 16, 13, 6, 55, 60, 33, 42,
54, 61, 32, 43, 26, 17, 12, 7, 45, 38, 59, 48, 1, 10, 23, 28,
47, 36, 57, 50, 3, 8, 21, 30, 52, 63, 34, 41, 24, 19, 14, 5,
25, 18, 15, 4, 53, 62, 35, 40, 2, 9, 20, 31, 46, 37, 56, 51,
0, 36, 11, 47, 22, 50, 29, 57, 44, 8, 39, 3, 58, 30, 49, 21,
27, 63, 16, 52, 13, 41, 6, 34, 55, 19, 60, 24, 33, 5, 42, 14,
54, 18, 61, 25, 32, 4, 43, 15, 26, 62, 17, 53, 12, 40, 7, 35,
45, 9, 38, 2, 59, 31, 48, 20, 1, 37, 10, 46, 23, 51, 28, 56,
0, 18, 36, 54, 11, 25, 47, 61, 22, 4, 50, 32, 29, 15, 57, 43,
44, 62, 8, 26, 39, 53, 3, 17, 58, 40, 30, 12, 49, 35, 21, 7,
27, 9, 63, 45, 16, 2, 52, 38, 13, 31, 41, 59, 6, 20, 34, 48,
55, 37, 19, 1, 60, 46, 24, 10, 33, 51, 5, 23, 42, 56, 14, 28,
0, 9, 18, 27, 36, 45, 54, 63, 11, 2, 25, 16, 47, 38, 61, 52,
22, 31, 4, 13, 50, 59, 32, 41, 29, 20, 15, 6, 57, 48, 43, 34,
44, 37, 62, 55, 8, 1, 26, 19, 39, 46, 53, 60, 3, 10, 17, 24,
58, 51, 40, 33, 30, 23, 12, 5, 49, 56, 35, 42, 21, 28, 7, 14,
0, 37, 9, 44, 18, 55, 27, 62, 36, 1, 45, 8, 54, 19, 63, 26,
11, 46, 2, 39, 25, 60, 16, 53, 47, 10, 38, 3, 61, 24, 52, 17,
22, 51, 31, 58, 4, 33, 13, 40, 50, 23, 59, 30, 32, 5, 41, 12,
29, 56, 20, 49, 15, 42, 6, 35, 57, 28, 48, 21, 43, 14, 34, 7,
0, 51, 37, 22, 9, 58, 44, 31, 18, 33, 55, 4, 27, 40, 62, 13,
36, 23, 1, 50, 45, 30, 8, 59, 54, 5, 19, 32, 63, 12, 26, 41,
11, 56, 46, 29, 2, 49, 39, 20, 25, 42, 60, 15, 16, 35, 53, 6,
47, 28, 10, 57, 38, 21, 3, 48, 61, 14, 24, 43, 52, 7, 17, 34,
0, 56, 51, 11, 37, 29, 22, 46, 9, 49, 58, 2, 44, 20, 31, 39,
18, 42, 33, 25, 55, 15, 4, 60, 27, 35, 40, 16, 62, 6, 13, 53,
36, 28, 23, 47, 1, 57, 50, 10, 45, 21, 30, 38, 8, 48, 59, 3,
54, 14, 5, 61, 19, 43, 32, 24, 63, 7, 12, 52, 26, 34, 41, 17,
0, 28, 56, 36, 51, 47, 11, 23, 37, 57, 29, 1, 22, 10, 46, 50,
9, 21, 49, 45, 58, 38, 2, 30, 44, 48, 20, 8, 31, 3, 39, 59,
18, 14, 42, 54, 33, 61, 25, 5, 55, 43, 15, 19, 4, 24, 60, 32,
27, 7, 35, 63, 40, 52, 16, 12, 62, 34, 6, 26, 13, 17, 53, 41,
0, 14, 28, 18, 56, 54, 36, 42, 51, 61, 47, 33, 11, 5, 23, 25,
37, 43, 57, 55, 29, 19, 1, 15, 22, 24, 10, 4, 46, 32, 50, 60,
9, 7, 21, 27, 49, 63, 45, 35, 58, 52, 38, 40, 2, 12, 30, 16,
44, 34, 48, 62, 20, 26, 8, 6, 31, 17, 3, 13, 39, 41, 59, 53,
0, 7, 14, 9, 28, 27, 18, 21, 56, 63, 54, 49, 36, 35, 42, 45,
51, 52, 61, 58, 47, 40, 33, 38, 11, 12, 5, 2, 23, 16, 25, 30,
37, 34, 43, 44, 57, 62, 55, 48, 29, 26, 19, 20, 1, 6, 15, 8,
22, 17, 24, 31, 10, 13, 4, 3, 46, 41, 32, 39, 50, 53, 60, 59,
0, 34, 7, 37, 14, 44, 9, 43, 28, 62, 27, 57, 18, 48, 21, 55,
56, 26, 63, 29, 54, 20, 49, 19, 36, 6, 35, 1, 42, 8, 45, 15,
51, 17, 52, 22, 61, 31, 58, 24, 47, 13, 40, 10, 33, 3, 38, 4,
11, 41, 12, 46, 5, 39, 2, 32, 23, 53, 16, 50, 25, 59, 30, 60,
0, 17, 34, 51, 7, 22, 37, 52, 14, 31, 44, 61, 9, 24, 43, 58,
28, 13, 62, 47, 27, 10, 57, 40, 18, 3, 48, 33, 21, 4, 55, 38,
56, 41, 26, 11, 63, 46, 29, 12, 54, 39, 20, 5, 49, 32, 19, 2,
36, 53, 6, 23, 35, 50, 1, 16, 42, 59, 8, 25, 45, 60, 15, 30,
0, 41, 17, 56, 34, 11, 51, 26, 7, 46, 22, 63, 37, 12, 52, 29,
14, 39, 31, 54, 44, 5, 61, 20, 9, 32, 24, 49, 43, 2, 58, 19,
28, 53, 13, 36, 62, 23, 47, 6, 27, 50, 10, 35, 57, 16, 40, 1,
18, 59, 3, 42, 48, 25, 33, 8, 21, 60, 4, 45, 55, 30, 38, 15,
0, 53, 41, 28, 17, 36, 56, 13, 34, 23, 11, 62, 51, 6, 26, 47,
7, 50, 46, 27, 22, 35, 63, 10, 37, 16, 12, 57, 52, 1, 29, 40,
14, 59, 39, 18, 31, 42, 54, 3, 44, 25, 5, 48, 61, 8, 20, 33,
9, 60, 32, 21, 24, 45, 49, 4, 43, 30, 2, 55, 58, 15, 19, 38,
0, 59, 53, 14, 41, 18, 28, 39, 17, 42, 36, 31, 56, 3, 13, 54,
34, 25, 23, 44, 11, 48, 62, 5, 51, 8, 6, 61, 26, 33, 47, 20,
7, 60, 50, 9, 46, 21, 27, 32, 22, 45, 35, 24, 63, 4, 10, 49,
37, 30, 16, 43, 12, 55, 57, 2, 52, 15, 1, 58, 29, 38, 40, 19,
0, 60, 59, 7, 53, 9, 14, 50, 41, 21, 18, 46, 28, 32, 39, 27,
17, 45, 42, 22, 36, 24, 31, 35, 56, 4, 3, 63, 13, 49, 54, 10,
34, 30, 25, 37, 23, 43, 44, 16, 11, 55, 48, 12, 62, 2, 5, 57,
51, 15, 8, 52, 6, 58, 61, 1, 26, 38, 33, 29, 47, 19, 20, 40,
0, 30, 60, 34, 59, 37, 7, 25, 53, 43, 9, 23, 14, 16, 50, 44,
41, 55, 21, 11, 18, 12, 46, 48, 28, 2, 32, 62, 39, 57, 27, 5,
17, 15, 45, 51, 42, 52, 22, 8, 36, 58, 24, 6, 31, 1, 35, 61,
56, 38, 4, 26, 3, 29, 63, 33, 13, 19, 49, 47, 54, 40, 10, 20,
0, 15, 30, 17, 60, 51, 34, 45, 59, 52, 37, 42, 7, 8, 25, 22,
53, 58, 43, 36, 9, 6, 23, 24, 14, 1, 16, 31, 50, 61, 44, 35,
41, 38, 55, 56, 21, 26, 11, 4, 18, 29, 12, 3, 46, 33, 48, 63,
28, 19, 2, 13, 32, 47, 62, 49, 39, 40, 57, 54, 27, 20, 5, 10,
0, 38, 15, 41, 30, 56, 17, 55, 60, 26, 51, 21, 34, 4, 45, 11,
59, 29, 52, 18, 37, 3, 42, 12, 7, 33, 8, 46, 25, 63, 22, 48,
53, 19, 58, 28, 43, 13, 36, 2, 9, 47, 6, 32, 23, 49, 24, 62,
14, 40, 1, 39, 16, 54, 31, 57, 50, 20, 61, 27, 44, 10, 35, 5,
0, 19, 38, 53, 15, 28, 41, 58, 30, 13, 56, 43, 17, 2, 55, 36,
60, 47, 26, 9, 51, 32, 21, 6, 34, 49, 4, 23, 45, 62, 11, 24,
59, 40, 29, 14, 52, 39, 18, 1, 37, 54, 3, 16, 42, 57, 12, 31,
7, 20, 33, 50, 8, 27, 46, 61, 25, 10, 63, 44, 22, 5, 48, 35,
0, 40, 19, 59, 38, 14, 53, 29, 15, 39, 28, 52, 41, 1, 58, 18,
30, 54, 13, 37, 56, 16, 43, 3, 17, 57, 2, 42, 55, 31, 36, 12,
60, 20, 47, 7, 26, 50, 9, 33, 51, 27, 32, 8, 21, 61, 6, 46,
34, 10, 49, 25, 4, 44, 23, 63, 45, 5, 62, 22, 11, 35, 24, 48,
0, 20, 40, 60, 19, 7, 59, 47, 38, 50, 14, 26, 53, 33, 29, 9,
15, 27, 39, 51, 28, 8, 52, 32, 41, 61, 1, 21, 58, 46, 18, 6,
30, 10, 54, 34, 13, 25, 37, 49, 56, 44, 16, 4, 43, 63, 3, 23,
17, 5, 57, 45, 2, 22, 42, 62, 55, 35, 31, 11, 36, 48, 12, 24,
0, 10, 20, 30, 40, 34, 60, 54, 19, 25, 7, 13, 59, 49, 47, 37,
38, 44, 50, 56, 14, 4, 26, 16, 53, 63, 33, 43, 29, 23, 9, 3,
15, 5, 27, 17, 39, 45, 51, 57, 28, 22, 8, 2, 52, 62, 32, 42,
41, 35, 61, 55, 1, 11, 21, 31, 58, 48, 46, 36, 18, 24, 6, 12,
0, 5, 10, 15, 20, 17, 30, 27, 40, 45, 34, 39, 60, 57, 54, 51,
19, 22, 25, 28, 7, 2, 13, 8, 59, 62, 49, 52, 47, 42, 37, 32,
38, 35, 44, 41, 50, 55, 56, 61, 14, 11, 4, 1, 26, 31, 16, 21,
53, 48, 63, 58, 33, 36, 43, 46, 29, 24, 23, 18, 9, 12, 3, 6,
0, 35, 5, 38, 10, 41, 15, 44, 20, 55, 17, 50, 30, 61, 27, 56,
40, 11, 45, 14, 34, 1, 39, 4, 60, 31, 57, 26, 54, 21, 51, 16,
19, 48, 22, 53, 25, 58, 28, 63, 7, 36, 2, 33, 13, 46, 8, 43,
59, 24, 62, 29, 49, 18, 52, 23, 47, 12, 42, 9, 37, 6, 32, 3,
0, 48, 35, 19, 5, 53, 38, 22, 10, 58, 41, 25, 15, 63, 44, 28,
20, 36, 55, 7, 17, 33, 50, 2, 30, 46, 61, 13, 27, 43, 56, 8,
40, 24, 11, 59, 45, 29, 14, 62, 34, 18, 1, 49, 39, 23, 4, 52,
60, 12, 31, 47, 57, 9, 26, 42, 54, 6, 21, 37, 51, 3, 16, 32,
0, 24, 48, 40, 35, 59, 19, 11, 5, 29, 53, 45, 38, 62, 22, 14,
10, 18, 58, 34, 41, 49, 25, 1, 15, 23, 63, 39, 44, 52, 28, 4,
20, 12, 36, 60, 55, 47, 7, 31, 17, 9, 33, 57, 50, 42, 2, 26,
30, 6, 46, 54, 61, 37, 13, 21, 27, 3, 43, 51, 56, 32, 8, 16,
0, 12, 24, 20, 48, 60, 40, 36, 35, 47, 59, 55, 19, 31, 11, 7,
5, 9, 29, 17, 53, 57, 45, 33, 38, 42, 62, 50, 22, 26, 14, 2,
10, 6, 18, 30, 58, 54, 34, 46, 41, 37, 49, 61, 25, 21, 1, 13,
15, 3, 23, 27, 63, 51, 39, 43, 44, 32, 52, 56, 28, 16, 4, 8,
0, 6, 12, 10, 24, 30, 20, 18, 48, 54, 60, 58, 40, 46, 36, 34,
35, 37, 47, 41, 59, 61, 55, 49, 19, 21, 31, 25, 11, 13, 7, 1,
5, 3, 9, 15, 29, 27, 17, 23, 53, 51, 57, 63, 45, 43, 33, 39,
38, 32, 42, 44, 62, 56, 50, 52, 22, 16, 26, 28, 14, 8, 2, 4,
0, 3, 6, 5, 12, 15, 10, 9, 24, 27, 30, 29, 20, 23, 18, 17,
48, 51, 54, 53, 60, 63, 58, 57, 40, 43, 46, 45, 36, 39, 34, 33,
35, 32, 37, 38, 47, 44, 41, 42, 59, 56, 61, 62, 55, 52, 49, 50,
19, 16, 21, 22, 31, 28, 25, 26, 11, 8, 13, 14, 7, 4, 1, 2,
0, 32, 3, 35, 6, 38, 5, 37, 12, 44, 15, 47, 10, 42, 9, 41,
24, 56, 27, 59, 30, 62, 29, 61, 20, 52, 23, 55, 18, 50, 17, 49,
48, 16, 51, 19, 54, 22, 53, 21, 60, 28, 63, 31, 58, 26, 57, 25,
40, 8, 43, 11, 46, 14, 45, 13, 36, 4, 39, 7, 34, 2, 33, 1,
0, 16, 32, 48, 3, 19, 35, 51, 6, 22, 38, 54, 5, 21, 37, 53,
12, 28, 44, 60, 15, 31, 47, 63, 10, 26, 42, 58, 9, 25, 41, 57,
24, 8, 56, 40, 27, 11, 59, 43, 30, 14, 62, 46, 29, 13, 61, 45,
20, 4, 52, 36, 23, 7, 55, 39, 18, 2, 50, 34, 17, 1, 49, 33,
0, 8, 16, 24, 32, 40, 48, 56, 3, 11, 19, 27, 35, 43, 51, 59,
6, 14, 22, 30, 38, 46, 54, 62, 5, 13, 21, 29, 37, 45, 53, 61,
12, 4, 28, 20, 44, 36, 60, 52, 15, 7, 31, 23, 47, 39, 63, 55,
10, 2, 26, 18, 42, 34, 58, 50, 9, 1, 25, 17, 41, 33, 57, 49,
0, 4, 8, 12, 16, 20, 24, 28, 32, 36, 40, 44, 48, 52, 56, 60,
3, 7, 11, 15, 19, 23, 27, 31, 35, 39, 43, 47, 51, 55, 59, 63,
6, 2, 14, 10, 22, 18, 30, 26, 38, 34, 46, 42, 54, 50, 62, 58,
5, 1, 13, 9, 21, 17, 29, 25, 37, 33, 45, 41, 53, 49, 61, 57,
0, 2, 4, 6, 8, 10, 12, 14, 16, 18, 20, 22, 24, 26, 28, 30,
32, 34, 36, 38, 40, 42, 44, 46, 48, 50, 52, 54, 56, 58, 60, 62,
3, 1, 7, 5, 11, 9, 15, 13, 19, 17, 23, 21, 27, 25, 31, 29,
35, 33, 39, 37, 43, 41, 47, 45, 51, 49, 55, 53, 59, 57, 63, 61
};
const qracode qra_12_63_64_irr_b = {
qra_K,
qra_N,
qra_m,
qra_M,
qra_a,
qra_NC,
qra_V,
qra_C,
qra_NMSG,
qra_MAXVDEG,
qra_MAXCDEG,
QRATYPE_NORMAL,
qra_R,
CODE_NAME,
qra_acc_input_idx,
qra_acc_input_wlog,
qra_log,
qra_exp,
qra_msgw,
qra_vdeg,
qra_cdeg,
qra_v2cmidx,
qra_c2vmidx,
qra_pmat
};
#undef qra_K
#undef qra_N
#undef qra_m
#undef qra_M
#undef qra_a
#undef qra_NC
#undef qra_V
#undef qra_C
#undef qra_NMSG
#undef qra_MAXVDEG
#undef qra_MAXCDEG
#undef qra_R
#undef CODE_NAME

View File

@ -0,0 +1,39 @@
// qra12_63_64_irr_b.h
// Code tables and defines for Q-ary RA code (12,63) over GF(64)
// Code Name: qra12_63_64_irr_b
// (12,63) RA Code over GF(64) - RF=333344455567
// (c) 2016 - Nico Palermo - IV3NWV - Microtelecom Srl, Italy
// This file is part of the qracodes project, a Forward Error Control
// encoding/decoding package based on Q-ary RA (Repeat and Accumulate) LDPC codes.
//
// qracodes is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
// qracodes is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with qracodes source distribution.
// If not, see <http://www.gnu.org/licenses/>.
#ifndef _qra12_63_64_irr_b_h
#define _qra12_63_64_irr_b_h
#include "qracodes.h"
#ifdef __cplusplus
extern "C" {
#endif
extern const qracode qra_12_63_64_irr_b;
#ifdef __cplusplus
}
#endif
#endif // _qra12_63_64_irr_b_h

View File

@ -0,0 +1,534 @@
// qra13_64_64_irr_e.c
// Encoding/Decoding tables for Q-ary RA code (13,64) over GF(64)
// Code Name: qra13_64_64_irr_e
// (13,64) RA Code over GF(64) RF=[3x4 4x4 6x1 3x2 5x1 7x1]/18
// (c) 2016 - Nico Palermo - IV3NWV - Microtelecom Srl, Italy
// This file is part of the qracodes project, a Forward Error Control
// encoding/decoding package based on Q-ary RA (Repeat and Accumulate) LDPC codes.
//
// qracodes is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
// qracodes is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with qracodes source distribution.
// If not, see <http://www.gnu.org/licenses/>.
#include "qra13_64_64_irr_e.h"
#define qra_K 13 // number of information symbols
#define qra_N 64 // codeword length in symbols
#define qra_m 6 // bits/symbol
#define qra_M 64 // Symbol alphabet cardinality
#define qra_a 1 // grouping factor
#define qra_NC 51 // number of check symbols (N-K)
// Defines used by the message passing decoder --------
#define qra_V 64 // number of variables in the code graph (N)
#define qra_C 116 // number of factors in the code graph (N +(N-K)+1)
#define qra_NMSG 218 // number of msgs in the code graph
#define qra_MAXVDEG 8 // maximum variable degree
#define qra_MAXCDEG 3 // maximum factor degree
#define qra_R 0.20313f // code rate (K/N)
#define CODE_NAME "qra_13_64_64_irr_e"
// table of the systematic symbols indexes in the accumulator chain
static const int qra_acc_input_idx[qra_NC+1] = {
12, 4, 3, 9, 0, 11, 6, 8, 12, 1,
2, 7, 4, 11, 3, 5, 9, 8, 12, 7,
2, 4, 10, 3, 5, 11, 12, 8, 9, 6,
7, 2, 5, 4, 12, 8, 11, 1, 6, 7,
0, 10, 12, 8, 11, 5, 6, 1, 0, 10,
12, 8
};
// table of the systematic symbols weight logarithms over GF(M)
static const unsigned int qra_acc_input_wlog[qra_NC+1] = {
0, 27, 0, 0, 0, 31, 28, 61, 31, 0,
0, 52, 22, 7, 19, 47, 44, 62, 32, 50,
52, 42, 48, 56, 40, 50, 51, 37, 37, 0,
5, 14, 0, 0, 18, 2, 0, 45, 21, 0,
62, 8, 11, 60, 36, 32, 17, 9, 5, 0,
53, 0
};
// table of the logarithms of the elements of GF(M) (log(0) never used)
static const int qra_log[qra_M] = {
-1, 0, 1, 6, 2, 12, 7, 26, 3, 32,
13, 35, 8, 48, 27, 18, 4, 24, 33, 16,
14, 52, 36, 54, 9, 45, 49, 38, 28, 41,
19, 56, 5, 62, 25, 11, 34, 31, 17, 47,
15, 23, 53, 51, 37, 44, 55, 40, 10, 61,
46, 30, 50, 22, 39, 43, 29, 60, 42, 21,
20, 59, 57, 58
};
// table of GF(M) elements given their logarithm
static const unsigned int qra_exp[qra_M-1] = {
1, 2, 4, 8, 16, 32, 3, 6, 12, 24,
48, 35, 5, 10, 20, 40, 19, 38, 15, 30,
60, 59, 53, 41, 17, 34, 7, 14, 28, 56,
51, 37, 9, 18, 36, 11, 22, 44, 27, 54,
47, 29, 58, 55, 45, 25, 50, 39, 13, 26,
52, 43, 21, 42, 23, 46, 31, 62, 63, 61,
57, 49, 33
};
// table of the messages weight logarithms over GF(M)
static const unsigned int qra_msgw[qra_NMSG] = {
0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 27, 0, 0, 0, 31,
28, 61, 31, 0, 0, 52, 22, 7, 19, 47,
44, 62, 32, 50, 52, 42, 48, 56, 40, 50,
51, 37, 37, 0, 5, 14, 0, 0, 18, 2,
0, 45, 21, 0, 62, 8, 11, 60, 36, 32,
17, 9, 5, 0, 53, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0
};
// table of the degrees of the variable nodes
static const unsigned int qra_vdeg[qra_V] = {
4, 4, 4, 4, 5, 5, 5, 5, 7, 4,
4, 6, 8, 3, 3, 3, 3, 3, 3, 3,
3, 3, 3, 3, 3, 3, 3, 3, 3, 3,
3, 3, 3, 3, 3, 3, 3, 3, 3, 3,
3, 3, 3, 3, 3, 3, 3, 3, 3, 3,
3, 3, 3, 3, 3, 3, 3, 3, 3, 3,
3, 3, 3, 3
};
// table of the degrees of the factor nodes
static const unsigned int qra_cdeg[qra_C] = {
1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 2, 3, 3, 3, 3, 3,
3, 3, 3, 3, 3, 3, 3, 3, 3, 3,
3, 3, 3, 3, 3, 3, 3, 3, 3, 3,
3, 3, 3, 3, 3, 3, 3, 3, 3, 3,
3, 3, 3, 3, 3, 3, 3, 3, 3, 3,
3, 3, 3, 3, 3, 2
};
// table (uncompressed) of the v->c message indexes (-1=unused entry)
static const int qra_v2cmidx[qra_V*qra_MAXVDEG] = {
0, 68, 104, 112, -1, -1, -1, -1,
1, 73, 101, 111, -1, -1, -1, -1,
2, 74, 84, 95, -1, -1, -1, -1,
3, 66, 78, 87, -1, -1, -1, -1,
4, 65, 76, 85, 97, -1, -1, -1,
5, 79, 88, 96, 109, -1, -1, -1,
6, 70, 93, 102, 110, -1, -1, -1,
7, 75, 83, 94, 103, -1, -1, -1,
8, 71, 81, 91, 99, 107, 115, -1,
9, 67, 80, 92, -1, -1, -1, -1,
10, 86, 105, 113, -1, -1, -1, -1,
11, 69, 77, 89, 100, 108, -1, -1,
12, 64, 72, 82, 90, 98, 106, 114,
13, 116, 117, -1, -1, -1, -1, -1,
14, 118, 119, -1, -1, -1, -1, -1,
15, 120, 121, -1, -1, -1, -1, -1,
16, 122, 123, -1, -1, -1, -1, -1,
17, 124, 125, -1, -1, -1, -1, -1,
18, 126, 127, -1, -1, -1, -1, -1,
19, 128, 129, -1, -1, -1, -1, -1,
20, 130, 131, -1, -1, -1, -1, -1,
21, 132, 133, -1, -1, -1, -1, -1,
22, 134, 135, -1, -1, -1, -1, -1,
23, 136, 137, -1, -1, -1, -1, -1,
24, 138, 139, -1, -1, -1, -1, -1,
25, 140, 141, -1, -1, -1, -1, -1,
26, 142, 143, -1, -1, -1, -1, -1,
27, 144, 145, -1, -1, -1, -1, -1,
28, 146, 147, -1, -1, -1, -1, -1,
29, 148, 149, -1, -1, -1, -1, -1,
30, 150, 151, -1, -1, -1, -1, -1,
31, 152, 153, -1, -1, -1, -1, -1,
32, 154, 155, -1, -1, -1, -1, -1,
33, 156, 157, -1, -1, -1, -1, -1,
34, 158, 159, -1, -1, -1, -1, -1,
35, 160, 161, -1, -1, -1, -1, -1,
36, 162, 163, -1, -1, -1, -1, -1,
37, 164, 165, -1, -1, -1, -1, -1,
38, 166, 167, -1, -1, -1, -1, -1,
39, 168, 169, -1, -1, -1, -1, -1,
40, 170, 171, -1, -1, -1, -1, -1,
41, 172, 173, -1, -1, -1, -1, -1,
42, 174, 175, -1, -1, -1, -1, -1,
43, 176, 177, -1, -1, -1, -1, -1,
44, 178, 179, -1, -1, -1, -1, -1,
45, 180, 181, -1, -1, -1, -1, -1,
46, 182, 183, -1, -1, -1, -1, -1,
47, 184, 185, -1, -1, -1, -1, -1,
48, 186, 187, -1, -1, -1, -1, -1,
49, 188, 189, -1, -1, -1, -1, -1,
50, 190, 191, -1, -1, -1, -1, -1,
51, 192, 193, -1, -1, -1, -1, -1,
52, 194, 195, -1, -1, -1, -1, -1,
53, 196, 197, -1, -1, -1, -1, -1,
54, 198, 199, -1, -1, -1, -1, -1,
55, 200, 201, -1, -1, -1, -1, -1,
56, 202, 203, -1, -1, -1, -1, -1,
57, 204, 205, -1, -1, -1, -1, -1,
58, 206, 207, -1, -1, -1, -1, -1,
59, 208, 209, -1, -1, -1, -1, -1,
60, 210, 211, -1, -1, -1, -1, -1,
61, 212, 213, -1, -1, -1, -1, -1,
62, 214, 215, -1, -1, -1, -1, -1,
63, 216, 217, -1, -1, -1, -1, -1
};
// table (uncompressed) of the c->v message indexes (-1=unused entry)
static const int qra_c2vmidx[qra_C*qra_MAXCDEG] = {
0, -1, -1, 1, -1, -1, 2, -1, -1, 3, -1, -1,
4, -1, -1, 5, -1, -1, 6, -1, -1, 7, -1, -1,
8, -1, -1, 9, -1, -1, 10, -1, -1, 11, -1, -1,
12, -1, -1, 13, -1, -1, 14, -1, -1, 15, -1, -1,
16, -1, -1, 17, -1, -1, 18, -1, -1, 19, -1, -1,
20, -1, -1, 21, -1, -1, 22, -1, -1, 23, -1, -1,
24, -1, -1, 25, -1, -1, 26, -1, -1, 27, -1, -1,
28, -1, -1, 29, -1, -1, 30, -1, -1, 31, -1, -1,
32, -1, -1, 33, -1, -1, 34, -1, -1, 35, -1, -1,
36, -1, -1, 37, -1, -1, 38, -1, -1, 39, -1, -1,
40, -1, -1, 41, -1, -1, 42, -1, -1, 43, -1, -1,
44, -1, -1, 45, -1, -1, 46, -1, -1, 47, -1, -1,
48, -1, -1, 49, -1, -1, 50, -1, -1, 51, -1, -1,
52, -1, -1, 53, -1, -1, 54, -1, -1, 55, -1, -1,
56, -1, -1, 57, -1, -1, 58, -1, -1, 59, -1, -1,
60, -1, -1, 61, -1, -1, 62, -1, -1, 63, -1, -1,
64, 116, -1, 65, 117, 118, 66, 119, 120, 67, 121, 122,
68, 123, 124, 69, 125, 126, 70, 127, 128, 71, 129, 130,
72, 131, 132, 73, 133, 134, 74, 135, 136, 75, 137, 138,
76, 139, 140, 77, 141, 142, 78, 143, 144, 79, 145, 146,
80, 147, 148, 81, 149, 150, 82, 151, 152, 83, 153, 154,
84, 155, 156, 85, 157, 158, 86, 159, 160, 87, 161, 162,
88, 163, 164, 89, 165, 166, 90, 167, 168, 91, 169, 170,
92, 171, 172, 93, 173, 174, 94, 175, 176, 95, 177, 178,
96, 179, 180, 97, 181, 182, 98, 183, 184, 99, 185, 186,
100, 187, 188, 101, 189, 190, 102, 191, 192, 103, 193, 194,
104, 195, 196, 105, 197, 198, 106, 199, 200, 107, 201, 202,
108, 203, 204, 109, 205, 206, 110, 207, 208, 111, 209, 210,
112, 211, 212, 113, 213, 214, 114, 215, 216, 115, 217, -1
};
// permutation matrix to compute Prob(x*alfa^logw)
static const unsigned int qra_pmat[qra_M*qra_M] = {
0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15,
16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47,
48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63,
0, 33, 1, 32, 2, 35, 3, 34, 4, 37, 5, 36, 6, 39, 7, 38,
8, 41, 9, 40, 10, 43, 11, 42, 12, 45, 13, 44, 14, 47, 15, 46,
16, 49, 17, 48, 18, 51, 19, 50, 20, 53, 21, 52, 22, 55, 23, 54,
24, 57, 25, 56, 26, 59, 27, 58, 28, 61, 29, 60, 30, 63, 31, 62,
0, 49, 33, 16, 1, 48, 32, 17, 2, 51, 35, 18, 3, 50, 34, 19,
4, 53, 37, 20, 5, 52, 36, 21, 6, 55, 39, 22, 7, 54, 38, 23,
8, 57, 41, 24, 9, 56, 40, 25, 10, 59, 43, 26, 11, 58, 42, 27,
12, 61, 45, 28, 13, 60, 44, 29, 14, 63, 47, 30, 15, 62, 46, 31,
0, 57, 49, 8, 33, 24, 16, 41, 1, 56, 48, 9, 32, 25, 17, 40,
2, 59, 51, 10, 35, 26, 18, 43, 3, 58, 50, 11, 34, 27, 19, 42,
4, 61, 53, 12, 37, 28, 20, 45, 5, 60, 52, 13, 36, 29, 21, 44,
6, 63, 55, 14, 39, 30, 22, 47, 7, 62, 54, 15, 38, 31, 23, 46,
0, 61, 57, 4, 49, 12, 8, 53, 33, 28, 24, 37, 16, 45, 41, 20,
1, 60, 56, 5, 48, 13, 9, 52, 32, 29, 25, 36, 17, 44, 40, 21,
2, 63, 59, 6, 51, 14, 10, 55, 35, 30, 26, 39, 18, 47, 43, 22,
3, 62, 58, 7, 50, 15, 11, 54, 34, 31, 27, 38, 19, 46, 42, 23,
0, 63, 61, 2, 57, 6, 4, 59, 49, 14, 12, 51, 8, 55, 53, 10,
33, 30, 28, 35, 24, 39, 37, 26, 16, 47, 45, 18, 41, 22, 20, 43,
1, 62, 60, 3, 56, 7, 5, 58, 48, 15, 13, 50, 9, 54, 52, 11,
32, 31, 29, 34, 25, 38, 36, 27, 17, 46, 44, 19, 40, 23, 21, 42,
0, 62, 63, 1, 61, 3, 2, 60, 57, 7, 6, 56, 4, 58, 59, 5,
49, 15, 14, 48, 12, 50, 51, 13, 8, 54, 55, 9, 53, 11, 10, 52,
33, 31, 30, 32, 28, 34, 35, 29, 24, 38, 39, 25, 37, 27, 26, 36,
16, 46, 47, 17, 45, 19, 18, 44, 41, 23, 22, 40, 20, 42, 43, 21,
0, 31, 62, 33, 63, 32, 1, 30, 61, 34, 3, 28, 2, 29, 60, 35,
57, 38, 7, 24, 6, 25, 56, 39, 4, 27, 58, 37, 59, 36, 5, 26,
49, 46, 15, 16, 14, 17, 48, 47, 12, 19, 50, 45, 51, 44, 13, 18,
8, 23, 54, 41, 55, 40, 9, 22, 53, 42, 11, 20, 10, 21, 52, 43,
0, 46, 31, 49, 62, 16, 33, 15, 63, 17, 32, 14, 1, 47, 30, 48,
61, 19, 34, 12, 3, 45, 28, 50, 2, 44, 29, 51, 60, 18, 35, 13,
57, 23, 38, 8, 7, 41, 24, 54, 6, 40, 25, 55, 56, 22, 39, 9,
4, 42, 27, 53, 58, 20, 37, 11, 59, 21, 36, 10, 5, 43, 26, 52,
0, 23, 46, 57, 31, 8, 49, 38, 62, 41, 16, 7, 33, 54, 15, 24,
63, 40, 17, 6, 32, 55, 14, 25, 1, 22, 47, 56, 30, 9, 48, 39,
61, 42, 19, 4, 34, 53, 12, 27, 3, 20, 45, 58, 28, 11, 50, 37,
2, 21, 44, 59, 29, 10, 51, 36, 60, 43, 18, 5, 35, 52, 13, 26,
0, 42, 23, 61, 46, 4, 57, 19, 31, 53, 8, 34, 49, 27, 38, 12,
62, 20, 41, 3, 16, 58, 7, 45, 33, 11, 54, 28, 15, 37, 24, 50,
63, 21, 40, 2, 17, 59, 6, 44, 32, 10, 55, 29, 14, 36, 25, 51,
1, 43, 22, 60, 47, 5, 56, 18, 30, 52, 9, 35, 48, 26, 39, 13,
0, 21, 42, 63, 23, 2, 61, 40, 46, 59, 4, 17, 57, 44, 19, 6,
31, 10, 53, 32, 8, 29, 34, 55, 49, 36, 27, 14, 38, 51, 12, 25,
62, 43, 20, 1, 41, 60, 3, 22, 16, 5, 58, 47, 7, 18, 45, 56,
33, 52, 11, 30, 54, 35, 28, 9, 15, 26, 37, 48, 24, 13, 50, 39,
0, 43, 21, 62, 42, 1, 63, 20, 23, 60, 2, 41, 61, 22, 40, 3,
46, 5, 59, 16, 4, 47, 17, 58, 57, 18, 44, 7, 19, 56, 6, 45,
31, 52, 10, 33, 53, 30, 32, 11, 8, 35, 29, 54, 34, 9, 55, 28,
49, 26, 36, 15, 27, 48, 14, 37, 38, 13, 51, 24, 12, 39, 25, 50,
0, 52, 43, 31, 21, 33, 62, 10, 42, 30, 1, 53, 63, 11, 20, 32,
23, 35, 60, 8, 2, 54, 41, 29, 61, 9, 22, 34, 40, 28, 3, 55,
46, 26, 5, 49, 59, 15, 16, 36, 4, 48, 47, 27, 17, 37, 58, 14,
57, 13, 18, 38, 44, 24, 7, 51, 19, 39, 56, 12, 6, 50, 45, 25,
0, 26, 52, 46, 43, 49, 31, 5, 21, 15, 33, 59, 62, 36, 10, 16,
42, 48, 30, 4, 1, 27, 53, 47, 63, 37, 11, 17, 20, 14, 32, 58,
23, 13, 35, 57, 60, 38, 8, 18, 2, 24, 54, 44, 41, 51, 29, 7,
61, 39, 9, 19, 22, 12, 34, 56, 40, 50, 28, 6, 3, 25, 55, 45,
0, 13, 26, 23, 52, 57, 46, 35, 43, 38, 49, 60, 31, 18, 5, 8,
21, 24, 15, 2, 33, 44, 59, 54, 62, 51, 36, 41, 10, 7, 16, 29,
42, 39, 48, 61, 30, 19, 4, 9, 1, 12, 27, 22, 53, 56, 47, 34,
63, 50, 37, 40, 11, 6, 17, 28, 20, 25, 14, 3, 32, 45, 58, 55,
0, 39, 13, 42, 26, 61, 23, 48, 52, 19, 57, 30, 46, 9, 35, 4,
43, 12, 38, 1, 49, 22, 60, 27, 31, 56, 18, 53, 5, 34, 8, 47,
21, 50, 24, 63, 15, 40, 2, 37, 33, 6, 44, 11, 59, 28, 54, 17,
62, 25, 51, 20, 36, 3, 41, 14, 10, 45, 7, 32, 16, 55, 29, 58,
0, 50, 39, 21, 13, 63, 42, 24, 26, 40, 61, 15, 23, 37, 48, 2,
52, 6, 19, 33, 57, 11, 30, 44, 46, 28, 9, 59, 35, 17, 4, 54,
43, 25, 12, 62, 38, 20, 1, 51, 49, 3, 22, 36, 60, 14, 27, 41,
31, 45, 56, 10, 18, 32, 53, 7, 5, 55, 34, 16, 8, 58, 47, 29,
0, 25, 50, 43, 39, 62, 21, 12, 13, 20, 63, 38, 42, 51, 24, 1,
26, 3, 40, 49, 61, 36, 15, 22, 23, 14, 37, 60, 48, 41, 2, 27,
52, 45, 6, 31, 19, 10, 33, 56, 57, 32, 11, 18, 30, 7, 44, 53,
46, 55, 28, 5, 9, 16, 59, 34, 35, 58, 17, 8, 4, 29, 54, 47,
0, 45, 25, 52, 50, 31, 43, 6, 39, 10, 62, 19, 21, 56, 12, 33,
13, 32, 20, 57, 63, 18, 38, 11, 42, 7, 51, 30, 24, 53, 1, 44,
26, 55, 3, 46, 40, 5, 49, 28, 61, 16, 36, 9, 15, 34, 22, 59,
23, 58, 14, 35, 37, 8, 60, 17, 48, 29, 41, 4, 2, 47, 27, 54,
0, 55, 45, 26, 25, 46, 52, 3, 50, 5, 31, 40, 43, 28, 6, 49,
39, 16, 10, 61, 62, 9, 19, 36, 21, 34, 56, 15, 12, 59, 33, 22,
13, 58, 32, 23, 20, 35, 57, 14, 63, 8, 18, 37, 38, 17, 11, 60,
42, 29, 7, 48, 51, 4, 30, 41, 24, 47, 53, 2, 1, 54, 44, 27,
0, 58, 55, 13, 45, 23, 26, 32, 25, 35, 46, 20, 52, 14, 3, 57,
50, 8, 5, 63, 31, 37, 40, 18, 43, 17, 28, 38, 6, 60, 49, 11,
39, 29, 16, 42, 10, 48, 61, 7, 62, 4, 9, 51, 19, 41, 36, 30,
21, 47, 34, 24, 56, 2, 15, 53, 12, 54, 59, 1, 33, 27, 22, 44,
0, 29, 58, 39, 55, 42, 13, 16, 45, 48, 23, 10, 26, 7, 32, 61,
25, 4, 35, 62, 46, 51, 20, 9, 52, 41, 14, 19, 3, 30, 57, 36,
50, 47, 8, 21, 5, 24, 63, 34, 31, 2, 37, 56, 40, 53, 18, 15,
43, 54, 17, 12, 28, 1, 38, 59, 6, 27, 60, 33, 49, 44, 11, 22,
0, 47, 29, 50, 58, 21, 39, 8, 55, 24, 42, 5, 13, 34, 16, 63,
45, 2, 48, 31, 23, 56, 10, 37, 26, 53, 7, 40, 32, 15, 61, 18,
25, 54, 4, 43, 35, 12, 62, 17, 46, 1, 51, 28, 20, 59, 9, 38,
52, 27, 41, 6, 14, 33, 19, 60, 3, 44, 30, 49, 57, 22, 36, 11,
0, 54, 47, 25, 29, 43, 50, 4, 58, 12, 21, 35, 39, 17, 8, 62,
55, 1, 24, 46, 42, 28, 5, 51, 13, 59, 34, 20, 16, 38, 63, 9,
45, 27, 2, 52, 48, 6, 31, 41, 23, 33, 56, 14, 10, 60, 37, 19,
26, 44, 53, 3, 7, 49, 40, 30, 32, 22, 15, 57, 61, 11, 18, 36,
0, 27, 54, 45, 47, 52, 25, 2, 29, 6, 43, 48, 50, 41, 4, 31,
58, 33, 12, 23, 21, 14, 35, 56, 39, 60, 17, 10, 8, 19, 62, 37,
55, 44, 1, 26, 24, 3, 46, 53, 42, 49, 28, 7, 5, 30, 51, 40,
13, 22, 59, 32, 34, 57, 20, 15, 16, 11, 38, 61, 63, 36, 9, 18,
0, 44, 27, 55, 54, 26, 45, 1, 47, 3, 52, 24, 25, 53, 2, 46,
29, 49, 6, 42, 43, 7, 48, 28, 50, 30, 41, 5, 4, 40, 31, 51,
58, 22, 33, 13, 12, 32, 23, 59, 21, 57, 14, 34, 35, 15, 56, 20,
39, 11, 60, 16, 17, 61, 10, 38, 8, 36, 19, 63, 62, 18, 37, 9,
0, 22, 44, 58, 27, 13, 55, 33, 54, 32, 26, 12, 45, 59, 1, 23,
47, 57, 3, 21, 52, 34, 24, 14, 25, 15, 53, 35, 2, 20, 46, 56,
29, 11, 49, 39, 6, 16, 42, 60, 43, 61, 7, 17, 48, 38, 28, 10,
50, 36, 30, 8, 41, 63, 5, 19, 4, 18, 40, 62, 31, 9, 51, 37,
0, 11, 22, 29, 44, 39, 58, 49, 27, 16, 13, 6, 55, 60, 33, 42,
54, 61, 32, 43, 26, 17, 12, 7, 45, 38, 59, 48, 1, 10, 23, 28,
47, 36, 57, 50, 3, 8, 21, 30, 52, 63, 34, 41, 24, 19, 14, 5,
25, 18, 15, 4, 53, 62, 35, 40, 2, 9, 20, 31, 46, 37, 56, 51,
0, 36, 11, 47, 22, 50, 29, 57, 44, 8, 39, 3, 58, 30, 49, 21,
27, 63, 16, 52, 13, 41, 6, 34, 55, 19, 60, 24, 33, 5, 42, 14,
54, 18, 61, 25, 32, 4, 43, 15, 26, 62, 17, 53, 12, 40, 7, 35,
45, 9, 38, 2, 59, 31, 48, 20, 1, 37, 10, 46, 23, 51, 28, 56,
0, 18, 36, 54, 11, 25, 47, 61, 22, 4, 50, 32, 29, 15, 57, 43,
44, 62, 8, 26, 39, 53, 3, 17, 58, 40, 30, 12, 49, 35, 21, 7,
27, 9, 63, 45, 16, 2, 52, 38, 13, 31, 41, 59, 6, 20, 34, 48,
55, 37, 19, 1, 60, 46, 24, 10, 33, 51, 5, 23, 42, 56, 14, 28,
0, 9, 18, 27, 36, 45, 54, 63, 11, 2, 25, 16, 47, 38, 61, 52,
22, 31, 4, 13, 50, 59, 32, 41, 29, 20, 15, 6, 57, 48, 43, 34,
44, 37, 62, 55, 8, 1, 26, 19, 39, 46, 53, 60, 3, 10, 17, 24,
58, 51, 40, 33, 30, 23, 12, 5, 49, 56, 35, 42, 21, 28, 7, 14,
0, 37, 9, 44, 18, 55, 27, 62, 36, 1, 45, 8, 54, 19, 63, 26,
11, 46, 2, 39, 25, 60, 16, 53, 47, 10, 38, 3, 61, 24, 52, 17,
22, 51, 31, 58, 4, 33, 13, 40, 50, 23, 59, 30, 32, 5, 41, 12,
29, 56, 20, 49, 15, 42, 6, 35, 57, 28, 48, 21, 43, 14, 34, 7,
0, 51, 37, 22, 9, 58, 44, 31, 18, 33, 55, 4, 27, 40, 62, 13,
36, 23, 1, 50, 45, 30, 8, 59, 54, 5, 19, 32, 63, 12, 26, 41,
11, 56, 46, 29, 2, 49, 39, 20, 25, 42, 60, 15, 16, 35, 53, 6,
47, 28, 10, 57, 38, 21, 3, 48, 61, 14, 24, 43, 52, 7, 17, 34,
0, 56, 51, 11, 37, 29, 22, 46, 9, 49, 58, 2, 44, 20, 31, 39,
18, 42, 33, 25, 55, 15, 4, 60, 27, 35, 40, 16, 62, 6, 13, 53,
36, 28, 23, 47, 1, 57, 50, 10, 45, 21, 30, 38, 8, 48, 59, 3,
54, 14, 5, 61, 19, 43, 32, 24, 63, 7, 12, 52, 26, 34, 41, 17,
0, 28, 56, 36, 51, 47, 11, 23, 37, 57, 29, 1, 22, 10, 46, 50,
9, 21, 49, 45, 58, 38, 2, 30, 44, 48, 20, 8, 31, 3, 39, 59,
18, 14, 42, 54, 33, 61, 25, 5, 55, 43, 15, 19, 4, 24, 60, 32,
27, 7, 35, 63, 40, 52, 16, 12, 62, 34, 6, 26, 13, 17, 53, 41,
0, 14, 28, 18, 56, 54, 36, 42, 51, 61, 47, 33, 11, 5, 23, 25,
37, 43, 57, 55, 29, 19, 1, 15, 22, 24, 10, 4, 46, 32, 50, 60,
9, 7, 21, 27, 49, 63, 45, 35, 58, 52, 38, 40, 2, 12, 30, 16,
44, 34, 48, 62, 20, 26, 8, 6, 31, 17, 3, 13, 39, 41, 59, 53,
0, 7, 14, 9, 28, 27, 18, 21, 56, 63, 54, 49, 36, 35, 42, 45,
51, 52, 61, 58, 47, 40, 33, 38, 11, 12, 5, 2, 23, 16, 25, 30,
37, 34, 43, 44, 57, 62, 55, 48, 29, 26, 19, 20, 1, 6, 15, 8,
22, 17, 24, 31, 10, 13, 4, 3, 46, 41, 32, 39, 50, 53, 60, 59,
0, 34, 7, 37, 14, 44, 9, 43, 28, 62, 27, 57, 18, 48, 21, 55,
56, 26, 63, 29, 54, 20, 49, 19, 36, 6, 35, 1, 42, 8, 45, 15,
51, 17, 52, 22, 61, 31, 58, 24, 47, 13, 40, 10, 33, 3, 38, 4,
11, 41, 12, 46, 5, 39, 2, 32, 23, 53, 16, 50, 25, 59, 30, 60,
0, 17, 34, 51, 7, 22, 37, 52, 14, 31, 44, 61, 9, 24, 43, 58,
28, 13, 62, 47, 27, 10, 57, 40, 18, 3, 48, 33, 21, 4, 55, 38,
56, 41, 26, 11, 63, 46, 29, 12, 54, 39, 20, 5, 49, 32, 19, 2,
36, 53, 6, 23, 35, 50, 1, 16, 42, 59, 8, 25, 45, 60, 15, 30,
0, 41, 17, 56, 34, 11, 51, 26, 7, 46, 22, 63, 37, 12, 52, 29,
14, 39, 31, 54, 44, 5, 61, 20, 9, 32, 24, 49, 43, 2, 58, 19,
28, 53, 13, 36, 62, 23, 47, 6, 27, 50, 10, 35, 57, 16, 40, 1,
18, 59, 3, 42, 48, 25, 33, 8, 21, 60, 4, 45, 55, 30, 38, 15,
0, 53, 41, 28, 17, 36, 56, 13, 34, 23, 11, 62, 51, 6, 26, 47,
7, 50, 46, 27, 22, 35, 63, 10, 37, 16, 12, 57, 52, 1, 29, 40,
14, 59, 39, 18, 31, 42, 54, 3, 44, 25, 5, 48, 61, 8, 20, 33,
9, 60, 32, 21, 24, 45, 49, 4, 43, 30, 2, 55, 58, 15, 19, 38,
0, 59, 53, 14, 41, 18, 28, 39, 17, 42, 36, 31, 56, 3, 13, 54,
34, 25, 23, 44, 11, 48, 62, 5, 51, 8, 6, 61, 26, 33, 47, 20,
7, 60, 50, 9, 46, 21, 27, 32, 22, 45, 35, 24, 63, 4, 10, 49,
37, 30, 16, 43, 12, 55, 57, 2, 52, 15, 1, 58, 29, 38, 40, 19,
0, 60, 59, 7, 53, 9, 14, 50, 41, 21, 18, 46, 28, 32, 39, 27,
17, 45, 42, 22, 36, 24, 31, 35, 56, 4, 3, 63, 13, 49, 54, 10,
34, 30, 25, 37, 23, 43, 44, 16, 11, 55, 48, 12, 62, 2, 5, 57,
51, 15, 8, 52, 6, 58, 61, 1, 26, 38, 33, 29, 47, 19, 20, 40,
0, 30, 60, 34, 59, 37, 7, 25, 53, 43, 9, 23, 14, 16, 50, 44,
41, 55, 21, 11, 18, 12, 46, 48, 28, 2, 32, 62, 39, 57, 27, 5,
17, 15, 45, 51, 42, 52, 22, 8, 36, 58, 24, 6, 31, 1, 35, 61,
56, 38, 4, 26, 3, 29, 63, 33, 13, 19, 49, 47, 54, 40, 10, 20,
0, 15, 30, 17, 60, 51, 34, 45, 59, 52, 37, 42, 7, 8, 25, 22,
53, 58, 43, 36, 9, 6, 23, 24, 14, 1, 16, 31, 50, 61, 44, 35,
41, 38, 55, 56, 21, 26, 11, 4, 18, 29, 12, 3, 46, 33, 48, 63,
28, 19, 2, 13, 32, 47, 62, 49, 39, 40, 57, 54, 27, 20, 5, 10,
0, 38, 15, 41, 30, 56, 17, 55, 60, 26, 51, 21, 34, 4, 45, 11,
59, 29, 52, 18, 37, 3, 42, 12, 7, 33, 8, 46, 25, 63, 22, 48,
53, 19, 58, 28, 43, 13, 36, 2, 9, 47, 6, 32, 23, 49, 24, 62,
14, 40, 1, 39, 16, 54, 31, 57, 50, 20, 61, 27, 44, 10, 35, 5,
0, 19, 38, 53, 15, 28, 41, 58, 30, 13, 56, 43, 17, 2, 55, 36,
60, 47, 26, 9, 51, 32, 21, 6, 34, 49, 4, 23, 45, 62, 11, 24,
59, 40, 29, 14, 52, 39, 18, 1, 37, 54, 3, 16, 42, 57, 12, 31,
7, 20, 33, 50, 8, 27, 46, 61, 25, 10, 63, 44, 22, 5, 48, 35,
0, 40, 19, 59, 38, 14, 53, 29, 15, 39, 28, 52, 41, 1, 58, 18,
30, 54, 13, 37, 56, 16, 43, 3, 17, 57, 2, 42, 55, 31, 36, 12,
60, 20, 47, 7, 26, 50, 9, 33, 51, 27, 32, 8, 21, 61, 6, 46,
34, 10, 49, 25, 4, 44, 23, 63, 45, 5, 62, 22, 11, 35, 24, 48,
0, 20, 40, 60, 19, 7, 59, 47, 38, 50, 14, 26, 53, 33, 29, 9,
15, 27, 39, 51, 28, 8, 52, 32, 41, 61, 1, 21, 58, 46, 18, 6,
30, 10, 54, 34, 13, 25, 37, 49, 56, 44, 16, 4, 43, 63, 3, 23,
17, 5, 57, 45, 2, 22, 42, 62, 55, 35, 31, 11, 36, 48, 12, 24,
0, 10, 20, 30, 40, 34, 60, 54, 19, 25, 7, 13, 59, 49, 47, 37,
38, 44, 50, 56, 14, 4, 26, 16, 53, 63, 33, 43, 29, 23, 9, 3,
15, 5, 27, 17, 39, 45, 51, 57, 28, 22, 8, 2, 52, 62, 32, 42,
41, 35, 61, 55, 1, 11, 21, 31, 58, 48, 46, 36, 18, 24, 6, 12,
0, 5, 10, 15, 20, 17, 30, 27, 40, 45, 34, 39, 60, 57, 54, 51,
19, 22, 25, 28, 7, 2, 13, 8, 59, 62, 49, 52, 47, 42, 37, 32,
38, 35, 44, 41, 50, 55, 56, 61, 14, 11, 4, 1, 26, 31, 16, 21,
53, 48, 63, 58, 33, 36, 43, 46, 29, 24, 23, 18, 9, 12, 3, 6,
0, 35, 5, 38, 10, 41, 15, 44, 20, 55, 17, 50, 30, 61, 27, 56,
40, 11, 45, 14, 34, 1, 39, 4, 60, 31, 57, 26, 54, 21, 51, 16,
19, 48, 22, 53, 25, 58, 28, 63, 7, 36, 2, 33, 13, 46, 8, 43,
59, 24, 62, 29, 49, 18, 52, 23, 47, 12, 42, 9, 37, 6, 32, 3,
0, 48, 35, 19, 5, 53, 38, 22, 10, 58, 41, 25, 15, 63, 44, 28,
20, 36, 55, 7, 17, 33, 50, 2, 30, 46, 61, 13, 27, 43, 56, 8,
40, 24, 11, 59, 45, 29, 14, 62, 34, 18, 1, 49, 39, 23, 4, 52,
60, 12, 31, 47, 57, 9, 26, 42, 54, 6, 21, 37, 51, 3, 16, 32,
0, 24, 48, 40, 35, 59, 19, 11, 5, 29, 53, 45, 38, 62, 22, 14,
10, 18, 58, 34, 41, 49, 25, 1, 15, 23, 63, 39, 44, 52, 28, 4,
20, 12, 36, 60, 55, 47, 7, 31, 17, 9, 33, 57, 50, 42, 2, 26,
30, 6, 46, 54, 61, 37, 13, 21, 27, 3, 43, 51, 56, 32, 8, 16,
0, 12, 24, 20, 48, 60, 40, 36, 35, 47, 59, 55, 19, 31, 11, 7,
5, 9, 29, 17, 53, 57, 45, 33, 38, 42, 62, 50, 22, 26, 14, 2,
10, 6, 18, 30, 58, 54, 34, 46, 41, 37, 49, 61, 25, 21, 1, 13,
15, 3, 23, 27, 63, 51, 39, 43, 44, 32, 52, 56, 28, 16, 4, 8,
0, 6, 12, 10, 24, 30, 20, 18, 48, 54, 60, 58, 40, 46, 36, 34,
35, 37, 47, 41, 59, 61, 55, 49, 19, 21, 31, 25, 11, 13, 7, 1,
5, 3, 9, 15, 29, 27, 17, 23, 53, 51, 57, 63, 45, 43, 33, 39,
38, 32, 42, 44, 62, 56, 50, 52, 22, 16, 26, 28, 14, 8, 2, 4,
0, 3, 6, 5, 12, 15, 10, 9, 24, 27, 30, 29, 20, 23, 18, 17,
48, 51, 54, 53, 60, 63, 58, 57, 40, 43, 46, 45, 36, 39, 34, 33,
35, 32, 37, 38, 47, 44, 41, 42, 59, 56, 61, 62, 55, 52, 49, 50,
19, 16, 21, 22, 31, 28, 25, 26, 11, 8, 13, 14, 7, 4, 1, 2,
0, 32, 3, 35, 6, 38, 5, 37, 12, 44, 15, 47, 10, 42, 9, 41,
24, 56, 27, 59, 30, 62, 29, 61, 20, 52, 23, 55, 18, 50, 17, 49,
48, 16, 51, 19, 54, 22, 53, 21, 60, 28, 63, 31, 58, 26, 57, 25,
40, 8, 43, 11, 46, 14, 45, 13, 36, 4, 39, 7, 34, 2, 33, 1,
0, 16, 32, 48, 3, 19, 35, 51, 6, 22, 38, 54, 5, 21, 37, 53,
12, 28, 44, 60, 15, 31, 47, 63, 10, 26, 42, 58, 9, 25, 41, 57,
24, 8, 56, 40, 27, 11, 59, 43, 30, 14, 62, 46, 29, 13, 61, 45,
20, 4, 52, 36, 23, 7, 55, 39, 18, 2, 50, 34, 17, 1, 49, 33,
0, 8, 16, 24, 32, 40, 48, 56, 3, 11, 19, 27, 35, 43, 51, 59,
6, 14, 22, 30, 38, 46, 54, 62, 5, 13, 21, 29, 37, 45, 53, 61,
12, 4, 28, 20, 44, 36, 60, 52, 15, 7, 31, 23, 47, 39, 63, 55,
10, 2, 26, 18, 42, 34, 58, 50, 9, 1, 25, 17, 41, 33, 57, 49,
0, 4, 8, 12, 16, 20, 24, 28, 32, 36, 40, 44, 48, 52, 56, 60,
3, 7, 11, 15, 19, 23, 27, 31, 35, 39, 43, 47, 51, 55, 59, 63,
6, 2, 14, 10, 22, 18, 30, 26, 38, 34, 46, 42, 54, 50, 62, 58,
5, 1, 13, 9, 21, 17, 29, 25, 37, 33, 45, 41, 53, 49, 61, 57,
0, 2, 4, 6, 8, 10, 12, 14, 16, 18, 20, 22, 24, 26, 28, 30,
32, 34, 36, 38, 40, 42, 44, 46, 48, 50, 52, 54, 56, 58, 60, 62,
3, 1, 7, 5, 11, 9, 15, 13, 19, 17, 23, 21, 27, 25, 31, 29,
35, 33, 39, 37, 43, 41, 47, 45, 51, 49, 55, 53, 59, 57, 63, 61
};
const qracode qra_13_64_64_irr_e = {
qra_K,
qra_N,
qra_m,
qra_M,
qra_a,
qra_NC,
qra_V,
qra_C,
qra_NMSG,
qra_MAXVDEG,
qra_MAXCDEG,
QRATYPE_CRCPUNCTURED,
qra_R,
CODE_NAME,
qra_acc_input_idx,
qra_acc_input_wlog,
qra_log,
qra_exp,
qra_msgw,
qra_vdeg,
qra_cdeg,
qra_v2cmidx,
qra_c2vmidx,
qra_pmat
};
#undef qra_K
#undef qra_N
#undef qra_m
#undef qra_M
#undef qra_a
#undef qra_NC
#undef qra_V
#undef qra_C
#undef qra_NMSG
#undef qra_MAXVDEG
#undef qra_MAXCDEG
#undef qra_R
#undef CODE_NAME

View File

@ -0,0 +1,39 @@
// qra13_64_64_irr_e.h
// Code tables and defines for Q-ary RA code (13,64) over GF(64)
// Code Name: qra13_64_64_irr_e
// (13,64) RA Code over GF(64) RF=[3x4 4x4 6x1 3x2 5x1 7x1]/18
// (c) 2016 - Nico Palermo - IV3NWV - Microtelecom Srl, Italy
// This file is part of the qracodes project, a Forward Error Control
// encoding/decoding package based on Q-ary RA (Repeat and Accumulate) LDPC codes.
//
// qracodes is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
// qracodes is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with qracodes source distribution.
// If not, see <http://www.gnu.org/licenses/>.
#ifndef _qra13_64_64_irr_e_h
#define _qra13_64_64_irr_e_h
#include "qracodes.h"
#ifdef __cplusplus
extern "C" {
#endif
extern const qracode qra_13_64_64_irr_e;
#ifdef __cplusplus
}
#endif
#endif // _qra13_64_64_irr_e_h

474
lib/qra/qracodes/qracodes.c Normal file
View File

@ -0,0 +1,474 @@
// qracodes.c
// Q-ary RA codes encoding/decoding functions
//
// (c) 2016 - Nico Palermo, IV3NWV - Microtelecom Srl, Italy
// ------------------------------------------------------------------------------
// This file is part of the qracodes project, a Forward Error Control
// encoding/decoding package based on Q-ary RA (Repeat and Accumulate) LDPC codes.
//
// qracodes is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
// qracodes is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
// You should have received a copy of the GNU General Public License
// along with qracodes source distribution.
// If not, see <http://www.gnu.org/licenses/>.
#include <stdio.h>
#include <math.h>
#include "npfwht.h"
#include "pdmath.h"
#include "qracodes.h"
#define QRA_DEBUG
int qra_encode(const qracode *pcode, uint *y, const uint *x)
{
uint k,j,kk,jj;
uint t, chk = 0;
const uint K = pcode->K;
const uint M = pcode->M;
const uint NC= pcode->NC;
const uint a = pcode->a;
const int *acc_input_idx = pcode->acc_input_idx;
const uint *acc_input_wlog = pcode->acc_input_wlog;
const int *gflog = pcode->gflog;
const uint *gfexp = pcode->gfexp;
// copy the systematic symbols to destination
memcpy(y,x,K*sizeof(uint));
y = y+K; // point to check symbols
// compute the code check symbols as a weighted accumulation of a permutated
// sequence of the (repeated) systematic input symbols:
// chk(k+1) = x(idx(k))*alfa^(logw(k)) + chk(k)
// (all operations performed over GF(M))
if (a==1) { // grouping factor = 1
for (k=0;k<NC;k++) {
t = x[acc_input_idx[k]];
if (t) {
// multiply input by weight[k] and xor it with previous check
t = (gflog[t] + acc_input_wlog[k])%(M-1);
t = gfexp[t];
chk ^=t;
}
y[k] = chk;
}
#ifdef QRA_DEBUG
// verify that the encoder accumulator is terminated to 0
// (we designed the code this way so that Iex = 1 when Ia = 1)
t = x[acc_input_idx[k]];
if (t) {
t = (gflog[t] + acc_input_wlog[k])%(M-1);
t = gfexp[t];
// accumulation
chk ^=t;
}
return (chk==0);
#else
return 1;
#endif // QRA_DEBUG
}
else { // grouping factor > 1
for (k=0;k<NC;k++) {
kk = a*k;
for (j=0;j<a;j++) {
jj = kk+j;
// irregular grouping support
if (acc_input_idx[jj]<0)
continue;
t = x[acc_input_idx[jj]];
if (t) {
// multiply input by weight[k] and xor it with previous check
t = (gflog[t] + acc_input_wlog[jj])%(M-1);
t = gfexp[t];
chk ^=t;
}
}
y[k] = chk;
}
#ifdef QRA_DEBUG
// verify that the encoder accumulator is terminated to 0
// (we designed the code this way so that Iex = 1 when Ia = 1)
kk = a*k;
for (j=0;j<a;j++) {
jj = kk+j;
if (acc_input_idx[jj]<0)
continue;
t = x[acc_input_idx[jj]];
if (t) {
// multiply input by weight[k] and xor it with previous check
t = (gflog[t] + acc_input_wlog[jj])%(M-1);
t = gfexp[t];
chk ^=t;
}
}
return (chk==0);
#else
return 1;
#endif // QRA_DEBUG
}
}
static void qra_ioapprox(float *src, float C, int nitems)
{
// In place approximation of the modified bessel function I0(x*C)
// Computes src[k] = Io(src[k]*C) where Io() is the modified Bessel function of first kind and order 0
float v;
float vsq;
while (nitems--) {
v = src[nitems]*C;
// rational approximation of log(Io(v))
vsq = v*v;
v = vsq*(v+0.039f)/(vsq*.9931f+v*2.6936f+0.5185f);
if (v>80.f) // avoid floating point exp() overflows
v=80.f;
src[nitems] = (float)exp(v);
}
}
void qra_mfskbesselmetric(float *pix, const float *rsq, const uint m, const uint N, float EsNoMetric)
{
// Computes the codeword symbols intrinsic probabilities
// given the square of the received input amplitudes.
// The input vector rqs must be a linear array of size M*N, where M=2^m,
// containing the squared amplitudes (rp*rp+rq*rq) of the input samples
// First symbol amplitudes should be stored in the first M positions,
// second symbol amplitudes stored at positions [M ... 2*M-1], and so on.
// Output vector is the intrinsic symbol metric (the probability distribution)
// assuming that symbols are transmitted using a M-FSK modulation
// and incoherent demodulation.
// As the input Es/No is generally unknown (as it cannot be exstimated accurately
// when the codeword length is few tens symbols) but an exact metric requires it
// we simply fix it to a predefined EsNoMetric value so that the metric is what
// expected at that specific value.
// The metric computed in this way is optimal only at this predefined Es/No value,
// nevertheless it is usually better than a generic parameter-free metric which
// makes no assumptions on the input Es/No.
uint k;
float rsum = 0.f;
float sigmaest, cmetric;
const uint M = 1<<m;
const uint nsamples = M*N;
// compute total power and modulus of input signal
for (k=0;k<nsamples;k++) {
rsum = rsum+rsq[k];
pix[k] = (float)sqrt(rsq[k]);
}
rsum = rsum/nsamples; // average S+N
// IMPORTANT NOTE: in computing the noise stdev it is assumed that
// in the input amplitudes there's no strong interference!
// A more robust estimation can be done evaluating the histogram of the input amplitudes
sigmaest = (float)sqrt(rsum/(1.0f+EsNoMetric/M)/2); // estimated noise stdev
cmetric = (float)sqrt(2*EsNoMetric)/sigmaest;
for (k=0;k<N;k++) {
// compute bessel metric for each symbol in the codeword
qra_ioapprox(PD_ROWADDR(pix,M,k),cmetric,M);
// normalize to a probability distribution
pd_norm(PD_ROWADDR(pix,M,k),m);
}
return;
}
#ifdef QRA_DEBUG
void pd_print(int imsg,float *ppd,int size)
{
int k;
printf("imsg=%d\n",imsg);
for (k=0;k<size;k++)
printf("%7.1e ",ppd[k]);
printf("\n");
}
#endif
#define ADDRMSG(fp, msgidx) PD_ROWADDR(fp,qra_M,msgidx)
#define C2VMSG(msgidx) PD_ROWADDR(qra_c2vmsg,qra_M,msgidx)
#define V2CMSG(msgidx) PD_ROWADDR(qra_v2cmsg,qra_M,msgidx)
#define MSGPERM(logw) PD_ROWADDR(qra_pmat,qra_M,logw)
#define QRACODE_MAX_M 256 // Maximum alphabet size handled by qra_extrinsic
int qra_extrinsic(const qracode *pcode,
float *pex,
const float *pix,
int maxiter,
float *qra_v2cmsg,
float *qra_c2vmsg)
{
const uint qra_M = pcode->M;
const uint qra_m = pcode->m;
const uint qra_V = pcode->V;
const uint qra_MAXVDEG = pcode->MAXVDEG;
const int *qra_vdeg = pcode->vdeg;
const uint qra_C = pcode->C;
const uint qra_MAXCDEG = pcode->MAXCDEG;
const uint *qra_cdeg = pcode->cdeg;
const int *qra_v2cmidx = pcode->v2cmidx;
const int *qra_c2vmidx = pcode->c2vmidx;
const int *qra_pmat = pcode->gfpmat;
const uint *qra_msgw = pcode->msgw;
// float msgout[qra_M]; // buffer to store temporary results
float msgout[QRACODE_MAX_M]; // we use a fixed size in order to avoid mallocs
float totex; // total extrinsic information
int nit; // current iteration
uint nv; // current variable
uint nc; // current check
uint k,kk; // loop indexes
uint ndeg; // current node degree
int msgbase; // current offset in the table of msg indexes
int imsg; // current message index
int wmsg; // current message weight
int rc = -1; // rc>=0 extrinsic converged to 1 at iteration rc (rc=0..maxiter-1)
// rc=-1 no convergence in the given number of iterations
// rc=-2 error in the code tables (code checks degrees must be >1)
// rc=-3 M is larger than QRACODE_MAX_M
if (qra_M>QRACODE_MAX_M)
return -3;
// message initialization -------------------------------------------------------
// init c->v variable intrinsic msgs
pd_init(C2VMSG(0),pix,qra_M*qra_V);
// init the v->c messages directed to code factors (k=1..ndeg) with the intrinsic info
for (nv=0;nv<qra_V;nv++) {
ndeg = qra_vdeg[nv]; // degree of current node
msgbase = nv*qra_MAXVDEG; // base to msg index row for the current node
// copy intrinsics on v->c
for (k=1;k<ndeg;k++) {
imsg = qra_v2cmidx[msgbase+k];
pd_init(V2CMSG(imsg),ADDRMSG(pix,nv),qra_M);
}
}
// message passing algorithm iterations ------------------------------
for (nit=0;nit<maxiter;nit++) {
// c->v step -----------------------------------------------------
// Computes messages from code checks to code variables.
// As the first qra_V checks are associated with intrinsic information
// (the code tables have been constructed in this way)
// we need to do this step only for code checks in the range [qra_V..qra_C)
// The convolutions of probability distributions over the alphabet of a finite field GF(qra_M)
// are performed with a fast convolution algorithm over the given field.
//
// I.e. given the code check x1+x2+x3 = 0 (with x1,x2,x3 in GF(2^m))
// and given Prob(x2) and Prob(x3), we have that:
// Prob(x1=X1) = Prob((x2+x3)=X1) = sum((Prob(x2=X2)*Prob(x3=(X1+X2))) for all the X2s in the field
// This translates to Prob(x1) = IWHT(WHT(Prob(x2))*WHT(Prob(x3)))
// where WHT and IWHT are the direct and inverse Walsh-Hadamard transforms of the argument.
// Note that the WHT and the IWHF differs only by a multiplicative coefficent and since in this step
// we don't need that the output distribution is normalized we use the relationship
// Prob(x1) =(proportional to) WH(WH(Prob(x2))*WH(Prob(x3)))
// In general given the check code x1+x2+x3+..+xm = 0
// the output distribution of a variable given the distributions of the other m-1 variables
// is the inverse WHT of the product of the WHTs of the distribution of the other m-1 variables
// The complexity of this algorithm scales with M*log2(M) instead of the M^2 complexity of
// the brute force approach (M=size of the alphabet)
for (nc=qra_V;nc<qra_C;nc++) {
ndeg = qra_cdeg[nc]; // degree of current node
if (ndeg==1) // this should never happen (code factors must have deg>1)
return -2; // bad code tables
msgbase = nc*qra_MAXCDEG; // base to msg index row for the current node
// transforms inputs in the Walsh-Hadamard "frequency" domain
// v->c -> fwht(v->c)
for (k=0;k<ndeg;k++) {
imsg = qra_c2vmidx[msgbase+k]; // msg index
np_fwht(qra_m,V2CMSG(imsg),V2CMSG(imsg)); // compute fwht
}
// compute products and transform them back in the WH "time" domain
for (k=0;k<ndeg;k++) {
// init output message to uniform distribution
pd_init(msgout,pd_uniform(qra_m),qra_M);
// c->v = prod(fwht(v->c))
// TODO: we assume that checks degrees are not larger than three but
// if they are larger the products can be computed more efficiently
for (kk=0;kk<ndeg;kk++)
if (kk!=k) {
imsg = qra_c2vmidx[msgbase+kk];
pd_imul(msgout,V2CMSG(imsg),qra_m);
}
// transform product back in the WH "time" domain
// Very important trick:
// we bias WHT[0] so that the sum of output pd components is always strictly positive
// this helps avoiding the effects of underflows in the v->c steps when multipling
// small fp numbers
msgout[0]+=1E-7f; // TODO: define the bias accordingly to the field size
np_fwht(qra_m,msgout,msgout);
// inverse weight and output
imsg = qra_c2vmidx[msgbase+k]; // current output msg index
wmsg = qra_msgw[imsg]; // current msg weight
if (wmsg==0)
pd_init(C2VMSG(imsg),msgout,qra_M);
else
// output p(alfa^(-w)*x)
pd_bwdperm(C2VMSG(imsg),msgout, MSGPERM(wmsg), qra_M);
} // for (k=0;k<ndeg;k++)
} // for (nc=qra_V;nc<qra_C;nc++)
// v->c step -----------------------------------------------------
for (nv=0;nv<qra_V;nv++) {
ndeg = qra_vdeg[nv]; // degree of current node
msgbase = nv*qra_MAXVDEG; // base to msg index row for the current node
for (k=0;k<ndeg;k++) {
// init output message to uniform distribution
pd_init(msgout,pd_uniform(qra_m),qra_M);
// v->c msg = prod(c->v)
// TODO: factor factors to reduce the number of computations for high degree nodes
for (kk=0;kk<ndeg;kk++)
if (kk!=k) {
imsg = qra_v2cmidx[msgbase+kk];
pd_imul(msgout,C2VMSG(imsg),qra_m);
}
#ifdef QRA_DEBUG
// normalize and check if product of messages v->c are null
// normalize output to a probability distribution
if (pd_norm(msgout,qra_m)<=0) {
// dump msgin;
printf("warning: v->c pd with invalid norm. nit=%d nv=%d k=%d\n",nit,nv,k);
for (kk=0;kk<ndeg;kk++) {
imsg = qra_v2cmidx[msgbase+kk];
pd_print(imsg,C2VMSG(imsg),qra_M);
}
printf("-----------------\n");
}
#else
// normalize the result to a probability distribution
pd_norm(msgout,qra_m);
#endif
// weight and output
imsg = qra_v2cmidx[msgbase+k]; // current output msg index
wmsg = qra_msgw[imsg]; // current msg weight
if (wmsg==0) {
pd_init(V2CMSG(imsg),msgout,qra_M);
}
else {
// output p(alfa^w*x)
pd_fwdperm(V2CMSG(imsg),msgout, MSGPERM(wmsg), qra_M);
}
} // for (k=0;k<ndeg;k++)
} // for (nv=0;nv<qra_V;nv++)
// check extrinsic information ------------------------------
// We assume that decoding is successful if each of the extrinsic
// symbol probability is close to ej, where ej = [0 0 0 1(j-th position) 0 0 0 ]
// Therefore, for each symbol k in the codeword we compute max(prob(Xk))
// and we stop the iterations if sum(max(prob(xk)) is close to the codeword length
// Note: this is a more restrictive criterium than that of computing the a
// posteriori probability of each symbol, making a hard decision and then check
// if the codeword syndrome is null.
// WARNING: this is tricky and probably works only for the particular class of RA codes
// we are coping with (we designed the code weights so that for any input symbol the
// sum of its weigths is always 0, thus terminating the accumulator trellis to zero
// for every combination of the systematic symbols).
// More generally we should instead compute the max a posteriori probabilities
// (as a product of the intrinsic and extrinsic information), make a symbol by symbol hard
// decision and then check that the syndrome of the result is indeed null.
totex = 0;
for (nv=0;nv<qra_V;nv++)
totex += pd_max(V2CMSG(nv),qra_M);
if (totex>(1.*(qra_V)-0.01)) {
// the total maximum extrinsic information of each symbol in the codeword
// is very close to one. This means that we have reached the (1,1) point in the
// code EXIT chart(s) and we have successfully decoded the input.
rc = nit;
break; // remove the break to evaluate the decoder speed performance as a function of the max iterations number)
}
} // for (nit=0;nit<maxiter;nit++)
// copy extrinsic information to output to do the actual max a posteriori prob decoding
pd_init(pex,V2CMSG(0),(qra_M*qra_V));
return rc;
}
void qra_mapdecode(const qracode *pcode, uint *xdec, float *pex, const float *pix)
{
// Maximum a posteriori probability decoding.
// Given the intrinsic information (pix) and extrinsic information (pex) (computed with qra_extrinsic(...))
// compute pmap = pex*pix and decode each (information) symbol of the received codeword
// as the symbol which maximizes pmap
// Returns:
// xdec[k] = decoded (information) symbols k=[0..qra_K-1]
// Note: pex is destroyed and overwritten with mapp
const uint qra_M = pcode->M;
const uint qra_m = pcode->m;
const uint qra_K = pcode->K;
uint k;
for (k=0;k<qra_K;k++) {
// compute a posteriori prob
pd_imul(PD_ROWADDR(pex,qra_M,k),PD_ROWADDR(pix,qra_M,k),qra_m);
xdec[k]=pd_argmax(NULL, PD_ROWADDR(pex,qra_M,k), qra_M);
}
}

View File

@ -0,0 +1,81 @@
// qracodes.h
// Q-ary RA codes encoding/decoding functions
//
// (c) 2016 - Nico Palermo, IV3NWV - Microtelecom Srl, Italy
// ------------------------------------------------------------------------------
// This file is part of the qracodes project, a Forward Error Control
// encoding/decoding package based on Q-ary RA (Repeat and Accumulate) LDPC codes.
//
// qracodes is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
// qracodes is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
// You should have received a copy of the GNU General Public License
// along with qracodes source distribution.
// If not, see <http://www.gnu.org/licenses/>.
#ifndef _qracodes_h_
#define _qracodes_h_
typedef unsigned int uint;
// type of codes
#define QRATYPE_NORMAL 0x00 // normal code
#define QRATYPE_CRC 0x01 // code with crc - last information symbol is a CRC
#define QRATYPE_CRCPUNCTURED 0x02 // the CRC symbol is punctured (not sent along the channel)
typedef struct {
// code parameters
const uint K; // number of information symbols
const uint N; // codeword length in symbols
const uint m; // bits/symbol
const uint M; // Symbol alphabet cardinality (2^m)
const uint a; // code grouping factor
const uint NC; // number of check symbols (N-K)
const uint V; // number of variables in the code graph (N)
const uint C; // number of factors in the code graph (N +(N-K)+1)
const uint NMSG; // number of msgs in the code graph
const uint MAXVDEG; // maximum variable degree
const uint MAXCDEG; // maximum factor degree
const uint type; // see QRATYPE_xx defines
const float R; // code rate (K/N)
const char name[64]; // code name
// tables used by the encoder
const int *acc_input_idx;
const uint *acc_input_wlog;
const int *gflog;
const uint *gfexp;
// tables used by the decoder -------------------------
const uint *msgw;
const uint *vdeg;
const uint *cdeg;
const int *v2cmidx;
const int *c2vmidx;
const int *gfpmat;
} qracode;
// Uncomment the header file of the code which needs to be tested
//#include "qra12_63_64_irr_b.h" // irregular code (12,63) over GF(64)
//#include "qra13_64_64_irr_e.h" // irregular code with good performance and best UER protection at AP56
//#include "qra13_64_64_reg_a.h" // regular code with good UER but perf. inferior to that of code qra12_63_64_irr_b
#ifdef __cplusplus
extern "C" {
#endif
int qra_encode(const qracode *pcode, uint *y, const uint *x);
void qra_mfskbesselmetric(float *pix, const float *rsq, const uint m, const uint N, float EsNoMetric);
int qra_extrinsic(const qracode *pcode, float *pex, const float *pix, int maxiter,float *qra_v2cmsg,float *qra_c2vmsg);
void qra_mapdecode(const qracode *pcode, uint *xdec, float *pex, const float *pix);
#ifdef __cplusplus
}
#endif
#endif // _qracodes_h_

View File

@ -0,0 +1,251 @@
<?xml version="1.0" encoding="Windows-1252"?>
<VisualStudioProject
ProjectType="Visual C++"
Version="9,00"
Name="qracodes"
ProjectGUID="{8540B348-B8F2-4104-84CB-6286AC19158B}"
RootNamespace="qracodes"
Keyword="Win32Proj"
TargetFrameworkVersion="196613"
>
<Platforms>
<Platform
Name="Win32"
/>
</Platforms>
<ToolFiles>
</ToolFiles>
<Configurations>
<Configuration
Name="Debug|Win32"
OutputDirectory="$(SolutionDir)$(ConfigurationName)"
IntermediateDirectory="$(ConfigurationName)"
ConfigurationType="1"
CharacterSet="0"
>
<Tool
Name="VCPreBuildEventTool"
/>
<Tool
Name="VCCustomBuildTool"
/>
<Tool
Name="VCXMLDataGeneratorTool"
/>
<Tool
Name="VCWebServiceProxyGeneratorTool"
/>
<Tool
Name="VCMIDLTool"
/>
<Tool
Name="VCCLCompilerTool"
Optimization="0"
FavorSizeOrSpeed="1"
PreprocessorDefinitions="WIN32;_DEBUG;_CONSOLE"
MinimalRebuild="true"
BasicRuntimeChecks="3"
RuntimeLibrary="3"
EnableEnhancedInstructionSet="2"
UsePrecompiledHeader="0"
WarningLevel="3"
DebugInformationFormat="4"
/>
<Tool
Name="VCManagedResourceCompilerTool"
/>
<Tool
Name="VCResourceCompilerTool"
/>
<Tool
Name="VCPreLinkEventTool"
/>
<Tool
Name="VCLinkerTool"
LinkIncremental="2"
GenerateDebugInformation="true"
SubSystem="1"
TargetMachine="1"
/>
<Tool
Name="VCALinkTool"
/>
<Tool
Name="VCManifestTool"
/>
<Tool
Name="VCXDCMakeTool"
/>
<Tool
Name="VCBscMakeTool"
/>
<Tool
Name="VCFxCopTool"
/>
<Tool
Name="VCAppVerifierTool"
/>
<Tool
Name="VCPostBuildEventTool"
/>
</Configuration>
<Configuration
Name="Release|Win32"
OutputDirectory="$(SolutionDir)$(ConfigurationName)"
IntermediateDirectory="$(ConfigurationName)"
ConfigurationType="1"
CharacterSet="0"
WholeProgramOptimization="1"
>
<Tool
Name="VCPreBuildEventTool"
/>
<Tool
Name="VCCustomBuildTool"
/>
<Tool
Name="VCXMLDataGeneratorTool"
/>
<Tool
Name="VCWebServiceProxyGeneratorTool"
/>
<Tool
Name="VCMIDLTool"
/>
<Tool
Name="VCCLCompilerTool"
Optimization="3"
EnableIntrinsicFunctions="true"
FavorSizeOrSpeed="1"
OmitFramePointers="true"
EnableFiberSafeOptimizations="true"
PreprocessorDefinitions="WIN32;NDEBUG;_CONSOLE"
ExceptionHandling="0"
RuntimeLibrary="2"
StructMemberAlignment="4"
BufferSecurityCheck="false"
EnableFunctionLevelLinking="true"
EnableEnhancedInstructionSet="2"
FloatingPointModel="2"
UsePrecompiledHeader="0"
WarningLevel="3"
DebugInformationFormat="0"
/>
<Tool
Name="VCManagedResourceCompilerTool"
/>
<Tool
Name="VCResourceCompilerTool"
/>
<Tool
Name="VCPreLinkEventTool"
/>
<Tool
Name="VCLinkerTool"
LinkIncremental="1"
GenerateDebugInformation="true"
SubSystem="1"
OptimizeReferences="2"
EnableCOMDATFolding="2"
TargetMachine="1"
/>
<Tool
Name="VCALinkTool"
/>
<Tool
Name="VCManifestTool"
/>
<Tool
Name="VCXDCMakeTool"
/>
<Tool
Name="VCBscMakeTool"
/>
<Tool
Name="VCFxCopTool"
/>
<Tool
Name="VCAppVerifierTool"
/>
<Tool
Name="VCPostBuildEventTool"
/>
</Configuration>
</Configurations>
<References>
</References>
<Files>
<Filter
Name="Source Files"
Filter="cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx"
UniqueIdentifier="{4FC737F1-C7A5-4376-A066-2A32D752A2FF}"
>
<File
RelativePath=".\main.c"
>
</File>
<File
RelativePath=".\normrnd.c"
>
</File>
<File
RelativePath=".\npfwht.c"
>
</File>
<File
RelativePath=".\pdmath.c"
>
</File>
<File
RelativePath=".\qra12_63_64_irr_b.c"
>
</File>
<File
RelativePath=".\qra13_64_64_irr_e.c"
>
</File>
<File
RelativePath=".\qracodes.c"
>
</File>
</Filter>
<Filter
Name="Header Files"
Filter="h;hpp;hxx;hm;inl;inc;xsd"
UniqueIdentifier="{93995380-89BD-4b04-88EB-625FBE52EBFB}"
>
<File
RelativePath=".\normrnd.h"
>
</File>
<File
RelativePath=".\npfwht.h"
>
</File>
<File
RelativePath=".\pdmath.h"
>
</File>
<File
RelativePath=".\qra12_63_64_irr_b.h"
>
</File>
<File
RelativePath=".\qra13_64_64_irr_e.h"
>
</File>
<File
RelativePath=".\qracodes.h"
>
</File>
</Filter>
<Filter
Name="Resource Files"
Filter="rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav"
UniqueIdentifier="{67DA6AB6-F800-4c08-8B7A-83BB121AAD01}"
>
</Filter>
</Files>
<Globals>
</Globals>
</VisualStudioProject>