Localized global variables, corrected comments

Added descriptive comments on data handling and also a couple of Todo notes.
pull/16/merge
Bob Larkin 2 years ago
parent fa19a9cfb9
commit c9553fb3bb
  1. 20
      examples/FT8Receive/FT8Receive.ino
  2. 80
      examples/FT8Receive/Process_DSP_R.ino
  3. 11
      radioFT8Demodulator_F32.cpp

@ -123,6 +123,12 @@ char Station_Call[11]; // six character call sign + /0
char home_Locator[11]; // four character locator + /0 char home_Locator[11]; // four character locator + /0
char Locator[11]; // four character locator + /0 char Locator[11]; // four character locator + /0
uint8_t ft8_hours, ft8_minutes, ft8_seconds; uint8_t ft8_hours, ft8_minutes, ft8_seconds;
//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;
// rcvFT8State // rcvFT8State
#define FT8_RCV_IDLE 0 #define FT8_RCV_IDLE 0
@ -131,20 +137,15 @@ uint8_t ft8_hours, ft8_minutes, ft8_seconds;
#define FT8_RCV_READY_DECODE 3 #define FT8_RCV_READY_DECODE 3
#define FT8_RCV_DECODE 4 #define FT8_RCV_DECODE 4
int rcvFT8State = FT8_RCV_IDLE; int rcvFT8State = FT8_RCV_IDLE;
int offset_step;
//From gen_ft8.cpp, i.e., also used for transmit int offset_step;
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;
int32_t current_time, start_time; int32_t current_time, start_time;
int32_t ft8_time, ft8_mod_time, ft8_mod_time_last; int32_t ft8_time, ft8_mod_time, ft8_mod_time_last;
int32_t tOffset = 0; // Added Sept 22 int32_t tOffset = 0; // Added Sept 22
uint8_t secLast = 0; uint8_t secLast = 0;
const int ledPin = 13; const int ledPin = 13;
bool showPower = false; bool showPower = false;
bool noiseMeasured = false;
uint32_t tp = 0; uint32_t tp = 0;
uint32_t tu = 0; uint32_t tu = 0;
@ -283,6 +284,9 @@ void loop(void) {
if(rcvFT8State==FT8_RCV_DATA_COLLECT && demod1.available()) if(rcvFT8State==FT8_RCV_DATA_COLLECT && demod1.available())
{ {
// Note: The RadioFT8Demodulator provides at least 2.7 milliseconds, after data is
// available, before pData2K is written over. The extract_power() here must stay
// on schedule to protect the data. THis should be OK.
// Here every 80 mSec for FFT // Here every 80 mSec for FFT
rcvFT8State = FT8_RCV_FIND_POWERS; rcvFT8State = FT8_RCV_FIND_POWERS;
// 1472 * 92 = 135424 // 1472 * 92 = 135424
@ -317,7 +321,7 @@ void loop(void) {
Serial.println(micros() - tu); Serial.println(micros() - tu);
#endif #endif
} }
delay(1); delay(1); // Don't increase
} // End loop() } // End loop()
time_t getTeensy3Time() { time_t getTeensy3Time() {

@ -42,25 +42,14 @@ SOFTWARE.
* to pass all frequencies up to, at least 2800 Hz. * to pass all frequencies up to, at least 2800 Hz.
*/ */
// Following are used inside extract_power() float32_t window[1024]; // Holds half of symmetrical curve
float32_t fft_buffer[2048];
float fftOutput[2048];
float window[2048]; // Change to 1024 by symmetry <<<<<<<<<<<<<<<<<<<
arm_rfft_fast_instance_f32 Sfft; arm_rfft_fast_instance_f32 Sfft;
float32_t powerSum = 0.0f; // Use these for snr estimate
float32_t runningSum = 0.0f;
float32_t powerMax = 0.0f;
float32_t runningMax = 0.0f;
float32_t noiseBuffer[8]; // Circular storage
uint16_t noiseBufferWrite = 0; // Array index
bool noiseMeasured = false; // <<<<<<GLOBAL
uint8_t noisePower8 = 0; // half dB per noise estimate GLOBAL
void init_DSP(void) { void init_DSP(void) {
arm_rfft_fast_init_f32(&Sfft, 2048); arm_rfft_fast_init_f32(&Sfft, 2048);
for (int i = 0; i < FFT_SIZE; ++i) // The window is symmetric, so create half of it
window[i] = ft_blackman_i(i, FFT_SIZE); for (int i = 0; i < 1024; ++i)
window[i] = ft_blackman_i(i, 2048);
offset_step = 1472; // (int) HIGH_FREQ_INDEX*4; offset_step = 1472; // (int) HIGH_FREQ_INDEX*4;
} }
@ -78,25 +67,60 @@ float ft_blackman_i(int i, int N) {
// Compute FFT magnitudes (log power) for each timeslot in the signal // Compute FFT magnitudes (log power) for each timeslot in the signal
void extract_power( int offset) { void extract_power( int offset) {
float32_t fft_buffer[2048];
float32_t fftOutput[2048];
float32_t powerSum = 0.0f; // Use these for snr estimate
float32_t runningSum = 0.0f;
float32_t powerMax = 0.0f;
float32_t runningMax = 0.0f;
float32_t noiseBuffer[8]; // Circular storage
uint16_t noiseBufferWrite = 0; // Array index
uint8_t noisePower8 = 0; // half dB per noise estimate GLOBAL
float32_t y[8]; float32_t y[8];
float32_t noiseCoeff[3]; float32_t noiseCoeff[3];
/* Format of export_fft_power[] array: /* The FFT's are arranged to have overlap in both time and frequency.
368 bytes of power for even time for 0.32 sec sample DESCRIBE BETTER <<<<<<<<<<<<<<<<<<<<<< * This allows good decoding sensitivity. It remains difficult to decode a weak
368 bytes of power for odd time for 0.32 sec sample * signal that is close in frequency to a strong one. It also causes multiple
... * combinations of time and frequency to show the same signal.
Repeated about 14.7/(0.08 sec) = 184 times. (Transmitted message length is 12.96 sec) *
Total bytes 4 * 368 * 92 = 135424 * The 2048 point real FFT yields 1024 power outputs, corresponding to 0 to 3200 Hz.
* Only the frequencies up to 2300 Hz are inspected in this implementation. That
The power byte is log encoded with a half dB MSB. This can handle a * corresponds with outputs 0 to 736. The windowing of the FFT results in frequency
dynamic range of 256/2 = 128 dB. * resolution that is close to double the bin spacing. So, the power data is grouped
*/ * up in 736/2=368 power data points. It is done twice, using every other bins.
* Format of export_fft_power[] array:
for(int i=0; i<2048; i++) * 368 bytes of power for even frequencies, 0, 2, 4, ... 366
* 368 bytes of power for odd frequencies, 1, 3, 5, ... 367
* Repeated 14.72/(0.08 sec) = 184 times.
* The transmitted message length is 12.96 sec so the difference allows timing errors
* along with the decoding allowing missing symbols.
* Total bytes saved for decoding is 2 * 368 * 194 = 135424 for the 14.72 seconds.
*
* The power byte is log encoded with a half dB MSB. This can handle a
* dynamic range of 256/2 = 128 dB.
*/
// TODO: It would seem easy to offset the frequencies being examined and, without
// increasing the data burden, make the range more productive. For instance, move the
// 0 to 2300 up to 300 to 2600 Hz. Needs investigation.
// TODO: The 135424 byte array is using more than a fourth of Teensy 4.x main RAM1.
// Might the array be put in RAM2 (and perhaps enlarged somewhat) and re-arranged
// in frequency order. This would allow transfers to RAM1 in, say, 300 Hz overlapping
// segments. This might be 300 to 600 Hz, 500 to 800, 700 to 1000 and so forth. That
// would cut way back on RAM 1 array size. Problems with this, except complexity??
// Note: The RadioFT8Demodulator provides at least 2.7 milliseconds, after data is
// available, before pData2K is written over. This needs to be thought of in the design
// of the loop() in the main INO. Long delays are trouble. The following transfer
// of data to fft_buffer is very fast. After that, pData2K[] is available.
for(int i=0; i<1024; i++)
{ {
fft_buffer[i] = window[i]*pData2K[i]; // Protect pData2K from in-place FFT (17 uSec) fft_buffer[i] = window[i]*pData2K[i]; // Protect pData2K from in-place FFT (17 uSec)
fft_buffer[2047 - i] = window[i]*pData2K[2047 - i]; // Symmetrical window
} }
// (float32_t* pIn, float32_t* pOut, uint8_t ifftFlag) // (float32_t* pIn, float32_t* pOut, uint8_t ifftFlag)
arm_rfft_fast_f32(&Sfft, fft_buffer, fftOutput, 0); arm_rfft_fast_f32(&Sfft, fft_buffer, fftOutput, 0);
arm_cmplx_mag_squared_f32(fftOutput, fftOutput, 1024); arm_cmplx_mag_squared_f32(fftOutput, fftOutput, 1024);

@ -1,9 +1,11 @@
/* /*
* radioFT8Demodulator_F32.cpp Assembled by Bob Larkin 8 Sept 2022 * radioFT8Demodulator_F32.cpp
* Assembled by Bob Larkin 8 Sept 2022
* Comments corrected 16 Nov 2022
* *
* This class is Teensy 4.x ONLY. * This class is Teensy 4.x ONLY.
* *
* Copyright (c) 2021 Bob Larkin * Copyright (c) 2022 Bob Larkin
* *
* Permission is hereby granted, free of charge, to any person obtaining a copy * Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal * of this software and associated documentation files (the "Software"), to deal
@ -28,11 +30,6 @@
* Every 5 audio samples at 96 kHz produce 1 19.2 kHz sample * Every 5 audio samples at 96 kHz produce 1 19.2 kHz sample
* Every 3 audio samples at 19.2 produce 1 6.4 kHz sample * Every 3 audio samples at 19.2 produce 1 6.4 kHz sample
* Every 15*128=1920 audio samples at 96 kHz produce 128 samples at 6.4 kHz * Every 15*128=1920 audio samples at 96 kHz produce 128 samples at 6.4 kHz
*
* Every 120 (for 48 kHz) or 60 (for 96 kHz) blocks produces 1024 data points
* at 6.4 kHz reduced sample rate. This 1024 size is sent to the .INO as it
* is *half* of a 2048 data block, and thus supports 50% overlap FFT's.
*
*/ */
// NOTE Changed class name to start with capital "R" RSL 7 Nov 2022 // NOTE Changed class name to start with capital "R" RSL 7 Nov 2022

Loading…
Cancel
Save