mirror of
https://github.com/SatDump/SatDump
synced 2026-08-13 17:47:30 -04:00
549 lines
16 KiB
C
549 lines
16 KiB
C
//
|
|
// Created by gianluca on 20/02/17.
|
|
//
|
|
#include <stdio.h>
|
|
#include <stdlib.h>
|
|
#include <string.h>
|
|
#include <math.h>
|
|
#include "libconvcodes.h"
|
|
|
|
int get_bit(int num, int position)
|
|
{
|
|
return (num >> position) & 1;
|
|
}
|
|
|
|
char* state2str(int state, int memory)
|
|
{
|
|
char *str_state = malloc(memory + 1);/*{{{*/
|
|
str_state[memory] = '\0';
|
|
|
|
for (int i = 0; i < memory; i++) {
|
|
str_state[i] = '0' + get_bit(state, memory - 1 - i);
|
|
}
|
|
|
|
return str_state;/*}}}*/
|
|
}
|
|
|
|
int convcode_stateupdate(int state, int input, t_convcode code)
|
|
{
|
|
int memory = code.memory;/*{{{*/
|
|
|
|
int first_reg = 0;
|
|
for (int i = 0; i < memory; i++)
|
|
first_reg = (first_reg + code.backward_connections[i]*get_bit(state, memory - 1 - i)) % 2;
|
|
|
|
// shift the content of the registers
|
|
int new_state = state >> 1;
|
|
|
|
// compute the new content of the first register (MSB)
|
|
first_reg = (first_reg + input) % 2;
|
|
|
|
// switch last bit
|
|
new_state ^= (-first_reg ^ new_state) & (1 << (memory - 1));
|
|
|
|
return new_state;/*}}}*/
|
|
}
|
|
|
|
int *convcode_output(int state, int input, t_convcode code)
|
|
{
|
|
int *output = calloc(code.components, sizeof(int));/*{{{*/
|
|
int new_state = convcode_stateupdate(state, input, code);
|
|
|
|
// get content of first register of the new state
|
|
// we have to add it to the feedforward part
|
|
int first_reg = get_bit(new_state, code.memory - 1);
|
|
|
|
for (int c = 0; c < code.components; c++) {
|
|
output[c] = code.forward_connections[c][0]*first_reg;
|
|
|
|
for (int i = 0; i < code.memory; i++)
|
|
output[c] = (output[c] + code.forward_connections[c][i+1]*get_bit(state, code.memory - 1 - i)) % 2;
|
|
}
|
|
|
|
return output;/*}}}*/
|
|
}
|
|
|
|
t_convcode convcode_initialize(char *forward[], char *backward, int N_components)
|
|
{
|
|
/*{{{*/
|
|
// code initialized
|
|
t_convcode code;
|
|
|
|
code.components = N_components;
|
|
|
|
// number of shift registers
|
|
int code_memory = strlen(backward);
|
|
code.memory = code_memory;
|
|
|
|
// initialize connection arrays
|
|
int **fwd_con = malloc(N_components * sizeof(int*));
|
|
int *bwd_con = malloc(code_memory*sizeof(int));
|
|
|
|
// convert input strings to arrays
|
|
for (int i = 0; i < N_components; i++) {
|
|
fwd_con[i] = malloc((code_memory+1) * sizeof(int));
|
|
|
|
int j = 0;
|
|
for (; j < code_memory; j++) {
|
|
fwd_con[i][j] = forward[i][j] - '0';
|
|
bwd_con[j] = backward[j] - '0';
|
|
}
|
|
fwd_con[i][j] = forward[i][j] - '0';
|
|
}
|
|
|
|
code.forward_connections = fwd_con;
|
|
code.backward_connections = bwd_con;
|
|
|
|
int N_states = 2 << (code_memory - 1);
|
|
int **neighbors = malloc(N_states * sizeof(int*));
|
|
|
|
// populate lookup table for state-update function
|
|
// and create neighbors array
|
|
int **next_state = malloc(N_states * sizeof(int*));
|
|
for (int i = 0; i < N_states; i++) {
|
|
// initialize to 0
|
|
neighbors[i] = calloc(2, sizeof(int));
|
|
}
|
|
|
|
for (int i = 0; i < N_states; i++) {
|
|
next_state[i] = malloc(2 * sizeof(int));
|
|
|
|
int updated0 = convcode_stateupdate(i, 0, code);
|
|
next_state[i][0] = updated0;
|
|
|
|
|
|
// save to neighbords array, use minus sign if input is 0
|
|
// plus sign if input is 1. check whether it's possible to
|
|
// write by checking if it's content is zero.
|
|
// Exploit the fact that in binary codes a state only
|
|
// has two neighbors
|
|
if (!neighbors[updated0][0])
|
|
neighbors[updated0][0] = -(i + 1);
|
|
else
|
|
neighbors[updated0][1] = -(i + 1);
|
|
|
|
int updated1 = convcode_stateupdate(i, 1, code);
|
|
next_state[i][1] = updated1;
|
|
|
|
if (!neighbors[updated1][0])
|
|
neighbors[updated1][0] = i + 1;
|
|
else
|
|
neighbors[updated1][1] = i + 1;
|
|
}
|
|
|
|
code.next_state = next_state;
|
|
code.neighbors = neighbors;
|
|
|
|
|
|
// populate output function lookup table
|
|
int ***output;
|
|
output = malloc(N_states * sizeof(int**));
|
|
for (int i = 0; i < N_states; i++) {
|
|
output[i] = malloc(2*sizeof(int*));
|
|
for (int j = 0; j < 2; j++)
|
|
output[i][j] = convcode_output(i, j, code);
|
|
}
|
|
code.output = output;
|
|
|
|
return code;/*}}}*/
|
|
}
|
|
|
|
void convcode_clear(t_convcode code)
|
|
{
|
|
for (int i = 0; i < code.components; i++) {/*{{{*/
|
|
/* printf("Component %d \t Address %p\n", i, code.forward_connections[i]); */
|
|
free(code.forward_connections[i]);
|
|
free(code.next_state[i]);
|
|
free(code.neighbors[i]);
|
|
}
|
|
free(code.output);
|
|
free(code.forward_connections);
|
|
free(code.backward_connections);
|
|
free(code.next_state);
|
|
free(code.neighbors);/*}}}*/
|
|
}
|
|
/*void convcode_clear(t_convcode *code)
|
|
{
|
|
for (int i = 0; i < code->components; i++)
|
|
// printf("Component %d \t Address %p\n", i, code.forward_connections[i]);
|
|
free(code->forward_connections[i]);
|
|
free(code->next_state[i]);
|
|
free(code->neighbors[i]);
|
|
|
|
|
|
for (int j = 0; j < 2; ++j) {
|
|
free(code->output[i][j]);
|
|
}
|
|
}
|
|
|
|
free(code->output);
|
|
free(code->forward_connections);
|
|
free(code->backward_connections);
|
|
free(code->next_state);
|
|
free(code->neighbors);
|
|
}*/
|
|
int* convcode_encode(int *packet, int packet_length, t_convcode code)
|
|
{
|
|
// add support for puncturing patterns?/*{{{*/
|
|
int encoded_length = (packet_length + code.memory) * code.components;
|
|
int *encoded_packet = malloc(encoded_length * sizeof *encoded_packet);
|
|
|
|
int state = 0;
|
|
|
|
for (int i = 0; i < packet_length; i++)
|
|
{
|
|
int current_bit = packet[i];
|
|
int *output = code.output[state][current_bit];
|
|
state = code.next_state[state][current_bit];
|
|
|
|
for (int c = 0; c < code.components; c++)
|
|
{
|
|
int out = output[c];
|
|
encoded_packet[code.components * i + c] = output[c];
|
|
}
|
|
}
|
|
|
|
// add trellis termination
|
|
for (int i = packet_length; i < packet_length + code.memory; i++)
|
|
{
|
|
int input = 0;
|
|
|
|
// input is equal to the feedback part in order to inject zeros into the registers
|
|
for (int j = 0; j < code.memory; j++)
|
|
input = (input + code.backward_connections[j]*get_bit(state, code.memory - 1 - j)) % 2;
|
|
|
|
int *output = code.output[state][input];
|
|
state = code.next_state[state][input];
|
|
|
|
for (int c = 0; c < code.components; c++)
|
|
encoded_packet[code.components * i + c] = output[c];
|
|
|
|
}
|
|
|
|
return encoded_packet;/*}}}*/
|
|
}
|
|
|
|
int* convcode_decode(double *received, int length, t_convcode code)
|
|
{
|
|
int N_states = 2 << (code.memory - 1);/*{{{*/
|
|
int packet_length = length / code.components - code.memory;
|
|
int *decoded_packet = malloc(packet_length * sizeof *decoded_packet);
|
|
|
|
// allocate matrix containing survivor sequences and metric vector
|
|
double *metric = malloc(N_states * sizeof *metric);
|
|
int **data_matrix;
|
|
data_matrix = malloc(N_states * sizeof(int*));
|
|
|
|
for (int i = 0; i < N_states; i++ )
|
|
{
|
|
data_matrix[i] = malloc((packet_length + code.memory)* sizeof(int));
|
|
metric[i] = 1e6; // should be Infinity
|
|
}
|
|
|
|
// trellis starts at state 0
|
|
metric[0] = 0;
|
|
|
|
double *tmp_metric = malloc(N_states * sizeof *tmp_metric);
|
|
double *rho = malloc(code.components * sizeof *rho);
|
|
for (int k = 0; k < packet_length + code.memory; k++) {
|
|
|
|
// get received symbol
|
|
for (int r = 0; r < code.components; r++)
|
|
rho[r] = received[k*code.components + r];
|
|
|
|
for (int s = 0; s < N_states; s++) {
|
|
|
|
// get neighbors
|
|
int nA = abs(code.neighbors[s][0]) - 1;
|
|
int uA = (code.neighbors[s][0] > 0);
|
|
int nB = abs(code.neighbors[s][1]) - 1;
|
|
int uB = (code.neighbors[s][1] > 0);
|
|
|
|
int *outA = code.output[nA][uA];
|
|
int *outB = code.output[nB][uB];
|
|
|
|
double costA = 0;
|
|
double costB = 0;
|
|
for (int i = 0; i < code.components; i++) {
|
|
costA += pow(rho[i] - 2*outA[i] + 1, 2);
|
|
costB += pow(rho[i] - 2*outB[i] + 1, 2);
|
|
}
|
|
|
|
costA += metric[nA];
|
|
costB += metric[nB];
|
|
|
|
double minimum_cost = (costA > costB) ? costB : costA;
|
|
int idx = minimum_cost == costB;
|
|
tmp_metric[s] = minimum_cost;
|
|
|
|
data_matrix[s][k] = code.neighbors[s][idx];
|
|
}
|
|
|
|
// find minimum
|
|
double min_metric = tmp_metric[0];
|
|
for (int s = 0; s < N_states; s++)
|
|
min_metric = (min_metric < tmp_metric[s]) ? min_metric : tmp_metric[s];
|
|
|
|
// normalize
|
|
for (int s = 0; s < N_states; s++)
|
|
metric[s] = tmp_metric[s] - min_metric;
|
|
|
|
}
|
|
|
|
// backtrack
|
|
int state = 0; // trellis is terminated
|
|
for (int k = packet_length + code.memory - 1; k >= 0; k--)
|
|
{
|
|
int input = (data_matrix[state][k] > 0);
|
|
state = abs(data_matrix[state][k]) - 1;
|
|
|
|
if (k < packet_length)
|
|
decoded_packet[k] = input;
|
|
}
|
|
|
|
// free memory
|
|
free(metric);
|
|
free(rho);
|
|
free(tmp_metric);
|
|
|
|
for (int i = 0; i < N_states; i++ )
|
|
free(data_matrix[i]);
|
|
free(data_matrix);
|
|
|
|
return decoded_packet;/*}}}*/
|
|
}
|
|
|
|
void print_neighbors(t_convcode code)
|
|
{
|
|
int N_states = 2 << (code.memory - 1);/*{{{*/
|
|
|
|
for (int i = 0; i < 34; i++){
|
|
if (i % 11)
|
|
printf("-");
|
|
else
|
|
printf("+");
|
|
}
|
|
printf("\n");
|
|
printf("|%-10s|%-10s|%-10s|\n", "STATE", "NEIGHBOR", "INPUT");
|
|
for (int i = 0; i < 34; i++){
|
|
if (i % 11)
|
|
printf("-");
|
|
else
|
|
printf("+");
|
|
}
|
|
printf("\n");
|
|
|
|
for (int i = 0; i < N_states; i++) {
|
|
int s0 = abs(code.neighbors[i][0])-1;
|
|
int s1 = abs(code.neighbors[i][1])-1;
|
|
|
|
int u0 = (code.neighbors[i][0] > 0) ? 1 : 0;
|
|
int u1 = (code.neighbors[i][1] > 0) ? 1 : 0;
|
|
|
|
printf("|%-10s|%-10s|%-10d|\n", state2str(i, code.memory), state2str(s0, code.memory), u0);
|
|
printf("|%-10s|%-10s|%-10d|\n", state2str(i, code.memory), state2str(s1, code.memory), u1);
|
|
}
|
|
for (int i = 0; i < 34; i++){
|
|
if (i % 11)
|
|
printf("-");
|
|
else
|
|
printf("+");
|
|
}
|
|
printf("\n");/*}}}*/
|
|
}
|
|
|
|
int *convcode_extrinsic(double *received, double length, double ***a_priori, t_convcode code, double noise_variance,
|
|
int decision)
|
|
{
|
|
int N_states = 2 << (code.memory - 1);/*{{{*/
|
|
int packet_length = (int) length / code.components - code.memory;
|
|
|
|
long int threshold = 1e10;
|
|
// copy a priori probabilities on local array
|
|
double **app = malloc(2 * sizeof(double*));/*{{{*/
|
|
|
|
for (int i = 0; i < 2; ++i)
|
|
app[i] = malloc((packet_length + code.memory) * sizeof *app);
|
|
|
|
for (int i = 0; i < packet_length; ++i){
|
|
app[0][i] = (*a_priori)[0][i];
|
|
app[1][i] = (*a_priori)[1][i];
|
|
}
|
|
|
|
for (int i = 0; i < code.memory; i++) {
|
|
app[0][packet_length + i] = log(0.5);
|
|
app[1][packet_length + i] = log(0.5);
|
|
}
|
|
|
|
/*}}}*/
|
|
|
|
// initialize backward messages
|
|
double **backward = malloc(N_states * sizeof(double*));/*{{{*/
|
|
for (int k = 0; k < N_states; ++k) {
|
|
backward[k] = malloc((packet_length + code.memory) * sizeof(double));
|
|
backward[k][packet_length + code.memory - 1] = -threshold;
|
|
}
|
|
|
|
backward[0][packet_length + code.memory - 1] = 0;
|
|
|
|
double *rho = malloc(code.components * sizeof *rho);
|
|
|
|
for (int i = packet_length + code.memory - 2; i >= 0; i--) {
|
|
|
|
for (int j = 0; j < code.components; ++j)
|
|
rho[j] = received[code.components*(i+1) + j];
|
|
|
|
for (int s = 0; s < N_states; ++s) {
|
|
double B = -threshold;
|
|
|
|
for (int u = 0; u < 2; ++u) {
|
|
int next = code.next_state[s][u];
|
|
int *out = code.output[s][u];
|
|
|
|
double g = 0;
|
|
for (int j = 0; j < code.components; ++j)
|
|
g += pow(rho[j]- (2*out[j] - 1), 2);
|
|
|
|
B = exp_sum(B, app[u][i+1] + backward[next][i+1] + (-g/(2*noise_variance)));
|
|
}
|
|
|
|
backward[s][i] = B;
|
|
}
|
|
|
|
// normalize
|
|
double max = backward[0][i];
|
|
for (int s = 0; s < N_states; ++s)
|
|
max = backward[s][i] > max ? backward[s][i] : max;
|
|
|
|
for (int s = 0; s < N_states; ++s)
|
|
backward[s][i] -= max;
|
|
}/*}}}*/
|
|
|
|
// initialize forward messages
|
|
double **forward = malloc(N_states * sizeof(double*));/*{{{*/
|
|
for (int k = 0; k < N_states; ++k) {
|
|
forward[k] = malloc((packet_length + code.memory) * sizeof(double));
|
|
forward[k][0] = -threshold;
|
|
}
|
|
forward[0][0] = 0;
|
|
|
|
|
|
for (int i = 1; i < packet_length + code.memory; ++i) {
|
|
|
|
for (int j = 0; j < code.components; ++j)
|
|
rho[j] = received[code.components*(i-1) + j];
|
|
|
|
for (int s = 0; s < N_states; ++s) {
|
|
|
|
double F = -threshold;
|
|
|
|
// pass through each neighbour
|
|
int *neigh = code.neighbors[s];
|
|
for (int n = 0; n < 2; ++n) {
|
|
int state = abs(neigh[n]) - 1;
|
|
int input = neigh[n] > 0;
|
|
|
|
int *out = code.output[state][input];
|
|
|
|
double g = 0;
|
|
// compute g
|
|
for (int j = 0; j < code.components; ++j)
|
|
g += pow(rho[j] - (2*out[j] - 1),2);
|
|
|
|
F = exp_sum(F, app[input][i-1] + forward[state][i-1] + (-g/(2*noise_variance)));
|
|
}
|
|
|
|
forward[s][i] = F;
|
|
|
|
}
|
|
|
|
// normalize
|
|
double max = forward[0][i];
|
|
for (int s = 0; s < N_states; ++s)
|
|
max = forward[s][i] > max ? forward[s][i] : max;
|
|
|
|
for (int s = 0; s < N_states; ++s)
|
|
forward[s][i] -= max;
|
|
}/*}}}*/
|
|
|
|
// initialize extrinsic messages
|
|
double **extrinsic = malloc(2 * sizeof(double*));/*{{{*/
|
|
|
|
for (int k = 0; k < 2; ++k) {
|
|
extrinsic[k] = malloc((packet_length * code.memory) * sizeof(double));
|
|
}
|
|
|
|
for (int i = 0; i < packet_length + code.memory; ++i) {
|
|
for (int j = 0; j < code.components; ++j)
|
|
rho[j] = received[code.components*i + j];
|
|
|
|
|
|
for (int u = 0; u < 2; ++u) {
|
|
double E = -threshold;
|
|
for (int s = 0; s < N_states; ++s) {
|
|
|
|
int state = code.next_state[s][u];
|
|
|
|
double g = 0;
|
|
|
|
int *out = code.output[s][u];
|
|
for (int j = 0; j < code.components; ++j)
|
|
g += pow(rho[j] - (2*out[j] - 1),2);
|
|
|
|
double fwd = forward[s][i];
|
|
double bwd = backward[state][i];
|
|
E = exp_sum(E, fwd + bwd + (-g/(2*noise_variance)));
|
|
}
|
|
|
|
extrinsic[u][i] = E;
|
|
}
|
|
|
|
// double normalization = log(exp(extrinsic[0][i]) + exp(extrinsic[1][i]));
|
|
// extrinsic[0][i] -= normalization;
|
|
// extrinsic[1][i] -= normalization;
|
|
if (i < packet_length)
|
|
{
|
|
(*a_priori)[0][i] = extrinsic[0][i];
|
|
(*a_priori)[1][i] = extrinsic[1][i];
|
|
}
|
|
}/*}}}*/
|
|
|
|
// decision
|
|
int *decoded = NULL;
|
|
|
|
if (decision){
|
|
decoded = malloc(packet_length * sizeof(int) ); //sizeof *decoded
|
|
for (int i = 0; i < packet_length; ++i) {
|
|
double one = app[1][i] + extrinsic[1][i];
|
|
double zero = app[0][i] + extrinsic[0][i];
|
|
decoded[i] = one > zero;
|
|
}
|
|
}
|
|
|
|
// free memory
|
|
for (int l = 0; l < N_states; ++l) {/*{{{*/
|
|
free(backward[l]);
|
|
free(forward[l]);
|
|
}
|
|
free(backward);
|
|
free(forward);
|
|
|
|
for (int i = 0; i < 2; i++) {
|
|
free(extrinsic[i]);
|
|
free(app[i]);
|
|
}
|
|
free(extrinsic);
|
|
free(app);
|
|
free(rho);/*}}}*/
|
|
|
|
return decoded;
|
|
|
|
/*}}}*/
|
|
}
|
|
|
|
double exp_sum(double a, double b)
|
|
{
|
|
double diff = a-b;/*{{{*/
|
|
return (a > b) ? a : b + log(1 + exp(-diff > 0 ? diff : -diff));/*}}}*//*}}}*/
|
|
}
|
|
|