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