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