// 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 . #include #include #include "npfwht.h" #include "pdmath.h" #include "qracodes.h" int qra_encode(const qracode *pcode, int *y, const int *x) { int k,j,kk,jj; int t, chk = 0; const int K = pcode->K; const int M = pcode->M; const int NC= pcode->NC; const int a = pcode->a; const int *acc_input_idx = pcode->acc_input_idx; const int *acc_input_wlog = pcode->acc_input_wlog; const int *gflog = pcode->gflog; const int *gfexp = pcode->gfexp; // copy the systematic symbols to destination memcpy(y,x,K*sizeof(int)); 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 1 for (k=0;k80.f) // avoid floating point exp() overflows v=80.f; src[nitems] = (float)exp(v); } } float qra_mfskbesselmetric(float *pix, const float *rsq, const int m, const int 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. // returns the estimated noise standard deviation int k; float rsum = 0.f; float sigmaest, cmetric; const int M = 1<M; const int qra_m = pcode->m; const int qra_V = pcode->V; const int qra_MAXVDEG = pcode->MAXVDEG; const int *qra_vdeg = pcode->vdeg; const int qra_C = pcode->C; const int qra_MAXCDEG = pcode->MAXCDEG; const int *qra_cdeg = pcode->cdeg; const int *qra_v2cmidx = pcode->v2cmidx; const int *qra_c2vmidx = pcode->c2vmidx; const int *qra_pmat = pcode->gfpmat; const int *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 int nv; // current variable int nc; // current check int k,kk; // loop indexes int 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;nvc for (k=1;kv 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;nc1) 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;kv = 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;kkc 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;kc step ----------------------------------------------------- for (nv=0;nvc msg = prod(c->v) // TODO: factor factors to reduce the number of computations for high degree nodes for (kk=0;kkc 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(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;nitM; const int qra_m = pcode->m; const int qra_K = pcode->K; int k; for (k=0;k