Juan Salazar / robotic_fish_7

Dependencies:   mbed ESC mbed MODDMA

Embed: (wiki syntax)

« Back to documentation index

Show/hide line numbers ToneDetector.h Source File

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