blob: f47d75cddcf46a83fcb85efcfde2a03fe80e4574 [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 */
32
Sylvain Munaut19dc5c92011-04-23 16:09:19 +020033#include <alloca.h>
34#include <stdint.h>
35#include <stdlib.h>
36#include <string.h>
37
38#include <osmocom/core/bits.h>
39#include <osmocom/core/conv.h>
40
41
42/* ------------------------------------------------------------------------ */
43/* Encoding */
44/* ------------------------------------------------------------------------ */
45
Harald Welteba6988b2011-08-17 12:46:48 +020046/*! \brief Initialize a convolutional encoder
47 * \param[in,out] encoder Encoder state to initialize
48 * \param[in] code Description of convolutional code
49 */
Sylvain Munaut19dc5c92011-04-23 16:09:19 +020050void
51osmo_conv_encode_init(struct osmo_conv_encoder *encoder,
52 const struct osmo_conv_code *code)
53{
54 memset(encoder, 0x00, sizeof(struct osmo_conv_encoder));
55 encoder->code = code;
56}
57
58static inline int
59_conv_encode_do_output(struct osmo_conv_encoder *encoder,
60 uint8_t out, ubit_t *output)
61{
62 const struct osmo_conv_code *code = encoder->code;
63 int o_idx = 0;
64 int j;
65
66 if (code->puncture) {
67 for (j=0; j<code->N; j++)
68 {
69 int bit_no = code->N - j - 1;
70 int r_idx = encoder->i_idx * code->N + j;
71
72 if (code->puncture[encoder->p_idx] == r_idx)
73 encoder->p_idx++;
74 else
75 output[o_idx++] = (out >> bit_no) & 1;
76 }
77 } else {
78 for (j=0; j<code->N; j++)
79 {
80 int bit_no = code->N - j - 1;
81 output[o_idx++] = (out >> bit_no) & 1;
82 }
83 }
84
85 return o_idx;
86}
87
88int
89osmo_conv_encode_raw(struct osmo_conv_encoder *encoder,
90 const ubit_t *input, ubit_t *output, int n)
91{
92 const struct osmo_conv_code *code = encoder->code;
93 uint8_t state;
94 int i;
95 int o_idx;
96
97 o_idx = 0;
98 state = encoder->state;
99
100 for (i=0; i<n; i++) {
101 int bit = input[i];
102 uint8_t out;
103
104 out = code->next_output[state][bit];
105 state = code->next_state[state][bit];
106
107 o_idx += _conv_encode_do_output(encoder, out, &output[o_idx]);
108
109 encoder->i_idx++;
110 }
111
112 encoder->state = state;
113
114 return o_idx;
115}
116
117int
118osmo_conv_encode_finish(struct osmo_conv_encoder *encoder,
119 ubit_t *output)
120{
121 const struct osmo_conv_code *code = encoder->code;
122 uint8_t state;
123 int n;
124 int i;
125 int o_idx;
126
127 n = code->K - 1;
128
129 o_idx = 0;
130 state = encoder->state;
131
132 for (i=0; i<n; i++) {
133 uint8_t out;
134
135 if (code->next_term_output) {
136 out = code->next_term_output[state];
137 state = code->next_term_state[state];
138 } else {
139 out = code->next_output[state][0];
140 state = code->next_state[state][0];
141 }
142
143 o_idx += _conv_encode_do_output(encoder, out, &output[o_idx]);
144
145 encoder->i_idx++;
146 }
147
148 encoder->state = state;
149
150 return o_idx;
151}
152
Harald Welteba6988b2011-08-17 12:46:48 +0200153/*! \brief All-in-one convolutional encoding function
154 * \param[in] code description of convolutional code to be used
155 * \param[in] input array of unpacked bits (uncoded)
156 * \param[out] output array of unpacked bits (encoded)
157 *
158 * This is an all-in-one function, taking care of
159 * \ref osmo_conv_init, \ref osmo_conv_encode_raw and
160 * \ref osmo_conv_encode_finish.
161 */
Sylvain Munaut19dc5c92011-04-23 16:09:19 +0200162int
163osmo_conv_encode(const struct osmo_conv_code *code,
164 const ubit_t *input, ubit_t *output)
165{
166 struct osmo_conv_encoder encoder;
167 int l;
168
169 osmo_conv_encode_init(&encoder, code);
170 l = osmo_conv_encode_raw(&encoder, input, output, code->len);
171 l += osmo_conv_encode_finish(&encoder, &output[l]);
172
173 return l;
174}
175
176
177/* ------------------------------------------------------------------------ */
178/* Decoding (viterbi) */
179/* ------------------------------------------------------------------------ */
180
181#define MAX_AE 0x00ffffff
182
183void
184osmo_conv_decode_init(struct osmo_conv_decoder *decoder,
185 const struct osmo_conv_code *code, int len)
186{
187 int n_states;
188
189 /* Init */
190 if (len <= 0)
191 len = code->len;
192
193 n_states = 1 << (code->K - 1);
194
195 memset(decoder, 0x00, sizeof(struct osmo_conv_decoder));
196
197 decoder->code = code;
198 decoder->n_states = n_states;
199 decoder->len = len;
200
201 /* Allocate arrays */
202 decoder->ae = malloc(sizeof(unsigned int) * n_states);
203 decoder->ae_next = malloc(sizeof(unsigned int) * n_states);
204
205 decoder->state_history = malloc(sizeof(uint8_t) * n_states * (len + decoder->code->K - 1));
206
207 /* Classic reset */
208 osmo_conv_decode_reset(decoder);
209}
210
211void
212osmo_conv_decode_reset(struct osmo_conv_decoder *decoder)
213{
214 int i;
215
216 /* Reset indexes */
217 decoder->o_idx = 0;
218 decoder->p_idx = 0;
219
220 /* Initial error (only state 0 is valid) */
221 decoder->ae[0] = 0;
222 for (i=1; i<decoder->n_states; i++) {
223 decoder->ae[i] = MAX_AE;
224 }
225}
226
227void
228osmo_conv_decode_deinit(struct osmo_conv_decoder *decoder)
229{
230 free(decoder->ae);
231 free(decoder->ae_next);
232 free(decoder->state_history);
233
234 memset(decoder, 0x00, sizeof(struct osmo_conv_decoder));
235}
236
237int
238osmo_conv_decode_scan(struct osmo_conv_decoder *decoder,
239 const sbit_t *input, int n)
240{
241 const struct osmo_conv_code *code = decoder->code;
242
243 int i, s, b, j;
244
245 int n_states;
246 unsigned int *ae;
247 unsigned int *ae_next;
248 uint8_t *state_history;
249 sbit_t *in_sym;
250
251 int i_idx, p_idx;
252
253 /* Prepare */
254 n_states = decoder->n_states;
255
256 ae = decoder->ae;
257 ae_next = decoder->ae_next;
258 state_history = &decoder->state_history[n_states * decoder->o_idx];
259
260 in_sym = alloca(sizeof(sbit_t) * code->N);
261
262 i_idx = 0;
263 p_idx = decoder->p_idx;
264
265 /* Scan the treillis */
266 for (i=0; i<n; i++)
267 {
268 /* Reset next accumulated error */
269 for (s=0; s<n_states; s++) {
270 ae_next[s] = MAX_AE;
271 }
272
273 /* Get input */
274 if (code->puncture) {
275 /* Hard way ... */
276 for (j=0; j<code->N; j++) {
277 int idx = ((decoder->o_idx + i) * code->N) + j;
278 if (idx == code->puncture[p_idx]) {
279 in_sym[j] = 0; /* Undefined */
280 p_idx++;
281 } else {
282 in_sym[j] = input[i_idx];
283 i_idx++;
284 }
285 }
286 } else {
287 /* Easy, just copy N bits */
288 memcpy(in_sym, &input[i_idx], code->N);
289 i_idx += code->N;
290 }
291
292 /* Scan all state */
293 for (s=0; s<n_states; s++)
294 {
295 /* Scan possible input bits */
296 for (b=0; b<2; b++)
297 {
298 int nae, ov, e;
299 uint8_t m;
300
301 /* Next output and state */
302 uint8_t out = code->next_output[s][b];
303 uint8_t state = code->next_state[s][b];
304
305 /* New error for this path */
306 nae = ae[s]; /* start from last error */
307 m = 1 << (code->N - 1); /* mask for 'out' bit selection */
308
309 for (j=0; j<code->N; j++) {
310 ov = (out & m) ? -127 : 127; /* sbit_t value for it */
311 e = ((int)in_sym[j]) - ov; /* raw error for this bit */
312 nae += (e * e) >> 9; /* acc the squared/scaled value */
313 m >>= 1; /* next mask bit */
314 }
315
316 /* Is it survivor ? */
317 if (ae_next[state] > nae) {
318 ae_next[state] = nae;
319 state_history[(n_states * i) + state] = s;
320 }
321 }
322 }
323
324 /* Copy accumulated error */
325 memcpy(ae, ae_next, sizeof(unsigned int) * n_states);
326 }
327
328 /* Update decoder state */
329 decoder->p_idx = p_idx;
330 decoder->o_idx += n;
331
332 return i_idx;
333}
334
335int
336osmo_conv_decode_finish(struct osmo_conv_decoder *decoder,
337 const sbit_t *input)
338{
339 const struct osmo_conv_code *code = decoder->code;
340
341 int i, s, j;
342
343 int n_states;
344 unsigned int *ae;
345 unsigned int *ae_next;
346 uint8_t *state_history;
347 sbit_t *in_sym;
348
349 int i_idx, p_idx;
350
351 /* Prepare */
352 n_states = decoder->n_states;
353
354 ae = decoder->ae;
355 ae_next = decoder->ae_next;
356 state_history = &decoder->state_history[n_states * decoder->o_idx];
357
358 in_sym = alloca(sizeof(sbit_t) * code->N);
359
360 i_idx = 0;
361 p_idx = decoder->p_idx;
362
363 /* Scan the treillis */
364 for (i=0; i<code->K-1; i++)
365 {
366 /* Reset next accumulated error */
367 for (s=0; s<n_states; s++) {
368 ae_next[s] = MAX_AE;
369 }
370
371 /* Get input */
372 if (code->puncture) {
373 /* Hard way ... */
374 for (j=0; j<code->N; j++) {
375 int idx = ((decoder->o_idx + i) * code->N) + j;
376 if (idx == code->puncture[p_idx]) {
377 in_sym[j] = 0; /* Undefined */
378 p_idx++;
379 } else {
380 in_sym[j] = input[i_idx];
381 i_idx++;
382 }
383 }
384 } else {
385 /* Easy, just copy N bits */
386 memcpy(in_sym, &input[i_idx], code->N);
387 i_idx += code->N;
388 }
389
390 /* Scan all state */
391 for (s=0; s<n_states; s++)
392 {
393 int nae, ov, e;
394 uint8_t m;
395
396 /* Next output and state */
397 uint8_t out;
398 uint8_t state;
399
400 if (code->next_term_output) {
401 out = code->next_term_output[s];
402 state = code->next_term_state[s];
403 } else {
404 out = code->next_output[s][0];
405 state = code->next_state[s][0];
406 }
407
408 /* New error for this path */
409 nae = ae[s]; /* start from last error */
410 m = 1 << (code->N - 1); /* mask for 'out' bit selection */
411
412 for (j=0; j<code->N; j++) {
Sylvain Munaut1dd7c842011-04-28 22:30:30 +0200413 int is = (int)in_sym[j];
414 if (is) {
415 ov = (out & m) ? -127 : 127; /* sbit_t value for it */
416 e = is - ov; /* raw error for this bit */
417 nae += (e * e) >> 9; /* acc the squared/scaled value */
418 }
Sylvain Munaut19dc5c92011-04-23 16:09:19 +0200419 m >>= 1; /* next mask bit */
420 }
421
422 /* Is it survivor ? */
423 if (ae_next[state] > nae) {
424 ae_next[state] = nae;
425 state_history[(n_states * i) + state] = s;
426 }
427 }
428
429 /* Copy accumulated error */
430 memcpy(ae, ae_next, sizeof(unsigned int) * n_states);
431 }
432
433 /* Update decoder state */
434 decoder->p_idx = p_idx;
435 decoder->o_idx += code->K - 1;
436
437 return i_idx;
438}
439
440int
441osmo_conv_decode_get_output(struct osmo_conv_decoder *decoder,
442 ubit_t *output, int has_finish)
443{
444 const struct osmo_conv_code *code = decoder->code;
445
446 int min_ae;
447 uint8_t min_state, cur_state;
448 int i, s, n;
449
450 uint8_t *sh_ptr;
451
452 /* Find state with least error */
453 min_ae = MAX_AE;
454 min_state = 0xff;
455
456 for (s=0; s<decoder->n_states; s++)
457 {
458 if (decoder->ae[s] < min_ae) {
459 min_ae = decoder->ae[s];
460 min_state = s;
461 }
462 }
463
464 if (min_state == 0xff)
465 return -1;
466
467 /* Traceback */
468 cur_state = min_state;
469
470 n = decoder->o_idx;
471
472 sh_ptr = &decoder->state_history[decoder->n_states * (n-1)];
473
474 /* No output for the K-1 termination input bits */
475 if (has_finish) {
476 for (i=0; i<code->K-1; i++) {
477 cur_state = sh_ptr[cur_state];
478 sh_ptr -= decoder->n_states;
479 }
480 n -= code->K - 1;
481 }
482
483 /* Generate output backward */
484 for (i=n-1; i>=0; i--)
485 {
486 min_state = cur_state;
487 cur_state = sh_ptr[cur_state];
488
489 sh_ptr -= decoder->n_states;
490
491 if (code->next_state[cur_state][0] == min_state)
492 output[i] = 0;
493 else
494 output[i] = 1;
495 }
496
497 return min_ae;
498}
499
Harald Welteba6988b2011-08-17 12:46:48 +0200500/*! \brief All-in-one convolutional decoding function
501 * \param[in] code description of convolutional code to be used
502 * \param[in] input array of soft bits (coded)
503 * \param[out] output array of unpacked bits (decoded)
504 *
505 * This is an all-in-one function, taking care of
506 * \ref osmo_conv_decode_init, \ref osmo_conv_decode_scan,
507 * \ref osmo_conv_decode_finish, \ref osmo_conv_decode_get_output and
508 * \ref osmo_conv_decode_deinit.
509 */
Sylvain Munaut19dc5c92011-04-23 16:09:19 +0200510int
511osmo_conv_decode(const struct osmo_conv_code *code,
512 const sbit_t *input, ubit_t *output)
513{
514 struct osmo_conv_decoder decoder;
515 int rv, l;
516
517 osmo_conv_decode_init(&decoder, code, 0);
518
519 l = osmo_conv_decode_scan(&decoder, input, code->len);
520 l = osmo_conv_decode_finish(&decoder, &input[l]);
521
522 rv = osmo_conv_decode_get_output(&decoder, output, 1);
523
524 osmo_conv_decode_deinit(&decoder);
525
526 return rv;
527}
Harald Welteba6988b2011-08-17 12:46:48 +0200528
529/*! }@ */