diff --git a/Makefile b/Makefile index 8109a3d..88561b0 100644 --- a/Makefile +++ b/Makefile @@ -14,5 +14,5 @@ gen_ft8: gen_ft8.o ft8/encode.o ft8/pack.o ft8/text.o ft8/pack_v2.o ft8/encode_v test: test.o ft8/encode.o ft8/pack.o ft8/text.o ft8/pack_v2.o ft8/encode_v2.o ft8/unpack.o $(CXX) $(LDFLAGS) -o $@ $^ -decode_ft8: decode_ft8.o fft/kiss_fftr.o fft/kiss_fft.o ft8/ldpc.o common/wave.o +decode_ft8: decode_ft8.o fft/kiss_fftr.o fft/kiss_fft.o ft8/ldpc.o ft8/unpack.o ft8/text.o common/wave.o $(CXX) $(LDFLAGS) -o $@ $^ diff --git a/decode_ft8.cpp b/decode_ft8.cpp index 41ee7ac..a9518bc 100644 --- a/decode_ft8.cpp +++ b/decode_ft8.cpp @@ -8,6 +8,7 @@ #include "ft8/encode.h" #include "ft8/pack_v2.h" #include "ft8/encode_v2.h" +#include "ft8/unpack.h" #include "ft8/ldpc.h" #include "fft/kiss_fftr.h" @@ -77,6 +78,7 @@ void heapify_up(Candidate * heap, int heap_size) { // Find 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). void find_sync(const uint8_t * power, int num_blocks, int num_bins, int num_candidates, Candidate * heap) { // Costas 7x7 tone pattern const uint8_t ICOS7[] = { 2,5,6,0,4,1,3 }; @@ -101,7 +103,7 @@ void find_sync(const uint8_t * power, int num_blocks, int num_bins, int num_cand } // If the heap is full AND the current candidate is better than - // the worst of the heap, we remove the worst and make space + // the worst in the heap, we remove the worst and make space if (heap_size == num_candidates && score > heap[0].score) { heap[0] = heap[heap_size - 1]; --heap_size; @@ -229,10 +231,10 @@ void extract_likelihood(const uint8_t * power, int num_bins, const Candidate & c sum += log174[i]; sum2 += log174[i] * log174[i]; } - float var = (sum2 - sum * sum * inv_n) * inv_n; + float variance = (sum2 - sum * sum * inv_n) * inv_n; // Normalize log174 such that sigma = 2.83 (Why? It's in WSJT-X) - float norm_factor = 2.83f / sqrtf(var); + float norm_factor = 2.83f / sqrtf(variance); for (int i = 0; i < 3 * ND; ++i) { log174[i] *= norm_factor; @@ -277,24 +279,51 @@ int main(int argc, char ** argv) { for (int idx = 0; idx < num_candidates; ++idx) { Candidate &cand = heap[idx]; - float freq_hz = (cand.freq_offset + cand.freq_sub / 2.0f) * fsk_dev; - float time_sec = (cand.time_offset + cand.time_sub / 2.0f) / fsk_dev; - // printf("%03d: score = %d freq = %.1f time = %.2f\n", i, - // heap[i].score, freq_hz, time_sec); float log174[3 * ND]; extract_likelihood(power, num_bins, cand, log174); const int num_iters = 20; int plain[3 * ND]; - int ok; + int ok = 0; bp_decode(log174, num_iters, plain, &ok); //ldpc_decode(log174, num_iters, plain, &ok); //printf("ldpc_decode() = %d\n", ok); + if (ok == 87) { - printf("%03d: score = %d freq = %.1f time = %.2f\n", idx, - cand.score, freq_hz, time_sec); + float freq_hz = (cand.freq_offset + cand.freq_sub / 2.0f) * fsk_dev; + float time_sec = (cand.time_offset + cand.time_sub / 2.0f) / fsk_dev; + //printf("%03d: score = %d freq = %.1f time = %.2f\n", idx, + // cand.score, freq_hz, time_sec); + + uint8_t a87[11]; + uint8_t mask = 0x80; + uint8_t position = 0; + for (int i = 0; i < 11; ++i) { + a87[i] = 0; + } + // Extract payload + CRC (last 87 bits) + for (int i = 174 - 87; i < 174; ++i) { + if (plain[i]) { + a87[position] |= mask; + } + mask >>= 1; + if (!mask) { + mask = 0x80; + ++position; + } + } + + for (int i = 0; i < 11; ++i) { + //printf("%02x ", a87[i]); + } + //printf("\n"); + + char message[20]; + unpack(a87, message); + + printf("000000 0 %4.1f %4d ~ %s\n", time_sec, (int)(freq_hz + 0.5f), message); } } diff --git a/ft8/unpack.cpp b/ft8/unpack.cpp index b59940e..5529048 100644 --- a/ft8/unpack.cpp +++ b/ft8/unpack.cpp @@ -133,6 +133,7 @@ void unpacktext(uint32_t nc1, uint32_t nc2, uint16_t ng, char *text) { } +// message should have at least 19 bytes allocated (18 characters + zero terminator) int unpack(const uint8_t *a72, char *message) { uint32_t nc1, nc2; uint16_t ng;