SDRAngel  4.11.5
Developer docs for <a href="https://github.com/f4exb/sdrangel">SDRangel<\a>, an Open Source Qt5 / OpenGL 3.0+ SDR and signal analyzer frontend to various hardware.
ldpc.h
Go to the documentation of this file.
1 // This file is part of LeanSDR Copyright (C) 2016-2018 <pabr@pabr.org>.
2 // See the toplevel README for more information.
3 //
4 // This program is free software: you can redistribute it and/or modify
5 // it under the terms of the GNU General Public License as published by
6 // the Free Software Foundation, either version 3 of the License, or
7 // (at your option) any later version.
8 //
9 // This program is distributed in the hope that it will be useful,
10 // but WITHOUT ANY WARRANTY; without even the implied warranty of
11 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 // GNU General Public License for more details.
13 //
14 // You should have received a copy of the GNU General Public License
15 // along with this program. If not, see <http://www.gnu.org/licenses/>.
16 
17 #ifndef LEANSDR_LDPC_H
18 #define LEANSDR_LDPC_H
19 
20 #define lfprintf(...) \
21  { \
22  }
23 
24 namespace leansdr
25 {
26 
27 // LDPC sparse matrix specified like in the DVB-S2 standard
28 // Taddr must be wide enough to index message bits and address bits.
29 
30 template <typename Taddr>
31 struct ldpc_table
32 {
33  // TBD Save space
34  static const int MAX_ROWS = 162; // 64800 * (9/10) / 360
35  static const int MAX_COLS = 13;
36  int q;
37  int nrows;
38  struct row
39  {
40  int ncols;
41  Taddr cols[MAX_COLS];
42  } rows[MAX_ROWS];
43 };
44 
45 // LDPC ENGINE
46 
47 // SOFTBITs can be hard (e.g. bool) or soft (e.g. llr_t).
48 // They are stored as SOFTWORDs containing SWSIZE SOFTBITs.
49 // See interface in softword.h.
50 
51 template <typename SOFTBIT, typename SOFTWORD, int SWSIZE, typename Taddr>
53 {
54 
56  : vnodes(NULL), cnodes(NULL)
57  {
58  }
59 
60  // vnodes: Value/variable nodes (message bits)
61  // cnodes: Check nodes (parity bits)
62 
63  int k; // Message size in bits
64  int n; // Codeword size in bits
65 
66  struct node
67  {
68  Taddr *edges;
69  int nedges;
70  static const int CHUNK = 4; // Grow edges[] in steps of CHUNK.
71  void append(Taddr a)
72  {
73  if (nedges % CHUNK == 0)
74  { // Full ?
75  edges = (Taddr *)realloc(edges, (nedges + CHUNK) * sizeof(Taddr));
76  if (!edges)
77  fatal("realloc");
78  }
79  edges[nedges++] = a;
80  }
81  };
82 
83  node *vnodes; // [k]
84  node *cnodes; // [n-k]
85 
86  // Initialize from a S2-style table.
87 
88  ldpc_engine(const ldpc_table<Taddr> *table, int _k, int _n)
89  : k(_k), n(_n)
90  {
91  // Sanity checks
92  if (360 % SWSIZE)
93  fatal("Bad LDPC word size");
94  if (k % SWSIZE)
95  fatal("Bad LDPC k");
96  if (n % SWSIZE)
97  fatal("Bad LDPC n");
98  if (k != table->nrows * 360)
99  fatal("Bad table");
100  int n_k = n - k;
101  if (table->q * 360 != n_k)
102  fatal("Bad q");
103 
104  vnodes = new node[k];
105  memset(vnodes, 0, sizeof(node) * k);
106  cnodes = new node[n_k];
107  memset(cnodes, 0, sizeof(node) * n_k);
108 
109  // Expand the graph.
110 
111  int m = 0;
112  // Iterate over rows
113  for (const typename ldpc_table<Taddr>::row *prow = table->rows;
114  prow < table->rows + table->nrows;
115  ++prow)
116  {
117  // Process 360 bits per row.
118  int q = table->q;
119  int qoffs = 0;
120  for (int mw = 360; mw--; ++m, qoffs += q)
121  {
122  const Taddr *pa = prow->cols;
123  for (int nc = prow->ncols; nc--; ++pa)
124  {
125  int a = (int)*pa + qoffs;
126  if (a >= n_k)
127  a -= n_k; // Modulo n-k. Note qoffs<360*q.
128  if (a >= n_k)
129  fail("Invalid LDPC table");
130  vnodes[m].append(a);
131  cnodes[a].append(m);
132  }
133  }
134  }
135  }
136 
138  {
139  int nedges = count_edges(vnodes, k);
140  fprintf(stderr, "LDPC(%5d,%5d)(%.2f)"
141  " %5.2f edges/vnode, %5.2f edges/cnode\n",
142  k, n - k, (float)k / n, (float)nedges / k, (float)nedges / (n - k));
143  }
144 
145  int count_edges(node *nodes, int nnodes)
146  {
147  int c = 0;
148  for (int i = 0; i < nnodes; ++i)
149  c += nodes[i].nedges;
150  return c;
151  }
152 
153  // k: Message size in bits
154  // n: Codeword size in bits
155  // integrate: Optional S2-style post-processing
156 
157 #if 0
158  void encode_hard(const ldpc_table<Taddr> *table, const uint8_t *msg,
159  int k, int n, uint8_t *parity, bool integrate=true) {
160  // Sanity checks
161  if ( 360 % SWSIZE ) fatal("Bad LDPC word size");
162  if ( k % SWSIZE ) fatal("Bad LDPC k");
163  if ( n % SWSIZE ) fatal("Bad LDPC n");
164  if ( k != table->nrows*360 ) fatal("Bad table");
165  int n_k = n - k;
166  if ( table->q*360 != n_k ) fatal("Bad q");
167 
168  for ( int i=0; i<n_k/SWSIZE; ++i ) softword_zero(&parity[i]);
169 
170  // Iterate over rows
171  for ( const typename ldpc_table<Taddr>::row *prow = table->rows; // quirk
172  prow < table->rows+table->nrows;
173  ++prow ) {
174  // Process 360 bits per row, in words of SWSIZE bits
175  int q = table->q;
176  int qoffs = 0;
177  for ( int mw=360/SWSIZE; mw--; ++msg ) {
178  SOFTWORD msgword = *msg;
179  for ( int wbit=0; wbit<SWSIZE; ++wbit,qoffs+=q ) {
180  SOFTBIT msgbit = softword_get(msgword, wbit);
181  if ( ! msgbit ) continue; // TBD Generic soft version
182  const Taddr *pa = prow->cols;
183  for ( int nc=prow->ncols; nc--; ++pa ) {
184  // Don't wrap modulo range of Taddr
185  int a = (int)*pa + qoffs;
186  // Note: qoffs < 360*q=n-k
187  if ( a >= n_k ) a -= n_k; // TBD not predictable
188  softwords_flip(parity, a);
189  }
190  }
191  }
192  }
193 
194  if ( integrate )
195  integrate_bits(parity, parity, n_k/SWSIZE);
196  }
197 #endif
198 
199  void encode(const ldpc_table<Taddr> *table, const SOFTWORD *msg,
200  int k, int n, SOFTWORD *parity, int integrate = true)
201  {
202  // Sanity checks
203  if (360 % SWSIZE)
204  fatal("Bad LDPC word size");
205  if (k % SWSIZE)
206  fatal("Bad LDPC k");
207  if (n % SWSIZE)
208  fatal("Bad LDPC n");
209  if (k != table->nrows * 360)
210  fatal("Bad table");
211  int n_k = n - k;
212  if (table->q * 360 != n_k)
213  fatal("Bad q");
214 
215  for (int i = 0; i < n_k / SWSIZE; ++i)
216  softword_zero(&parity[i]);
217 
218  // Iterate over rows
219  for (const typename ldpc_table<Taddr>::row *prow = table->rows; // quirk
220  prow < table->rows + table->nrows;
221  ++prow)
222  {
223  // Process 360 bits per row, in words of SWSIZE bits
224  int q = table->q;
225  int qoffs = 0;
226  for (int mw = 360 / SWSIZE; mw--; ++msg)
227  {
228  SOFTWORD msgword = *msg;
229  for (int wbit = 0; wbit < SWSIZE; ++wbit, qoffs += q)
230  {
231  SOFTBIT msgbit = softword_get(msgword, wbit);
232  if (!softbit_harden(msgbit))
233  continue;
234  const Taddr *pa = prow->cols;
235  for (int nc = prow->ncols; nc--; ++pa)
236  {
237  int a = (int)*pa + qoffs;
238  // Note: qoffs < 360*q=n-k
239  if (a >= n_k)
240  a -= n_k; // TBD not predictable
241  softwords_flip(parity, a);
242  }
243  }
244  }
245  }
246 
247  if (integrate)
248  integrate_bits(parity, parity, n_k / SWSIZE);
249  }
250 
251  // Flip bits connected to parity errors, one at a time,
252  // as long as things improve and max_bitflips is not exceeded.
253 
254  // cw: codeword (k value bits followed by n-k check bits)
255 
256  static const int PPCM = 39;
257 
258  typedef int64_t score_t;
259 
260  score_t compute_scores(SOFTWORD *m, SOFTWORD *p, SOFTWORD *q, int nc,
261  score_t *score, int k)
262  {
263  int total = 0;
264  memset(score, 0, k * sizeof(*score));
265  for (int c = 0; c < nc; ++c)
266  {
267  SOFTBIT err = softwords_xor(p, q, c);
268  if (softbit_harden(err))
269  {
270  Taddr *pe = cnodes[c].edges;
271  for (int e = cnodes[c].nedges; e--; ++pe)
272  {
273  int v = *pe;
274  int s = err * softwords_weight<SOFTBIT, SOFTWORD>(m, v) * PPCM / vnodes[v].nedges;
275  //fprintf(stderr, "c[%d] bad => v[%d] += %d (%d*%d)\n",
277  score[v] += s;
278  total += s;
279  }
280  }
281  }
282  return total;
283  }
284 
285  int decode_bitflip(const ldpc_table<Taddr> *table, SOFTWORD *cw,
286  int k, int n,
287  int max_bitflips)
288  {
289  if (!vnodes)
290  fail("LDPC graph not initialized");
291  int n_k = n - k;
292 
293  // Compute the expected check bits (without the final mixing)
294  SOFTWORD *expected = new SOFTWORD[n_k / SWSIZE]; // Forbidden to statically allocate with non constant size
295  encode(table, cw, k, n, expected, false);
296  // Reverse the integrator mixing from the received check bits
297  SOFTWORD *received = new SOFTWORD[n_k / SWSIZE]; // Forbidden to statically allocate with non constant size
298  diff_bits(cw + k / SWSIZE, received, n_k / SWSIZE);
299 
300  // Compute initial scores
301  score_t *score = new score_t[k]; // Forbidden to statically allocate with non constant size
302  score_t tots = compute_scores(cw, expected, received, n_k, score, k);
303  lfprintf(stderr, "Initial score %d\n", (int)tots);
304 
305  int nflipped = 0;
306 
307  score_t score_threshold;
308  {
309  SOFTBIT one;
310  softbit_set(&one, true);
311  score_threshold = (int)one * 2;
312  }
313 
314  bool progress = true;
315  while (progress && nflipped < max_bitflips)
316  {
317  progress = false;
318  // Try to flip parity bits.
319  // Due to differential decoding, they appear as consecutive errors.
320  SOFTBIT prev_err = softwords_xor(expected, received, 0);
321  for (int b = 0; b < n - k - 1; ++b)
322  {
323  prev_err = softwords_xor(expected, received, b); //TBD
324  SOFTBIT err = softwords_xor(expected, received, b + 1);
325  if (softbit_harden(prev_err) && softbit_harden(err))
326  {
327  lfprintf(stderr, "flip parity %d\n", b);
328  softwords_flip(received, b);
329  softwords_flip(received, b + 1);
330  ++nflipped; // Counts as one flip before differential decoding.
331  progress = true;
332  int dtot = 0;
333  // Depenalize adjacent message bits.
334  {
335  Taddr *pe = cnodes[b].edges;
336  for (int e = cnodes[b].nedges; e--; ++pe)
337  {
338  int d = prev_err * softwords_weight<SOFTBIT, SOFTWORD>(cw, *pe) * PPCM / vnodes[*pe].nedges;
339  score[*pe] -= d;
340  dtot -= d;
341  }
342  }
343  {
344  Taddr *pe = cnodes[b + 1].edges;
345  for (int e = cnodes[b + 1].nedges; e--; ++pe)
346  {
347  int d = err * softwords_weight<SOFTBIT, SOFTWORD>(cw, *pe) * PPCM / vnodes[*pe].nedges;
348  score[*pe] -= d;
349  dtot -= d;
350  }
351  }
352  tots += dtot;
353 #if 1
354  // Also update the codeword in-place.
355  // TBD Useful for debugging only.
356  softwords_flip(cw, k + b);
357 #endif
358  // TBD version soft. err = ! err;
359  }
360  prev_err = err;
361  } // c nodes
362  score_t maxs = -(1 << 30);
363  for (int v = 0; v < k; ++v)
364  if (score[v] > maxs)
365  maxs = score[v];
366  if (!maxs)
367  break;
368  lfprintf(stderr, "maxs %d\n", (int)maxs);
369  // Try to flip each message bits with maximal score
370  for (int v = 0; v < k; ++v)
371  {
372  if (score[v] < score_threshold)
373  continue;
374  // if ( score[v] < maxs*9/10 ) continue;
375  if (score[v] < maxs - 4)
376  continue;
377  lfprintf(stderr, " flip %d score=%d\n", (int)v, (int)score[v]);
378  // Update expected parities and scores that depend on them.
379  score_t dtot = 0;
380  for (int commit = 0; commit <= 1; ++commit)
381  {
382  Taddr *pe = vnodes[v].edges;
383  for (int e = vnodes[v].nedges; e--; ++pe)
384  {
385  Taddr c = *pe;
386  SOFTBIT was_bad = softwords_xor(expected, received, c);
387  if (softbit_harden(was_bad))
388  {
389  Taddr *pe = cnodes[c].edges;
390  for (int e = cnodes[c].nedges; e--; ++pe)
391  {
392  int d = was_bad * softwords_weight<SOFTBIT, SOFTWORD>(cw, *pe) * PPCM / vnodes[*pe].nedges;
393  if (commit)
394  score[*pe] -= d;
395  else
396  dtot -= d;
397  }
398  }
399  softwords_flip(expected, c);
400  SOFTBIT is_bad = softwords_xor(expected, received, c);
401  if (softbit_harden(is_bad))
402  {
403  Taddr *pe = cnodes[c].edges;
404  for (int e = cnodes[c].nedges; e--; ++pe)
405  {
406  int d = is_bad * softwords_weight<SOFTBIT, SOFTWORD>(cw, *pe) * PPCM / vnodes[*pe].nedges;
407  if (commit)
408  score[*pe] += d;
409  else
410  dtot += d;
411  }
412  }
413  if (!commit)
414  softwords_flip(expected, c);
415  }
416  if (!commit)
417  {
418  if (dtot >= 0)
419  {
420  lfprintf(stderr, " abort %d\n", v);
421  break; // Next v
422  }
423  }
424  else
425  {
426  softwords_flip(cw, v);
427  ++nflipped;
428  tots += dtot;
429  progress = true;
430  v = k - 1; // Force exit to update maxs ?
431  }
432  } // commit
433  } // v
434  lfprintf(stderr, "progress %d\n", progress);
435 #if 0
436  fprintf(stderr, "CHECKING TOTS INCREMENT (slow) %d\n", tots);
437  score_t tots2 = compute_scores(cw, expected, received, n_k, score, k);
438  if ( tots2 != tots ) fail("bad tots update");
439 #endif
440  }
441 
442  delete[] score;
443  delete[] received;
444  delete[] expected;
445 
446  return nflipped;
447  }
448 
449  // EN 302 307-1 5.3.2.1 post-processing of parity bits.
450  // In-place allowed.
451 
452 #if 1
453  static void integrate_bits(const SOFTWORD *in, SOFTWORD *out, int nwords)
454  {
455  SOFTBIT sum;
456  softbit_clear(&sum);
457  for (int i = 0; i < nwords; ++i)
458  {
459  SOFTWORD w = in[i];
460  for (int b = 0; b < SWSIZE; ++b)
461  {
462  sum = softbit_xor(sum, softword_get(w, b));
463  softword_write(w, b, sum);
464  }
465  out[i] = w;
466  }
467  }
468 #else
469  // Optimized for hard_sb
470  static void integrate_bits(const uint8_t *in, uint8_t *out, int nwords)
471  {
472  // TBD Optimize
473  uint8_t prev = 0;
474  for (int i = 0; i < nwords; ++i)
475  {
476  uint8_t c = in[i];
477  for (int j = SWSIZE; j--;)
478  {
479  c ^= prev << j;
480  prev = (c >> j) & 1;
481  }
482  out[i] = c;
483  }
484  }
485 #endif
486 
487  // Undo EN 302 307-1 5.3.2.1, post-processing of parity bits.
488  // In-place allowed.
489 
490 #if 1
491  static void diff_bits(const SOFTWORD *in, SOFTWORD *out, int nwords)
492  {
493  SOFTBIT prev;
494  softbit_clear(&prev);
495  for (int i = 0; i < nwords; ++i, ++in, ++out)
496  {
497  SOFTWORD w = *in;
498  for (int b = 0; b < SWSIZE; ++b)
499  {
500  SOFTBIT n = softword_get(w, b);
501  softword_write(w, b, softbit_xor(prev, n));
502  prev = n;
503  }
504  *out = w;
505  }
506  }
507 #else
508  // Optimized for hard_sb
509  static void diff_bits(const uint8_t *in, uint8_t *out, int nwords)
510  {
511  uint8_t prev = 0;
512  for (int i = 0; i < nwords; ++i)
513  {
514  uint8_t c = in[i];
515  out[i] = c ^ (prev | (c >> 1));
516  prev = (c & 1) << (SWSIZE - 1);
517  }
518  }
519 #endif
520 
521 }; // ldpc_engine
522 
523 } // namespace leansdr
524 
525 #endif // LEANSDR_LDPC_H
int64_t score_t
Definition: ldpc.h:258
node * cnodes
Definition: ldpc.h:84
void softword_write(hard_sb &p, int b, bool v)
Definition: softword.h:54
void print_node_stats()
Definition: ldpc.h:137
bool softwords_xor(const hard_sb p1[], const hard_sb p2[], int b)
Definition: softword.h:42
score_t compute_scores(SOFTWORD *m, SOFTWORD *p, SOFTWORD *q, int nc, score_t *score, int k)
Definition: ldpc.h:260
bool softbit_harden(bool b)
Definition: softword.h:38
ldpc_engine(const ldpc_table< Taddr > *table, int _k, int _n)
Definition: ldpc.h:88
static void integrate_bits(const SOFTWORD *in, SOFTWORD *out, int nwords)
Definition: ldpc.h:453
void softwords_flip(hard_sb p[], int b)
Definition: softword.h:63
__int64 int64_t
Definition: rtptypes_win.h:47
Taddr cols[MAX_COLS]
Definition: ldpc.h:41
void softbit_clear(bool *p)
Definition: softword.h:41
#define lfprintf(...)
Definition: ldpc.h:20
unsigned char uint8_t
Definition: rtptypes_win.h:42
void fail(const char *s)
Definition: framework.cpp:11
void encode(const ldpc_table< Taddr > *table, const SOFTWORD *msg, int k, int n, SOFTWORD *parity, int integrate=true)
Definition: ldpc.h:199
static const int MAX_ROWS
Definition: ldpc.h:34
int32_t i
Definition: decimators.h:244
void append(Taddr a)
Definition: ldpc.h:71
static const int MAX_COLS
Definition: ldpc.h:35
int count_edges(node *nodes, int nnodes)
Definition: ldpc.h:145
void fatal(const char *s)
Definition: framework.cpp:6
void softword_zero(hard_sb *p)
Definition: softword.h:46
int decode_bitflip(const ldpc_table< Taddr > *table, SOFTWORD *cw, int k, int n, int max_bitflips)
Definition: ldpc.h:285
struct leansdr::ldpc_table::row rows[MAX_ROWS]
unsigned char parity(uint8_t x)
Definition: math.cpp:27
bool softbit_xor(bool x, bool y)
Definition: softword.h:40
static void diff_bits(const SOFTWORD *in, SOFTWORD *out, int nwords)
Definition: ldpc.h:491
void softbit_set(bool *p, bool v)
Definition: softword.h:37
node * vnodes
Definition: ldpc.h:83
bool softword_get(const hard_sb &p, int b)
Definition: softword.h:23