blob: ebc3eda7b78dbf4e8d56421872611e808980d434 [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
30 * \file Osmocom convolutional encoder and decoder
31 */
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
241void
242osmo_conv_decode_init(struct osmo_conv_decoder *decoder,
Sylvain Munaut297d13f2011-11-24 17:46:58 +0100243 const struct osmo_conv_code *code, int len, int start_state)
Sylvain Munaut19dc5c92011-04-23 16:09:19 +0200244{
245 int n_states;
246
247 /* Init */
248 if (len <= 0)
249 len = code->len;
250
251 n_states = 1 << (code->K - 1);
252
253 memset(decoder, 0x00, sizeof(struct osmo_conv_decoder));
254
255 decoder->code = code;
256 decoder->n_states = n_states;
257 decoder->len = len;
258
259 /* Allocate arrays */
260 decoder->ae = malloc(sizeof(unsigned int) * n_states);
261 decoder->ae_next = malloc(sizeof(unsigned int) * n_states);
262
263 decoder->state_history = malloc(sizeof(uint8_t) * n_states * (len + decoder->code->K - 1));
264
265 /* Classic reset */
Sylvain Munaut297d13f2011-11-24 17:46:58 +0100266 osmo_conv_decode_reset(decoder, start_state);
Sylvain Munaut19dc5c92011-04-23 16:09:19 +0200267}
268
269void
Sylvain Munaut297d13f2011-11-24 17:46:58 +0100270osmo_conv_decode_reset(struct osmo_conv_decoder *decoder, int start_state)
Sylvain Munaut19dc5c92011-04-23 16:09:19 +0200271{
272 int i;
273
274 /* Reset indexes */
275 decoder->o_idx = 0;
276 decoder->p_idx = 0;
277
Sylvain Munaut297d13f2011-11-24 17:46:58 +0100278 /* Initial error */
279 if (start_state < 0) {
280 /* All states possible */
281 memset(decoder->ae, 0x00, sizeof(unsigned int) * decoder->n_states);
282 } else {
283 /* Fixed start state */
284 for (i=0; i<decoder->n_states; i++) {
285 decoder->ae[i] = (i == start_state) ? 0 : MAX_AE;
286 }
Sylvain Munaut19dc5c92011-04-23 16:09:19 +0200287 }
288}
289
290void
Sylvain Munaut297d13f2011-11-24 17:46:58 +0100291osmo_conv_decode_rewind(struct osmo_conv_decoder *decoder)
292{
293 int i;
294 unsigned int min_ae = MAX_AE;
295
296 /* Reset indexes */
297 decoder->o_idx = 0;
298 decoder->p_idx = 0;
299
300 /* Initial error normalize (remove constant) */
301 for (i=0; i<decoder->n_states; i++) {
302 if (decoder->ae[i] < min_ae)
303 min_ae = decoder->ae[i];
304 }
305
306 for (i=0; i<decoder->n_states; i++)
307 decoder->ae[i] -= min_ae;
308}
309
310void
Sylvain Munaut19dc5c92011-04-23 16:09:19 +0200311osmo_conv_decode_deinit(struct osmo_conv_decoder *decoder)
312{
313 free(decoder->ae);
314 free(decoder->ae_next);
315 free(decoder->state_history);
316
317 memset(decoder, 0x00, sizeof(struct osmo_conv_decoder));
318}
319
320int
321osmo_conv_decode_scan(struct osmo_conv_decoder *decoder,
322 const sbit_t *input, int n)
323{
324 const struct osmo_conv_code *code = decoder->code;
325
326 int i, s, b, j;
327
328 int n_states;
329 unsigned int *ae;
330 unsigned int *ae_next;
331 uint8_t *state_history;
332 sbit_t *in_sym;
333
334 int i_idx, p_idx;
335
336 /* Prepare */
337 n_states = decoder->n_states;
338
339 ae = decoder->ae;
340 ae_next = decoder->ae_next;
341 state_history = &decoder->state_history[n_states * decoder->o_idx];
342
343 in_sym = alloca(sizeof(sbit_t) * code->N);
344
345 i_idx = 0;
346 p_idx = decoder->p_idx;
347
348 /* Scan the treillis */
349 for (i=0; i<n; i++)
350 {
351 /* Reset next accumulated error */
352 for (s=0; s<n_states; s++) {
353 ae_next[s] = MAX_AE;
354 }
355
356 /* Get input */
357 if (code->puncture) {
358 /* Hard way ... */
359 for (j=0; j<code->N; j++) {
360 int idx = ((decoder->o_idx + i) * code->N) + j;
361 if (idx == code->puncture[p_idx]) {
362 in_sym[j] = 0; /* Undefined */
363 p_idx++;
364 } else {
365 in_sym[j] = input[i_idx];
366 i_idx++;
367 }
368 }
369 } else {
370 /* Easy, just copy N bits */
371 memcpy(in_sym, &input[i_idx], code->N);
372 i_idx += code->N;
373 }
374
375 /* Scan all state */
376 for (s=0; s<n_states; s++)
377 {
378 /* Scan possible input bits */
379 for (b=0; b<2; b++)
380 {
381 int nae, ov, e;
382 uint8_t m;
383
384 /* Next output and state */
385 uint8_t out = code->next_output[s][b];
386 uint8_t state = code->next_state[s][b];
387
388 /* New error for this path */
389 nae = ae[s]; /* start from last error */
390 m = 1 << (code->N - 1); /* mask for 'out' bit selection */
391
392 for (j=0; j<code->N; j++) {
Sylvain Munautd4440d42011-11-24 16:04:58 +0100393 int is = (int)in_sym[j];
394 if (is) {
395 ov = (out & m) ? -127 : 127; /* sbit_t value for it */
396 e = is - ov; /* raw error for this bit */
397 nae += (e * e) >> 9; /* acc the squared/scaled value */
398 }
Sylvain Munaut19dc5c92011-04-23 16:09:19 +0200399 m >>= 1; /* next mask bit */
400 }
401
402 /* Is it survivor ? */
403 if (ae_next[state] > nae) {
404 ae_next[state] = nae;
405 state_history[(n_states * i) + state] = s;
406 }
407 }
408 }
409
410 /* Copy accumulated error */
411 memcpy(ae, ae_next, sizeof(unsigned int) * n_states);
412 }
413
414 /* Update decoder state */
415 decoder->p_idx = p_idx;
416 decoder->o_idx += n;
417
418 return i_idx;
419}
420
421int
Sylvain Munaut297d13f2011-11-24 17:46:58 +0100422osmo_conv_decode_flush(struct osmo_conv_decoder *decoder,
423 const sbit_t *input)
Sylvain Munaut19dc5c92011-04-23 16:09:19 +0200424{
425 const struct osmo_conv_code *code = decoder->code;
426
427 int i, s, j;
428
429 int n_states;
430 unsigned int *ae;
431 unsigned int *ae_next;
432 uint8_t *state_history;
433 sbit_t *in_sym;
434
435 int i_idx, p_idx;
436
437 /* Prepare */
438 n_states = decoder->n_states;
439
440 ae = decoder->ae;
441 ae_next = decoder->ae_next;
442 state_history = &decoder->state_history[n_states * decoder->o_idx];
443
444 in_sym = alloca(sizeof(sbit_t) * code->N);
445
446 i_idx = 0;
447 p_idx = decoder->p_idx;
448
449 /* Scan the treillis */
450 for (i=0; i<code->K-1; i++)
451 {
452 /* Reset next accumulated error */
453 for (s=0; s<n_states; s++) {
454 ae_next[s] = MAX_AE;
455 }
456
457 /* Get input */
458 if (code->puncture) {
459 /* Hard way ... */
460 for (j=0; j<code->N; j++) {
461 int idx = ((decoder->o_idx + i) * code->N) + j;
462 if (idx == code->puncture[p_idx]) {
463 in_sym[j] = 0; /* Undefined */
464 p_idx++;
465 } else {
466 in_sym[j] = input[i_idx];
467 i_idx++;
468 }
469 }
470 } else {
471 /* Easy, just copy N bits */
472 memcpy(in_sym, &input[i_idx], code->N);
473 i_idx += code->N;
474 }
475
476 /* Scan all state */
477 for (s=0; s<n_states; s++)
478 {
479 int nae, ov, e;
480 uint8_t m;
481
482 /* Next output and state */
483 uint8_t out;
484 uint8_t state;
485
486 if (code->next_term_output) {
487 out = code->next_term_output[s];
488 state = code->next_term_state[s];
489 } else {
490 out = code->next_output[s][0];
491 state = code->next_state[s][0];
492 }
493
494 /* New error for this path */
495 nae = ae[s]; /* start from last error */
496 m = 1 << (code->N - 1); /* mask for 'out' bit selection */
497
498 for (j=0; j<code->N; j++) {
Sylvain Munaut1dd7c842011-04-28 22:30:30 +0200499 int is = (int)in_sym[j];
500 if (is) {
501 ov = (out & m) ? -127 : 127; /* sbit_t value for it */
502 e = is - ov; /* raw error for this bit */
503 nae += (e * e) >> 9; /* acc the squared/scaled value */
504 }
Sylvain Munaut19dc5c92011-04-23 16:09:19 +0200505 m >>= 1; /* next mask bit */
506 }
507
508 /* Is it survivor ? */
509 if (ae_next[state] > nae) {
510 ae_next[state] = nae;
511 state_history[(n_states * i) + state] = s;
512 }
513 }
514
515 /* Copy accumulated error */
516 memcpy(ae, ae_next, sizeof(unsigned int) * n_states);
517 }
518
519 /* Update decoder state */
520 decoder->p_idx = p_idx;
521 decoder->o_idx += code->K - 1;
522
523 return i_idx;
524}
525
526int
527osmo_conv_decode_get_output(struct osmo_conv_decoder *decoder,
Sylvain Munaut297d13f2011-11-24 17:46:58 +0100528 ubit_t *output, int has_flush, int end_state)
Sylvain Munaut19dc5c92011-04-23 16:09:19 +0200529{
530 const struct osmo_conv_code *code = decoder->code;
531
532 int min_ae;
533 uint8_t min_state, cur_state;
534 int i, s, n;
535
536 uint8_t *sh_ptr;
537
Sylvain Munaut297d13f2011-11-24 17:46:58 +0100538 /* End state ? */
539 if (end_state < 0) {
540 /* Find state with least error */
541 min_ae = MAX_AE;
542 min_state = 0xff;
Sylvain Munaut19dc5c92011-04-23 16:09:19 +0200543
Sylvain Munaut297d13f2011-11-24 17:46:58 +0100544 for (s=0; s<decoder->n_states; s++)
545 {
546 if (decoder->ae[s] < min_ae) {
547 min_ae = decoder->ae[s];
548 min_state = s;
549 }
Sylvain Munaut19dc5c92011-04-23 16:09:19 +0200550 }
Sylvain Munaut19dc5c92011-04-23 16:09:19 +0200551
Sylvain Munaut297d13f2011-11-24 17:46:58 +0100552 if (min_state == 0xff)
553 return -1;
554 } else {
555 min_state = (uint8_t) end_state;
556 min_ae = decoder->ae[end_state];
557 }
Sylvain Munaut19dc5c92011-04-23 16:09:19 +0200558
559 /* Traceback */
560 cur_state = min_state;
561
562 n = decoder->o_idx;
563
564 sh_ptr = &decoder->state_history[decoder->n_states * (n-1)];
565
566 /* No output for the K-1 termination input bits */
Sylvain Munaut297d13f2011-11-24 17:46:58 +0100567 if (has_flush) {
Sylvain Munaut19dc5c92011-04-23 16:09:19 +0200568 for (i=0; i<code->K-1; i++) {
569 cur_state = sh_ptr[cur_state];
570 sh_ptr -= decoder->n_states;
571 }
572 n -= code->K - 1;
573 }
574
575 /* Generate output backward */
576 for (i=n-1; i>=0; i--)
577 {
578 min_state = cur_state;
579 cur_state = sh_ptr[cur_state];
580
581 sh_ptr -= decoder->n_states;
582
583 if (code->next_state[cur_state][0] == min_state)
584 output[i] = 0;
585 else
586 output[i] = 1;
587 }
588
589 return min_ae;
590}
591
Harald Welteba6988b2011-08-17 12:46:48 +0200592/*! \brief All-in-one convolutional decoding function
593 * \param[in] code description of convolutional code to be used
594 * \param[in] input array of soft bits (coded)
595 * \param[out] output array of unpacked bits (decoded)
596 *
597 * This is an all-in-one function, taking care of
598 * \ref osmo_conv_decode_init, \ref osmo_conv_decode_scan,
Sylvain Munaut297d13f2011-11-24 17:46:58 +0100599 * \ref osmo_conv_decode_flush, \ref osmo_conv_decode_get_output and
Harald Welteba6988b2011-08-17 12:46:48 +0200600 * \ref osmo_conv_decode_deinit.
601 */
Sylvain Munaut19dc5c92011-04-23 16:09:19 +0200602int
603osmo_conv_decode(const struct osmo_conv_code *code,
604 const sbit_t *input, ubit_t *output)
605{
606 struct osmo_conv_decoder decoder;
607 int rv, l;
608
Sylvain Munaut297d13f2011-11-24 17:46:58 +0100609 osmo_conv_decode_init(&decoder, code, 0, 0);
610
611 if (code->term == CONV_TERM_TAIL_BITING) {
612 osmo_conv_decode_scan(&decoder, input, code->len);
613 osmo_conv_decode_rewind(&decoder);
614 }
Sylvain Munaut19dc5c92011-04-23 16:09:19 +0200615
616 l = osmo_conv_decode_scan(&decoder, input, code->len);
Sylvain Munaut19dc5c92011-04-23 16:09:19 +0200617
Sylvain Munaut297d13f2011-11-24 17:46:58 +0100618 if (code->term == CONV_TERM_FLUSH)
619 l = osmo_conv_decode_flush(&decoder, &input[l]);
620
621 rv = osmo_conv_decode_get_output(&decoder, output,
622 code->term == CONV_TERM_FLUSH, /* has_flush */
623 code->term == CONV_TERM_FLUSH ? 0 : -1 /* end_state */
624 );
Sylvain Munaut19dc5c92011-04-23 16:09:19 +0200625
626 osmo_conv_decode_deinit(&decoder);
627
628 return rv;
629}
Harald Welteba6988b2011-08-17 12:46:48 +0200630
Sylvain Munautdca7d2c2012-04-18 21:53:23 +0200631/*! @} */