blob: 0be65109fd366b0a40a9eaa958716fbb6f454daf [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/* ------------------------------------------------------------------------ */
45/* Encoding */
46/* ------------------------------------------------------------------------ */
47
Harald Welteba6988b2011-08-17 12:46:48 +020048/*! \brief Initialize a convolutional encoder
49 * \param[in,out] encoder Encoder state to initialize
50 * \param[in] code Description of convolutional code
51 */
Sylvain Munaut19dc5c92011-04-23 16:09:19 +020052void
53osmo_conv_encode_init(struct osmo_conv_encoder *encoder,
54 const struct osmo_conv_code *code)
55{
56 memset(encoder, 0x00, sizeof(struct osmo_conv_encoder));
57 encoder->code = code;
58}
59
Sylvain Munaut297d13f2011-11-24 17:46:58 +010060void
61osmo_conv_encode_load_state(struct osmo_conv_encoder *encoder,
62 const ubit_t *input)
63{
64 int i;
65 uint8_t state = 0;
66
67 for (i=0; i<(encoder->code->K-1); i++)
68 state = (state << 1) | input[i];
69
70 encoder->state = state;
71}
72
Sylvain Munaut19dc5c92011-04-23 16:09:19 +020073static inline int
74_conv_encode_do_output(struct osmo_conv_encoder *encoder,
75 uint8_t out, ubit_t *output)
76{
77 const struct osmo_conv_code *code = encoder->code;
78 int o_idx = 0;
79 int j;
80
81 if (code->puncture) {
82 for (j=0; j<code->N; j++)
83 {
84 int bit_no = code->N - j - 1;
85 int r_idx = encoder->i_idx * code->N + j;
86
87 if (code->puncture[encoder->p_idx] == r_idx)
88 encoder->p_idx++;
89 else
90 output[o_idx++] = (out >> bit_no) & 1;
91 }
92 } else {
93 for (j=0; j<code->N; j++)
94 {
95 int bit_no = code->N - j - 1;
96 output[o_idx++] = (out >> bit_no) & 1;
97 }
98 }
99
100 return o_idx;
101}
102
103int
104osmo_conv_encode_raw(struct osmo_conv_encoder *encoder,
105 const ubit_t *input, ubit_t *output, int n)
106{
107 const struct osmo_conv_code *code = encoder->code;
108 uint8_t state;
109 int i;
110 int o_idx;
111
112 o_idx = 0;
113 state = encoder->state;
114
115 for (i=0; i<n; i++) {
116 int bit = input[i];
117 uint8_t out;
118
119 out = code->next_output[state][bit];
120 state = code->next_state[state][bit];
121
122 o_idx += _conv_encode_do_output(encoder, out, &output[o_idx]);
123
124 encoder->i_idx++;
125 }
126
127 encoder->state = state;
128
129 return o_idx;
130}
131
132int
Sylvain Munaut297d13f2011-11-24 17:46:58 +0100133osmo_conv_encode_flush(struct osmo_conv_encoder *encoder,
134 ubit_t *output)
Sylvain Munaut19dc5c92011-04-23 16:09:19 +0200135{
136 const struct osmo_conv_code *code = encoder->code;
137 uint8_t state;
138 int n;
139 int i;
140 int o_idx;
141
142 n = code->K - 1;
143
144 o_idx = 0;
145 state = encoder->state;
146
147 for (i=0; i<n; i++) {
148 uint8_t out;
149
150 if (code->next_term_output) {
151 out = code->next_term_output[state];
152 state = code->next_term_state[state];
153 } else {
154 out = code->next_output[state][0];
155 state = code->next_state[state][0];
156 }
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
Harald Welteba6988b2011-08-17 12:46:48 +0200168/*! \brief All-in-one convolutional encoding function
169 * \param[in] code description of convolutional code to be used
170 * \param[in] input array of unpacked bits (uncoded)
171 * \param[out] output array of unpacked bits (encoded)
Sylvain Munaut03d2c892011-11-24 11:53:49 +0100172 * \return Number of produced output bits
Harald Welteba6988b2011-08-17 12:46:48 +0200173 *
174 * This is an all-in-one function, taking care of
Sylvain Munaut297d13f2011-11-24 17:46:58 +0100175 * \ref osmo_conv_init, \ref osmo_conv_encode_load_state,
176 * \ref osmo_conv_encode_raw and \ref osmo_conv_encode_flush as needed.
Harald Welteba6988b2011-08-17 12:46:48 +0200177 */
Sylvain Munaut19dc5c92011-04-23 16:09:19 +0200178int
179osmo_conv_encode(const struct osmo_conv_code *code,
180 const ubit_t *input, ubit_t *output)
181{
182 struct osmo_conv_encoder encoder;
183 int l;
184
185 osmo_conv_encode_init(&encoder, code);
Sylvain Munaut297d13f2011-11-24 17:46:58 +0100186
187 if (code->term == CONV_TERM_TAIL_BITING) {
188 int eidx = code->len - code->K + 1;
189 osmo_conv_encode_load_state(&encoder, &input[eidx]);
190 }
191
192 l = osmo_conv_encode_raw(&encoder, input, output, code->len);
193
194 if (code->term == CONV_TERM_FLUSH)
195 l += osmo_conv_encode_flush(&encoder, &output[l]);
Sylvain Munaut19dc5c92011-04-23 16:09:19 +0200196
197 return l;
198}
199
200
201/* ------------------------------------------------------------------------ */
202/* Decoding (viterbi) */
203/* ------------------------------------------------------------------------ */
204
205#define MAX_AE 0x00ffffff
206
207void
208osmo_conv_decode_init(struct osmo_conv_decoder *decoder,
Sylvain Munaut297d13f2011-11-24 17:46:58 +0100209 const struct osmo_conv_code *code, int len, int start_state)
Sylvain Munaut19dc5c92011-04-23 16:09:19 +0200210{
211 int n_states;
212
213 /* Init */
214 if (len <= 0)
215 len = code->len;
216
217 n_states = 1 << (code->K - 1);
218
219 memset(decoder, 0x00, sizeof(struct osmo_conv_decoder));
220
221 decoder->code = code;
222 decoder->n_states = n_states;
223 decoder->len = len;
224
225 /* Allocate arrays */
226 decoder->ae = malloc(sizeof(unsigned int) * n_states);
227 decoder->ae_next = malloc(sizeof(unsigned int) * n_states);
228
229 decoder->state_history = malloc(sizeof(uint8_t) * n_states * (len + decoder->code->K - 1));
230
231 /* Classic reset */
Sylvain Munaut297d13f2011-11-24 17:46:58 +0100232 osmo_conv_decode_reset(decoder, start_state);
Sylvain Munaut19dc5c92011-04-23 16:09:19 +0200233}
234
235void
Sylvain Munaut297d13f2011-11-24 17:46:58 +0100236osmo_conv_decode_reset(struct osmo_conv_decoder *decoder, int start_state)
Sylvain Munaut19dc5c92011-04-23 16:09:19 +0200237{
238 int i;
239
240 /* Reset indexes */
241 decoder->o_idx = 0;
242 decoder->p_idx = 0;
243
Sylvain Munaut297d13f2011-11-24 17:46:58 +0100244 /* Initial error */
245 if (start_state < 0) {
246 /* All states possible */
247 memset(decoder->ae, 0x00, sizeof(unsigned int) * decoder->n_states);
248 } else {
249 /* Fixed start state */
250 for (i=0; i<decoder->n_states; i++) {
251 decoder->ae[i] = (i == start_state) ? 0 : MAX_AE;
252 }
Sylvain Munaut19dc5c92011-04-23 16:09:19 +0200253 }
254}
255
256void
Sylvain Munaut297d13f2011-11-24 17:46:58 +0100257osmo_conv_decode_rewind(struct osmo_conv_decoder *decoder)
258{
259 int i;
260 unsigned int min_ae = MAX_AE;
261
262 /* Reset indexes */
263 decoder->o_idx = 0;
264 decoder->p_idx = 0;
265
266 /* Initial error normalize (remove constant) */
267 for (i=0; i<decoder->n_states; i++) {
268 if (decoder->ae[i] < min_ae)
269 min_ae = decoder->ae[i];
270 }
271
272 for (i=0; i<decoder->n_states; i++)
273 decoder->ae[i] -= min_ae;
274}
275
276void
Sylvain Munaut19dc5c92011-04-23 16:09:19 +0200277osmo_conv_decode_deinit(struct osmo_conv_decoder *decoder)
278{
279 free(decoder->ae);
280 free(decoder->ae_next);
281 free(decoder->state_history);
282
283 memset(decoder, 0x00, sizeof(struct osmo_conv_decoder));
284}
285
286int
287osmo_conv_decode_scan(struct osmo_conv_decoder *decoder,
288 const sbit_t *input, int n)
289{
290 const struct osmo_conv_code *code = decoder->code;
291
292 int i, s, b, j;
293
294 int n_states;
295 unsigned int *ae;
296 unsigned int *ae_next;
297 uint8_t *state_history;
298 sbit_t *in_sym;
299
300 int i_idx, p_idx;
301
302 /* Prepare */
303 n_states = decoder->n_states;
304
305 ae = decoder->ae;
306 ae_next = decoder->ae_next;
307 state_history = &decoder->state_history[n_states * decoder->o_idx];
308
309 in_sym = alloca(sizeof(sbit_t) * code->N);
310
311 i_idx = 0;
312 p_idx = decoder->p_idx;
313
314 /* Scan the treillis */
315 for (i=0; i<n; i++)
316 {
317 /* Reset next accumulated error */
318 for (s=0; s<n_states; s++) {
319 ae_next[s] = MAX_AE;
320 }
321
322 /* Get input */
323 if (code->puncture) {
324 /* Hard way ... */
325 for (j=0; j<code->N; j++) {
326 int idx = ((decoder->o_idx + i) * code->N) + j;
327 if (idx == code->puncture[p_idx]) {
328 in_sym[j] = 0; /* Undefined */
329 p_idx++;
330 } else {
331 in_sym[j] = input[i_idx];
332 i_idx++;
333 }
334 }
335 } else {
336 /* Easy, just copy N bits */
337 memcpy(in_sym, &input[i_idx], code->N);
338 i_idx += code->N;
339 }
340
341 /* Scan all state */
342 for (s=0; s<n_states; s++)
343 {
344 /* Scan possible input bits */
345 for (b=0; b<2; b++)
346 {
347 int nae, ov, e;
348 uint8_t m;
349
350 /* Next output and state */
351 uint8_t out = code->next_output[s][b];
352 uint8_t state = code->next_state[s][b];
353
354 /* New error for this path */
355 nae = ae[s]; /* start from last error */
356 m = 1 << (code->N - 1); /* mask for 'out' bit selection */
357
358 for (j=0; j<code->N; j++) {
Sylvain Munautd4440d42011-11-24 16:04:58 +0100359 int is = (int)in_sym[j];
360 if (is) {
361 ov = (out & m) ? -127 : 127; /* sbit_t value for it */
362 e = is - ov; /* raw error for this bit */
363 nae += (e * e) >> 9; /* acc the squared/scaled value */
364 }
Sylvain Munaut19dc5c92011-04-23 16:09:19 +0200365 m >>= 1; /* next mask bit */
366 }
367
368 /* Is it survivor ? */
369 if (ae_next[state] > nae) {
370 ae_next[state] = nae;
371 state_history[(n_states * i) + state] = s;
372 }
373 }
374 }
375
376 /* Copy accumulated error */
377 memcpy(ae, ae_next, sizeof(unsigned int) * n_states);
378 }
379
380 /* Update decoder state */
381 decoder->p_idx = p_idx;
382 decoder->o_idx += n;
383
384 return i_idx;
385}
386
387int
Sylvain Munaut297d13f2011-11-24 17:46:58 +0100388osmo_conv_decode_flush(struct osmo_conv_decoder *decoder,
389 const sbit_t *input)
Sylvain Munaut19dc5c92011-04-23 16:09:19 +0200390{
391 const struct osmo_conv_code *code = decoder->code;
392
393 int i, s, j;
394
395 int n_states;
396 unsigned int *ae;
397 unsigned int *ae_next;
398 uint8_t *state_history;
399 sbit_t *in_sym;
400
401 int i_idx, p_idx;
402
403 /* Prepare */
404 n_states = decoder->n_states;
405
406 ae = decoder->ae;
407 ae_next = decoder->ae_next;
408 state_history = &decoder->state_history[n_states * decoder->o_idx];
409
410 in_sym = alloca(sizeof(sbit_t) * code->N);
411
412 i_idx = 0;
413 p_idx = decoder->p_idx;
414
415 /* Scan the treillis */
416 for (i=0; i<code->K-1; i++)
417 {
418 /* Reset next accumulated error */
419 for (s=0; s<n_states; s++) {
420 ae_next[s] = MAX_AE;
421 }
422
423 /* Get input */
424 if (code->puncture) {
425 /* Hard way ... */
426 for (j=0; j<code->N; j++) {
427 int idx = ((decoder->o_idx + i) * code->N) + j;
428 if (idx == code->puncture[p_idx]) {
429 in_sym[j] = 0; /* Undefined */
430 p_idx++;
431 } else {
432 in_sym[j] = input[i_idx];
433 i_idx++;
434 }
435 }
436 } else {
437 /* Easy, just copy N bits */
438 memcpy(in_sym, &input[i_idx], code->N);
439 i_idx += code->N;
440 }
441
442 /* Scan all state */
443 for (s=0; s<n_states; s++)
444 {
445 int nae, ov, e;
446 uint8_t m;
447
448 /* Next output and state */
449 uint8_t out;
450 uint8_t state;
451
452 if (code->next_term_output) {
453 out = code->next_term_output[s];
454 state = code->next_term_state[s];
455 } else {
456 out = code->next_output[s][0];
457 state = code->next_state[s][0];
458 }
459
460 /* New error for this path */
461 nae = ae[s]; /* start from last error */
462 m = 1 << (code->N - 1); /* mask for 'out' bit selection */
463
464 for (j=0; j<code->N; j++) {
Sylvain Munaut1dd7c842011-04-28 22:30:30 +0200465 int is = (int)in_sym[j];
466 if (is) {
467 ov = (out & m) ? -127 : 127; /* sbit_t value for it */
468 e = is - ov; /* raw error for this bit */
469 nae += (e * e) >> 9; /* acc the squared/scaled value */
470 }
Sylvain Munaut19dc5c92011-04-23 16:09:19 +0200471 m >>= 1; /* next mask bit */
472 }
473
474 /* Is it survivor ? */
475 if (ae_next[state] > nae) {
476 ae_next[state] = nae;
477 state_history[(n_states * i) + state] = s;
478 }
479 }
480
481 /* Copy accumulated error */
482 memcpy(ae, ae_next, sizeof(unsigned int) * n_states);
483 }
484
485 /* Update decoder state */
486 decoder->p_idx = p_idx;
487 decoder->o_idx += code->K - 1;
488
489 return i_idx;
490}
491
492int
493osmo_conv_decode_get_output(struct osmo_conv_decoder *decoder,
Sylvain Munaut297d13f2011-11-24 17:46:58 +0100494 ubit_t *output, int has_flush, int end_state)
Sylvain Munaut19dc5c92011-04-23 16:09:19 +0200495{
496 const struct osmo_conv_code *code = decoder->code;
497
498 int min_ae;
499 uint8_t min_state, cur_state;
500 int i, s, n;
501
502 uint8_t *sh_ptr;
503
Sylvain Munaut297d13f2011-11-24 17:46:58 +0100504 /* End state ? */
505 if (end_state < 0) {
506 /* Find state with least error */
507 min_ae = MAX_AE;
508 min_state = 0xff;
Sylvain Munaut19dc5c92011-04-23 16:09:19 +0200509
Sylvain Munaut297d13f2011-11-24 17:46:58 +0100510 for (s=0; s<decoder->n_states; s++)
511 {
512 if (decoder->ae[s] < min_ae) {
513 min_ae = decoder->ae[s];
514 min_state = s;
515 }
Sylvain Munaut19dc5c92011-04-23 16:09:19 +0200516 }
Sylvain Munaut19dc5c92011-04-23 16:09:19 +0200517
Sylvain Munaut297d13f2011-11-24 17:46:58 +0100518 if (min_state == 0xff)
519 return -1;
520 } else {
521 min_state = (uint8_t) end_state;
522 min_ae = decoder->ae[end_state];
523 }
Sylvain Munaut19dc5c92011-04-23 16:09:19 +0200524
525 /* Traceback */
526 cur_state = min_state;
527
528 n = decoder->o_idx;
529
530 sh_ptr = &decoder->state_history[decoder->n_states * (n-1)];
531
532 /* No output for the K-1 termination input bits */
Sylvain Munaut297d13f2011-11-24 17:46:58 +0100533 if (has_flush) {
Sylvain Munaut19dc5c92011-04-23 16:09:19 +0200534 for (i=0; i<code->K-1; i++) {
535 cur_state = sh_ptr[cur_state];
536 sh_ptr -= decoder->n_states;
537 }
538 n -= code->K - 1;
539 }
540
541 /* Generate output backward */
542 for (i=n-1; i>=0; i--)
543 {
544 min_state = cur_state;
545 cur_state = sh_ptr[cur_state];
546
547 sh_ptr -= decoder->n_states;
548
549 if (code->next_state[cur_state][0] == min_state)
550 output[i] = 0;
551 else
552 output[i] = 1;
553 }
554
555 return min_ae;
556}
557
Harald Welteba6988b2011-08-17 12:46:48 +0200558/*! \brief All-in-one convolutional decoding function
559 * \param[in] code description of convolutional code to be used
560 * \param[in] input array of soft bits (coded)
561 * \param[out] output array of unpacked bits (decoded)
562 *
563 * This is an all-in-one function, taking care of
564 * \ref osmo_conv_decode_init, \ref osmo_conv_decode_scan,
Sylvain Munaut297d13f2011-11-24 17:46:58 +0100565 * \ref osmo_conv_decode_flush, \ref osmo_conv_decode_get_output and
Harald Welteba6988b2011-08-17 12:46:48 +0200566 * \ref osmo_conv_decode_deinit.
567 */
Sylvain Munaut19dc5c92011-04-23 16:09:19 +0200568int
569osmo_conv_decode(const struct osmo_conv_code *code,
570 const sbit_t *input, ubit_t *output)
571{
572 struct osmo_conv_decoder decoder;
573 int rv, l;
574
Sylvain Munaut297d13f2011-11-24 17:46:58 +0100575 osmo_conv_decode_init(&decoder, code, 0, 0);
576
577 if (code->term == CONV_TERM_TAIL_BITING) {
578 osmo_conv_decode_scan(&decoder, input, code->len);
579 osmo_conv_decode_rewind(&decoder);
580 }
Sylvain Munaut19dc5c92011-04-23 16:09:19 +0200581
582 l = osmo_conv_decode_scan(&decoder, input, code->len);
Sylvain Munaut19dc5c92011-04-23 16:09:19 +0200583
Sylvain Munaut297d13f2011-11-24 17:46:58 +0100584 if (code->term == CONV_TERM_FLUSH)
585 l = osmo_conv_decode_flush(&decoder, &input[l]);
586
587 rv = osmo_conv_decode_get_output(&decoder, output,
588 code->term == CONV_TERM_FLUSH, /* has_flush */
589 code->term == CONV_TERM_FLUSH ? 0 : -1 /* end_state */
590 );
Sylvain Munaut19dc5c92011-04-23 16:09:19 +0200591
592 osmo_conv_decode_deinit(&decoder);
593
594 return rv;
595}
Harald Welteba6988b2011-08-17 12:46:48 +0200596
597/*! }@ */