Important changes to repositories hosted on mbed.com
Mbed hosted mercurial repositories are deprecated and are due to be permanently deleted in July 2026.
To keep a copy of this software download the repository Zip archive or clone locally using Mercurial.
It is also possible to export all your personal repositories from the account settings page.
Dependencies: mbed ESC mbed MODDMA
ToneDetector.h
00001 /** 00002 * Author: Joseph DelPreto 00003 * A class for sampling a signal and detecting whether certain frequencies are present 00004 * Implements the Goertzel algorithm for tone detection 00005 * Uses fixed-point arithmetic to a > 10x speedup over a floating-point implementation 00006 * Uses Q15 number format 00007 * 00008 * Can easily configure the sampling frequency, the tones to detect, and the length of the buffer window 00009 * Can set a callback function to be called at the end of each buffer processing to see the relative powers of each target tone 00010 * Make sure the callback function execution time, plus the time to process a buffer of samples, takes less time than it takes to acquire the buffer! 00011 * You can check how long it takes to process a buffer of samples by enabling "timeProcess" below then using initProcessTimer() and getProcessTimes() 00012 * 00013 * Debugging options such as LEDs to indicate status are also available 00014 * Can also choose to time each processing stage to ensure it is not taking longer the time needed to acquire the buffer of samples 00015 * Can also record samples and write them to a file (max 1000 will be recorded) 00016 * LED pattern if enabled: 00017 * LED1 indicates tone detection in progress 00018 * LED2 indicates at least two buffers have been filled 00019 * LED3 turns on when processing starts and off when it finishes (so lower duty cycle is better) 00020 * LED4 turns on when tone detection is stopped (and then other LEDs turn off) 00021 * Debug pins will go high/low in same pattern as described above for LEDs, but using pins p5-p8 00022 * 00023 * Test mode can be enabled, in which case samples can be artificially generated instead of using the ADC 00024 * 00025 * Currently only set up for one instance of ToneDetector to be in operation 00026 * Use the object toneDetector, declared in this file, for all of your tone detecting needs! 00027 * 00028 */ 00029 00030 #define acousticControl 00031 00032 #ifdef acousticControl 00033 00034 #ifndef TONE_DETECTOR_H 00035 #define TONE_DETECTOR_H 00036 00037 //#define streamAcousticControlLog // for every buffer, streams goertzel powers f1, goerztel powers f2, signal level, gain, fish state/events over Serial 00038 00039 // Configuration 00040 #define sampleInterval 4 // us between samples 00041 #define sampleWindow 125 // number of samples in a Goertzel buffer 00042 #define numTones 2 00043 #define numFSKGroups 1 00044 static const double targetTones[numTones] = {36000, 30000}; // Tones to detect (in Hz): first tone is a 0 bit second is a 1 bit 00045 00046 // Test / Debugging options 00047 //#define artificialSamplesMode // if this is defined, should define either sampleFilename OR sumSampleFrequencies 00048 //#define sampleFilename "/local/2tone11.txt" 00049 //#define sumSampleFrequencies {10000,30000} // will be used to initialize float[] array. Test signal will be summation of cosines with these frequencies (in Hz) 00050 00051 #define debugLEDs 00052 #define debugPins 00053 #define recordStreaming // print to COM each sample/output (save everything), as opposed to only write last few hundred to a file (but faster since don't write to file while processing) 00054 // note that either recordOutput or recordSamples must be undefined to actually record anything 00055 //#define recordOutput // save tone powers - will either stream to COM or save the last numSavedTonePowers powers to a file (based on recordStreaming) 00056 //#define recordSamples // save samples - will either stream to COM or save the last numSavedSamples samples to a file (based on recordStreaming) 00057 00058 00059 #if defined(recordSamples) && !defined(recordStreaming) 00060 #define numSavedSamples 1000 00061 #endif 00062 #if defined(recordOutput) && !defined(recordStreaming) 00063 #define numSavedTonePowers 250 00064 #endif 00065 00066 // Will use fixed-point arithmetic for speed 00067 // numbers will be int32_t with 10 bits as fractional portion 00068 // note: this means the 12 bits from the ADC can be used directly, implicitly scaling them to be floats in range [0,4] 00069 // (so if you want to change the Q format, make sure to shift the samples accordingly in the processSamples() method) 00070 #define toFixedPoint(floatNum) ((int32_t)((float)(floatNum) * 1024.0f)) 00071 #define toFloat(fixedPointNum) ((float)(fixedPointNum)/1024.0f) 00072 #define fixedPointMultiply(a,b) ((int32_t)(((int64_t)a * (int64_t)b) >> 10)) 00073 00074 // Constants 00075 #define tonePowersWindow 32 // change to 5 for threshold1 00076 00077 // Include files 00078 #include <stdint.h> // for types like int32_t 00079 #include <math.h> // for cos // TODO remove this once samples are real samples 00080 #define PI 3.1415926 // not included with math.h for some reason 00081 #include "mbed.h" // for the ticker 00082 #ifndef artificialSamplesMode 00083 #include "MODDMA.h" // DMA for reading the ADC 00084 #endif 00085 00086 // Debugging 00087 #ifdef debugLEDs 00088 static DigitalOut led1(LED1); 00089 static DigitalOut led2(LED2); 00090 static DigitalOut led3(LED3); 00091 static DigitalOut led4(LED4); 00092 #endif 00093 #ifdef debugPins 00094 static DigitalOut debugPin1(p5); 00095 static DigitalOut debugPin2(p6); 00096 static DigitalOut debugPin3(p7); 00097 static DigitalOut debugPin4(p8); 00098 #endif 00099 00100 // Define the ToneDetector! 00101 class ToneDetector 00102 { 00103 public: 00104 // Initialization 00105 ToneDetector(); 00106 void init(); 00107 void setCallback(void (*myFunction)(int32_t* tonePowers, uint32_t signalLevel)); 00108 // Execution Control 00109 virtual void run(); // main loop, runs forever or until stop() is called 00110 virtual void stop(); // stop the main loop 00111 void finish(); // write final output to files and whatnot 00112 volatile bool terminated; // indicates main loop should stop (may be set by error callback or by stop()) 00113 // Sampling / Processing (these are public to allow DMA callbacks to access them) 00114 volatile bool fillingBuffer0; // Whether sampling is currently writing to buffer 0 or buffer 1 00115 volatile bool transferComplete; // Signals that samplesProcessing is ready to be processed 00116 uint32_t sampleBuffer0[sampleWindow]; // Buffer of samples used by one DMA operation 00117 uint32_t sampleBuffer1[sampleWindow]; // Buffer of samples used by second DMA operation 00118 volatile uint32_t* samplesWriting; // Pointer to the buffer to which we should write (alternates between buffer0 and buffer1) 00119 volatile uint32_t* samplesProcessing; // Pointer to the buffer which we should process (alternates between buffer0 and buffer1) 00120 int32_t* getTonePowers(); // Get the most recent tone powers 00121 #ifndef artificialSamplesMode 00122 MODDMA dma; // DMA controller 00123 #endif 00124 00125 private: 00126 // Initialization 00127 bool readyToBegin; // Whether sample window, sample interval, and tones have all been specified 00128 #ifndef artificialSamplesMode 00129 MODDMA_Config *dmaConf; // Overall DMA configuration 00130 MODDMA_LLI *lli[2]; // Linked List Items for chaining DMA operations (will have one for each ADC buffer) 00131 void startDMA(); 00132 void startADC(); 00133 #endif 00134 // Sampling 00135 // Goertzel Processing (arrays will have an element per desired tone) 00136 // Tone detecting 00137 int32_t goertzelCoefficients[numTones]; // Pre-computed coefficients based on target tones 00138 int32_t tonePowersSum[numTones]; // Result of Goertzel algorithm (summed over tonePowersWindow to smooth results) 00139 int32_t tonePowers[numTones][tonePowersWindow]; // For each tone, store the most recent tonePowersWindow powers (in circular buffers) 00140 uint8_t tonePowersWindowIndex; // Index into the circular buffers of tonePowers 00141 bool readyToThreshold; // Whether thresholding is ready, or first buffer is still being filled 00142 void (*callbackFunction)(int32_t* tonePowers, uint32_t signalLevel); // Called when new powers are computed 00143 void processSamples(); // Process a buffer of samples to detect tones 00144 00145 // Testing / Debugging 00146 #ifdef artificialSamplesMode 00147 Ticker sampleTicker; // Triggers a sample to be read from the pre-filled array 00148 void initTestModeSamples(); // Creates the samples, either from a file or by summing tones 00149 void tickerCallback(); // Called each time a sample is read 00150 uint32_t* testSamples; // Array of pre-stored sample values to use 00151 uint16_t numTestSamples; // Length of the testSamples array (need not be same as buffer length) 00152 volatile uint16_t testSampleIndex; // Current index into testSamples 00153 volatile uint16_t sampleIndex; // Index into current sample buffer 00154 #endif 00155 #ifndef recordStreaming 00156 #ifdef recordSamples 00157 uint16_t savedSamplesIndex; 00158 uint32_t savedSamples[numSavedSamples]; 00159 #endif 00160 #ifdef recordOutput 00161 uint16_t savedTonePowersIndex; 00162 int32_t savedTonePowers[numSavedTonePowers][numTones]; 00163 #endif 00164 #endif 00165 }; 00166 00167 // DMA IRQ callback methods 00168 void TC0_callback(); // Callback for when DMA channel 0 has filled a buffer 00169 void ERR0_callback(); // Error on dma channel 0 00170 00171 // Create a static instance of ToneDetector to be used by anyone doing detection 00172 // This allows the ticker callback to be a member function 00173 extern ToneDetector toneDetector; 00174 #ifdef streamAcousticControlLog 00175 extern int32_t acousticControlLogToStream[5]; // goertzel powers f1, goerztel powers f2, signal level, gain, events (events is deprecated) 00176 #endif 00177 00178 #endif // ifndef TONE_DETECTOR_H 00179 00180 #endif // #ifdef acousticControl 00181 00182
Generated on Wed Jul 13 2022 13:43:34 by
