blob: 0e07e1f77d400efbf86830769215eac5dd76ea91 [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.
Sylvain Munaut19dc5c92011-04-23 16:09:19 +020019 */
20
Harald Welteba6988b2011-08-17 12:46:48 +020021/*! \addtogroup conv
22 * @{
Neels Hofmeyr17518fe2017-06-20 04:35:06 +020023 * Osmocom convolutional encoder and decoder.
24 *
25 * \file conv.c */
Harald Welteba6988b2011-08-17 12:46:48 +020026
Holger Hans Peter Freyther47723482011-11-09 11:26:15 +010027#include "config.h"
28#ifdef HAVE_ALLOCA_H
Sylvain Munaut19dc5c92011-04-23 16:09:19 +020029#include <alloca.h>
Holger Hans Peter Freyther47723482011-11-09 11:26:15 +010030#endif
Sylvain Munaut19dc5c92011-04-23 16:09:19 +020031#include <stdint.h>
32#include <stdlib.h>
33#include <string.h>
34
Vadim Yanitskiya8809f02020-02-09 04:12:53 +070035#include <osmocom/core/utils.h>
Sylvain Munaut19dc5c92011-04-23 16:09:19 +020036#include <osmocom/core/bits.h>
37#include <osmocom/core/conv.h>
38
39
40/* ------------------------------------------------------------------------ */
Sylvain Munautae8dbb42011-11-24 17:47:32 +010041/* Common */
42/* ------------------------------------------------------------------------ */
43
44int
45osmo_conv_get_input_length(const struct osmo_conv_code *code, int len)
46{
47 return len <= 0 ? code->len : len;
48}
49
50int
51osmo_conv_get_output_length(const struct osmo_conv_code *code, int len)
52{
53 int pbits, in_len, out_len;
54
55 /* Input length */
56 in_len = osmo_conv_get_input_length(code, len);
57
58 /* Output length */
59 out_len = in_len * code->N;
60
61 if (code->term == CONV_TERM_FLUSH)
62 out_len += code->N * (code->K - 1);
63
64 /* Count punctured bits */
65 if (code->puncture) {
66 for (pbits=0; code->puncture[pbits] >= 0; pbits++);
67 out_len -= pbits;
68 }
69
70 return out_len;
71}
72
73
74/* ------------------------------------------------------------------------ */
Sylvain Munaut19dc5c92011-04-23 16:09:19 +020075/* Encoding */
76/* ------------------------------------------------------------------------ */
77
Neels Hofmeyr87e45502017-06-20 00:17:59 +020078/*! Initialize a convolutional encoder
Harald Welteba6988b2011-08-17 12:46:48 +020079 * \param[in,out] encoder Encoder state to initialize
80 * \param[in] code Description of convolutional code
81 */
Sylvain Munaut19dc5c92011-04-23 16:09:19 +020082void
83osmo_conv_encode_init(struct osmo_conv_encoder *encoder,
84 const struct osmo_conv_code *code)
85{
86 memset(encoder, 0x00, sizeof(struct osmo_conv_encoder));
Vadim Yanitskiya8809f02020-02-09 04:12:53 +070087 OSMO_ASSERT(code != NULL);
Sylvain Munaut19dc5c92011-04-23 16:09:19 +020088 encoder->code = code;
89}
90
Sylvain Munaut297d13f2011-11-24 17:46:58 +010091void
92osmo_conv_encode_load_state(struct osmo_conv_encoder *encoder,
93 const ubit_t *input)
94{
95 int i;
96 uint8_t state = 0;
97
98 for (i=0; i<(encoder->code->K-1); i++)
99 state = (state << 1) | input[i];
100
101 encoder->state = state;
102}
103
Sylvain Munaut19dc5c92011-04-23 16:09:19 +0200104static inline int
105_conv_encode_do_output(struct osmo_conv_encoder *encoder,
106 uint8_t out, ubit_t *output)
107{
108 const struct osmo_conv_code *code = encoder->code;
109 int o_idx = 0;
110 int j;
111
112 if (code->puncture) {
113 for (j=0; j<code->N; j++)
114 {
115 int bit_no = code->N - j - 1;
116 int r_idx = encoder->i_idx * code->N + j;
117
118 if (code->puncture[encoder->p_idx] == r_idx)
119 encoder->p_idx++;
120 else
121 output[o_idx++] = (out >> bit_no) & 1;
122 }
123 } else {
124 for (j=0; j<code->N; j++)
125 {
126 int bit_no = code->N - j - 1;
127 output[o_idx++] = (out >> bit_no) & 1;
128 }
129 }
130
131 return o_idx;
132}
133
134int
135osmo_conv_encode_raw(struct osmo_conv_encoder *encoder,
136 const ubit_t *input, ubit_t *output, int n)
137{
138 const struct osmo_conv_code *code = encoder->code;
139 uint8_t state;
140 int i;
141 int o_idx;
142
143 o_idx = 0;
144 state = encoder->state;
145
146 for (i=0; i<n; i++) {
147 int bit = input[i];
148 uint8_t out;
149
150 out = code->next_output[state][bit];
151 state = code->next_state[state][bit];
152
153 o_idx += _conv_encode_do_output(encoder, out, &output[o_idx]);
154
155 encoder->i_idx++;
156 }
157
158 encoder->state = state;
159
160 return o_idx;
161}
162
163int
Sylvain Munaut297d13f2011-11-24 17:46:58 +0100164osmo_conv_encode_flush(struct osmo_conv_encoder *encoder,
165 ubit_t *output)
Sylvain Munaut19dc5c92011-04-23 16:09:19 +0200166{
167 const struct osmo_conv_code *code = encoder->code;
168 uint8_t state;
169 int n;
170 int i;
171 int o_idx;
172
173 n = code->K - 1;
174
175 o_idx = 0;
176 state = encoder->state;
177
178 for (i=0; i<n; i++) {
179 uint8_t out;
180
181 if (code->next_term_output) {
182 out = code->next_term_output[state];
183 state = code->next_term_state[state];
184 } else {
185 out = code->next_output[state][0];
186 state = code->next_state[state][0];
187 }
188
189 o_idx += _conv_encode_do_output(encoder, out, &output[o_idx]);
190
191 encoder->i_idx++;
192 }
193
194 encoder->state = state;
195
196 return o_idx;
197}
198
Neels Hofmeyr87e45502017-06-20 00:17:59 +0200199/*! All-in-one convolutional encoding function
Harald Welteba6988b2011-08-17 12:46:48 +0200200 * \param[in] code description of convolutional code to be used
201 * \param[in] input array of unpacked bits (uncoded)
202 * \param[out] output array of unpacked bits (encoded)
Sylvain Munaut03d2c892011-11-24 11:53:49 +0100203 * \return Number of produced output bits
Harald Welteba6988b2011-08-17 12:46:48 +0200204 *
205 * This is an all-in-one function, taking care of
Sylvain Munaut297d13f2011-11-24 17:46:58 +0100206 * \ref osmo_conv_init, \ref osmo_conv_encode_load_state,
207 * \ref osmo_conv_encode_raw and \ref osmo_conv_encode_flush as needed.
Harald Welteba6988b2011-08-17 12:46:48 +0200208 */
Sylvain Munaut19dc5c92011-04-23 16:09:19 +0200209int
210osmo_conv_encode(const struct osmo_conv_code *code,
211 const ubit_t *input, ubit_t *output)
212{
213 struct osmo_conv_encoder encoder;
214 int l;
215
216 osmo_conv_encode_init(&encoder, code);
Sylvain Munaut297d13f2011-11-24 17:46:58 +0100217
218 if (code->term == CONV_TERM_TAIL_BITING) {
219 int eidx = code->len - code->K + 1;
220 osmo_conv_encode_load_state(&encoder, &input[eidx]);
221 }
222
223 l = osmo_conv_encode_raw(&encoder, input, output, code->len);
224
225 if (code->term == CONV_TERM_FLUSH)
226 l += osmo_conv_encode_flush(&encoder, &output[l]);
Sylvain Munaut19dc5c92011-04-23 16:09:19 +0200227
228 return l;
229}
230
231
232/* ------------------------------------------------------------------------ */
233/* Decoding (viterbi) */
234/* ------------------------------------------------------------------------ */
235
236#define MAX_AE 0x00ffffff
237
Tom Tsou35536802016-11-24 19:24:32 +0700238/* Forward declaration for accerlated decoding with certain codes */
239int
240osmo_conv_decode_acc(const struct osmo_conv_code *code,
241 const sbit_t *input, ubit_t *output);
242
Sylvain Munaut19dc5c92011-04-23 16:09:19 +0200243void
244osmo_conv_decode_init(struct osmo_conv_decoder *decoder,
Sylvain Munaut297d13f2011-11-24 17:46:58 +0100245 const struct osmo_conv_code *code, int len, int start_state)
Sylvain Munaut19dc5c92011-04-23 16:09:19 +0200246{
247 int n_states;
248
249 /* Init */
250 if (len <= 0)
251 len = code->len;
252
253 n_states = 1 << (code->K - 1);
254
255 memset(decoder, 0x00, sizeof(struct osmo_conv_decoder));
256
257 decoder->code = code;
258 decoder->n_states = n_states;
259 decoder->len = len;
260
261 /* Allocate arrays */
262 decoder->ae = malloc(sizeof(unsigned int) * n_states);
263 decoder->ae_next = malloc(sizeof(unsigned int) * n_states);
264
265 decoder->state_history = malloc(sizeof(uint8_t) * n_states * (len + decoder->code->K - 1));
266
267 /* Classic reset */
Sylvain Munaut297d13f2011-11-24 17:46:58 +0100268 osmo_conv_decode_reset(decoder, start_state);
Sylvain Munaut19dc5c92011-04-23 16:09:19 +0200269}
270
271void
Sylvain Munaut297d13f2011-11-24 17:46:58 +0100272osmo_conv_decode_reset(struct osmo_conv_decoder *decoder, int start_state)
Sylvain Munaut19dc5c92011-04-23 16:09:19 +0200273{
274 int i;
275
276 /* Reset indexes */
277 decoder->o_idx = 0;
278 decoder->p_idx = 0;
279
Sylvain Munaut297d13f2011-11-24 17:46:58 +0100280 /* Initial error */
281 if (start_state < 0) {
282 /* All states possible */
283 memset(decoder->ae, 0x00, sizeof(unsigned int) * decoder->n_states);
284 } else {
285 /* Fixed start state */
286 for (i=0; i<decoder->n_states; i++) {
287 decoder->ae[i] = (i == start_state) ? 0 : MAX_AE;
288 }
Sylvain Munaut19dc5c92011-04-23 16:09:19 +0200289 }
290}
291
292void
Sylvain Munaut297d13f2011-11-24 17:46:58 +0100293osmo_conv_decode_rewind(struct osmo_conv_decoder *decoder)
294{
295 int i;
296 unsigned int min_ae = MAX_AE;
297
298 /* Reset indexes */
299 decoder->o_idx = 0;
300 decoder->p_idx = 0;
301
302 /* Initial error normalize (remove constant) */
303 for (i=0; i<decoder->n_states; i++) {
304 if (decoder->ae[i] < min_ae)
305 min_ae = decoder->ae[i];
306 }
307
308 for (i=0; i<decoder->n_states; i++)
309 decoder->ae[i] -= min_ae;
310}
311
312void
Sylvain Munaut19dc5c92011-04-23 16:09:19 +0200313osmo_conv_decode_deinit(struct osmo_conv_decoder *decoder)
314{
315 free(decoder->ae);
316 free(decoder->ae_next);
317 free(decoder->state_history);
318
319 memset(decoder, 0x00, sizeof(struct osmo_conv_decoder));
320}
321
322int
323osmo_conv_decode_scan(struct osmo_conv_decoder *decoder,
324 const sbit_t *input, int n)
325{
326 const struct osmo_conv_code *code = decoder->code;
327
328 int i, s, b, j;
329
330 int n_states;
331 unsigned int *ae;
332 unsigned int *ae_next;
333 uint8_t *state_history;
334 sbit_t *in_sym;
335
336 int i_idx, p_idx;
337
338 /* Prepare */
339 n_states = decoder->n_states;
340
341 ae = decoder->ae;
342 ae_next = decoder->ae_next;
343 state_history = &decoder->state_history[n_states * decoder->o_idx];
344
345 in_sym = alloca(sizeof(sbit_t) * code->N);
346
347 i_idx = 0;
348 p_idx = decoder->p_idx;
349
350 /* Scan the treillis */
351 for (i=0; i<n; i++)
352 {
353 /* Reset next accumulated error */
354 for (s=0; s<n_states; s++) {
355 ae_next[s] = MAX_AE;
356 }
357
358 /* Get input */
359 if (code->puncture) {
360 /* Hard way ... */
361 for (j=0; j<code->N; j++) {
362 int idx = ((decoder->o_idx + i) * code->N) + j;
363 if (idx == code->puncture[p_idx]) {
364 in_sym[j] = 0; /* Undefined */
365 p_idx++;
366 } else {
367 in_sym[j] = input[i_idx];
368 i_idx++;
369 }
370 }
371 } else {
372 /* Easy, just copy N bits */
373 memcpy(in_sym, &input[i_idx], code->N);
374 i_idx += code->N;
375 }
376
377 /* Scan all state */
378 for (s=0; s<n_states; s++)
379 {
380 /* Scan possible input bits */
381 for (b=0; b<2; b++)
382 {
383 int nae, ov, e;
384 uint8_t m;
385
386 /* Next output and state */
387 uint8_t out = code->next_output[s][b];
388 uint8_t state = code->next_state[s][b];
389
390 /* New error for this path */
391 nae = ae[s]; /* start from last error */
392 m = 1 << (code->N - 1); /* mask for 'out' bit selection */
393
394 for (j=0; j<code->N; j++) {
Sylvain Munautd4440d42011-11-24 16:04:58 +0100395 int is = (int)in_sym[j];
396 if (is) {
397 ov = (out & m) ? -127 : 127; /* sbit_t value for it */
398 e = is - ov; /* raw error for this bit */
399 nae += (e * e) >> 9; /* acc the squared/scaled value */
400 }
Sylvain Munaut19dc5c92011-04-23 16:09:19 +0200401 m >>= 1; /* next mask bit */
402 }
403
404 /* Is it survivor ? */
405 if (ae_next[state] > nae) {
406 ae_next[state] = nae;
407 state_history[(n_states * i) + state] = s;
408 }
409 }
410 }
411
412 /* Copy accumulated error */
413 memcpy(ae, ae_next, sizeof(unsigned int) * n_states);
414 }
415
416 /* Update decoder state */
417 decoder->p_idx = p_idx;
418 decoder->o_idx += n;
419
420 return i_idx;
421}
422
423int
Sylvain Munaut297d13f2011-11-24 17:46:58 +0100424osmo_conv_decode_flush(struct osmo_conv_decoder *decoder,
425 const sbit_t *input)
Sylvain Munaut19dc5c92011-04-23 16:09:19 +0200426{
427 const struct osmo_conv_code *code = decoder->code;
428
429 int i, s, j;
430
431 int n_states;
432 unsigned int *ae;
433 unsigned int *ae_next;
434 uint8_t *state_history;
435 sbit_t *in_sym;
436
437 int i_idx, p_idx;
438
439 /* Prepare */
440 n_states = decoder->n_states;
441
442 ae = decoder->ae;
443 ae_next = decoder->ae_next;
444 state_history = &decoder->state_history[n_states * decoder->o_idx];
445
446 in_sym = alloca(sizeof(sbit_t) * code->N);
447
448 i_idx = 0;
449 p_idx = decoder->p_idx;
450
451 /* Scan the treillis */
452 for (i=0; i<code->K-1; i++)
453 {
454 /* Reset next accumulated error */
455 for (s=0; s<n_states; s++) {
456 ae_next[s] = MAX_AE;
457 }
458
459 /* Get input */
460 if (code->puncture) {
461 /* Hard way ... */
462 for (j=0; j<code->N; j++) {
463 int idx = ((decoder->o_idx + i) * code->N) + j;
464 if (idx == code->puncture[p_idx]) {
465 in_sym[j] = 0; /* Undefined */
466 p_idx++;
467 } else {
468 in_sym[j] = input[i_idx];
469 i_idx++;
470 }
471 }
472 } else {
473 /* Easy, just copy N bits */
474 memcpy(in_sym, &input[i_idx], code->N);
475 i_idx += code->N;
476 }
477
478 /* Scan all state */
479 for (s=0; s<n_states; s++)
480 {
481 int nae, ov, e;
482 uint8_t m;
483
484 /* Next output and state */
485 uint8_t out;
486 uint8_t state;
487
488 if (code->next_term_output) {
489 out = code->next_term_output[s];
490 state = code->next_term_state[s];
491 } else {
492 out = code->next_output[s][0];
493 state = code->next_state[s][0];
494 }
495
496 /* New error for this path */
497 nae = ae[s]; /* start from last error */
498 m = 1 << (code->N - 1); /* mask for 'out' bit selection */
499
500 for (j=0; j<code->N; j++) {
Sylvain Munaut1dd7c842011-04-28 22:30:30 +0200501 int is = (int)in_sym[j];
502 if (is) {
503 ov = (out & m) ? -127 : 127; /* sbit_t value for it */
504 e = is - ov; /* raw error for this bit */
505 nae += (e * e) >> 9; /* acc the squared/scaled value */
506 }
Sylvain Munaut19dc5c92011-04-23 16:09:19 +0200507 m >>= 1; /* next mask bit */
508 }
509
510 /* Is it survivor ? */
511 if (ae_next[state] > nae) {
512 ae_next[state] = nae;
513 state_history[(n_states * i) + state] = s;
514 }
515 }
516
517 /* Copy accumulated error */
518 memcpy(ae, ae_next, sizeof(unsigned int) * n_states);
519 }
520
521 /* Update decoder state */
522 decoder->p_idx = p_idx;
523 decoder->o_idx += code->K - 1;
524
525 return i_idx;
526}
527
528int
529osmo_conv_decode_get_output(struct osmo_conv_decoder *decoder,
Sylvain Munaut297d13f2011-11-24 17:46:58 +0100530 ubit_t *output, int has_flush, int end_state)
Sylvain Munaut19dc5c92011-04-23 16:09:19 +0200531{
532 const struct osmo_conv_code *code = decoder->code;
533
534 int min_ae;
535 uint8_t min_state, cur_state;
536 int i, s, n;
537
538 uint8_t *sh_ptr;
539
Sylvain Munaut297d13f2011-11-24 17:46:58 +0100540 /* End state ? */
541 if (end_state < 0) {
542 /* Find state with least error */
543 min_ae = MAX_AE;
544 min_state = 0xff;
Sylvain Munaut19dc5c92011-04-23 16:09:19 +0200545
Sylvain Munaut297d13f2011-11-24 17:46:58 +0100546 for (s=0; s<decoder->n_states; s++)
547 {
548 if (decoder->ae[s] < min_ae) {
549 min_ae = decoder->ae[s];
550 min_state = s;
551 }
Sylvain Munaut19dc5c92011-04-23 16:09:19 +0200552 }
Sylvain Munaut19dc5c92011-04-23 16:09:19 +0200553
Sylvain Munaut297d13f2011-11-24 17:46:58 +0100554 if (min_state == 0xff)
555 return -1;
556 } else {
557 min_state = (uint8_t) end_state;
558 min_ae = decoder->ae[end_state];
559 }
Sylvain Munaut19dc5c92011-04-23 16:09:19 +0200560
561 /* Traceback */
562 cur_state = min_state;
563
564 n = decoder->o_idx;
565
566 sh_ptr = &decoder->state_history[decoder->n_states * (n-1)];
567
568 /* No output for the K-1 termination input bits */
Sylvain Munaut297d13f2011-11-24 17:46:58 +0100569 if (has_flush) {
Sylvain Munaut19dc5c92011-04-23 16:09:19 +0200570 for (i=0; i<code->K-1; i++) {
571 cur_state = sh_ptr[cur_state];
572 sh_ptr -= decoder->n_states;
573 }
574 n -= code->K - 1;
575 }
576
577 /* Generate output backward */
578 for (i=n-1; i>=0; i--)
579 {
580 min_state = cur_state;
581 cur_state = sh_ptr[cur_state];
582
583 sh_ptr -= decoder->n_states;
584
585 if (code->next_state[cur_state][0] == min_state)
586 output[i] = 0;
587 else
588 output[i] = 1;
589 }
590
591 return min_ae;
592}
593
Neels Hofmeyr87e45502017-06-20 00:17:59 +0200594/*! All-in-one convolutional decoding function
Harald Welteba6988b2011-08-17 12:46:48 +0200595 * \param[in] code description of convolutional code to be used
596 * \param[in] input array of soft bits (coded)
597 * \param[out] output array of unpacked bits (decoded)
598 *
599 * This is an all-in-one function, taking care of
600 * \ref osmo_conv_decode_init, \ref osmo_conv_decode_scan,
Sylvain Munaut297d13f2011-11-24 17:46:58 +0100601 * \ref osmo_conv_decode_flush, \ref osmo_conv_decode_get_output and
Harald Welteba6988b2011-08-17 12:46:48 +0200602 * \ref osmo_conv_decode_deinit.
603 */
Sylvain Munaut19dc5c92011-04-23 16:09:19 +0200604int
605osmo_conv_decode(const struct osmo_conv_code *code,
606 const sbit_t *input, ubit_t *output)
607{
608 struct osmo_conv_decoder decoder;
609 int rv, l;
610
Tom Tsou35536802016-11-24 19:24:32 +0700611 /* Use accelerated implementation for supported codes */
612 if ((code->N <= 4) && ((code->K == 5) || (code->K == 7)))
613 return osmo_conv_decode_acc(code, input, output);
614
Sylvain Munaut297d13f2011-11-24 17:46:58 +0100615 osmo_conv_decode_init(&decoder, code, 0, 0);
616
617 if (code->term == CONV_TERM_TAIL_BITING) {
618 osmo_conv_decode_scan(&decoder, input, code->len);
619 osmo_conv_decode_rewind(&decoder);
620 }
Sylvain Munaut19dc5c92011-04-23 16:09:19 +0200621
622 l = osmo_conv_decode_scan(&decoder, input, code->len);
Sylvain Munaut19dc5c92011-04-23 16:09:19 +0200623
Sylvain Munaut297d13f2011-11-24 17:46:58 +0100624 if (code->term == CONV_TERM_FLUSH)
Vadim Yanitskiy6e6978a2017-06-12 03:47:34 +0700625 osmo_conv_decode_flush(&decoder, &input[l]);
Sylvain Munaut297d13f2011-11-24 17:46:58 +0100626
627 rv = osmo_conv_decode_get_output(&decoder, output,
628 code->term == CONV_TERM_FLUSH, /* has_flush */
629 code->term == CONV_TERM_FLUSH ? 0 : -1 /* end_state */
630 );
Sylvain Munaut19dc5c92011-04-23 16:09:19 +0200631
632 osmo_conv_decode_deinit(&decoder);
633
634 return rv;
635}
Harald Welteba6988b2011-08-17 12:46:48 +0200636
Sylvain Munautdca7d2c2012-04-18 21:53:23 +0200637/*! @} */