...
 
Commits (11)
This diff is collapsed.
#include <stddef.h>
#include <stdlib.h>
#include <stdio.h>
#include <reds-dvb-decoder.h>
#include "64800x32400-dvb-s2-table.h"
// TODO comment style
// TODO variable name
static const int cn_deg_max = DEG_1;
static const int vn_deg_max = DEG_VN_MAX;
//const size_t CDecoder_MS_fixed_flooded::nb_vn = _N;
//const char CDecoder_MS_fixed_flooded::hard_decision_threshold = 0;
//
typedef struct {
char** p_vn_addr;
char** p_cn_addr;
size_t *p_cn_addrSize;
char* vn_msgs;
char* cn_msgs;
} REDS_DVB_DECODER_Decoder;
int REDS_DVB_DECODER_flooded_Init(REDS_DVB_DECODER_Decoder* decoder)
{
const size_t nb_edges = _M;
const size_t nb_rows = _K;
const size_t nb_cols = _N;
size_t row;
size_t vn_slot_offset, cn_slot_offset;
size_t vn_idx;
size_t* p_vn_addrSize;
// Allocate VNs and CNs
decoder->vn_msgs = malloc(sizeof(*decoder->vn_msgs) * vn_deg_max * _N);
decoder->cn_msgs = malloc(sizeof(*decoder->cn_msgs) * cn_deg_max * _K);
// We allocate a max of cn_deg_max per CN
decoder->p_vn_addr = malloc(sizeof(*decoder->p_vn_addr) * nb_rows * cn_deg_max);
p_vn_addrSize = malloc(sizeof(*p_vn_addrSize) * nb_rows);
for(size_t i = 0; i < nb_rows; i++) {
p_vn_addrSize[i] = 0;
}
// We allocate a max of vn_deg_max per VN
decoder->p_cn_addr = malloc(sizeof(*decoder->p_cn_addr) * nb_cols * vn_deg_max);
decoder->p_cn_addrSize = malloc(sizeof(*decoder->p_cn_addrSize) * nb_cols);
for(size_t i = 0; i < nb_cols; i++) {
decoder->p_cn_addrSize[i] = 0;
}
/* Iterate over the entire matrix H */
for(size_t edge_idx = 0; edge_idx < nb_edges; edge_idx++) {
vn_idx = PosNoeudsVariable[edge_idx];
/* The following line is quite problematic. We assume that all CNs
* have the same degree like it is the case with a DVB-S2 LDPC code.
* (excluding the last CN, but it's not a problem here).
*
* What if the code has variable degree per CN ?
*/
row = edge_idx / cn_deg_max; // Also indicates the current CN
// Associate vn addr to cn index, and cn addr to vn index
vn_slot_offset = p_vn_addrSize[row];
cn_slot_offset = decoder->p_cn_addrSize[vn_idx];
if (p_vn_addrSize[row] < cn_deg_max) {
p_vn_addrSize[row]++;
} else {
fprintf(stderr, "vn_addr offset out of bound");
break;
}
if (decoder->p_cn_addrSize[vn_idx] < vn_deg_max) {
decoder->p_cn_addrSize[vn_idx]++;
} else {
fprintf(stderr, "cn_addr offset out of bound");
break;
}
decoder->p_vn_addr[row*cn_deg_max + vn_slot_offset] =
&decoder->vn_msgs[vn_idx*vn_deg_max + cn_slot_offset];
decoder->p_cn_addr[vn_idx*vn_deg_max + cn_slot_offset] =
&decoder->cn_msgs[row*cn_deg_max + vn_slot_offset];
}
free(p_vn_addrSize);
}
int REDS_DVB_DECODER_flooded_Terminate(REDS_DVB_DECODER_Decoder* decoder)
{
free(decoder->p_vn_addr);
free(decoder->p_cn_addr);
free(decoder->p_cn_addrSize);
free(decoder->vn_msgs);
free(decoder->cn_msgs);
}
void REDS_DVB_DECODER_flooded_Decode(REDS_DVB_DECODER_Decoder* decoder,
char var_nodes[],
char Rprime_fix[],
int nombre_iterations)
{
/* Initialize variable node messages */
for(size_t i = 0; i < nb_vn; i++) {
for(size_t j = 0; j < vn_deg_max; j++) {
decoder->vn_msgs[i*vn_deg_max + j] = var_nodes[i];
}
}
/* Loop a fixed number of iterations */
while(nombre_iterations--) {
/* Check node updates.
* For each check node, send a message containing a new estimate
* to each of its neighbouring variable node.
*/
for(size_t cn_idx = 0; cn_idx < DEG_1_COMPUTATIONS; cn_idx++) {
int cn_offset = cn_idx*cn_deg_max;
char signGlobal = 0;
char minLLR1 = vSAT_POS_MSG;
char minLLR2 = vSAT_POS_MSG;
char abs[DEG_1];
/* We compute a different estimate (the message sent), for each
* neighbouring VN */
for(size_t edge_idx = 0; edge_idx < DEG_1; edge_idx++) {
char vn = *decoder->p_vn_addr[cn_offset + edge_idx];
signGlobal ^= vn;
abs[edge_idx] = (vn >= 0 ? vn : -vn);
minLLR2 = minLLR2 < abs[edge_idx] ? minLLR2 : abs[edge_idx] > minLLR1 ? abs[edge_idx] : minLLR1;
minLLR1 = minLLR1 < abs[edge_idx] ? minLLR1 : abs[edge_idx];
}
#if (DEG_1 & 0x1)
signGlobal = ~signGlobal;
#endif
for(size_t edge_idx = 0; edge_idx < DEG_1; edge_idx++) {
char sign = *p_vn_addr[cn_offset + edge_idx] ^ signGlobal;
char min = abs[edge_idx] == minLLR1 ? minLLR2 : minLLR1;
decoder->cn_msgs[cn_offset + edge_idx] = sign < 0 ? -min : min;
}
}
#if (NB_DEGRES <= 2)
for(size_t cn_idx = DEG_1_COMPUTATIONS;
cn_idx < DEG_1_COMPUTATIONS + DEG_2_COMPUTATIONS;
cn_idx++) {
int cn_offset = cn_idx*cn_deg_max;
char signGlobal = 0;
char minLLR1 = vSAT_POS_MSG;
char minLLR2 = vSAT_POS_MSG;
char abs[DEG_2];
/* We compute a different estimate (the message sent), for each
* neighbouring VN */
for(size_t edge_idx = 0; edge_idx < DEG_2; edge_idx++) {
char vn = *p_vn_addr[cn_offset + edge_idx];
signGlobal ^= vn;
abs[edge_idx] = (vn >= 0 ? vn : -vn);
minLLR2 = minLLR2 < abs[edge_idx] ? minLLR2 : abs[edge_idx] > minLLR1 ? abs[edge_idx] : minLLR1;
minLLR1 = minLLR1 < abs[edge_idx] ? minLLR1 : abs[edge_idx];
}
#if (DEG_2 & 0x1)
signGlobal = ~signGlobal;
#endif
for(size_t edge_idx = 0; edge_idx < DEG_2; edge_idx++) {
char sign = *p_vn_addr[cn_offset + edge_idx] ^ signGlobal;
char min = abs[edge_idx] == minLLR1 ? minLLR2 : minLLR1;
decoder->cn_msgs[cn_offset + edge_idx] = sign < 0 ? -min : min;
}
}
#else
#error "Code should be adapted to handle more degrees"
#endif
/* Bit node updates.
* For each variable node, compute two things :
* 1) A new message to be sent to each of its neighbouring CNs
* 2) A new estimate to be kept to itself
*/
for(size_t vn_idx = 0; vn_idx < nb_vn; vn_idx++) {
int estimate_acc = var_nodes[vn_idx];
size_t vn_offset = vn_idx*vn_deg_max;
for(size_t edge_idx = 0; edge_idx < decoder->p_cn_addrSize[vn_idx]; edge_idx++)
{
estimate_acc += *decoder->p_cn_addr[vn_offset + edge_idx];
}
if(estimate_acc > vSAT_POS_VAR) _vn_est[vn_idx] = vSAT_POS_VAR;
else if(estimate_acc < vSAT_NEG_VAR) _vn_est[vn_idx] = vSAT_NEG_VAR;
else _vn_est[vn_idx] = (char)estimate_acc;
for(size_t edge_idx = 0; edge_idx < decoder->p_cn_addrSize[vn_idx]; edge_idx++)
{
int msg = *decoder->p_cn_addr[vn_offset + edge_idx];
int vn_msg = estimate_acc - msg;
if(vn_msg > vSAT_POS_VAR) vn_msg = vSAT_POS_VAR;
else if(vn_msg < vSAT_NEG_VAR) vn_msg = vSAT_NEG_VAR;
decoder->vn_msgs[vn_offset + edge_idx] = (char)vn_msg;
}
}
}
/* Hard decision */
for(size_t vn_idx = 0; vn_idx < nb_vn; vn_idx++) {
Rprime_fix[vn_idx] = _vn_est[vn_idx] > hard_decision_threshold ? 1 : 0;
}
}
This diff is collapsed.