blob: e60ce351601ec867448e4fee786af58868b879f1 [file] [log] [blame]
Piotr Krysik9e2e8352018-02-27 12:16:25 +01001/*! \file conv.c
2 * Generic convolutional encoding / decoding. */
3/*
4 * Copyright (C) 2011 Sylvain Munaut <tnt@246tNt.com>
5 *
6 * All Rights Reserved
7 *
8 * SPDX-License-Identifier: GPL-2.0+
9 *
10 * 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
25/*! \addtogroup conv
26 * @{
27 * Osmocom convolutional encoder and decoder.
28 *
29 * \file conv.c */
30
31#ifdef HAVE_CONFIG_H
32#include "config.h"
33#endif
34
35#ifdef HAVE_ALLOCA_H
36#include <alloca.h>
37#endif
38#include <stdint.h>
39#include <stdlib.h>
40#include <string.h>
41
42#include <osmocom/core/bits.h>
43#include <osmocom/core/conv.h>
44
45
46/* ------------------------------------------------------------------------ */
47/* Common */
48/* ------------------------------------------------------------------------ */
49
50int
51osmo_conv_get_input_length(const struct osmo_conv_code *code, int len)
52{
53 return len <= 0 ? code->len : len;
54}
55
56int
57osmo_conv_get_output_length(const struct osmo_conv_code *code, int len)
58{
59 int pbits, in_len, out_len;
60
61 /* Input length */
62 in_len = osmo_conv_get_input_length(code, len);
63
64 /* Output length */
65 out_len = in_len * code->N;
66
67 if (code->term == CONV_TERM_FLUSH)
68 out_len += code->N * (code->K - 1);
69
70 /* Count punctured bits */
71 if (code->puncture) {
72 for (pbits=0; code->puncture[pbits] >= 0; pbits++);
73 out_len -= pbits;
74 }
75
76 return out_len;
77}
78
79
80/* ------------------------------------------------------------------------ */
81/* Encoding */
82/* ------------------------------------------------------------------------ */
83
84/*! Initialize a convolutional encoder
85 * \param[in,out] encoder Encoder state to initialize
86 * \param[in] code Description of convolutional code
87 */
88void
89osmo_conv_encode_init(struct osmo_conv_encoder *encoder,
90 const struct osmo_conv_code *code)
91{
92 memset(encoder, 0x00, sizeof(struct osmo_conv_encoder));
93 encoder->code = code;
94}
95
96void
97osmo_conv_encode_load_state(struct osmo_conv_encoder *encoder,
98 const ubit_t *input)
99{
100 int i;
101 uint8_t state = 0;
102
103 for (i=0; i<(encoder->code->K-1); i++)
104 state = (state << 1) | input[i];
105
106 encoder->state = state;
107}
108
109static inline int
110_conv_encode_do_output(struct osmo_conv_encoder *encoder,
111 uint8_t out, ubit_t *output)
112{
113 const struct osmo_conv_code *code = encoder->code;
114 int o_idx = 0;
115 int j;
116
117 if (code->puncture) {
118 for (j=0; j<code->N; j++)
119 {
120 int bit_no = code->N - j - 1;
121 int r_idx = encoder->i_idx * code->N + j;
122
123 if (code->puncture[encoder->p_idx] == r_idx)
124 encoder->p_idx++;
125 else
126 output[o_idx++] = (out >> bit_no) & 1;
127 }
128 } else {
129 for (j=0; j<code->N; j++)
130 {
131 int bit_no = code->N - j - 1;
132 output[o_idx++] = (out >> bit_no) & 1;
133 }
134 }
135
136 return o_idx;
137}
138
139int
140osmo_conv_encode_raw(struct osmo_conv_encoder *encoder,
141 const ubit_t *input, ubit_t *output, int n)
142{
143 const struct osmo_conv_code *code = encoder->code;
144 uint8_t state;
145 int i;
146 int o_idx;
147
148 o_idx = 0;
149 state = encoder->state;
150
151 for (i=0; i<n; i++) {
152 int bit = input[i];
153 uint8_t out;
154
155 out = code->next_output[state][bit];
156 state = code->next_state[state][bit];
157
158 o_idx += _conv_encode_do_output(encoder, out, &output[o_idx]);
159
160 encoder->i_idx++;
161 }
162
163 encoder->state = state;
164
165 return o_idx;
166}
167
168int
169osmo_conv_encode_flush(struct osmo_conv_encoder *encoder,
170 ubit_t *output)
171{
172 const struct osmo_conv_code *code = encoder->code;
173 uint8_t state;
174 int n;
175 int i;
176 int o_idx;
177
178 n = code->K - 1;
179
180 o_idx = 0;
181 state = encoder->state;
182
183 for (i=0; i<n; i++) {
184 uint8_t out;
185
186 if (code->next_term_output) {
187 out = code->next_term_output[state];
188 state = code->next_term_state[state];
189 } else {
190 out = code->next_output[state][0];
191 state = code->next_state[state][0];
192 }
193
194 o_idx += _conv_encode_do_output(encoder, out, &output[o_idx]);
195
196 encoder->i_idx++;
197 }
198
199 encoder->state = state;
200
201 return o_idx;
202}
203
204/*! All-in-one convolutional encoding function
205 * \param[in] code description of convolutional code to be used
206 * \param[in] input array of unpacked bits (uncoded)
207 * \param[out] output array of unpacked bits (encoded)
208 * \return Number of produced output bits
209 *
210 * This is an all-in-one function, taking care of
211 * \ref osmo_conv_init, \ref osmo_conv_encode_load_state,
212 * \ref osmo_conv_encode_raw and \ref osmo_conv_encode_flush as needed.
213 */
214int
215osmo_conv_encode(const struct osmo_conv_code *code,
216 const ubit_t *input, ubit_t *output)
217{
218 struct osmo_conv_encoder encoder;
219 int l;
220
221 osmo_conv_encode_init(&encoder, code);
222
223 if (code->term == CONV_TERM_TAIL_BITING) {
224 int eidx = code->len - code->K + 1;
225 osmo_conv_encode_load_state(&encoder, &input[eidx]);
226 }
227
228 l = osmo_conv_encode_raw(&encoder, input, output, code->len);
229
230 if (code->term == CONV_TERM_FLUSH)
231 l += osmo_conv_encode_flush(&encoder, &output[l]);
232
233 return l;
234}
235
236
237/* ------------------------------------------------------------------------ */
238/* Decoding (viterbi) */
239/* ------------------------------------------------------------------------ */
240
241#define MAX_AE 0x00ffffff
242
243/* Forward declaration for accerlated decoding with certain codes */
244int
245osmo_conv_decode_acc(const struct osmo_conv_code *code,
246 const sbit_t *input, ubit_t *output);
247
248void
249osmo_conv_decode_init(struct osmo_conv_decoder *decoder,
250 const struct osmo_conv_code *code, int len, int start_state)
251{
252 int n_states;
253
254 /* Init */
255 if (len <= 0)
256 len = code->len;
257
258 n_states = 1 << (code->K - 1);
259
260 memset(decoder, 0x00, sizeof(struct osmo_conv_decoder));
261
262 decoder->code = code;
263 decoder->n_states = n_states;
264 decoder->len = len;
265
266 /* Allocate arrays */
267 decoder->ae = malloc(sizeof(unsigned int) * n_states);
268 decoder->ae_next = malloc(sizeof(unsigned int) * n_states);
269
270 decoder->state_history = malloc(sizeof(uint8_t) * n_states * (len + decoder->code->K - 1));
271
272 /* Classic reset */
273 osmo_conv_decode_reset(decoder, start_state);
274}
275
276void
277osmo_conv_decode_reset(struct osmo_conv_decoder *decoder, int start_state)
278{
279 int i;
280
281 /* Reset indexes */
282 decoder->o_idx = 0;
283 decoder->p_idx = 0;
284
285 /* Initial error */
286 if (start_state < 0) {
287 /* All states possible */
288 memset(decoder->ae, 0x00, sizeof(unsigned int) * decoder->n_states);
289 } else {
290 /* Fixed start state */
291 for (i=0; i<decoder->n_states; i++) {
292 decoder->ae[i] = (i == start_state) ? 0 : MAX_AE;
293 }
294 }
295}
296
297void
298osmo_conv_decode_rewind(struct osmo_conv_decoder *decoder)
299{
300 int i;
301 unsigned int min_ae = MAX_AE;
302
303 /* Reset indexes */
304 decoder->o_idx = 0;
305 decoder->p_idx = 0;
306
307 /* Initial error normalize (remove constant) */
308 for (i=0; i<decoder->n_states; i++) {
309 if (decoder->ae[i] < min_ae)
310 min_ae = decoder->ae[i];
311 }
312
313 for (i=0; i<decoder->n_states; i++)
314 decoder->ae[i] -= min_ae;
315}
316
317void
318osmo_conv_decode_deinit(struct osmo_conv_decoder *decoder)
319{
320 free(decoder->ae);
321 free(decoder->ae_next);
322 free(decoder->state_history);
323
324 memset(decoder, 0x00, sizeof(struct osmo_conv_decoder));
325}
326
327int
328osmo_conv_decode_scan(struct osmo_conv_decoder *decoder,
329 const sbit_t *input, int n)
330{
331 const struct osmo_conv_code *code = decoder->code;
332
333 int i, s, b, j;
334
335 int n_states;
336 unsigned int *ae;
337 unsigned int *ae_next;
338 uint8_t *state_history;
339 sbit_t *in_sym;
340
341 int i_idx, p_idx;
342
343 /* Prepare */
344 n_states = decoder->n_states;
345
346 ae = decoder->ae;
347 ae_next = decoder->ae_next;
348 state_history = &decoder->state_history[n_states * decoder->o_idx];
349
350 in_sym = malloc(sizeof(sbit_t) * code->N);
351
352 i_idx = 0;
353 p_idx = decoder->p_idx;
354
355 /* Scan the treillis */
356 for (i=0; i<n; i++)
357 {
358 /* Reset next accumulated error */
359 for (s=0; s<n_states; s++) {
360 ae_next[s] = MAX_AE;
361 }
362
363 /* Get input */
364 if (code->puncture) {
365 /* Hard way ... */
366 for (j=0; j<code->N; j++) {
367 int idx = ((decoder->o_idx + i) * code->N) + j;
368 if (idx == code->puncture[p_idx]) {
369 in_sym[j] = 0; /* Undefined */
370 p_idx++;
371 } else {
372 in_sym[j] = input[i_idx];
373 i_idx++;
374 }
375 }
376 } else {
377 /* Easy, just copy N bits */
378 memcpy(in_sym, &input[i_idx], code->N);
379 i_idx += code->N;
380 }
381
382 /* Scan all state */
383 for (s=0; s<n_states; s++)
384 {
385 /* Scan possible input bits */
386 for (b=0; b<2; b++)
387 {
388 int nae, ov, e;
389 uint8_t m;
390
391 /* Next output and state */
392 uint8_t out = code->next_output[s][b];
393 uint8_t state = code->next_state[s][b];
394
395 /* New error for this path */
396 nae = ae[s]; /* start from last error */
397 m = 1 << (code->N - 1); /* mask for 'out' bit selection */
398
399 for (j=0; j<code->N; j++) {
400 int is = (int)in_sym[j];
401 if (is) {
402 ov = (out & m) ? -127 : 127; /* sbit_t value for it */
403 e = is - ov; /* raw error for this bit */
404 nae += (e * e) >> 9; /* acc the squared/scaled value */
405 }
406 m >>= 1; /* next mask bit */
407 }
408
409 /* Is it survivor ? */
410 if (ae_next[state] > nae) {
411 ae_next[state] = nae;
412 state_history[(n_states * i) + state] = s;
413 }
414 }
415 }
416
417 /* Copy accumulated error */
418 memcpy(ae, ae_next, sizeof(unsigned int) * n_states);
419 }
420
421 /* Update decoder state */
422 decoder->p_idx = p_idx;
423 decoder->o_idx += n;
424
425 free(in_sym);
426 return i_idx;
427}
428
429int
430osmo_conv_decode_flush(struct osmo_conv_decoder *decoder,
431 const sbit_t *input)
432{
433 const struct osmo_conv_code *code = decoder->code;
434
435 int i, s, j;
436
437 int n_states;
438 unsigned int *ae;
439 unsigned int *ae_next;
440 uint8_t *state_history;
441 sbit_t *in_sym;
442
443 int i_idx, p_idx;
444
445 /* Prepare */
446 n_states = decoder->n_states;
447
448 ae = decoder->ae;
449 ae_next = decoder->ae_next;
450 state_history = &decoder->state_history[n_states * decoder->o_idx];
451
452 in_sym = malloc(sizeof(sbit_t) * code->N);
453
454 i_idx = 0;
455 p_idx = decoder->p_idx;
456
457 /* Scan the treillis */
458 for (i=0; i<code->K-1; i++)
459 {
460 /* Reset next accumulated error */
461 for (s=0; s<n_states; s++) {
462 ae_next[s] = MAX_AE;
463 }
464
465 /* Get input */
466 if (code->puncture) {
467 /* Hard way ... */
468 for (j=0; j<code->N; j++) {
469 int idx = ((decoder->o_idx + i) * code->N) + j;
470 if (idx == code->puncture[p_idx]) {
471 in_sym[j] = 0; /* Undefined */
472 p_idx++;
473 } else {
474 in_sym[j] = input[i_idx];
475 i_idx++;
476 }
477 }
478 } else {
479 /* Easy, just copy N bits */
480 memcpy(in_sym, &input[i_idx], code->N);
481 i_idx += code->N;
482 }
483
484 /* Scan all state */
485 for (s=0; s<n_states; s++)
486 {
487 int nae, ov, e;
488 uint8_t m;
489
490 /* Next output and state */
491 uint8_t out;
492 uint8_t state;
493
494 if (code->next_term_output) {
495 out = code->next_term_output[s];
496 state = code->next_term_state[s];
497 } else {
498 out = code->next_output[s][0];
499 state = code->next_state[s][0];
500 }
501
502 /* New error for this path */
503 nae = ae[s]; /* start from last error */
504 m = 1 << (code->N - 1); /* mask for 'out' bit selection */
505
506 for (j=0; j<code->N; j++) {
507 int is = (int)in_sym[j];
508 if (is) {
509 ov = (out & m) ? -127 : 127; /* sbit_t value for it */
510 e = is - ov; /* raw error for this bit */
511 nae += (e * e) >> 9; /* acc the squared/scaled value */
512 }
513 m >>= 1; /* next mask bit */
514 }
515
516 /* Is it survivor ? */
517 if (ae_next[state] > nae) {
518 ae_next[state] = nae;
519 state_history[(n_states * i) + state] = s;
520 }
521 }
522
523 /* Copy accumulated error */
524 memcpy(ae, ae_next, sizeof(unsigned int) * n_states);
525 }
526
527 /* Update decoder state */
528 decoder->p_idx = p_idx;
529 decoder->o_idx += code->K - 1;
530
531 free(in_sym);
532 return i_idx;
533}
534
535int
536osmo_conv_decode_get_output(struct osmo_conv_decoder *decoder,
537 ubit_t *output, int has_flush, int end_state)
538{
539 const struct osmo_conv_code *code = decoder->code;
540
541 int min_ae;
542 uint8_t min_state, cur_state;
543 int i, s, n;
544
545 uint8_t *sh_ptr;
546
547 /* End state ? */
548 if (end_state < 0) {
549 /* Find state with least error */
550 min_ae = MAX_AE;
551 min_state = 0xff;
552
553 for (s=0; s<decoder->n_states; s++)
554 {
555 if (decoder->ae[s] < min_ae) {
556 min_ae = decoder->ae[s];
557 min_state = s;
558 }
559 }
560
561 if (min_state == 0xff)
562 return -1;
563 } else {
564 min_state = (uint8_t) end_state;
565 min_ae = decoder->ae[end_state];
566 }
567
568 /* Traceback */
569 cur_state = min_state;
570
571 n = decoder->o_idx;
572
573 sh_ptr = &decoder->state_history[decoder->n_states * (n-1)];
574
575 /* No output for the K-1 termination input bits */
576 if (has_flush) {
577 for (i=0; i<code->K-1; i++) {
578 cur_state = sh_ptr[cur_state];
579 sh_ptr -= decoder->n_states;
580 }
581 n -= code->K - 1;
582 }
583
584 /* Generate output backward */
585 for (i=n-1; i>=0; i--)
586 {
587 min_state = cur_state;
588 cur_state = sh_ptr[cur_state];
589
590 sh_ptr -= decoder->n_states;
591
592 if (code->next_state[cur_state][0] == min_state)
593 output[i] = 0;
594 else
595 output[i] = 1;
596 }
597
598 return min_ae;
599}
600
601/*! All-in-one convolutional decoding function
602 * \param[in] code description of convolutional code to be used
603 * \param[in] input array of soft bits (coded)
604 * \param[out] output array of unpacked bits (decoded)
605 *
606 * This is an all-in-one function, taking care of
607 * \ref osmo_conv_decode_init, \ref osmo_conv_decode_scan,
608 * \ref osmo_conv_decode_flush, \ref osmo_conv_decode_get_output and
609 * \ref osmo_conv_decode_deinit.
610 */
611int
612osmo_conv_decode(const struct osmo_conv_code *code,
613 const sbit_t *input, ubit_t *output)
614{
615 struct osmo_conv_decoder decoder;
616 int rv, l;
617
618 /* Use accelerated implementation for supported codes */
619 if ((code->N <= 4) && ((code->K == 5) || (code->K == 7)))
620 return osmo_conv_decode_acc(code, input, output);
621
622 osmo_conv_decode_init(&decoder, code, 0, 0);
623
624 if (code->term == CONV_TERM_TAIL_BITING) {
625 osmo_conv_decode_scan(&decoder, input, code->len);
626 osmo_conv_decode_rewind(&decoder);
627 }
628
629 l = osmo_conv_decode_scan(&decoder, input, code->len);
630
631 if (code->term == CONV_TERM_FLUSH)
632 osmo_conv_decode_flush(&decoder, &input[l]);
633
634 rv = osmo_conv_decode_get_output(&decoder, output,
635 code->term == CONV_TERM_FLUSH, /* has_flush */
636 code->term == CONV_TERM_FLUSH ? 0 : -1 /* end_state */
637 );
638
639 osmo_conv_decode_deinit(&decoder);
640
641 return rv;
642}
643
644/*! @} */