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
AcousticController.h
00001 /* 00002 * AcousticController.h 00003 * Author: Joseph DelPreto 00004 */ 00005 00006 //#define acousticControl 00007 00008 #ifdef acousticControl 00009 00010 #ifndef ACOUSTICCONTROL_ACOUSTICCONTROLLER_H_ 00011 #define ACOUSTICCONTROL_ACOUSTICCONTROLLER_H_ 00012 00013 #include "ToneDetector.h" 00014 #include "FishController.h" 00015 #include "mbed.h" 00016 00017 // ===== INPUT/OUTPUT ===== 00018 // NOTE: To be silent (to not use usbSerial object at all), undefine printBufferSummary, streamAcousticControlLog, streamData, and streamSignalLevel 00019 // To stream the log info used in Fiji, just define streamAcousticControlLog - these are not human-readable streams 00020 // To view the data as it's being received/decoded, define streamData (or streamSignalLevel for signal level) - these are human-readable streams 00021 // To view a data summary (ex. number of buffers processed, words received, etc.) define printBufferSummary 00022 #define serialDefaultBaudUSB 921600 // IMPORTANT: must be 921600 when using streaAcousticControlLog (to be fast enough to keep up with data stream) 00023 #define printBufferSummary // print a summary of how many buffers were processed, the last computed tone powers, etc. once the controller is stopped 00024 /* SEE ALSO: streamAcousticControlLog, defined in ToneDetector.h 00025 If defined, will update the following (see end of processTonePowers for how they're packaged): 00026 00027 acousticControlLogToStream: 00028 [0]: goertzel powers f1 00029 [1]: goerztel powers f2 00030 [2]: signal level 00031 [3]: AGC gain 00032 [4]: fish state/events over Serial 00033 -1: erroneously missed a bit 00034 -2: erroneously added a bit 00035 -3: detected an uncorrectable error in the Hamming decoding 00036 -4: fish timeout (reset to neutral) 00037 >0: the data word that was successfully decoded and processed 00038 -10: no event 00039 00040 UPDATE: 00041 00042 acousticControlLogToStream[4] has been deprecated and replaced with streamCurFishStateEventAcoustic and streamCurFishStateAcoustic 00043 streamCurFishStateEventAcoustic can have the following values: 00044 1: erroneously missed a bit 00045 2: erroneously added a bit 00046 3: detected an uncorrectable error in the Hamming decoding 00047 4: fish timeout (reset to neutral) 00048 5: successfully received a word (note streamCurFishState indicates the current fish state) 00049 6: button board yaw left 00050 7: button board yaw right 00051 8: button board faster 00052 9: button board slower 00053 10: button board pitch up 00054 11: button board pitch down 00055 12: button board shutdown pi 00056 13: button board reset mbed 00057 14: button board auto mode 00058 15: button board unknown 00059 */ 00060 00061 //#define artificialPowers // will use tone powers saved in a file rather than actually sampling (expects two tab-separated columns of powers in /local/powers.wp) 00062 //#define singleDataStream // just read a single continuous stream of bits (as opposed to segmenting into words/decoding) 00063 00064 //#define saveData // save data such as received words to an array, then save it to a file at the end - faster than printing continuously but worry about overflow 00065 //#define streamData // stream data to the screen as it's received (controlled independently of saveData) 00066 //#define streamSignalLevel // stream current signal level to the screen 00067 00068 // ===== EXECUTION ===== 00069 #define infiniteLoopAcoustic // if undefined, will stop after loopCount buffers are processed 00070 #define loopCount 20000 // number of buffers to process before terminating the program (if infiniteLoopAcoustic is not defined) 00071 #define fishTimeoutAcoustic // whether to reset the fish to neutral if an acoustic word hasn't been received in a while. Not used with singleDataStream. 00072 #define fishTimeoutAcousticWindow 5000000 // time between good words that cause a timeout (in microseconds) 00073 00074 #define acousticControllerControlFish // whether to start fishController to control the servos and motor 00075 00076 #define useAGC // if undefined, will only set agc (adjustable gain control of the acoustic input board) once at startup 00077 //#define AGCLeds // if defined, will light the mBed LEDs to indicate the chosen agc gain index (whether or not useAGC is on) 00078 #define agcUpdateWindow 10000000 // how often to update the AGC gain (in microseconds) 00079 00080 #define dataRate 20 // data rate in bps. Can be 20, 50, 77, or 100. 20 was used in Fiji. Above 50 may be less reliable. 00081 00082 //#define threshold1 // older algorithm for processing Goertzel buffers (not sure if it still works) 00083 #define threshold2 00084 00085 // ===== PINS ===== 00086 #define agcPin0 p16 00087 #define agcPin1 p17 00088 #define agcPin2 p18 00089 // note lowBatteryVoltagePin is defined in FishController 00090 00091 // ===== Sampling / Thresholding configuration ===== 00092 // 20 bps (5/45 ms tone/silence) 00093 #if dataRate == 20 00094 #define detectWindow 10 // number of buffers to look at when deciding if a tone is present 00095 #define detectThresh 6 // number of 1s that must be present in a detectWindow group of buffer outputs to declare a tone present 00096 #define period 80 // the number of buffers from a rising edge to when we start looking for the next rising edge 00097 #define bitPeriod 100 // only used with saveData: how many buffers it should actually be between rising edges (only used to size the data array) 00098 #define interWordWait 300 // how many buffers of silence to expect between words 00099 #elif dataRate == 50 00100 // 50 bps (5/15 ms tone/silence) 00101 #define detectWindow 10 // number of buffers to look at when deciding if a tone is present 00102 #define detectThresh 6 // number of 1s that must be present in a detectWindow group of buffer outputs to declare a tone present 00103 #define period 20 // the number of buffers from a rising edge to when we start looking for the next rising edge 00104 #define bitPeriod 40 // only used with saveData: how many buffers it should actually be between rising edges (only used to size the data array) 00105 #define interWordWait 300 // how many buffers of silence to expect between words 00106 #elif dataRate == 77 00107 // 77 bps (5/8 ms tone/silence) 00108 #define detectWindow 10 // number of buffers to look at when deciding if a tone is present 00109 #define detectThresh 6 // number of 1s that must be present in a detectWindow group of buffer outputs to declare a tone present 00110 #define period 10 // the number of buffers from a rising edge to when we start looking for the next rising edge 00111 #define bitPeriod 26 // only used with saveData: how many buffers it should actually be between rising edges (only used to size the data array) 00112 #define interWordWait 300 // how many buffers of silence to expect between words 00113 #elif dataRate == 100 00114 // 100 bps (5/5 ms tone/silence) 00115 #define detectWindow 10 // number of buffers to look at when deciding if a tone is present 00116 #define detectThresh 6 // number of 1s that must be present in a detectWindow group of buffer outputs to declare a tone present 00117 #define period 6 // the number of buffers from a rising edge to when we start looking for the next rising edge 00118 #define bitPeriod 20 // only used with saveData: how many buffers it should actually be between rising edges (only used to size the data array) 00119 #define interWordWait 300 // how many buffers of silence to expect between words 00120 #endif 00121 00122 // ===== Macros for extracting state from data words ===== 00123 #define getSelectIndexAcoustic(d) ((d & (1 << 0)) >> 0) 00124 #define getPitchIndexAcoustic(d) ((d & (7 << 1)) >> 1) 00125 #define getYawIndexAcoustic(d) ((d & (7 << 4)) >> 4) 00126 #define getThrustIndexAcoustic(d) ((d & (3 << 7)) >> 7) 00127 #define getFrequencyIndexAcoustic(d) ((d & (3 << 9)) >> 9) 00128 00129 #define getCurStateWordAcoustic (uint16_t)((uint16_t)newSelectButtonIndex + ((uint16_t)newPitchIndex << 1) + ((uint16_t)newYawIndex << 4) + ((uint16_t)newThrustIndex << 7) + ((uint16_t)newFrequencyIndex << 9)); 00130 00131 class AcousticController 00132 { 00133 public: 00134 // Initialization 00135 AcousticController(Serial* usbSerialObject = NULL); // if serial object is null, one will be created 00136 void init(Serial* usbSerialObject = NULL); // if serial object is null, one will be created 00137 // Execution control 00138 void run(); 00139 void stop(); 00140 // Called by toneDetector when new tone powers are computed 00141 // Only public since we needed a dummy non-member function to call it from the static instance to pass a pointer to tonedetector (see comments on toneDetectorCallback) 00142 void processTonePowers(int32_t* newTonePowers, uint32_t signalLevel); 00143 private: 00144 // Control 00145 volatile uint32_t bufferCount; 00146 Timer programTimer; 00147 Serial* usbSerial; 00148 00149 #ifndef singleDataStream 00150 void decodeAcousticWord(volatile bool* data); // Use Hamming code to decode the data word and check for an error 00151 void processAcousticWord(uint16_t word); // Parse the decoded word into the various fish states 00152 #endif 00153 00154 // TODO check what actually needs to be volatile 00155 00156 // Data detection 00157 volatile bool waitingForEnd; // got data, now waiting until next bit transmission is expected (waiting until "period" buffers have elapsed since edge) 00158 volatile uint16_t periodIndex; // how many buffers it's been since the last clock edge 00159 volatile uint8_t fskIndex; // which set of 0/1 frequencies are next expected 00160 00161 #if defined(threshold2) 00162 #define powerHistoryLength 50 // number of buffer results to consider when deciding if a tone is present. should be half of a bit-width 00163 #define powerHistoryDetectWindow 20 // portion of powerHistory to consider as the detection zone (where a peak is expected) 00164 volatile int32_t powerHistory[powerHistoryLength][numTones]; // History of Goertzel results for the last powerHistoryLength buffers 00165 volatile int16_t powerHistoryIndex; // Index into powerHistory (circular buffer) 00166 volatile int16_t powerHistoryDetectIndex; // Marks where in powerHistory to start window for detection; will always be detectWindow elements behind powerHistoryIndex in the circular buffer 00167 volatile int32_t powerHistorySumDetect[numTones]; // Sum of powers stored in powerHistory in the detect window (stand-in for mean) 00168 volatile int32_t powerHistorySumNoDetect[numTones]; // Sum of powers stored in powerHistory outside the detect window (stand-in for mean) 00169 volatile int32_t powerHistoryMaxDetect[numTones]; // Max of powers stored in powerHistory in the detect window 00170 volatile int32_t powerHistoryMaxNoDetect[numTones]; // Max of powers stored in powerHistory outside the detect window 00171 volatile bool readyToThreshold; // Whether powerHistory has been filled at least once 00172 volatile bool tonesPresent[detectWindow][numTones]; // Circular buffer of whether tones were detected in last detectWindow powers 00173 volatile uint8_t detectSums[numTones]; // Rolling sum over last detectWindow tonesPresent results (when > detectWindow/2, declares data bit) 00174 volatile uint8_t detectWindowIndex; 00175 #elif defined(threshold1) 00176 #define powerHistoryLength 50 // number of results to consider when deciding if a tone is present. should be half of a bit-width 00177 volatile uint8_t detectSums[numTones]; // Rolling sum over last detectWindow buffer results (when > detectWindow/2, declares clock/data) 00178 int32_t powerHistory[powerHistoryLength][numTones]; // History of Goertzel results for the last powerHistoryLength buffers 00179 volatile int16_t powerHistoryIndex; // Index into powerHistory (circular buffer) 00180 volatile int16_t powerHistoryDetectIndex; // Marks where in powerHistory to start window for detection; will always be detectWindow elements behind powerHistoryIndex in the circular buffer 00181 int32_t powerHistorySum[numTones]; // Sum of powers stored in powerHistory (stand-in for mean) 00182 int32_t powerHistoryMax[numTones]; // Max of powers stored in powerHistory 00183 volatile bool readyToThreshold; // Whether powerHistory has been filled at least once 00184 #endif 00185 00186 // Segmenting of data into bits/words 00187 #if defined(singleDataStream) && defined(saveData) 00188 volatile bool data[loopCount/(bitPeriod) * (numTones-1) + 50]; // Received data (each clock pulse is associated with numTones-1 bits) // TODO update for multi-hop FSK, but this is fine for one FSK group 00189 volatile uint16_t dataIndex; 00190 #else 00191 #define dataWordLength 16 // bits per word. note that changing this also requires adjusting the decodeAcousticWord algorithm, since it currently assumes Hamming encoding 00192 volatile uint8_t dataBitIndex; // current bit of that word 00193 volatile bool interWord; // whether we are currently in between words (waiting out the long inter-word pause) 00194 #ifdef saveData 00195 volatile bool data[loopCount/(bitPeriod*dataWordLength)][dataWordLength]; // Each element is a word as an array of bits 00196 volatile uint16_t dataWordIndex; // current data word 00197 #else 00198 volatile bool dataWord[dataWordLength]; // an array of bits making up the current word 00199 #endif 00200 #endif 00201 volatile uint16_t lastDataWord; // not used anymore, but still updated 00202 00203 // Adjustable gain control (AGC) 00204 volatile uint8_t currentGainIndex; // the current index into agcGains 00205 volatile int32_t signalLevelSum; // the running sum of signal level readings 00206 volatile uint16_t signalLevelBufferIndex; // index into signal level buffer // note we don't have a buffer anymore, but use this to know when to reset the sum 00207 00208 DigitalOut* gain0; 00209 DigitalOut* gain1; 00210 DigitalOut* gain2; 00211 DigitalOut* agc[3]; // facilitates loops and whatnot 00212 #ifdef AGCLeds 00213 #undef debugLEDs 00214 DigitalOut* agcLED0; 00215 DigitalOut* agcLED1; 00216 DigitalOut* agcLED2; 00217 DigitalOut* agcLEDs[3]; 00218 #endif 00219 00220 // Fish reset timeout 00221 volatile uint16_t timeSinceGoodWord; // measured in buffers 00222 00223 // Low battery monitor 00224 DigitalIn* lowBatteryVoltageInput; 00225 void lowBatteryCallback(); 00226 00227 // Testing/debugging 00228 #ifdef saveData 00229 LocalFileSystem local("local"); 00230 FILE* foutDataWords; 00231 #endif 00232 #ifdef artificialPowers 00233 #if (!defined recordStreaming || (!defined recordOutput && !defined recordSamples)) && !defined saveData 00234 LocalFileSystem local("local"); 00235 #endif 00236 FILE* finPowers; 00237 int32_t nextPowers[numTones]; 00238 #endif 00239 volatile uint16_t streamCurFishStateAcoustic; // the current state of the fish 00240 volatile uint16_t streamCurFishStateEventAcoustic; // events such as decoding words, errors, etc. 00241 00242 // Fish state extracted from acoustic data word (index into lookup tables defined above) 00243 volatile uint8_t newSelectButtonIndex; 00244 volatile uint8_t newPitchIndex; 00245 volatile uint8_t newYawIndex; 00246 volatile uint8_t newThrustIndex; 00247 volatile uint8_t newFrequencyIndex; 00248 }; 00249 00250 00251 // Create a static instance of AcousticController to be used by anyone doing detection 00252 extern AcousticController acousticController; 00253 00254 #endif 00255 00256 #endif // #ifdef acousticControl
Generated on Wed Jul 13 2022 13:43:34 by
