diff --git a/Makefile b/Makefile index a414ce7..ebe69f9 100644 --- a/Makefile +++ b/Makefile @@ -1,4 +1,5 @@ -CXXFLAGS = -std=c++14 -I. +CFLAGS = -O3 +CPPFLAGS = -std=c11 -I. LDFLAGS = -lm TARGETS = gen_ft8 decode_ft8 test diff --git a/decode_ft8.c b/decode_ft8.c index d8e1baa..e288c0a 100644 --- a/decode_ft8.c +++ b/decode_ft8.c @@ -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, kCostas_map, kMax_candidates, candidate_list, kMin_score); + int num_candidates = find_sync(&power, kFT8_Costas_pattern, 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, kGray_map, log174); + extract_likelihood(&power, cand, kFT8_Gray_map, log174); for (int k = 100; k < 174; ++k) { diff --git a/ft8/constants.c b/ft8/constants.c index 94bf494..8bdba6e 100644 --- a/ft8/constants.c +++ b/ft8/constants.c @@ -1,13 +1,13 @@ #include "constants.h" // Costas 7x7 tone pattern -const uint8_t kCostas_map[7] = {3, 1, 4, 0, 6, 5, 2}; +const uint8_t kFT8_Costas_pattern[7] = {3, 1, 4, 0, 6, 5, 2}; // Gray code map -const uint8_t kGray_map[8] = {0, 1, 3, 2, 5, 6, 4, 7}; +const uint8_t kFT8_Gray_map[8] = {0, 1, 3, 2, 5, 6, 4, 7}; // Parity generator matrix for (174,91) LDPC code, stored in bitpacked format (MSB first) -const uint8_t kGenerator[FT8_M][FT8_K_BYTES] = { +const uint8_t kFT8_LDPC_generator[FT8_M][FT8_K_BYTES] = { {0x83, 0x29, 0xce, 0x11, 0xbf, 0x31, 0xea, 0xf5, 0x09, 0xf2, 0x7f, 0xc0}, {0x76, 0x1c, 0x26, 0x4e, 0x25, 0xc2, 0x59, 0x33, 0x54, 0x93, 0x13, 0x20}, {0xdc, 0x26, 0x59, 0x02, 0xfb, 0x27, 0x7c, 0x64, 0x10, 0xa1, 0xbd, 0xc0}, @@ -94,7 +94,7 @@ const uint8_t kGenerator[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) -const uint8_t kColumn_order[FT8_N] = { +const uint8_t kFT8_LDPC_column_order[FT8_N] = { 0, 1, 2, 3, 28, 4, 5, 6, 7, 8, 9, 10, 11, 34, 12, 32, 13, 14, 15, 16, 17, 18, 36, 29, 43, 19, 20, 42, 21, 40, 30, 37, 22, 47, 61, 45, 44, 23, 41, 39, 49, 24, 46, 50, 48, 26, 31, 33, 51, 38, 52, 59, 55, 66, 57, 27, 60, 35, 54, 58, @@ -111,7 +111,7 @@ const uint8_t kColumn_order[FT8_N] = { // 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. -const uint8_t kNm[FT8_M][7] = { +const uint8_t kFT8_LDPC_Nm[FT8_M][7] = { {4, 31, 59, 91, 92, 96, 153}, {5, 32, 60, 93, 115, 146, 0}, {6, 24, 61, 94, 122, 151, 0}, @@ -201,7 +201,7 @@ const uint8_t kNm[FT8_M][7] = { // the numbers indicate which three parity // checks (rows in Nm) refer to the codeword bit. // 1-origin. -const uint8_t kMn[FT8_N][3] = { +const uint8_t kFT8_LDPC_Mn[FT8_N][3] = { {16, 45, 73}, {25, 51, 62}, {33, 58, 78}, @@ -377,7 +377,7 @@ const uint8_t kMn[FT8_N][3] = { {20, 44, 48}, {42, 49, 57}}; -const uint8_t kNrw[FT8_M] = { +const uint8_t kFT8_LDPC_num_rows[FT8_M] = { 7, 6, 6, 6, 7, 6, 7, 6, 6, 7, 6, 6, 7, 7, 6, 6, 6, 7, 6, 7, 6, 7, 6, 6, 6, 7, 6, 6, 6, 7, 6, 6, 6, 6, 7, 6, 6, 6, 7, 7, 6, 6, 6, 6, 7, 7, 6, 6, diff --git a/ft8/encode.c b/ft8/encode.c index 609df77..a448415 100644 --- a/ft8/encode.c +++ b/ft8/encode.c @@ -3,7 +3,7 @@ #include -#define TOPBIT (1 << (CRC_WIDTH - 1)) +#define TOPBIT (1 << (FT8_CRC_WIDTH - 1)) // Returns 1 if an odd number of bits are set in x, zero otherwise uint8_t parity8(uint8_t x) @@ -24,7 +24,7 @@ uint8_t parity8(uint8_t x) void encode174(const uint8_t *message, uint8_t *codeword) { // Here we don't generate the generator bit matrix as in WSJT-X implementation - // Instead we access the generator bits straight from the binary representation in kGenerator + // Instead we access the generator bits straight from the binary representation in kFT8_LDPC_generator // For reference: // codeword(1:K)=message @@ -49,13 +49,13 @@ void encode174(const uint8_t *message, uint8_t *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 kGenerator[i], + // Normally nsum would contain the result of dot product between message and kFT8_LDPC_generator[i], // but we only compute the sum modulo 2. uint8_t nsum = 0; for (int j = 0; j < FT8_K_BYTES; ++j) { - uint8_t bits = message[j] & kGenerator[i][j]; // bitwise AND (bitwise multiplication) - nsum ^= parity8(bits); // bitwise XOR (addition modulo 2) + 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 if (nsum % 2) @@ -93,14 +93,14 @@ uint16_t ft8_crc(uint8_t *message, int num_bits) if (idx_bit % 8 == 0) { // Bring the next byte into the remainder. - remainder ^= (message[idx_byte] << (CRC_WIDTH - 8)); + remainder ^= (message[idx_byte] << (FT8_CRC_WIDTH - 8)); ++idx_byte; } // Try to divide the current data bit. if (remainder & TOPBIT) { - remainder = (remainder << 1) ^ CRC_POLYNOMIAL; + remainder = (remainder << 1) ^ FT8_CRC_POLYNOMIAL; } else { @@ -108,7 +108,7 @@ uint16_t ft8_crc(uint8_t *message, int num_bits) } } - return remainder & ((1 << CRC_WIDTH) - 1); + return remainder & ((1 << FT8_CRC_WIDTH) - 1); } // Generate FT8 tone sequence from payload data @@ -142,9 +142,9 @@ void genft8(const uint8_t *payload, uint8_t *itone) // Message structure: S7 D29 S7 D29 S7 for (int i = 0; i < 7; ++i) { - itone[i] = kCostas_map[i]; - itone[36 + i] = kCostas_map[i]; - itone[72 + i] = kCostas_map[i]; + itone[i] = kFT8_Costas_pattern[i]; + itone[36 + i] = kFT8_Costas_pattern[i]; + itone[72 + i] = kFT8_Costas_pattern[i]; } int k = 7; // Skip over the first set of Costas symbols @@ -183,7 +183,7 @@ void genft8(const uint8_t *payload, uint8_t *itone) i_byte++; } - itone[k] = kGray_map[bits3]; + itone[k] = kFT8_Gray_map[bits3]; ++k; } } diff --git a/ft8/ldpc.c b/ft8/ldpc.c index 0c22bf5..a4da265 100644 --- a/ft8/ldpc.c +++ b/ft8/ldpc.c @@ -70,13 +70,13 @@ void ldpc_decode(float codeword[], int max_iters, uint8_t plain[], int *ok) { for (int j = 0; j < FT8_M; j++) { - for (int ii1 = 0; ii1 < kNrw[j]; ii1++) + for (int ii1 = 0; ii1 < kFT8_LDPC_num_rows[j]; ii1++) { - int i1 = kNm[j][ii1] - 1; + int i1 = kFT8_LDPC_Nm[j][ii1] - 1; float a = 1.0f; - for (int ii2 = 0; ii2 < kNrw[j]; ii2++) + for (int ii2 = 0; ii2 < kFT8_LDPC_num_rows[j]; ii2++) { - int i2 = kNm[j][ii2] - 1; + int i2 = kFT8_LDPC_Nm[j][ii2] - 1; if (i2 != i1) { a *= fast_tanh(-m[j][i2] / 2.0f); @@ -90,7 +90,7 @@ void ldpc_decode(float codeword[], int max_iters, uint8_t plain[], int *ok) { float l = codeword[i]; for (int j = 0; j < 3; j++) - l += e[kMn[i][j] - 1][i]; + l += e[kFT8_LDPC_Mn[i][j] - 1][i]; plain[i] = (l > 0) ? 1 : 0; } @@ -111,13 +111,13 @@ void ldpc_decode(float codeword[], int max_iters, uint8_t plain[], int *ok) { for (int ji1 = 0; ji1 < 3; ji1++) { - int j1 = kMn[i][ji1] - 1; + int j1 = kFT8_LDPC_Mn[i][ji1] - 1; float l = codeword[i]; for (int ji2 = 0; ji2 < 3; ji2++) { if (ji1 != ji2) { - int j2 = kMn[i][ji2] - 1; + int j2 = kFT8_LDPC_Mn[i][ji2] - 1; l += e[j2][i]; } } @@ -141,9 +141,9 @@ static int ldpc_check(uint8_t codeword[]) for (int j = 0; j < FT8_M; ++j) { uint8_t x = 0; - for (int i = 0; i < kNrw[j]; ++i) + for (int i = 0; i < kFT8_LDPC_num_rows[j]; ++i) { - x ^= codeword[kNm[j][i] - 1]; + x ^= codeword[kFT8_LDPC_Nm[j][i] - 1]; } if (x != 0) { @@ -166,9 +166,9 @@ void bp_decode(float codeword[], int max_iters, uint8_t plain[], int *ok) // initialize messages to checks for (int i = 0; i < FT8_M; ++i) { - for (int j = 0; j < kNrw[i]; ++j) + for (int j = 0; j < kFT8_LDPC_num_rows[i]; ++j) { - toc[i][j] = codeword[kNm[i][j] - 1]; + toc[i][j] = codeword[kFT8_LDPC_Nm[i][j] - 1]; } } @@ -208,14 +208,14 @@ void bp_decode(float codeword[], int max_iters, uint8_t plain[], int *ok) // Send messages from bits to check nodes for (int i = 0; i < FT8_M; ++i) { - for (int j = 0; j < kNrw[i]; ++j) + for (int j = 0; j < kFT8_LDPC_num_rows[i]; ++j) { - int ibj = kNm[i][j] - 1; + int ibj = kFT8_LDPC_Nm[i][j] - 1; toc[i][j] = zn[ibj]; for (int kk = 0; kk < 3; ++kk) { // subtract off what the bit had received from the check - if (kMn[ibj][kk] - 1 == i) + if (kFT8_LDPC_Mn[ibj][kk] - 1 == i) { toc[i][j] -= tov[ibj][kk]; break; @@ -227,7 +227,7 @@ void bp_decode(float codeword[], int max_iters, uint8_t plain[], int *ok) // send messages from check nodes to variable nodes for (int i = 0; i < FT8_M; ++i) { - for (int j = 0; j < kNrw[i]; ++j) + for (int j = 0; j < kFT8_LDPC_num_rows[i]; ++j) { toc[i][j] = fast_tanh(-toc[i][j] / 2); } @@ -237,11 +237,11 @@ void bp_decode(float codeword[], int max_iters, uint8_t plain[], int *ok) { for (int j = 0; j < 3; ++j) { - int ichk = kMn[i][j] - 1; // kMn(:,j) are the checks that include bit j + int ichk = kFT8_LDPC_Mn[i][j] - 1; // kFT8_LDPC_Mn(:,j) are the checks that include bit j float Tmn = 1.0f; - for (int k = 0; k < kNrw[ichk]; ++k) + for (int k = 0; k < kFT8_LDPC_num_rows[ichk]; ++k) { - if (kNm[ichk][k] - 1 != i) + if (kFT8_LDPC_Nm[ichk][k] - 1 != i) { Tmn *= toc[ichk][k]; }