diff --git a/src/audioConfig.c b/src/audioConfig.c index 065dc86..bdf6722 100644 --- a/src/audioConfig.c +++ b/src/audioConfig.c @@ -54,7 +54,11 @@ #define VCO_GAIN 0.5f -#define AGC_FILTER_CUTOFF_FREQUENCY 20 +#define USE_AGC true +#define MANUAL_GAIN_DIVISOR 5000.0f +#define AGC_MINIMUM_AMPLITUDE 100.0f +#define AGC_FILTER_CUTOFF_FREQUENCY 1000 + #define CHANNEL_FILTER_CUTOFF_FREQUENCY 100 #define CHANNEL_FILTER_BANDWIDTH 2.0f #define CARRIER_FILTER_CUTOFF_FREQUENCY 1000 @@ -75,6 +79,8 @@ #define MIN(a, b) ((a) < (b) ? (a) : (b)) +#define MAX(a, b) ((a) > (b) ? (a) : (b)) + /* Sine table */ static const float sineTable[SINE_TABLE_LENGTH] = {0.000000000000f, 0.024541229010f, 0.049067676067f, 0.073564566672f, 0.098017141223f, 0.122410677373f, 0.146730467677f, 0.170961901546f, \ @@ -150,7 +156,7 @@ static BQ_filterCoefficients_t channelFilterCoefficients; /* Carrier generation variable */ -float omegaT = 0.0f; +static float omegaT = 0.0f; /* Configuration variables */ @@ -170,7 +176,7 @@ typedef enum {NONE, HIGH_BIT, LOW_BIT} receivedBit_t; /* CRC functions */ -static uint16_t updateCRC(uint16_t crc_in, int incr) { +static inline uint16_t updateCRC(uint16_t crc_in, int incr) { uint16_t xor = crc_in >> 15; uint16_t out = crc_in << 1; @@ -187,7 +193,7 @@ static uint16_t updateCRC(uint16_t crc_in, int incr) { } -static uint16_t calculateCRC(const uint8_t *data, uint32_t size) { +static inline uint16_t calculateCRC(const uint8_t *data, uint32_t size) { uint16_t crc, i; @@ -205,7 +211,7 @@ static uint16_t calculateCRC(const uint8_t *data, uint32_t size) { } -static bool checkCRC(const uint8_t *data, uint32_t size) { +static inline bool checkCRC(const uint8_t *data, uint32_t size) { uint16_t crc = calculateCRC(data, size - CRC_SIZE_IN_BYTES); @@ -218,15 +224,25 @@ static bool checkCRC(const uint8_t *data, uint32_t size) { /* Function to perform Costas loop */ -float updateCostasLoop(float sample) { +static inline float updateCostasLoop(float sample) { /* Apply gain control */ float filteredSample = Butterworth_applyBandPassFilter(sample, &carrierFilter, &carrierFilterCoefficients); - float agcOutput = Butterworth_applyLowPassFilter(filteredSample > 0 ? filteredSample : -filteredSample, &agcFilter, &agcFilterCoefficients); + if (USE_AGC) { + + float regulatedFilteredSample = filteredSample > 0.0f ? filteredSample : -filteredSample; + + float agcOutput = Butterworth_applyLowPassFilter(regulatedFilteredSample, &agcFilter, &agcFilterCoefficients); + + filteredSample /= MAX(agcOutput, AGC_MINIMUM_AMPLITUDE); - if (agcOutput != 0) filteredSample /= agcOutput; + } else { + + filteredSample /= MANUAL_GAIN_DIVISOR; + + } /* Demodulate input sound */ @@ -258,10 +274,10 @@ float updateCostasLoop(float sample) { inline void AudioMoth_handleMicrophoneInterrupt(int16_t sample) { - configSample = sample; - configSampleReady = true; + configSample = sample; + } /* Functions to handle audio configuration */ @@ -272,28 +288,30 @@ void AudioConfig_enableAudioConfiguration() { AudioMoth_enableMicrophone(CONFIG_GAIN_RANGE, CONFIG_GAIN, CONFIG_CLOCK_DIVIDER, CONFIG_ACQUISITION_CYCLES, CONFIG_OVERSAMPLE_RATE); - AudioMoth_startMicrophoneSamples(CONFIG_SAMPLE_RATE); - - AudioMoth_initialiseMicrophoneInterupts(); + AudioMoth_initialiseMicrophoneInterrupts(); /* Design filters */ - Butterworth_designLowPassFilter(&agcFilterCoefficients, CONFIG_SAMPLE_RATE, SPEED_FACTOR * AGC_FILTER_CUTOFF_FREQUENCY); - Butterworth_designBandPassFilter(&carrierFilterCoefficients, CONFIG_SAMPLE_RATE, CONFIG_CARRIER_FREQUENCY - CARRIER_FILTER_CUTOFF_FREQUENCY, CONFIG_CARRIER_FREQUENCY + CARRIER_FILTER_CUTOFF_FREQUENCY); + if (USE_AGC) Butterworth_designLowPassFilter(&agcFilterCoefficients, CONFIG_SAMPLE_RATE, SPEED_FACTOR * AGC_FILTER_CUTOFF_FREQUENCY); + Biquad_designLowPassFilter(&channelFilterCoefficients, CONFIG_SAMPLE_RATE, SPEED_FACTOR * CHANNEL_FILTER_CUTOFF_FREQUENCY, CHANNEL_FILTER_BANDWIDTH); /* Initialise filters */ - Butterworth_initialise(&agcFilter); - Butterworth_initialise(&carrierFilter); + if (USE_AGC) Butterworth_initialise(&agcFilter); + Biquad_initialise(&channel1Filter); Biquad_initialise(&channel2Filter); + /* Start the microphone samples */ + + AudioMoth_startMicrophoneSamples(CONFIG_SAMPLE_RATE); + } void AudioConfig_disableAudioConfiguration() { @@ -344,7 +362,7 @@ bool AudioConfig_listenForAudioConfigurationTone(uint32_t milliseconds) { /* Check thresholds */ - if ((lastValue > 0 && costasLoopOutput < 0) || (lastValue < 0 && costasLoopOutput > 0)) { + if ((lastValue >= 0 && costasLoopOutput < 0) || (lastValue < 0 && costasLoopOutput >= 0)) { uint32_t period = counter - lastCrossing; @@ -368,20 +386,16 @@ bool AudioConfig_listenForAudioConfigurationTone(uint32_t milliseconds) { } + /* Update counters and status */ + lastValue = costasLoopOutput; + configSampleReady = false; + counter += 1; } - /* Wait for next sample */ - - configSampleReady = false; - - /* Sleep until next interrupt occurs */ - - AudioMoth_sleep(); - } return false; @@ -434,7 +448,7 @@ bool AudioConfig_listenForAudioConfigurationPackets(bool timeout, uint32_t milli /* Check thresholds */ - if ((lastValue > 0 && costasLoopOutput < 0) || (lastValue < 0 && costasLoopOutput > 0)) { + if ((lastValue >= 0 && costasLoopOutput < 0) || (lastValue < 0 && costasLoopOutput >= 0)) { uint32_t period = counter - lastCrossing; @@ -606,20 +620,16 @@ bool AudioConfig_listenForAudioConfigurationPackets(bool timeout, uint32_t milli } + /* Update counters and status */ + lastValue = costasLoopOutput; + configSampleReady = false; + counter += 1; } - /* Wait for next sample */ - - configSampleReady = false; - - /* Sleep until next interrupt occurs */ - - AudioMoth_sleep(); - } return cancel == false; diff --git a/src/main.c b/src/main.c index 053e9b0..38270ec 100644 --- a/src/main.c +++ b/src/main.c @@ -911,7 +911,7 @@ static int16_t secondaryBuffer[MAXIMUM_SAMPLES_IN_DMA_TRANSFER]; /* Firmware version and description */ -static uint8_t firmwareVersion[AM_FIRMWARE_VERSION_LENGTH] = {1, 8, 0}; +static uint8_t firmwareVersion[AM_FIRMWARE_VERSION_LENGTH] = {1, 8, 1}; static uint8_t firmwareDescription[AM_FIRMWARE_DESCRIPTION_LENGTH] = "AudioMoth-Firmware-Basic"; @@ -1031,7 +1031,7 @@ static GPS_fixResult_t setTimeFromGPS(bool enableLED, uint32_t timeout) { } -/* Magenetic switch wait functions */ +/* Magnetic switch wait functions */ static void startWaitingForMagneticSwith() { @@ -2345,7 +2345,7 @@ static AM_recordingState_t makeRecording(uint32_t timeOfNextRecording, uint32_t /* Calculate time correction for sample rate due to file header */ - uint32_t numberOfSamplesInHeader = sizeof(wavHeader) / NUMBER_OF_BYTES_IN_SAMPLE; + uint32_t numberOfSamplesInHeader = sizeof(wavHeader_t) / NUMBER_OF_BYTES_IN_SAMPLE; int32_t sampleRateTimeOffset = ROUNDED_DIV(numberOfSamplesInHeader * MILLISECONDS_IN_SECOND, effectiveSampleRate); @@ -2375,7 +2375,7 @@ static AM_recordingState_t makeRecording(uint32_t timeOfNextRecording, uint32_t /* Calculate updated recording parameters */ - uint32_t maximumNumberOfSeconds = (MAXIMUM_WAV_FILE_SIZE - sizeof(wavHeader)) / NUMBER_OF_BYTES_IN_SAMPLE / effectiveSampleRate; + uint32_t maximumNumberOfSeconds = (MAXIMUM_WAV_FILE_SIZE - sizeof(wavHeader_t)) / NUMBER_OF_BYTES_IN_SAMPLE / effectiveSampleRate; bool fileSizeLimited = (recordDuration > maximumNumberOfSeconds); @@ -2469,11 +2469,11 @@ static AM_recordingState_t makeRecording(uint32_t timeOfNextRecording, uint32_t while (numberOfBlankSamplesToWrite > 0) { - uint32_t numberOfSmples = MIN(numberOfBlankSamplesToWrite, COMPRESSION_BUFFER_SIZE_IN_BYTES / NUMBER_OF_BYTES_IN_SAMPLE); + uint32_t numberOfSamples = MIN(numberOfBlankSamplesToWrite, COMPRESSION_BUFFER_SIZE_IN_BYTES / NUMBER_OF_BYTES_IN_SAMPLE); - FLASH_LED_AND_RETURN_ON_ERROR(AudioMoth_writeToFile(compressionBuffer, NUMBER_OF_BYTES_IN_SAMPLE * numberOfSmples)); + FLASH_LED_AND_RETURN_ON_ERROR(AudioMoth_writeToFile(compressionBuffer, NUMBER_OF_BYTES_IN_SAMPLE * numberOfSamples)); - numberOfBlankSamplesToWrite -= numberOfSmples; + numberOfBlankSamplesToWrite -= numberOfSamples; } @@ -2554,7 +2554,7 @@ static AM_recordingState_t makeRecording(uint32_t timeOfNextRecording, uint32_t FLASH_LED_AND_RETURN_ON_ERROR(AudioMoth_seekInFile(0)); - FLASH_LED_AND_RETURN_ON_ERROR(AudioMoth_writeToFile(&wavHeader, sizeof(wavHeader))); + FLASH_LED_AND_RETURN_ON_ERROR(AudioMoth_writeToFile(&wavHeader, sizeof(wavHeader_t))); /* Close the file */