blob: a2c13def40c3b86a7c4965c3bbc42ea7f5d7dd03 [file] [log] [blame]
Neels Hofmeyr17518fe2017-06-20 04:35:06 +02001/*! \file conv.c
2 * Generic convolutional encoding / decoding. */
Sylvain Munaut19dc5c92011-04-23 16:09:19 +02003/*
Sylvain Munaut19dc5c92011-04-23 16:09:19 +02004 * Copyright (C) 2011 Sylvain Munaut <tnt@246tNt.com>
5 *
6 * All Rights Reserved
7 *
Harald Weltee08da972017-11-13 01:00:26 +09008 * SPDX-License-Identifier: GPL-2.0+
9 *
Sylvain Munaut19dc5c92011-04-23 16:09:19 +020010 * This program is free software; you can redistribute it and/or modify
11 * it under the terms of the GNU General Public License as published by
12 * the Free Software Foundation; either version 2 of the License, or
13 * (at your option) any later version.
14 *
15 * This program is distributed in the hope that it will be useful,
16 * but WITHOUT ANY WARRANTY; without even the implied warranty of
17 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18 * GNU General Public License for more details.
19 *
20 * You should have received a copy of the GNU General Public License along
21 * with this program; if not, write to the Free Software Foundation, Inc.,
22 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
23 */
24
Harald Welteba6988b2011-08-17 12:46:48 +020025/*! \addtogroup conv
26 * @{
Neels Hofmeyr17518fe2017-06-20 04:35:06 +020027 * Osmocom convolutional encoder and decoder.
28 *
29 * \file conv.c */
Harald Welteba6988b2011-08-17 12:46:48 +020030
Holger Hans Peter Freyther47723482011-11-09 11:26:15 +010031#include "config.h"
32#ifdef HAVE_ALLOCA_H
Sylvain Munaut19dc5c92011-04-23 16:09:19 +020033#include <alloca.h>
Holger Hans Peter Freyther47723482011-11-09 11:26:15 +010034#endif
Sylvain Munaut19dc5c92011-04-23 16:09:19 +020035#include <stdint.h>
36#include <stdlib.h>
37#include <string.h>
38
39#include <osmocom/core/bits.h>
40#include <osmocom/core/conv.h>
41
42
43/* ------------------------------------------------------------------------ */
Sylvain Munautae8dbb42011-11-24 17:47:32 +010044/* Common */
45/* ------------------------------------------------------------------------ */
46
47int
48osmo_conv_get_input_length(const struct osmo_conv_code *code, int len)
49{
50 return len <= 0 ? code->len : len;
51}
52
53int
54osmo_conv_get_output_length(const struct osmo_conv_code *code, int len)
55{
56 int pbits, in_len, out_len;
57
58 /* Input length */
59 in_len = osmo_conv_get_input_length(code, len);
60
61 /* Output length */
62 out_len = in_len * code->N;
63
64 if (code->term == CONV_TERM_FLUSH)
65 out_len += code->N * (code->K - 1);
66
67 /* Count punctured bits */
68 if (code->puncture) {
69 for (pbits=0; code->puncture[pbits] >= 0; pbits++);
70 out_len -= pbits;
71 }
72
73 return out_len;
74}
75
76
77/* ------------------------------------------------------------------------ */
Sylvain Munaut19dc5c92011-04-23 16:09:19 +020078/* Encoding */
79/* ------------------------------------------------------------------------ */
80
Neels Hofmeyr87e45502017-06-20 00:17:59 +020081/*! Initialize a convolutional encoder
Harald Welteba6988b2011-08-17 12:46:48 +020082 * \param[in,out] encoder Encoder state to initialize
83 * \param[in] code Description of convolutional code
84 */
Sylvain Munaut19dc5c92011-04-23 16:09:19 +020085void
86osmo_conv_encode_init(struct osmo_conv_encoder *encoder,
87 const struct osmo_conv_code *code)
88{
89 memset(encoder, 0x00, sizeof(struct osmo_conv_encoder));
90 encoder->code = code;
91}
92
Sylvain Munaut297d13f2011-11-24 17:46:58 +010093void
94osmo_conv_encode_load_state(struct osmo_conv_encoder *encoder,
95 const ubit_t *input)
96{
97 int i;
98 uint8_t state = 0;
99
100 for (i=0; i<(encoder->code->K-1); i++)
101 state = (state << 1) | input[i];
102
103 encoder->state = state;
104}
105
Sylvain Munaut19dc5c92011-04-23 16:09:19 +0200106static inline int
107_conv_encode_do_output(struct osmo_conv_encoder *encoder,
108 uint8_t out, ubit_t *output)
109{
110 const struct osmo_conv_code *code = encoder->code;
111 int o_idx = 0;
112 int j;
113
114 if (code->puncture) {
115 for (j=0; j<code->N; j++)
116 {
117 int bit_no = code->N - j - 1;
118 int r_idx = encoder->i_idx * code->N + j;
119
120 if (code->puncture[encoder->p_idx] == r_idx)
121 encoder->p_idx++;
122 else
123 output[o_idx++] = (out >> bit_no) & 1;
124 }
125 } else {
126 for (j=0; j<code->N; j++)
127 {
128 int bit_no = code->N - j - 1;
129 output[o_idx++] = (out >> bit_no) & 1;
130 }
131 }
132
133 return o_idx;
134}
135
136int
137osmo_conv_encode_raw(struct osmo_conv_encoder *encoder,
138 const ubit_t *input, ubit_t *output, int n)
139{
140 const struct osmo_conv_code *code = encoder->code;
141 uint8_t state;
142 int i;
143 int o_idx;
144
145 o_idx = 0;
146 state = encoder->state;
147
148 for (i=0; i<n; i++) {
149 int bit = input[i];
150 uint8_t out;
151
152 out = code->next_output[state][bit];
153 state = code->next_state[state][bit];
154
155 o_idx += _conv_encode_do_output(encoder, out, &output[o_idx]);
156
157 encoder->i_idx++;
158 }
159
160 encoder->state = state;
161
162 return o_idx;
163}
164
165int
Sylvain Munaut297d13f2011-11-24 17:46:58 +0100166osmo_conv_encode_flush(struct osmo_conv_encoder *encoder,
167 ubit_t *output)
Sylvain Munaut19dc5c92011-04-23 16:09:19 +0200168{
169 const struct osmo_conv_code *code = encoder->code;
170 uint8_t state;
171 int n;
172 int i;
173 int o_idx;
174
175 n = code->K - 1;
176
177 o_idx = 0;
178 state = encoder->state;
179
180 for (i=0; i<n; i++) {
181 uint8_t out;
182
183 if (code->next_term_output) {
184 out = code->next_term_output[state];
185 state = code->next_term_state[state];
186 } else {
187 out = code->next_output[state][0];
188 state = code->next_state[state][0];
189 }
190
191 o_idx += _conv_encode_do_output(encoder, out, &output[o_idx]);
192
193 encoder->i_idx++;
194 }
195
196 encoder->state = state;
197
198 return o_idx;
199}
200
Neels Hofmeyr87e45502017-06-20 00:17:59 +0200201/*! All-in-one convolutional encoding function
Harald Welteba6988b2011-08-17 12:46:48 +0200202 * \param[in] code description of convolutional code to be used
203 * \param[in] input array of unpacked bits (uncoded)
204 * \param[out] output array of unpacked bits (encoded)
Sylvain Munaut03d2c892011-11-24 11:53:49 +0100205 * \return Number of produced output bits
Harald Welteba6988b2011-08-17 12:46:48 +0200206 *
207 * This is an all-in-one function, taking care of
Sylvain Munaut297d13f2011-11-24 17:46:58 +0100208 * \ref osmo_conv_init, \ref osmo_conv_encode_load_state,
209 * \ref osmo_conv_encode_raw and \ref osmo_conv_encode_flush as needed.
Harald Welteba6988b2011-08-17 12:46:48 +0200210 */
Sylvain Munaut19dc5c92011-04-23 16:09:19 +0200211int
212osmo_conv_encode(const struct osmo_conv_code *code,
213 const ubit_t *input, ubit_t *output)
214{
215 struct osmo_conv_encoder encoder;
216 int l;
217
218 osmo_conv_encode_init(&encoder, code);
Sylvain Munaut297d13f2011-11-24 17:46:58 +0100219
220 if (code->term == CONV_TERM_TAIL_BITING) {
221 int eidx = code->len - code->K + 1;
222 osmo_conv_encode_load_state(&encoder, &input[eidx]);
223 }
224
225 l = osmo_conv_encode_raw(&encoder, input, output, code->len);
226
227 if (code->term == CONV_TERM_FLUSH)
228 l += osmo_conv_encode_flush(&encoder, &output[l]);
Sylvain Munaut19dc5c92011-04-23 16:09:19 +0200229
230 return l;
231}
232
233
234/* ------------------------------------------------------------------------ */
235/* Decoding (viterbi) */
236/* ------------------------------------------------------------------------ */
237
238#define MAX_AE 0x00ffffff
239
Tom Tsou35536802016-11-24 19:24:32 +0700240/* Forward declaration for accerlated decoding with certain codes */
241int
242osmo_conv_decode_acc(const struct osmo_conv_code *code,
243 const sbit_t *input, ubit_t *output);
244
Sylvain Munaut19dc5c92011-04-23 16:09:19 +0200245void
246osmo_conv_decode_init(struct osmo_conv_decoder *decoder,
Sylvain Munaut297d13f2011-11-24 17:46:58 +0100247 const struct osmo_conv_code *code, int len, int start_state)
Sylvain Munaut19dc5c92011-04-23 16:09:19 +0200248{
249 int n_states;
250
251 /* Init */
252 if (len <= 0)
253 len = code->len;
254
255 n_states = 1 << (code->K - 1);
256
257 memset(decoder, 0x00, sizeof(struct osmo_conv_decoder));
258
259 decoder->code = code;
260 decoder->n_states = n_states;
261 decoder->len = len;
262
263 /* Allocate arrays */
264 decoder->ae = malloc(sizeof(unsigned int) * n_states);
265 decoder->ae_next = malloc(sizeof(unsigned int) * n_states);
266
267 decoder->state_history = malloc(sizeof(uint8_t) * n_states * (len + decoder->code->K - 1));
268
269 /* Classic reset */
Sylvain Munaut297d13f2011-11-24 17:46:58 +0100270 osmo_conv_decode_reset(decoder, start_state);
Sylvain Munaut19dc5c92011-04-23 16:09:19 +0200271}
272
273void
Sylvain Munaut297d13f2011-11-24 17:46:58 +0100274osmo_conv_decode_reset(struct osmo_conv_decoder *decoder, int start_state)
Sylvain Munaut19dc5c92011-04-23 16:09:19 +0200275{
276 int i;
277
278 /* Reset indexes */
279 decoder->o_idx = 0;
280 decoder->p_idx = 0;
281
Sylvain Munaut297d13f2011-11-24 17:46:58 +0100282 /* Initial error */
283 if (start_state < 0) {
284 /* All states possible */
285 memset(decoder->ae, 0x00, sizeof(unsigned int) * decoder->n_states);
286 } else {
287 /* Fixed start state */
288 for (i=0; i<decoder->n_states; i++) {
289 decoder->ae[i] = (i == start_state) ? 0 : MAX_AE;
290 }
Sylvain Munaut19dc5c92011-04-23 16:09:19 +0200291 }
292}
293
294void
Sylvain Munaut297d13f2011-11-24 17:46:58 +0100295osmo_conv_decode_rewind(struct osmo_conv_decoder *decoder)
296{
297 int i;
298 unsigned int min_ae = MAX_AE;
299
300 /* Reset indexes */
301 decoder->o_idx = 0;
302 decoder->p_idx = 0;
303
304 /* Initial error normalize (remove constant) */
305 for (i=0; i<decoder->n_states; i++) {
306 if (decoder->ae[i] < min_ae)
307 min_ae = decoder->ae[i];
308 }
309
310 for (i=0; i<decoder->n_states; i++)
311 decoder->ae[i] -= min_ae;
312}
313
314void
Sylvain Munaut19dc5c92011-04-23 16:09:19 +0200315osmo_conv_decode_deinit(struct osmo_conv_decoder *decoder)
316{
317 free(decoder->ae);
318 free(decoder->ae_next);
319 free(decoder->state_history);
320
321 memset(decoder, 0x00, sizeof(struct osmo_conv_decoder));
322}
323
324int
325osmo_conv_decode_scan(struct osmo_conv_decoder *decoder,
326 const sbit_t *input, int n)
327{
328 const struct osmo_conv_code *code = decoder->code;
329
330 int i, s, b, j;
331
332 int n_states;
333 unsigned int *ae;
334 unsigned int *ae_next;
335 uint8_t *state_history;
336 sbit_t *in_sym;
337
338 int i_idx, p_idx;
339
340 /* Prepare */
341 n_states = decoder->n_states;
342
343 ae = decoder->ae;
344 ae_next = decoder->ae_next;
345 state_history = &decoder->state_history[n_states * decoder->o_idx];
346
347 in_sym = alloca(sizeof(sbit_t) * code->N);
348
349 i_idx = 0;
350 p_idx = decoder->p_idx;
351
352 /* Scan the treillis */
353 for (i=0; i<n; i++)
354 {
355 /* Reset next accumulated error */
356 for (s=0; s<n_states; s++) {
357 ae_next[s] = MAX_AE;
358 }
359
360 /* Get input */
361 if (code->puncture) {
362 /* Hard way ... */
363 for (j=0; j<code->N; j++) {
364 int idx = ((decoder->o_idx + i) * code->N) + j;
365 if (idx == code->puncture[p_idx]) {
366 in_sym[j] = 0; /* Undefined */
367 p_idx++;
368 } else {
369 in_sym[j] = input[i_idx];
370 i_idx++;
371 }
372 }
373 } else {
374 /* Easy, just copy N bits */
375 memcpy(in_sym, &input[i_idx], code->N);
376 i_idx += code->N;
377 }
378
379 /* Scan all state */
380 for (s=0; s<n_states; s++)
381 {
382 /* Scan possible input bits */
383 for (b=0; b<2; b++)
384 {
385 int nae, ov, e;
386 uint8_t m;
387
388 /* Next output and state */
389 uint8_t out = code->next_output[s][b];
390 uint8_t state = code->next_state[s][b];
391
392 /* New error for this path */
393 nae = ae[s]; /* start from last error */
394 m = 1 << (code->N - 1); /* mask for 'out' bit selection */
395
396 for (j=0; j<code->N; j++) {
Sylvain Munautd4440d42011-11-24 16:04:58 +0100397 int is = (int)in_sym[j];
398 if (is) {
399 ov = (out & m) ? -127 : 127; /* sbit_t value for it */
400 e = is - ov; /* raw error for this bit */
401 nae += (e * e) >> 9; /* acc the squared/scaled value */
402 }
Sylvain Munaut19dc5c92011-04-23 16:09:19 +0200403 m >>= 1; /* next mask bit */
404 }
405
406 /* Is it survivor ? */
407 if (ae_next[state] > nae) {
408 ae_next[state] = nae;
409 state_history[(n_states * i) + state] = s;
410 }
411 }
412 }
413
414 /* Copy accumulated error */
415 memcpy(ae, ae_next, sizeof(unsigned int) * n_states);
416 }
417
418 /* Update decoder state */
419 decoder->p_idx = p_idx;
420 decoder->o_idx += n;
421
422 return i_idx;
423}
424
425int
Sylvain Munaut297d13f2011-11-24 17:46:58 +0100426osmo_conv_decode_flush(struct osmo_conv_decoder *decoder,
427 const sbit_t *input)
Sylvain Munaut19dc5c92011-04-23 16:09:19 +0200428{
429 const struct osmo_conv_code *code = decoder->code;
430
431 int i, s, j;
432
433 int n_states;
434 unsigned int *ae;
435 unsigned int *ae_next;
436 uint8_t *state_history;
437 sbit_t *in_sym;
438
439 int i_idx, p_idx;
440
441 /* Prepare */
442 n_states = decoder->n_states;
443
444 ae = decoder->ae;
445 ae_next = decoder->ae_next;
446 state_history = &decoder->state_history[n_states * decoder->o_idx];
447
448 in_sym = alloca(sizeof(sbit_t) * code->N);
449
450 i_idx = 0;
451 p_idx = decoder->p_idx;
452
453 /* Scan the treillis */
454 for (i=0; i<code->K-1; i++)
455 {
456 /* Reset next accumulated error */
457 for (s=0; s<n_states; s++) {
458 ae_next[s] = MAX_AE;
459 }
460
461 /* Get input */
462 if (code->puncture) {
463 /* Hard way ... */
464 for (j=0; j<code->N; j++) {
465 int idx = ((decoder->o_idx + i) * code->N) + j;
466 if (idx == code->puncture[p_idx]) {
467 in_sym[j] = 0; /* Undefined */
468 p_idx++;
469 } else {
470 in_sym[j] = input[i_idx];
471 i_idx++;
472 }
473 }
474 } else {
475 /* Easy, just copy N bits */
476 memcpy(in_sym, &input[i_idx], code->N);
477 i_idx += code->N;
478 }
479
480 /* Scan all state */
481 for (s=0; s<n_states; s++)
482 {
483 int nae, ov, e;
484 uint8_t m;
485
486 /* Next output and state */
487 uint8_t out;
488 uint8_t state;
489
490 if (code->next_term_output) {
491 out = code->next_term_output[s];
492 state = code->next_term_state[s];
493 } else {
494 out = code->next_output[s][0];
495 state = code->next_state[s][0];
496 }
497
498 /* New error for this path */
499 nae = ae[s]; /* start from last error */
500 m = 1 << (code->N - 1); /* mask for 'out' bit selection */
501
502 for (j=0; j<code->N; j++) {
Sylvain Munaut1dd7c842011-04-28 22:30:30 +0200503 int is = (int)in_sym[j];
504 if (is) {
505 ov = (out & m) ? -127 : 127; /* sbit_t value for it */
506 e = is - ov; /* raw error for this bit */
507 nae += (e * e) >> 9; /* acc the squared/scaled value */
508 }
Sylvain Munaut19dc5c92011-04-23 16:09:19 +0200509 m >>= 1; /* next mask bit */
510 }
511
512 /* Is it survivor ? */
513 if (ae_next[state] > nae) {
514 ae_next[state] = nae;
515 state_history[(n_states * i) + state] = s;
516 }
517 }
518
519 /* Copy accumulated error */
520 memcpy(ae, ae_next, sizeof(unsigned int) * n_states);
521 }
522
523 /* Update decoder state */
524 decoder->p_idx = p_idx;
525 decoder->o_idx += code->K - 1;
526
527 return i_idx;
528}
529
530int
531osmo_conv_decode_get_output(struct osmo_conv_decoder *decoder,
Sylvain Munaut297d13f2011-11-24 17:46:58 +0100532 ubit_t *output, int has_flush, int end_state)
Sylvain Munaut19dc5c92011-04-23 16:09:19 +0200533{
534 const struct osmo_conv_code *code = decoder->code;
535
536 int min_ae;
537 uint8_t min_state, cur_state;
538 int i, s, n;
539
540 uint8_t *sh_ptr;
541
Sylvain Munaut297d13f2011-11-24 17:46:58 +0100542 /* End state ? */
543 if (end_state < 0) {
544 /* Find state with least error */
545 min_ae = MAX_AE;
546 min_state = 0xff;
Sylvain Munaut19dc5c92011-04-23 16:09:19 +0200547
Sylvain Munaut297d13f2011-11-24 17:46:58 +0100548 for (s=0; s<decoder->n_states; s++)
549 {
550 if (decoder->ae[s] < min_ae) {
551 min_ae = decoder->ae[s];
552 min_state = s;
553 }
Sylvain Munaut19dc5c92011-04-23 16:09:19 +0200554 }
Sylvain Munaut19dc5c92011-04-23 16:09:19 +0200555
Sylvain Munaut297d13f2011-11-24 17:46:58 +0100556 if (min_state == 0xff)
557 return -1;
558 } else {
559 min_state = (uint8_t) end_state;
560 min_ae = decoder->ae[end_state];
561 }
Sylvain Munaut19dc5c92011-04-23 16:09:19 +0200562
563 /* Traceback */
564 cur_state = min_state;
565
566 n = decoder->o_idx;
567
568 sh_ptr = &decoder->state_history[decoder->n_states * (n-1)];
569
570 /* No output for the K-1 termination input bits */
Sylvain Munaut297d13f2011-11-24 17:46:58 +0100571 if (has_flush) {
Sylvain Munaut19dc5c92011-04-23 16:09:19 +0200572 for (i=0; i<code->K-1; i++) {
573 cur_state = sh_ptr[cur_state];
574 sh_ptr -= decoder->n_states;
575 }
576 n -= code->K - 1;
577 }
578
579 /* Generate output backward */
580 for (i=n-1; i>=0; i--)
581 {
582 min_state = cur_state;
583 cur_state = sh_ptr[cur_state];
584
585 sh_ptr -= decoder->n_states;
586
587 if (code->next_state[cur_state][0] == min_state)
588 output[i] = 0;
589 else
590 output[i] = 1;
591 }
592
593 return min_ae;
594}
595
Neels Hofmeyr87e45502017-06-20 00:17:59 +0200596/*! All-in-one convolutional decoding function
Harald Welteba6988b2011-08-17 12:46:48 +0200597 * \param[in] code description of convolutional code to be used
598 * \param[in] input array of soft bits (coded)
599 * \param[out] output array of unpacked bits (decoded)
600 *
601 * This is an all-in-one function, taking care of
602 * \ref osmo_conv_decode_init, \ref osmo_conv_decode_scan,
Sylvain Munaut297d13f2011-11-24 17:46:58 +0100603 * \ref osmo_conv_decode_flush, \ref osmo_conv_decode_get_output and
Harald Welteba6988b2011-08-17 12:46:48 +0200604 * \ref osmo_conv_decode_deinit.
605 */
Sylvain Munaut19dc5c92011-04-23 16:09:19 +0200606int
607osmo_conv_decode(const struct osmo_conv_code *code,
608 const sbit_t *input, ubit_t *output)
609{
610 struct osmo_conv_decoder decoder;
611 int rv, l;
612
Tom Tsou35536802016-11-24 19:24:32 +0700613 /* Use accelerated implementation for supported codes */
614 if ((code->N <= 4) && ((code->K == 5) || (code->K == 7)))
615 return osmo_conv_decode_acc(code, input, output);
616
Sylvain Munaut297d13f2011-11-24 17:46:58 +0100617 osmo_conv_decode_init(&decoder, code, 0, 0);
618
619 if (code->term == CONV_TERM_TAIL_BITING) {
620 osmo_conv_decode_scan(&decoder, input, code->len);
621 osmo_conv_decode_rewind(&decoder);
622 }
Sylvain Munaut19dc5c92011-04-23 16:09:19 +0200623
624 l = osmo_conv_decode_scan(&decoder, input, code->len);
Sylvain Munaut19dc5c92011-04-23 16:09:19 +0200625
Sylvain Munaut297d13f2011-11-24 17:46:58 +0100626 if (code->term == CONV_TERM_FLUSH)
Vadim Yanitskiy6e6978a2017-06-12 03:47:34 +0700627 osmo_conv_decode_flush(&decoder, &input[l]);
Sylvain Munaut297d13f2011-11-24 17:46:58 +0100628
629 rv = osmo_conv_decode_get_output(&decoder, output,
630 code->term == CONV_TERM_FLUSH, /* has_flush */
631 code->term == CONV_TERM_FLUSH ? 0 : -1 /* end_state */
632 );
Sylvain Munaut19dc5c92011-04-23 16:09:19 +0200633
634 osmo_conv_decode_deinit(&decoder);
635
636 return rv;
637}
Harald Welteba6988b2011-08-17 12:46:48 +0200638
Sylvain Munautdca7d2c2012-04-18 21:53:23 +0200639/*! @} */