Organized variable declarations

pull/16/merge
Bob Larkin 1 year ago
parent 1a2ba41e1b
commit fa19a9cfb9
  1. 96
      examples/FT8Receive/FT8Receive.ino
  2. 10
      examples/FT8Receive/Process_DSP_R.ino
  3. 20
      examples/FT8Receive/decodeR.ino
  4. 26
      examples/FT8Receive/decode_ft8R.ino
  5. 4
      examples/FT8Receive/encodeR.ino
  6. 38
      examples/FT8Receive/ldpcR.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);

@ -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
}

@ -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;
}

@ -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[] = " ";

@ -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);

@ -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;

Loading…
Cancel
Save