kopia lustrzana https://github.com/kgoba/ft8_lib
Some cleanup
rodzic
74ff78663b
commit
271756b4c7
|
@ -221,7 +221,7 @@ int main(int argc, char **argv)
|
|||
|
||||
// Find top candidates by Costas sync score and localize them in time and frequency
|
||||
Candidate candidate_list[kMax_candidates];
|
||||
int num_candidates = find_sync(&power, kFT8_Costas_pattern, kMax_candidates, candidate_list, kMin_score);
|
||||
int num_candidates = find_sync(&power, kMax_candidates, candidate_list, kMin_score);
|
||||
|
||||
// TODO: sort the candidates by strongest sync first?
|
||||
|
||||
|
@ -238,7 +238,7 @@ int main(int argc, char **argv)
|
|||
float time_sec = (cand->time_offset + (float)cand->time_sub / kTime_osr) / kFSK_dev;
|
||||
|
||||
float log174[FT8_N];
|
||||
extract_likelihood(&power, cand, kFT8_Gray_map, log174);
|
||||
extract_likelihood(&power, cand, log174);
|
||||
|
||||
for (int k = 100; k < 174; ++k)
|
||||
{
|
||||
|
|
|
@ -4,49 +4,47 @@
|
|||
#include <stdint.h>
|
||||
|
||||
// Define FT8 symbol counts
|
||||
#define FT8_ND (58) // Data symbols
|
||||
#define FT8_NS (21) // Sync symbols (3 @ Costas 7x7)
|
||||
#define FT8_NN (FT8_NS + FT8_ND) // Total channel symbols (79)
|
||||
#define FT8_ND (58) ///< Data symbols
|
||||
#define FT8_NS (21) ///< Sync symbols (3 @ Costas 7x7)
|
||||
#define FT8_NN (FT8_NS + FT8_ND) ///< Total channel symbols (79)
|
||||
|
||||
// Define the LDPC sizes
|
||||
#define FT8_N (174) // Number of bits in the encoded message (payload + checksum)
|
||||
#define FT8_K (91) // Number of payload bits
|
||||
#define FT8_M (FT8_N - FT8_K) // Number of checksum bits
|
||||
#define FT8_K_BYTES ((FT8_K + 7) / 8) // Number of whole bytes needed to store K bits
|
||||
// Define LDPC parameters
|
||||
#define FT8_N (174) ///< Number of bits in the encoded message (payload + checksum)
|
||||
#define FT8_K (91) ///< Number of payload bits
|
||||
#define FT8_M (FT8_N - FT8_K) ///< Number of LDPC checksum bits
|
||||
#define FT8_N_BYTES ((FT8_N + 7) / 8) ///< Number of whole bytes needed to store N bits (full message)
|
||||
#define FT8_K_BYTES ((FT8_K + 7) / 8) ///< Number of whole bytes needed to store K bits (payload only)
|
||||
|
||||
// Define CRC parameters
|
||||
#define CRC_POLYNOMIAL ((uint16_t)0x2757u) // CRC-14 polynomial without the leading (MSB) 1
|
||||
#define CRC_WIDTH (14)
|
||||
#define FT8_CRC_POLYNOMIAL ((uint16_t)0x2757u) ///< CRC-14 polynomial without the leading (MSB) 1
|
||||
#define FT8_CRC_WIDTH (14)
|
||||
|
||||
// Costas 7x7 tone pattern
|
||||
extern const uint8_t kCostas_map[7];
|
||||
/// Costas 7x7 tone pattern for synchronization
|
||||
extern const uint8_t kFT8_Costas_pattern[7];
|
||||
|
||||
// Gray code map
|
||||
extern const uint8_t kGray_map[8];
|
||||
/// Gray code map to encode 8 symbols (tones)
|
||||
extern const uint8_t kFT8_Gray_map[8];
|
||||
|
||||
// Parity generator matrix for (174,91) LDPC code, stored in bitpacked format (MSB first)
|
||||
extern const uint8_t kGenerator[FT8_M][FT8_K_BYTES];
|
||||
/// Parity generator matrix for (174,91) LDPC code, stored in bitpacked format (MSB first)
|
||||
extern const uint8_t kFT8_LDPC_generator[FT8_M][FT8_K_BYTES];
|
||||
|
||||
// Column order (permutation) in which the bits in codeword are stored
|
||||
// (Not really used in FT8 v2 - instead the Nm, Mn and generator matrices are already permuted)
|
||||
extern const uint8_t kColumn_order[FT8_N];
|
||||
/// Column order (permutation) in which the bits in codeword are stored
|
||||
/// (Not really used in FT8 v2 - instead the Nm, Mn and generator matrices are already permuted)
|
||||
extern const uint8_t kFT8_LDPC_column_order[FT8_N];
|
||||
|
||||
// this is the LDPC(174,91) parity check matrix.
|
||||
// 83 rows.
|
||||
// each row describes one parity check.
|
||||
// each number is an index into the codeword (1-origin).
|
||||
// the codeword bits mentioned in each row must xor to zero.
|
||||
// From WSJT-X's ldpc_174_91_c_reordered_parity.f90.
|
||||
extern const uint8_t kNm[FT8_M][7];
|
||||
/// LDPC(174,91) parity check matrix, containing 83 rows,
|
||||
/// each row describes one parity check,
|
||||
/// each number is an index into the codeword (1-origin).
|
||||
/// The codeword bits mentioned in each row must xor to zero.
|
||||
/// From WSJT-X's ldpc_174_91_c_reordered_parity.f90.
|
||||
extern const uint8_t kFT8_LDPC_Nm[FT8_M][7];
|
||||
|
||||
// Mn from WSJT-X's bpdecode174.f90.
|
||||
// each row corresponds to a codeword bit.
|
||||
// the numbers indicate which three parity
|
||||
// checks (rows in Nm) refer to the codeword bit.
|
||||
// 1-origin.
|
||||
extern const uint8_t kMn[FT8_N][3];
|
||||
/// Mn from WSJT-X's bpdecode174.f90. Each row corresponds to a codeword bit.
|
||||
/// The numbers indicate which three parity checks (rows in Nm) refer to the codeword bit.
|
||||
/// The numbers use 1 as the origin (first entry).
|
||||
extern const uint8_t kFT8_LDPC_Mn[FT8_N][3];
|
||||
|
||||
// Number of rows (columns in C/C++) in the array Nm.
|
||||
extern const uint8_t kNrw[FT8_M];
|
||||
/// Number of rows (columns in C/C++) in the array Nm.
|
||||
extern const uint8_t kFT8_LDPC_num_rows[FT8_M];
|
||||
|
||||
#endif // _INCLUDE_CONSTANTS_H_
|
||||
|
|
45
ft8/decode.c
45
ft8/decode.c
|
@ -6,19 +6,17 @@
|
|||
|
||||
static float max2(float a, float b);
|
||||
static float max4(float a, float b, float c, float d);
|
||||
static void heapify_down(Candidate *heap, int heap_size);
|
||||
static void heapify_up(Candidate *heap, int heap_size);
|
||||
static void decode_symbol(const uint8_t *power, const uint8_t *code_map, int bit_idx, float *log174);
|
||||
static void decode_multi_symbols(const uint8_t *power, int num_bins, int n_syms, const uint8_t *code_map, int bit_idx, float *log174);
|
||||
static void heapify_down(Candidate heap[], int heap_size);
|
||||
static void heapify_up(Candidate heap[], int heap_size);
|
||||
static void decode_symbol(const uint8_t *power, int bit_idx, float *log174);
|
||||
static void decode_multi_symbols(const uint8_t *power, int num_bins, int n_syms, int bit_idx, float *log174);
|
||||
|
||||
static int get_index(const MagArray *power, int block, int time_sub, int freq_sub, int bin)
|
||||
{
|
||||
return ((((block * power->time_osr) + time_sub) * power->freq_osr + freq_sub) * power->num_bins) + bin;
|
||||
}
|
||||
|
||||
// Localize top N candidates in frequency and time according to their sync strength (looking at Costas symbols)
|
||||
// We treat and organize the candidate list as a min-heap (empty initially).
|
||||
int find_sync(const MagArray *power, const uint8_t *sync_map, int num_candidates, Candidate *heap, int min_score)
|
||||
int find_sync(const MagArray *power, int num_candidates, Candidate heap[], int min_score)
|
||||
{
|
||||
int heap_size = 0;
|
||||
int num_alt = power->time_osr * power->freq_osr;
|
||||
|
@ -48,18 +46,17 @@ int find_sync(const MagArray *power, const uint8_t *sync_map, int num_candidates
|
|||
if (time_offset + k + m >= power->num_blocks)
|
||||
break;
|
||||
|
||||
// int offset = ((time_offset + k + m) * num_alt + alt) * power->num_bins + freq_offset;
|
||||
int offset = get_index(power, time_offset + k + m, time_sub, freq_sub, freq_offset);
|
||||
const uint8_t *p8 = power->mag + offset;
|
||||
|
||||
// Weighted difference between the expected and all other symbols
|
||||
// Does not work as well as the alternative score below
|
||||
// score += 8 * p8[sync_map[k]] -
|
||||
// score += 8 * p8[sync_pattern[k]] -
|
||||
// p8[0] - p8[1] - p8[2] - p8[3] -
|
||||
// p8[4] - p8[5] - p8[6] - p8[7];
|
||||
|
||||
// Check only the neighbors of the expected symbol frequency- and time-wise
|
||||
int sm = sync_map[k]; // Index of the expected bin
|
||||
int sm = kFT8_Costas_pattern[k]; // Index of the expected bin
|
||||
if (sm > 0)
|
||||
{
|
||||
// look at one frequency bin lower
|
||||
|
@ -119,9 +116,7 @@ int find_sync(const MagArray *power, const uint8_t *sync_map, int num_candidates
|
|||
return heap_size;
|
||||
}
|
||||
|
||||
// Compute log likelihood log(p(1) / p(0)) of 174 message bits
|
||||
// for later use in soft-decision LDPC decoding
|
||||
void extract_likelihood(const MagArray *power, const Candidate *cand, const uint8_t *code_map, float *log174)
|
||||
void extract_likelihood(const MagArray *power, const Candidate *cand, float *log174)
|
||||
{
|
||||
int num_alt = power->time_osr * power->freq_osr;
|
||||
int offset = get_index(power, cand->time_offset, cand->time_sub, cand->freq_sub, cand->freq_offset);
|
||||
|
@ -139,7 +134,7 @@ void extract_likelihood(const MagArray *power, const Candidate *cand, const uint
|
|||
// Pointer to 8 bins of the current symbol
|
||||
const uint8_t *ps = power->mag + (offset + sym_idx * num_alt * power->num_bins);
|
||||
|
||||
decode_symbol(ps, code_map, bit_idx, log174);
|
||||
decode_symbol(ps, bit_idx, log174);
|
||||
}
|
||||
|
||||
// Compute the variance of log174
|
||||
|
@ -172,7 +167,7 @@ static float max4(float a, float b, float c, float d)
|
|||
return max2(max2(a, b), max2(c, d));
|
||||
}
|
||||
|
||||
static void heapify_down(Candidate *heap, int heap_size)
|
||||
static void heapify_down(Candidate heap[], int heap_size)
|
||||
{
|
||||
// heapify from the root down
|
||||
int current = 0;
|
||||
|
@ -202,7 +197,7 @@ static void heapify_down(Candidate *heap, int heap_size)
|
|||
}
|
||||
}
|
||||
|
||||
static void heapify_up(Candidate *heap, int heap_size)
|
||||
static void heapify_up(Candidate heap[], int heap_size)
|
||||
{
|
||||
// heapify from the last node up
|
||||
int current = heap_size - 1;
|
||||
|
@ -222,14 +217,14 @@ static void heapify_up(Candidate *heap, int heap_size)
|
|||
}
|
||||
|
||||
// Compute unnormalized log likelihood log(p(1) / p(0)) of 3 message bits (1 FSK symbol)
|
||||
static void decode_symbol(const uint8_t *power, const uint8_t *code_map, int bit_idx, float *log174)
|
||||
static void decode_symbol(const uint8_t *power, int bit_idx, float *log174)
|
||||
{
|
||||
// Cleaned up code for the simple case of n_syms==1
|
||||
float s2[8];
|
||||
|
||||
for (int j = 0; j < 8; ++j)
|
||||
{
|
||||
s2[j] = (float)power[code_map[j]];
|
||||
s2[j] = (float)power[kFT8_Gray_map[j]];
|
||||
}
|
||||
|
||||
log174[bit_idx + 0] = max4(s2[4], s2[5], s2[6], s2[7]) - max4(s2[0], s2[1], s2[2], s2[3]);
|
||||
|
@ -238,7 +233,7 @@ static void decode_symbol(const uint8_t *power, const uint8_t *code_map, int bit
|
|||
}
|
||||
|
||||
// Compute unnormalized log likelihood log(p(1) / p(0)) of bits corresponding to several FSK symbols at once
|
||||
static void decode_multi_symbols(const uint8_t *power, int num_bins, int n_syms, const uint8_t *code_map, int bit_idx, float *log174)
|
||||
static void decode_multi_symbols(const uint8_t *power, int num_bins, int n_syms, int bit_idx, float *log174)
|
||||
{
|
||||
// The following section implements what seems to be multiple-symbol decode at one go,
|
||||
// corresponding to WSJT-X's ft8b.f90. Experimentally found not to be any better than
|
||||
|
@ -254,20 +249,20 @@ static void decode_multi_symbols(const uint8_t *power, int num_bins, int n_syms,
|
|||
int j1 = j & 0x07;
|
||||
if (n_syms == 1)
|
||||
{
|
||||
s2[j] = (float)power[code_map[j1]];
|
||||
s2[j] = (float)power[kFT8_Gray_map[j1]];
|
||||
continue;
|
||||
}
|
||||
int j2 = (j >> 3) & 0x07;
|
||||
if (n_syms == 2)
|
||||
{
|
||||
s2[j] = (float)power[code_map[j2]];
|
||||
s2[j] += (float)power[code_map[j1] + 4 * num_bins];
|
||||
s2[j] = (float)power[kFT8_Gray_map[j2]];
|
||||
s2[j] += (float)power[kFT8_Gray_map[j1] + 4 * num_bins];
|
||||
continue;
|
||||
}
|
||||
int j3 = (j >> 6) & 0x07;
|
||||
s2[j] = (float)power[code_map[j3]];
|
||||
s2[j] += (float)power[code_map[j2] + 4 * num_bins];
|
||||
s2[j] += (float)power[code_map[j1] + 8 * num_bins];
|
||||
s2[j] = (float)power[kFT8_Gray_map[j3]];
|
||||
s2[j] += (float)power[kFT8_Gray_map[j2] + 4 * num_bins];
|
||||
s2[j] += (float)power[kFT8_Gray_map[j1] + 8 * num_bins];
|
||||
}
|
||||
// No need to go back to linear scale any more. Works better in dB.
|
||||
// for (int j = 0; j < n_tones; ++j) {
|
||||
|
|
49
ft8/decode.h
49
ft8/decode.h
|
@ -3,30 +3,47 @@
|
|||
|
||||
#include <stdint.h>
|
||||
|
||||
/// Input structure to find_sync() function. This structure describes stored waterfall data over the whole message slot.
|
||||
/// Fields time_osr and freq_osr specify additional oversampling rate for time and frequency resolution.
|
||||
/// If time_osr=1, FFT magnitude data is collected once for every symbol transmitted, i.e. every 1/6.25 = 0.16 seconds.
|
||||
/// Values time_osr > 1 mean each symbol is further subdivided in time.
|
||||
/// If freq_osr=1, each bin in the FFT magnitude data corresponds to 6.25 Hz, which is the tone spacing.
|
||||
/// Values freq_osr > 1 mean the tone spacing is further subdivided by FFT analysis.
|
||||
typedef struct
|
||||
{
|
||||
int num_blocks; // number of total blocks (symbols)
|
||||
int num_bins; // number of FFT bins
|
||||
int time_osr; // number of time subdivisions
|
||||
int freq_osr; // number of frequency subdivisions
|
||||
uint8_t *mag; // FFT magnitudes as [blocks][time_sub][freq_sub][num_bins]
|
||||
int num_blocks; ///< number of total blocks (symbols) in terms of 160 ms time periods
|
||||
int num_bins; ///< number of FFT bins in terms of 6.25 Hz
|
||||
int time_osr; ///< number of time subdivisions
|
||||
int freq_osr; ///< number of frequency subdivisions
|
||||
uint8_t *mag; ///< FFT magnitudes stored as uint8_t[blocks][time_osr][freq_osr][num_bins]
|
||||
} MagArray;
|
||||
|
||||
/// Output structure of find_sync() and input structure of extract_likelihood().
|
||||
/// Holds the position of potential start of a message in time and frequency.
|
||||
typedef struct
|
||||
{
|
||||
int16_t score;
|
||||
int16_t time_offset;
|
||||
int16_t freq_offset;
|
||||
uint8_t time_sub;
|
||||
uint8_t freq_sub;
|
||||
int16_t score; ///< Candidate score (non-negative number; higher score means higher likelihood)
|
||||
int16_t time_offset; ///< Index of the time block
|
||||
int16_t freq_offset; ///< Index of the frequency bin
|
||||
uint8_t time_sub; ///< Index of the time subdivision used
|
||||
uint8_t freq_sub; ///< Index of the frequency subdivision used
|
||||
} Candidate;
|
||||
|
||||
// Localize top N candidates in frequency and time according to their sync strength (looking at Costas symbols)
|
||||
// We treat and organize the candidate list as a min-heap (empty initially).
|
||||
int find_sync(const MagArray *power, const uint8_t *sync_map, int num_candidates, Candidate *heap, int min_score);
|
||||
/// Localize top N candidates in frequency and time according to their sync strength (looking at Costas symbols)
|
||||
/// We treat and organize the candidate list as a min-heap (empty initially).
|
||||
/// @param[in] power Waterfall data collected during message slot
|
||||
/// @param[in] sync_pattern Synchronization pattern
|
||||
/// @param[in] num_candidates Number of maximum candidates (size of heap array)
|
||||
/// @param[in,out] heap Array of Candidate type entries (with num_candidates allocated entries)
|
||||
/// @param[in] min_score Minimal score allowed for trimming unlikely candidates (can be zero for no effect)
|
||||
/// @return Number of candidates filled in the heap
|
||||
int find_sync(const MagArray *power, int num_candidates, Candidate heap[], int min_score);
|
||||
|
||||
// Compute log likelihood log(p(1) / p(0)) of 174 message bits
|
||||
// for later use in soft-decision LDPC decoding
|
||||
void extract_likelihood(const MagArray *power, const Candidate *cand, const uint8_t *code_map, float *log174);
|
||||
/// Compute log likelihood log(p(1) / p(0)) of 174 message bits for later use in soft-decision LDPC decoding
|
||||
/// @param[in] power Waterfall data collected during message slot
|
||||
/// @param[in] cand Candidate to extract the message from
|
||||
/// @param[in] code_map Symbol encoding map
|
||||
/// @param[out] log174 Output of decoded log likelihoods for each of the 174 message bits
|
||||
void extract_likelihood(const MagArray *power, const Candidate *cand, float *log174);
|
||||
|
||||
#endif // _INCLUDE_DECODE_H_
|
||||
|
|
43
ft8/encode.c
43
ft8/encode.c
|
@ -3,15 +3,15 @@
|
|||
|
||||
#include <stdio.h>
|
||||
|
||||
#define TOPBIT (1 << (FT8_CRC_WIDTH - 1))
|
||||
#define TOPBIT (1u << (FT8_CRC_WIDTH - 1))
|
||||
|
||||
// Returns 1 if an odd number of bits are set in x, zero otherwise
|
||||
uint8_t parity8(uint8_t x)
|
||||
{
|
||||
x ^= x >> 4; // a b c d ae bf cg dh
|
||||
x ^= x >> 2; // a b ac bd cae dbf aecg bfdh
|
||||
x ^= x >> 1; // a ab bac acbd bdcae caedbf aecgbfdh
|
||||
return (x)&1;
|
||||
x ^= x >> 4; // a b c d ae bf cg dh
|
||||
x ^= x >> 2; // a b ac bd cae dbf aecg bfdh
|
||||
x ^= x >> 1; // a ab bac acbd bdcae caedbf aecgbfdh
|
||||
return x % 2; // modulo 2
|
||||
}
|
||||
|
||||
// Encode a 91-bit message and return a 174-bit codeword.
|
||||
|
@ -37,17 +37,18 @@ void encode174(const uint8_t *message, uint8_t *codeword)
|
|||
// printf("\n");
|
||||
|
||||
// Fill the codeword with message and zeros, as we will only update binary ones later
|
||||
for (int j = 0; j < (7 + FT8_N) / 8; ++j)
|
||||
for (int j = 0; j < FT8_N_BYTES; ++j)
|
||||
{
|
||||
codeword[j] = (j < FT8_K_BYTES) ? message[j] : 0;
|
||||
}
|
||||
|
||||
uint8_t col_mask = (0x80 >> (FT8_K % 8)); // bitmask of current byte
|
||||
uint8_t col_idx = FT8_K_BYTES - 1; // index into byte array
|
||||
// Compute the byte index and bit mask for the first checksum bit
|
||||
uint8_t col_mask = (0x80u >> (FT8_K % 8u)); // bitmask of current byte
|
||||
uint8_t col_idx = FT8_K_BYTES - 1; // index into byte array
|
||||
|
||||
// Compute the first part of itmp (1:FT8_M) and store the result in codeword
|
||||
// Compute the LDPC checksum bits and store them in codeword
|
||||
for (int i = 0; i < FT8_M; ++i)
|
||||
{ // do i=1,FT8_M
|
||||
{
|
||||
// Fast implementation of bitwise multiplication and parity checking
|
||||
// Normally nsum would contain the result of dot product between message and kFT8_LDPC_generator[i],
|
||||
// but we only compute the sum modulo 2.
|
||||
|
@ -57,25 +58,21 @@ void encode174(const uint8_t *message, uint8_t *codeword)
|
|||
uint8_t bits = message[j] & kFT8_LDPC_generator[i][j]; // bitwise AND (bitwise multiplication)
|
||||
nsum ^= parity8(bits); // bitwise XOR (addition modulo 2)
|
||||
}
|
||||
// Check if we need to set a bit in codeword
|
||||
|
||||
// Set the current checksum bit in codeword if nsum is odd
|
||||
if (nsum % 2)
|
||||
{ // pchecks(i)=mod(nsum,2)
|
||||
{
|
||||
codeword[col_idx] |= col_mask;
|
||||
}
|
||||
|
||||
// Update the byte index and bit mask for the next checksum bit
|
||||
col_mask >>= 1;
|
||||
if (col_mask == 0)
|
||||
{
|
||||
col_mask = 0x80;
|
||||
col_mask = 0x80u;
|
||||
++col_idx;
|
||||
}
|
||||
}
|
||||
|
||||
// printf("Result ");
|
||||
// for (int i = 0; i < (FT8_N + 7) / 8; ++i) {
|
||||
// printf("%02x ", codeword[i]);
|
||||
// }
|
||||
// printf("\n");
|
||||
}
|
||||
|
||||
// Compute 14-bit CRC for a sequence of given number of bits
|
||||
|
@ -108,7 +105,7 @@ uint16_t ft8_crc(uint8_t *message, int num_bits)
|
|||
}
|
||||
}
|
||||
|
||||
return remainder & ((1 << FT8_CRC_WIDTH) - 1);
|
||||
return remainder & ((TOPBIT << 1) - 1u);
|
||||
}
|
||||
|
||||
// Generate FT8 tone sequence from payload data
|
||||
|
@ -123,7 +120,7 @@ void genft8(const uint8_t *payload, uint8_t *itone)
|
|||
a91[i] = payload[i];
|
||||
|
||||
// Clear 3 bits after the payload to make 80 bits
|
||||
a91[9] &= 0xF8;
|
||||
a91[9] &= 0xF8u;
|
||||
a91[10] = 0;
|
||||
a91[11] = 0;
|
||||
|
||||
|
@ -149,10 +146,10 @@ void genft8(const uint8_t *payload, uint8_t *itone)
|
|||
|
||||
int k = 7; // Skip over the first set of Costas symbols
|
||||
|
||||
uint8_t mask = 0x80;
|
||||
uint8_t mask = 0x80u;
|
||||
int i_byte = 0;
|
||||
for (int j = 0; j < FT8_ND; ++j)
|
||||
{ // do j=1,FT8_ND
|
||||
{
|
||||
if (j == 29)
|
||||
{
|
||||
k += 7; // Skip over the second set of Costas symbols
|
||||
|
|
31
ft8/ldpc.c
31
ft8/ldpc.c
|
@ -19,6 +19,8 @@
|
|||
static int ldpc_check(uint8_t codeword[]);
|
||||
static float fast_tanh(float x);
|
||||
static float fast_atanh(float x);
|
||||
static float pltanh(float x);
|
||||
static float platanh(float x);
|
||||
|
||||
// Packs a string of bits each represented as a zero/non-zero byte in plain[],
|
||||
// as a string of packed bits starting from the MSB of the first byte of packed[]
|
||||
|
@ -163,15 +165,7 @@ void bp_decode(float codeword[], int max_iters, uint8_t plain[], int *ok)
|
|||
int nclast = 0;
|
||||
int ncnt = 0;
|
||||
|
||||
// initialize messages to checks
|
||||
for (int i = 0; i < FT8_M; ++i)
|
||||
{
|
||||
for (int j = 0; j < kFT8_LDPC_num_rows[i]; ++j)
|
||||
{
|
||||
toc[i][j] = codeword[kFT8_LDPC_Nm[i][j] - 1];
|
||||
}
|
||||
}
|
||||
|
||||
// initialize message data
|
||||
for (int i = 0; i < FT8_N; ++i)
|
||||
{
|
||||
for (int j = 0; j < 3; ++j)
|
||||
|
@ -211,37 +205,30 @@ void bp_decode(float codeword[], int max_iters, uint8_t plain[], int *ok)
|
|||
for (int j = 0; j < kFT8_LDPC_num_rows[i]; ++j)
|
||||
{
|
||||
int ibj = kFT8_LDPC_Nm[i][j] - 1;
|
||||
toc[i][j] = zn[ibj];
|
||||
float Tnm = zn[ibj];
|
||||
for (int kk = 0; kk < 3; ++kk)
|
||||
{
|
||||
// subtract off what the bit had received from the check
|
||||
if (kFT8_LDPC_Mn[ibj][kk] - 1 == i)
|
||||
if ((kFT8_LDPC_Mn[ibj][kk] - 1) == i)
|
||||
{
|
||||
toc[i][j] -= tov[ibj][kk];
|
||||
Tnm -= tov[ibj][kk];
|
||||
break;
|
||||
}
|
||||
}
|
||||
toc[i][j] = fast_tanh(-Tnm / 2);
|
||||
}
|
||||
}
|
||||
|
||||
// send messages from check nodes to variable nodes
|
||||
for (int i = 0; i < FT8_M; ++i)
|
||||
{
|
||||
for (int j = 0; j < kFT8_LDPC_num_rows[i]; ++j)
|
||||
{
|
||||
toc[i][j] = fast_tanh(-toc[i][j] / 2);
|
||||
}
|
||||
}
|
||||
|
||||
for (int i = 0; i < FT8_N; ++i)
|
||||
{
|
||||
for (int j = 0; j < 3; ++j)
|
||||
{
|
||||
int ichk = kFT8_LDPC_Mn[i][j] - 1; // kFT8_LDPC_Mn(:,j) are the checks that include bit j
|
||||
int ichk = kFT8_LDPC_Mn[i][j] - 1;
|
||||
float Tmn = 1.0f;
|
||||
for (int k = 0; k < kFT8_LDPC_num_rows[ichk]; ++k)
|
||||
{
|
||||
if (kFT8_LDPC_Nm[ichk][k] - 1 != i)
|
||||
if ((kFT8_LDPC_Nm[ichk][k] - 1) != i)
|
||||
{
|
||||
Tmn *= toc[ichk][k];
|
||||
}
|
||||
|
|
|
@ -393,6 +393,7 @@ int unpack77(const uint8_t *a77, char *message)
|
|||
char field1[14];
|
||||
char field2[14];
|
||||
char field3[7];
|
||||
|
||||
int rc = unpack77_fields(a77, field1, field2, field3);
|
||||
if (rc < 0)
|
||||
return rc;
|
||||
|
|
Ładowanie…
Reference in New Issue