diff --git a/examples/FT8Receive/FT8Receive.ino b/examples/FT8Receive/FT8Receive.ino index 11bc9c4..f925136 100644 --- a/examples/FT8Receive/FT8Receive.ino +++ b/examples/FT8Receive/FT8Receive.ino @@ -64,6 +64,16 @@ #define ft8_min_freq FT8_FREQ_SPACING * LOW_FREQ_INDEX #define ft8_msg_samples 92 +// Define FT8 symbol counts +#define FT8_ND 58 +#define FT8_NN 79 + +// Define the LDPC sizes +#define FT8_N 174 +#define FT8_K 91 +#define FT8_M 83 +#define FT8_K_BYTES 12 + // A couple of prototypes to help the compile order void init_DSP(void); void extract_power(int); @@ -87,35 +97,32 @@ AudioConnection_F32 patchCord2(gain1, demod1); AudioConnection_F32 patchCord3(gain1, peak1); AudioControlSGTL5000 sgtl5000_1; //xy=100,250 +// Communicate amongst decode functions: +typedef struct Candidate { + int16_t score; + int16_t time_offset; + int16_t freq_offset; + uint8_t time_sub; + uint8_t freq_sub; + uint8_t alt; // Added for convenience Teensy, RSL + float32_t syncPower; // Added for Teensy, RSL +} Candidate; + // This is the big file of log powers uint8_t export_fft_power[ft8_msg_samples*HIGH_FREQ_INDEX*4] ; // Pointer to 2048 float data for FFT array in radioDemodulator_F32 float32_t* pData2K = NULL; -float32_t noisePowerEstimateL = 0.0f; // Works when big signals are absent -int16_t noisePwrDBIntL = 0; -float32_t noisePowerEstimateH = 0.0f; // Works for big signals and QRMt -int16_t noisePwrDBIntH = 0; -float32_t noisePeakAveRatio = 0.0f; // > about 100 for big sigs +float32_t FT8noisePowerEstimateL = 0.0f; // Works when big signals are absent +int16_t FT8noisePwrDBIntL = 0; +float32_t FT8noisePowerEstimateH = 0.0f; // Works for big signals and QRMt +int16_t FT8noisePwrDBIntH = 0; +float32_t FT8noisePeakAveRatio = 0.0f; // > about 100 for big sigs -// /char Station_Call[11]; //six character call sign + /0 -// /char home_Locator[11];; // four character locator + /0 -// /char Locator[11]; // four character locator + /0 char Station_Call[11]; // six character call sign + /0 char home_Locator[11]; // four character locator + /0 char Locator[11]; // four character locator + /0 -uint16_t currentFrequency; - -// Next 3 lines were uint32_t Sept 22 change to allow tOffset -int32_t current_time, start_time, ft8_time, ft8_mod_time, ft8_mod_time_last; -int32_t days_fraction, hours_fraction, minute_fraction; -int32_t tOffset = 0; // Added Sept 22 uint8_t ft8_hours, ft8_minutes, ft8_seconds; -int ft8_flag, FT_8_counter, ft8_marker, decode_flag; -int num_decoded_msg; -int xmit_flag, ft8_xmit_counter, Transmit_Armned; -int DSP_Flag; // =1 if new data is ready for FFT -int master_decoded; // rcvFT8State #define FT8_RCV_IDLE 0 @@ -123,48 +130,23 @@ int master_decoded; #define FT8_RCV_FIND_POWERS 2 #define FT8_RCV_READY_DECODE 3 #define FT8_RCV_DECODE 4 - int rcvFT8State = FT8_RCV_IDLE; -int master_offset, offset_step; -int Target_Flag = 0; +int offset_step; -//From gen_ft8.cpp +//From gen_ft8.cpp, i.e., also used for transmit char Target_Call[7]; //six character call sign + /0 char Target_Locator[5]; // four character locator + /0 int Target_RSL; // four character RSL + /0 float32_t Station_Latitude, Station_Longitude; float32_t Target_Latitude, Target_Longitude; - -// Define FT8 symbol counts -int ND = 58; -int NS = 21; -int NN = 79; -// Define the LDPC sizes -int N = 174; -int K = 91; -int M = 83; -int K_BYTES = 12; -// Define CRC parameters -uint16_t CRC_POLYNOMIAL = 0X2757; // CRC-14 polynomial without the leading (MSB) 1 -int CRC_WIDTH = 14; - -// Communicate amongst decode functions: -typedef struct Candidate { - int16_t score; - int16_t time_offset; - int16_t freq_offset; - uint8_t time_sub; - uint8_t freq_sub; - uint8_t alt; // Added for convenience Teensy, RSL - float32_t syncPower; // Added for Teensy, RSL -} Candidate; - +int32_t current_time, start_time; +int32_t ft8_time, ft8_mod_time, ft8_mod_time_last; +int32_t tOffset = 0; // Added Sept 22 uint8_t secLast = 0; const int ledPin = 13; bool showPower = false; uint32_t tp = 0; -uint32_t tu; -uint32_t ct=0; +uint32_t tu = 0; void setup(void) { strcpy(Station_Call, "W7PUA"); @@ -196,7 +178,11 @@ void setup(void) { } void loop(void) { - int16_t inCmd; + int16_t inCmd; + int master_offset; + + + if( Serial.available() ) { inCmd = Serial.read(); @@ -323,16 +309,14 @@ void loop(void) { Serial.println("FT8 Decode"); #endif tu = micros(); - num_decoded_msg = ft8_decode(); + ft8_decode(); printFT8Received(); rcvFT8State = FT8_RCV_IDLE; - master_decoded = num_decoded_msg; #ifdef DEBUG1 Serial.print("ft8_decode Time, uSec = "); Serial.println(micros() - tu); - #endif +#endif } - delay(1); } // End loop() @@ -342,6 +326,8 @@ time_t getTeensy3Time() { // This starts the receiving data collection every 15 sec void update_synchronization() { + int32_t hours_fraction; + current_time = millis() + tOffset; ft8_time = current_time - start_time; ft8_hours = (int8_t)(ft8_time/3600000); diff --git a/examples/FT8Receive/Process_DSP_R.ino b/examples/FT8Receive/Process_DSP_R.ino index aad8129..f8936c1 100644 --- a/examples/FT8Receive/Process_DSP_R.ino +++ b/examples/FT8Receive/Process_DSP_R.ino @@ -143,16 +143,16 @@ void extract_power( int offset) { // This measurement occurs once every 15 sec, but may be just before // or just after decode. Either way, the "latest" noise estimate is used. noiseMeasured = true; // Reset after decode() - noisePowerEstimateH = 0.2f*(y[0]+y[1]+y[2]+y[3]+y[4]); - noisePwrDBIntH = (int16_t)(10.0f*log10f(noisePowerEstimateH)); - noisePeakAveRatio = runningMax/(0.00156*runningSum); + FT8noisePowerEstimateH = 0.2f*(y[0]+y[1]+y[2]+y[3]+y[4]); + FT8noisePwrDBIntH = (int16_t)(10.0f*log10f(FT8noisePowerEstimateH)); + FT8noisePeakAveRatio = runningMax/(0.00156*runningSum); #ifdef DEBUG_N Serial.println("Noise measurement between transmit time periods:"); Serial.print(" rSum, rMax= "); Serial.print(0.00156*runningSum, 5); Serial.print(" "); Serial.print(runningMax, 5); - Serial.print(" Ratio= "); Serial.print(noisePeakAveRatio, 3); + Serial.print(" Ratio= "); Serial.print(FT8noisePeakAveRatio, 3); Serial.print(" Int noise= "); - Serial.println(noisePwrDBIntH); // dB increments + Serial.println(FT8noisePwrDBIntH); // dB increments #endif } diff --git a/examples/FT8Receive/decodeR.ino b/examples/FT8Receive/decodeR.ino index 0295996..6ca7375 100644 --- a/examples/FT8Receive/decodeR.ino +++ b/examples/FT8Receive/decodeR.ino @@ -66,13 +66,13 @@ int find_sync(const uint8_t *power, int num_blocks, int num_bins, // npCount++; } } - noisePowerEstimateL = np/(float32_t)npCount; - noisePwrDBIntL = (int16_t)(0.5f*noisePowerEstimateL); + FT8noisePowerEstimateL = np/(float32_t)npCount; + FT8noisePwrDBIntL = (int16_t)(0.5f*FT8noisePowerEstimateL); #if DEBUG_N Serial.println("Data for low SNR noise estimate:"); - Serial.print(" Full Ave Noise = "); Serial.println(noisePowerEstimateL); - Serial.print(" Full Ave dB Noise Int = "); Serial.println(noisePwrDBIntL); + Serial.print(" Full Ave Noise = "); Serial.println(FT8noisePowerEstimateL); + Serial.print(" Full Ave dB Noise Int = "); Serial.println(FT8noisePwrDBIntL); Serial.print(" Noise Sample Count = "); Serial.println(npCount); #endif @@ -83,7 +83,7 @@ int find_sync(const uint8_t *power, int num_blocks, int num_bins, // for (int alt = 0; alt < 4; ++alt) { // 92-79+7=20 - for (int time_offset = -7; time_offset < num_blocks - NN + 7; ++time_offset) // NN=79 + for (int time_offset = -7; time_offset < num_blocks - FT8_NN + 7; ++time_offset) // FT8_NN=79 { // 48 368-8=360 for (int freq_offset = LOW_FREQ_INDEX; freq_offset < num_bins - 8; ++freq_offset) @@ -205,9 +205,9 @@ void extract_likelihood(const uint8_t *power, int num_bins, const int n_syms = 1; // const int n_bits = 3 * n_syms; // const int n_tones = (1 << n_bits); - for (int k = 0; k < ND; k += n_syms) + for (int k = 0; k < FT8_ND; k += n_syms) { - int sym_idx = (k < ND / 2) ? (k + 7) : (k + 14); + int sym_idx = (k < FT8_ND / 2) ? (k + 7) : (k + 14); int bit_idx = 3 * k; // Pointer to 8 bins of the current symbol const uint8_t *ps = power + (ft8_offset + sym_idx * 4 * num_bins); @@ -216,8 +216,8 @@ void extract_likelihood(const uint8_t *power, int num_bins, // Compute the variance of log174 float sum = 0; float sum2 = 0; - float inv_n = 1.0f / N; - for (int i = 0; i < N; ++i) + float inv_n = 1.0f / FT8_N; + for (int i = 0; i < FT8_N; ++i) { sum += log174[i]; sum2 += log174[i] * log174[i]; @@ -226,7 +226,7 @@ void extract_likelihood(const uint8_t *power, int num_bins, // Normalize log174 such that sigma = 2.83 (Why? It's in WSJT-X, ft8b.f90) // Seems to be 2.83 = sqrt(8). Experimentally sqrt(16) works better. float norm_factor = sqrtf(16.0f / variance); - for (int i = 0; i < N; ++i) + for (int i = 0; i < FT8_N; ++i) { log174[i] *= norm_factor; } diff --git a/examples/FT8Receive/decode_ft8R.ino b/examples/FT8Receive/decode_ft8R.ino index a8d2aa1..e71f65a 100644 --- a/examples/FT8Receive/decode_ft8R.ino +++ b/examples/FT8Receive/decode_ft8R.ino @@ -78,9 +78,9 @@ int ft8_decode(void) { char decoded[kMax_decoded_messages][kMax_message_length]; const float fsk_dev = 6.25f; // tone spacing in Hz and symbol rate Candidate candidate_list[kMax_candidates]; - float log174[N]; - uint8_t plain[N]; - uint8_t a91[K_BYTES]; + float log174[FT8_N]; + uint8_t plain[FT8_N]; + uint8_t a91[FT8_K_BYTES]; // Find top candidates by Costas sync score and localize them in time and frequency int num_candidates = find_sync(export_fft_power, @@ -100,7 +100,7 @@ int ft8_decode(void) { if (n_errors > 0) continue; // Extract payload + CRC (first K bits) - pack_bits(plain, K, a91); + pack_bits(plain, FT8_K, a91); // Extract CRC and check it uint16_t chksum = ((a91[9] & 0x07) << 11) | (a91[10] << 3) | (a91[11] >> 5); a91[9] &= 0xF8; @@ -159,16 +159,16 @@ int ft8_decode(void) { new_decoded[indexFound].sync_score = cand.score; new_decoded[indexFound].freq_hz = (int)freq_hz; new_decoded[indexFound].dTime = dt; - if(noisePeakAveRatio < 100.0f) // No big signals + if(FT8noisePeakAveRatio < 100.0f) // No big signals { new_decoded[indexFound].snr = - cand.syncPower - (float32_t)noisePwrDBIntL + 51.0f; + cand.syncPower - (float32_t)FT8noisePwrDBIntL + 51.0f; noiseType = 'L'; } else { new_decoded[indexFound].snr = - cand.syncPower - (float32_t)noisePwrDBIntH - 13.0f; + cand.syncPower - (float32_t)FT8noisePwrDBIntH - 13.0f; noiseType = 'H'; } if(new_decoded[indexFound].snr < -21) @@ -197,12 +197,12 @@ int ft8_decode(void) { strcpy(new_decoded[num_decoded].field2, field2); strcpy(new_decoded[num_decoded].field3, field3); strcpy(new_decoded[num_decoded].decode_time, rtc_string); - if(noisePeakAveRatio < 100.0f) // No big signals for quiet timing + if(FT8noisePeakAveRatio < 100.0f) // No big signals for quiet timing new_decoded[num_decoded].snr = - cand.syncPower - (float32_t)noisePwrDBIntL + 51.0f; + cand.syncPower - (float32_t)FT8noisePwrDBIntL + 51.0f; else new_decoded[num_decoded].snr = - cand.syncPower - (float32_t)noisePwrDBIntH - 13.0f; + cand.syncPower - (float32_t)FT8noisePwrDBIntH - 13.0f; if(new_decoded[num_decoded].snr < -21) new_decoded[num_decoded].snr = -21; // It is never lower!! #ifdef DEBUG_D @@ -212,9 +212,9 @@ int ft8_decode(void) { #endif #ifdef DEBUG_N Serial.print("syncPower, noiseL, noiseH, ratio { "); Serial.print(cand.syncPower, 1); - Serial.print(" "); Serial.print(noisePwrDBIntL); - Serial.print(" "); Serial.print(noisePwrDBIntH); - Serial.print(" "); Serial.print(noisePeakAveRatio, 1); + Serial.print(" "); Serial.print(FT8noisePwrDBIntL); + Serial.print(" "); Serial.print(FT8noisePwrDBIntH); + Serial.print(" "); Serial.print(FT8noisePeakAveRatio, 1); Serial.println(" }"); #endif char Target_Locator[] = " "; diff --git a/examples/FT8Receive/encodeR.ino b/examples/FT8Receive/encodeR.ino index 18e26c7..2ec9c43 100644 --- a/examples/FT8Receive/encodeR.ino +++ b/examples/FT8Receive/encodeR.ino @@ -117,6 +117,10 @@ void encode174(const uint8_t *message, uint8_t *codeword) { // [IN] num_bits - number of bits in the sequence uint16_t crc(uint8_t *message, int num_bits) { // Adapted from https://barrgroup.com/Embedded-Systems/How-To/CRC-Calculation-C-Code + + // Define CRC parameters + uint16_t CRC_POLYNOMIAL = 0X2757; // CRC-14 polynomial without the leading (MSB) 1 + int CRC_WIDTH = 14; //constexpr uint16_t TOPBIT = (1 << (CRC_WIDTH - 1)); uint16_t TOPBIT = (1 << (CRC_WIDTH - 1)); // printf("CRC, %d bits: ", num_bits); diff --git a/examples/FT8Receive/ldpcR.ino b/examples/FT8Receive/ldpcR.ino index 74d9752..affa630 100644 --- a/examples/FT8Receive/ldpcR.ino +++ b/examples/FT8Receive/ldpcR.ino @@ -75,18 +75,18 @@ void pack_bits(const uint8_t plain[], int num_bits, uint8_t packed[]) { // max_iters is how hard to try. // ok == 87 means success. void ldpc_decode(float codeword[], int max_iters, uint8_t plain[], int *ok) { - float m[M][N]; // ~60 kB - float e[M][N]; // ~60 kB - int min_errors = M; + float m[FT8_M][FT8_N]; // ~60 kB + float e[FT8_M][FT8_N]; // ~60 kB + int min_errors = FT8_M; - for (int j = 0; j < M; j++) { - for (int i = 0; i < N; i++) { + for (int j = 0; j < FT8_M; j++) { + for (int i = 0; i < FT8_N; i++) { m[j][i] = codeword[i]; e[j][i] = 0.0f; } } for (int iter = 0; iter < max_iters; iter++) { - for (int j = 0; j < M; j++) { + for (int j = 0; j < FT8_M; j++) { for (int ii1 = 0; ii1 < kNrw[j]; ii1++) { int i1 = kNm[j][ii1] - 1; float a = 1.0f; @@ -99,7 +99,7 @@ void ldpc_decode(float codeword[], int max_iters, uint8_t plain[], int *ok) { e[j][i1] = logf((1 - a) / (1 + a)); } } - for (int i = 0; i < N; i++) { + for (int i = 0; i < FT8_N; i++) { float l = codeword[i]; for (int j = 0; j < 3; j++) l += e[kMn[i][j] - 1][i]; @@ -117,7 +117,7 @@ void ldpc_decode(float codeword[], int max_iters, uint8_t plain[], int *ok) { } } - for (int i = 0; i < N; i++) { + for (int i = 0; i < FT8_N; i++) { for (int ji1 = 0; ji1 < 3; ji1++) { int j1 = kMn[i][ji1] - 1; float l = codeword[i]; @@ -143,7 +143,7 @@ void ldpc_decode(float codeword[], int max_iters, uint8_t plain[], int *ok) { static int ldpc_check(uint8_t codeword[]) { int errors = 0; - for (int j = 0; j < M; ++j) { + for (int j = 0; j < FT8_M; ++j) { uint8_t x = 0; for (int i = 0; i < kNrw[j]; ++i) { x ^= codeword[kNm[j][i] - 1]; @@ -157,28 +157,28 @@ static int ldpc_check(uint8_t codeword[]) { void bp_decode(float codeword[], int max_iters, uint8_t plain[], int *ok) { - float tov[N][3]; - float toc[M][7]; - int min_errors = M; + float tov[FT8_N][3]; + float toc[FT8_M][7]; + int min_errors = FT8_M; // initialize messages to checks - for (int i = 0; i < M; ++i) { + for (int i = 0; i < FT8_M; ++i) { for (int j = 0; j < kNrw[i]; ++j) { toc[i][j] = codeword[kNm[i][j] - 1]; } } - for (int i = 0; i < N; ++i) { + for (int i = 0; i < FT8_N; ++i) { for (int j = 0; j < 3; ++j) { tov[i][j] = 0; } } for (int iter = 0; iter < max_iters; ++iter) { - float zn[N]; + float zn[FT8_N]; // Update bit log likelihood ratios (tov=0 in iter 0) - for (int i = 0; i < N; ++i) { + for (int i = 0; i < FT8_N; ++i) { zn[i] = codeword[i] + tov[i][0] + tov[i][1] + tov[i][2]; plain[i] = (zn[i] > 0) ? 1 : 0; } @@ -196,7 +196,7 @@ 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 < M; ++i) { + for (int i = 0; i < FT8_M; ++i) { for (int j = 0; j < kNrw[i]; ++j) { int ibj = kNm[i][j] - 1; toc[i][j] = zn[ibj]; @@ -210,13 +210,13 @@ 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 < M; ++i) { + for (int i = 0; i < FT8_M; ++i) { for (int j = 0; j < kNrw[i]; ++j) { toc[i][j] = fast_tanh(-toc[i][j] / 2); } } - for (int i = 0; i < N; ++i) { + for (int i = 0; i < FT8_N; ++i) { for (int j = 0; j < 3; ++j) { int ichk = kMn[i][j] - 1; // kMn(:,j) are the checks that include bit j float Tmn = 1.0f;