mirror of https://gerrit.osmocom.org/osmo-tetra
lower_mac/viterbi: Use the viterbi code provided in libosmocore
Signed-off-by: Sylvain Munaut <tnt@246tNt.com>
This commit is contained in:
parent
24177bce48
commit
2d9b3e2560
|
@ -20,24 +20,26 @@
|
|||
#include <stdint.h>
|
||||
#include <string.h>
|
||||
|
||||
#include <osmocom/core/conv.h>
|
||||
|
||||
#include <lower_mac/viterbi_cch.h>
|
||||
|
||||
|
||||
#define CONV_CCH_N 4
|
||||
#define CONV_CCH_K 5
|
||||
#define CONV_CCH_N_STATES (1<<(CONV_CCH_K-1))
|
||||
/*
|
||||
* G1 = 1 + D + D4
|
||||
* G2 = 1 + D2 + D3 + D4
|
||||
* G3 = 1 + D + D2 + D4
|
||||
* G4 = 1 + D + D3 + D4
|
||||
*/
|
||||
|
||||
#define MAX_AE 0x00ffffff
|
||||
|
||||
|
||||
static const uint8_t conv_cch_next_output[CONV_CCH_N_STATES][2] = {
|
||||
static const uint8_t conv_cch_next_output[][2] = {
|
||||
{ 0, 15 }, { 11, 4 }, { 6, 9 }, { 13, 2 },
|
||||
{ 5, 10 }, { 14, 1 }, { 3, 12 }, { 8, 7 },
|
||||
{ 15, 0 }, { 4, 11 }, { 9, 6 }, { 2, 13 },
|
||||
{ 10, 5 }, { 1, 14 }, { 12, 3 }, { 7, 8 },
|
||||
};
|
||||
|
||||
static const uint8_t conv_cch_next_state[CONV_CCH_N_STATES][2] = {
|
||||
static const uint8_t conv_cch_next_state[][2] = {
|
||||
{ 0, 1 }, { 2, 3 }, { 4, 5 }, { 6, 7 },
|
||||
{ 8, 9 }, { 10, 11 }, { 12, 13 }, { 14, 15 },
|
||||
{ 0, 1 }, { 2, 3 }, { 4, 5 }, { 6, 7 },
|
||||
|
@ -45,119 +47,27 @@ static const uint8_t conv_cch_next_state[CONV_CCH_N_STATES][2] = {
|
|||
};
|
||||
|
||||
|
||||
int conv_cch_encode(uint8_t *input, uint8_t *output, int n)
|
||||
{
|
||||
uint8_t state;
|
||||
int i;
|
||||
static const struct osmo_conv_code conv_cch = {
|
||||
.N = 4,
|
||||
.K = 5,
|
||||
.next_output = conv_cch_next_output,
|
||||
.next_state = conv_cch_next_state,
|
||||
};
|
||||
|
||||
state = 0;
|
||||
|
||||
for (i=0; i<n; i++) {
|
||||
int bit = input[i];
|
||||
uint8_t out = conv_cch_next_output[state][bit];
|
||||
state = conv_cch_next_state[state][bit];
|
||||
|
||||
output[(i<<2) ] = (out >> 3) & 1;
|
||||
output[(i<<2)+1] = (out >> 2) & 1;
|
||||
output[(i<<2)+2] = (out >> 1) & 1;
|
||||
output[(i<<2)+3] = out & 1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int conv_cch_decode(int8_t *input, uint8_t *output, int n)
|
||||
{
|
||||
int i, s, b;
|
||||
unsigned int ae[CONV_CCH_N_STATES];
|
||||
unsigned int ae_next[CONV_CCH_N_STATES];
|
||||
int8_t in_sym[CONV_CCH_N];
|
||||
int8_t ev_sym[CONV_CCH_N];
|
||||
int state_history[CONV_CCH_N_STATES][n];
|
||||
int min_ae;
|
||||
int min_state;
|
||||
int cur_state;
|
||||
struct osmo_conv_decoder decoder;
|
||||
int rv, l;
|
||||
|
||||
/* Initial error (only state 0 is valid) */
|
||||
ae[0] = 0;
|
||||
for (i=1; i<CONV_CCH_N_STATES; i++) {
|
||||
ae[i] = MAX_AE;
|
||||
}
|
||||
osmo_conv_decode_init(&decoder, &conv_cch, n);
|
||||
|
||||
/* Scan the treillis */
|
||||
for (i=0; i<n; i++) {
|
||||
/* Reset next accumulated error */
|
||||
for (s=0; s<CONV_CCH_N_STATES; s++) {
|
||||
ae_next[s] = MAX_AE;
|
||||
}
|
||||
l = osmo_conv_decode_scan(&decoder, input, n);
|
||||
l = osmo_conv_decode_finish(&decoder, &input[l]);
|
||||
|
||||
/* Get input */
|
||||
in_sym[0] = input[(i<<2) ];
|
||||
in_sym[1] = input[(i<<2)+1];
|
||||
in_sym[2] = input[(i<<2)+2];
|
||||
in_sym[3] = input[(i<<2)+3];
|
||||
rv = osmo_conv_decode_get_output(&decoder, output, 1);
|
||||
|
||||
/* Scan all states */
|
||||
for (s=0; s<CONV_CCH_N_STATES; s++)
|
||||
{
|
||||
/* Scan possible input bits */
|
||||
for (b=0; b<2; b++)
|
||||
{
|
||||
int nae;
|
||||
osmo_conv_decode_deinit(&decoder);
|
||||
|
||||
/* Next output and state */
|
||||
uint8_t out = conv_cch_next_output[s][b];
|
||||
uint8_t state = conv_cch_next_state[s][b];
|
||||
|
||||
/* Expand */
|
||||
ev_sym[0] = (out >> 3) & 1 ? -127 : 127;
|
||||
ev_sym[1] = (out >> 2) & 1 ? -127 : 127;
|
||||
ev_sym[2] = (out >> 1) & 1 ? -127 : 127;
|
||||
ev_sym[3] = out & 1 ? -127 : 127;
|
||||
|
||||
/* New error for this path */
|
||||
#define DIFF(x,y) (((x-y)*(x-y)) >> 9)
|
||||
nae = ae[s] + \
|
||||
DIFF(ev_sym[0], in_sym[0]) + \
|
||||
DIFF(ev_sym[1], in_sym[1]) + \
|
||||
DIFF(ev_sym[2], in_sym[2]) + \
|
||||
DIFF(ev_sym[3], in_sym[3]);
|
||||
|
||||
/* Is it survivor */
|
||||
if (ae_next[state] > nae) {
|
||||
ae_next[state] = nae;
|
||||
state_history[state][i+1] = s;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* Copy accumulated error */
|
||||
memcpy(ae, ae_next, sizeof(int) * CONV_CCH_N_STATES);
|
||||
}
|
||||
|
||||
/* Find state with least error */
|
||||
min_ae = MAX_AE;
|
||||
min_state = -1;
|
||||
|
||||
for (s=0; s<CONV_CCH_N_STATES; s++)
|
||||
{
|
||||
if (ae[s] < min_ae) {
|
||||
min_ae = ae[s];
|
||||
min_state = s;
|
||||
}
|
||||
}
|
||||
|
||||
/* Traceback */
|
||||
cur_state = min_state;
|
||||
for (i=n-1; i >= 0; i--)
|
||||
{
|
||||
min_state = cur_state;
|
||||
cur_state = state_history[cur_state][i+1];
|
||||
if (conv_cch_next_state[cur_state][0] == min_state)
|
||||
output[i] = 0;
|
||||
else
|
||||
output[i] = 1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
return rv;
|
||||
}
|
||||
|
|
|
@ -20,140 +20,52 @@
|
|||
#include <stdint.h>
|
||||
#include <string.h>
|
||||
|
||||
#include <osmocom/core/conv.h>
|
||||
|
||||
#include <lower_mac/viterbi_tch.h>
|
||||
|
||||
|
||||
#define CONV_TCH_N 3
|
||||
#define CONV_TCH_K 5
|
||||
#define CONV_TCH_N_STATES (1<<(CONV_TCH_K-1))
|
||||
/*
|
||||
* G1 = 1 + D + D2 + D3 + D4
|
||||
* G2 = 1 + D + D3 + D4
|
||||
* G3 = 1 + D2 + D4
|
||||
*/
|
||||
|
||||
#define MAX_AE 0x00ffffff
|
||||
|
||||
|
||||
static const uint8_t conv_tch_next_output[CONV_TCH_N_STATES][2] = {
|
||||
static const uint8_t conv_tch_next_output[][2] = {
|
||||
{ 0, 7 }, { 6, 1 }, { 5, 2 }, { 3, 4 },
|
||||
{ 6, 1 }, { 0, 7 }, { 3, 4 }, { 5, 2 },
|
||||
{ 7, 0 }, { 1, 6 }, { 2, 5 }, { 4, 3 },
|
||||
{ 1, 6 }, { 7, 0 }, { 4, 3 }, { 2, 5 },
|
||||
};
|
||||
|
||||
static const uint8_t conv_tch_next_state[CONV_TCH_N_STATES][2] = {
|
||||
static const uint8_t conv_tch_next_state[][2] = {
|
||||
{ 0, 1 }, { 2, 3 }, { 4, 5 }, { 6, 7 },
|
||||
{ 8, 9 }, { 10, 11 }, { 12, 13 }, { 14, 15 },
|
||||
{ 0, 1 }, { 2, 3 }, { 4, 5 }, { 6, 7 },
|
||||
{ 8, 9 }, { 10, 11 }, { 12, 13 }, { 14, 15 },
|
||||
};
|
||||
|
||||
static const struct osmo_conv_code conv_tch = {
|
||||
.N = 4,
|
||||
.K = 5,
|
||||
.next_output = conv_tch_next_output,
|
||||
.next_state = conv_tch_next_state,
|
||||
};
|
||||
|
||||
int conv_tch_encode(uint8_t *input, uint8_t *output, int n)
|
||||
{
|
||||
uint8_t state;
|
||||
int i;
|
||||
|
||||
state = 0;
|
||||
|
||||
for (i=0; i<n; i++) {
|
||||
int bit = input[i];
|
||||
uint8_t out = conv_tch_next_output[state][bit];
|
||||
state = conv_tch_next_state[state][bit];
|
||||
|
||||
output[(i<<2) ] = (out >> 2) & 1;
|
||||
output[(i<<2)+1] = (out >> 1) & 1;
|
||||
output[(i<<2)+2] = out & 1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int conv_tch_decode(int8_t *input, uint8_t *output, int n)
|
||||
{
|
||||
int i, s, b;
|
||||
unsigned int ae[CONV_TCH_N_STATES];
|
||||
unsigned int ae_next[CONV_TCH_N_STATES];
|
||||
int8_t in_sym[CONV_TCH_N];
|
||||
int8_t ev_sym[CONV_TCH_N];
|
||||
int state_history[CONV_TCH_N_STATES][n];
|
||||
int min_ae;
|
||||
int min_state;
|
||||
int cur_state;
|
||||
struct osmo_conv_decoder decoder;
|
||||
int rv, l;
|
||||
|
||||
/* Initial error (only state 0 is valid) */
|
||||
ae[0] = 0;
|
||||
for (i=1; i<CONV_TCH_N_STATES; i++) {
|
||||
ae[i] = MAX_AE;
|
||||
}
|
||||
osmo_conv_decode_init(&decoder, &conv_tch, n);
|
||||
|
||||
/* Scan the treillis */
|
||||
for (i=0; i<n; i++) {
|
||||
/* Reset next accumulated error */
|
||||
for (s=0; s<CONV_TCH_N_STATES; s++) {
|
||||
ae_next[s] = MAX_AE;
|
||||
}
|
||||
l = osmo_conv_decode_scan(&decoder, input, n);
|
||||
l = osmo_conv_decode_finish(&decoder, &input[l]);
|
||||
|
||||
/* Get input */
|
||||
in_sym[0] = input[(i<<2) ];
|
||||
in_sym[1] = input[(i<<2)+1];
|
||||
in_sym[2] = input[(i<<2)+2];
|
||||
rv = osmo_conv_decode_get_output(&decoder, output, 1);
|
||||
|
||||
/* Scan all states */
|
||||
for (s=0; s<CONV_TCH_N_STATES; s++)
|
||||
{
|
||||
/* Scan possible input bits */
|
||||
for (b=0; b<2; b++)
|
||||
{
|
||||
int nae;
|
||||
osmo_conv_decode_deinit(&decoder);
|
||||
|
||||
/* Next output and state */
|
||||
uint8_t out = conv_tch_next_output[s][b];
|
||||
uint8_t state = conv_tch_next_state[s][b];
|
||||
|
||||
/* Expand */
|
||||
ev_sym[0] = (out >> 2) & 1 ? -127 : 127;
|
||||
ev_sym[1] = (out >> 1) & 1 ? -127 : 127;
|
||||
ev_sym[2] = out & 1 ? -127 : 127;
|
||||
|
||||
/* New error for this path */
|
||||
#define DIFF(x,y) (((x-y)*(x-y)) >> 9)
|
||||
nae = ae[s] + \
|
||||
DIFF(ev_sym[0], in_sym[0]) + \
|
||||
DIFF(ev_sym[1], in_sym[1]) + \
|
||||
DIFF(ev_sym[2], in_sym[2]);
|
||||
|
||||
/* Is it survivor */
|
||||
if (ae_next[state] > nae) {
|
||||
ae_next[state] = nae;
|
||||
state_history[state][i+1] = s;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* Copy accumulated error */
|
||||
memcpy(ae, ae_next, sizeof(int) * CONV_TCH_N_STATES);
|
||||
}
|
||||
|
||||
/* Find state with least error */
|
||||
min_ae = MAX_AE;
|
||||
min_state = -1;
|
||||
|
||||
for (s=0; s<CONV_TCH_N_STATES; s++)
|
||||
{
|
||||
if (ae[s] < min_ae) {
|
||||
min_ae = ae[s];
|
||||
min_state = s;
|
||||
}
|
||||
}
|
||||
|
||||
/* Traceback */
|
||||
cur_state = min_state;
|
||||
for (i=n-1; i >= 0; i--)
|
||||
{
|
||||
min_state = cur_state;
|
||||
cur_state = state_history[cur_state][i+1];
|
||||
if (conv_tch_next_state[cur_state][0] == min_state)
|
||||
output[i] = 0;
|
||||
else
|
||||
output[i] = 1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
return rv;
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue