napoleon leoni / Mbed 2 deprecated DirectionalMicrophone

Dependencies:   C12832_lcd crossCorrelation mbed-rtos mbed

Committer:
nleoni
Date:
Wed Mar 26 05:44:21 2014 +0000
Revision:
0:025037057a21
MBED RTOS Microphone array processing; Currently operating with two microphones; Correlataion calculation not yet fully functional

Who changed what in which revision?

UserRevisionLine numberNew contents of line
nleoni 0:025037057a21 1 #include "mbed.h"
nleoni 0:025037057a21 2 #include "rtos.h"
nleoni 0:025037057a21 3 #include "C12832_lcd.h"
nleoni 0:025037057a21 4 #include "stdint.h"
nleoni 0:025037057a21 5 #include <string.h>
nleoni 0:025037057a21 6 #include <math.h>
nleoni 0:025037057a21 7 #include <stdio.h>
nleoni 0:025037057a21 8
nleoni 0:025037057a21 9 #define DEBUG
nleoni 0:025037057a21 10
nleoni 0:025037057a21 11
nleoni 0:025037057a21 12 #define SAMPLINGPERIOD 60 //us, 20 us would correspond to a 50 kHz sampling rate
nleoni 0:025037057a21 13 #define EVENTLENGTH 1000//number of sample to collect a full event
nleoni 0:025037057a21 14 #define EVENTLOGSIZE 20 //Events are stored in this log, eventually read and cleared
nleoni 0:025037057a21 15 #define TRIGGERHIGH 0xC000
nleoni 0:025037057a21 16 #define TRIGGERLOW 0x4000
nleoni 0:025037057a21 17 #define PRETRIGSAMPLES 20 //samples to keep prior to trigger time.
nleoni 0:025037057a21 18 #define SAMPLEDELAY 20
nleoni 0:025037057a21 19 #define BUFFER 20 //serial terminal input command buffer
nleoni 0:025037057a21 20
nleoni 0:025037057a21 21
nleoni 0:025037057a21 22 //define signals
nleoni 0:025037057a21 23 #define COMPARESIGNAL 0x01//use this signal to signal the onDAQ thread to check for a trigger.
nleoni 0:025037057a21 24 #define PROCESSINGSIGNAL 0x10 //use this signal to start the processing thread
nleoni 0:025037057a21 25
nleoni 0:025037057a21 26 //There will be a thread checking on error conditions
nleoni 0:025037057a21 27 //this Thread will print to a terminal causes of error conditions and the exit
nleoni 0:025037057a21 28 //the program
nleoni 0:025037057a21 29 //signals related to error conditions
nleoni 0:025037057a21 30 #define NULLPOINTER 0xE1
nleoni 0:025037057a21 31
nleoni 0:025037057a21 32
nleoni 0:025037057a21 33 AnalogIn FLMic(p20),FRMic(p19);
nleoni 0:025037057a21 34 AnalogOut FLMout(p18);
nleoni 0:025037057a21 35 DigitalOut ISRcheck(p26);
nleoni 0:025037057a21 36 DigitalOut circularCheck(p24);
nleoni 0:025037057a21 37 LocalFileSystem local("local"); //use the MBED file system to store debug files
nleoni 0:025037057a21 38
nleoni 0:025037057a21 39 uint16_t FLMbuffer[EVENTLENGTH],FRMbuffer[EVENTLENGTH],flmLastValue,frmLastValue;
nleoni 0:025037057a21 40 float eventLog[2][EVENTLOGSIZE]; //down the line make an event class, and have an array of events.
nleoni 0:025037057a21 41 uint16_t *ptrflm,*ptrflmStart,*ptrfrm,*ptrfrmStart; //These pointers are used to implement a dual circular buffer architecture
nleoni 0:025037057a21 42 int indexMax,delayMax;
nleoni 0:025037057a21 43 int Max;
nleoni 0:025037057a21 44
nleoni 0:025037057a21 45 Ticker audioDAQ;
nleoni 0:025037057a21 46
nleoni 0:025037057a21 47 void acquireISR(void);//ISR routine for acquiring the microphone audio data
nleoni 0:025037057a21 48 Thread *onDAQTrigger;
nleoni 0:025037057a21 49 Thread *processingCrossCorr;
nleoni 0:025037057a21 50 Serial pc(USBTX, USBRX); //serial communication terminal
nleoni 0:025037057a21 51
nleoni 0:025037057a21 52 //define DirMic state type
nleoni 0:025037057a21 53 typedef enum {
nleoni 0:025037057a21 54 ACQUIRING,
nleoni 0:025037057a21 55 TRIGGERED,
nleoni 0:025037057a21 56 PROCESSING,
nleoni 0:025037057a21 57 IDLE //state to enter for debugginr purposes
nleoni 0:025037057a21 58 } DicMicStateType;
nleoni 0:025037057a21 59
nleoni 0:025037057a21 60 DicMicStateType dicMicState;
nleoni 0:025037057a21 61
nleoni 0:025037057a21 62 /******************************************************************
nleoni 0:025037057a21 63 *
nleoni 0:025037057a21 64 *This
nleoni 0:025037057a21 65 *
nleoni 0:025037057a21 66 *******************************************************************/
nleoni 0:025037057a21 67 void readTerminal(void const *args){
nleoni 0:025037057a21 68 int tempLFM,tempRFM,i;
nleoni 0:025037057a21 69 char buffer[BUFFER];
nleoni 0:025037057a21 70 int filecounter;
nleoni 0:025037057a21 71 char *ptrChar;
nleoni 0:025037057a21 72 ptrChar=buffer;
nleoni 0:025037057a21 73 FILE *fp;
nleoni 0:025037057a21 74 char filename[16],outputstr[16];
nleoni 0:025037057a21 75 //Test pointers
nleoni 0:025037057a21 76 uint16_t testbuffer[10];
nleoni 0:025037057a21 77 pc.printf(">Enter a command: (a..arm acquisition; t..trigger acquisition; s..state; r..results)\n>");
nleoni 0:025037057a21 78 filecounter=0;
nleoni 0:025037057a21 79 while(1){
nleoni 0:025037057a21 80 //Note the choice of using getc instead of scanf to read the fortune cookie,
nleoni 0:025037057a21 81 //this is a non-blocking call and allows the rest of our threads to continue operating
nleoni 0:025037057a21 82 //only when a new character is typed this thread executes its body otherwise
nleoni 0:025037057a21 83 //it immediately yields to other threads.
nleoni 0:025037057a21 84 if( pc.readable() ){
nleoni 0:025037057a21 85 *ptrChar=pc.getc();
nleoni 0:025037057a21 86 pc.putc(*ptrChar);
nleoni 0:025037057a21 87 if((*ptrChar=='\n') || ((ptrChar-buffer)>=(BUFFER-1)) ){
nleoni 0:025037057a21 88 if((ptrChar-buffer)>=(BUFFER-1)) *++ptrChar='\n';
nleoni 0:025037057a21 89 *ptrChar='\0';
nleoni 0:025037057a21 90 //Check the entered command
nleoni 0:025037057a21 91 switch(buffer[0]){
nleoni 0:025037057a21 92 case 'a': //arm command, to be used after a trigger event
nleoni 0:025037057a21 93 dicMicState=ACQUIRING;
nleoni 0:025037057a21 94 audioDAQ.attach_us(&acquireISR,200);
nleoni 0:025037057a21 95 #ifdef DEBUG
nleoni 0:025037057a21 96 pc.printf("State is %i\n",dicMicState);
nleoni 0:025037057a21 97 #endif
nleoni 0:025037057a21 98 break;
nleoni 0:025037057a21 99 case 's': //check current state command
nleoni 0:025037057a21 100 pc.printf("State is %i\n>",dicMicState);
nleoni 0:025037057a21 101 break;
nleoni 0:025037057a21 102 case 'r': //check current state command
nleoni 0:025037057a21 103 pc.printf("Last Correlation results: delay=%d\n>",delayMax);
nleoni 0:025037057a21 104 break;
nleoni 0:025037057a21 105 case 'f': //pointer test command
nleoni 0:025037057a21 106 fp=fopen("/local/out.txt", "w");
nleoni 0:025037057a21 107 fprintf(fp, "Hello World!");
nleoni 0:025037057a21 108 fclose(fp);
nleoni 0:025037057a21 109 break;
nleoni 0:025037057a21 110 case 'o': //output file
nleoni 0:025037057a21 111 filecounter++;
nleoni 0:025037057a21 112 sprintf(filename,"/local/data%d.txt",filecounter);
nleoni 0:025037057a21 113 pc.printf("Data file:%s\n>",filename);
nleoni 0:025037057a21 114 fp=fopen(filename, "w"); // Open filename on the local file system for writing
nleoni 0:025037057a21 115 if(fp!=NULL){
nleoni 0:025037057a21 116 for(i=0;i<EVENTLENGTH;i++){
nleoni 0:025037057a21 117 tempLFM=(int)FLMbuffer[i]-0x8000;
nleoni 0:025037057a21 118 tempRFM=(int)FRMbuffer[i]-0x8000;
nleoni 0:025037057a21 119 sprintf(outputstr,"%d,%d%c",tempLFM,tempRFM,13);
nleoni 0:025037057a21 120 pc.printf("%s",outputstr);
nleoni 0:025037057a21 121 fprintf(fp,outputstr);
nleoni 0:025037057a21 122 }//for i loop
nleoni 0:025037057a21 123 fclose(fp);
nleoni 0:025037057a21 124 } else {
nleoni 0:025037057a21 125 pc.printf("Error Opening File\n>");
nleoni 0:025037057a21 126 }//if fp!=null
nleoni 0:025037057a21 127
nleoni 0:025037057a21 128 }//end of switch
nleoni 0:025037057a21 129 pc.printf(">Enter a command: (a..arm acquisition; t..trigger acquisition)\n>");
nleoni 0:025037057a21 130 ptrChar=buffer;
nleoni 0:025037057a21 131 } else {
nleoni 0:025037057a21 132 ptrChar++;
nleoni 0:025037057a21 133 }//if ptrchar... check for buffer overflow
nleoni 0:025037057a21 134 }//if pc readable
nleoni 0:025037057a21 135 //A 100 ms wait seems like reasonable delay which allows operation of the remaining threads.
nleoni 0:025037057a21 136 Thread::wait(100);
nleoni 0:025037057a21 137 }//while(1)
nleoni 0:025037057a21 138 }//thread function
nleoni 0:025037057a21 139
nleoni 0:025037057a21 140 //*****************************************************************************************
nleoni 0:025037057a21 141 //Comparison thread
nleoni 0:025037057a21 142 //This thread is called with a signal from the timer interrupt
nleoni 0:025037057a21 143 //it checks whether a trigger level is exceeded and if so chanegs the state
nleoni 0:025037057a21 144 //to storage
nleoni 0:025037057a21 145 void onDAQ(void const *args){
nleoni 0:025037057a21 146 int sampleCounter=0;
nleoni 0:025037057a21 147 while(1){
nleoni 0:025037057a21 148 Thread::signal_wait(COMPARESIGNAL);
nleoni 0:025037057a21 149 //Here we check if signal exceeded trigger, currently only triggering on one mic
nleoni 0:025037057a21 150 switch(dicMicState){
nleoni 0:025037057a21 151 case ACQUIRING:
nleoni 0:025037057a21 152 if( ( (flmLastValue) > TRIGGERHIGH ) || ( (flmLastValue) < TRIGGERLOW ) ){//signal exceeded trigger
nleoni 0:025037057a21 153
nleoni 0:025037057a21 154 dicMicState=TRIGGERED;
nleoni 0:025037057a21 155 #ifdef DEBUG
nleoni 0:025037057a21 156 pc.printf("State is %i\n>",dicMicState);
nleoni 0:025037057a21 157 #endif
nleoni 0:025037057a21 158 }
nleoni 0:025037057a21 159 sampleCounter=0;
nleoni 0:025037057a21 160 break;
nleoni 0:025037057a21 161 case TRIGGERED:
nleoni 0:025037057a21 162 if(sampleCounter==0) pc.printf("Entered countdown trigger phase\n>");
nleoni 0:025037057a21 163 sampleCounter++;
nleoni 0:025037057a21 164 if(sampleCounter>(EVENTLENGTH-PRETRIGSAMPLES)){
nleoni 0:025037057a21 165 //if(sampleCounter>100){
nleoni 0:025037057a21 166 dicMicState=PROCESSING; //switching states should be done prior to detaching the interrup...
nleoni 0:025037057a21 167 #ifdef DEBUG
nleoni 0:025037057a21 168 pc.printf("State is %i\n>",dicMicState);
nleoni 0:025037057a21 169 Thread::wait(10);
nleoni 0:025037057a21 170 #endif
nleoni 0:025037057a21 171 processingCrossCorr->signal_set(PROCESSINGSIGNAL);
nleoni 0:025037057a21 172 audioDAQ.detach();//detach interrupt, this allows gathering data after the trigger yet leaving PRETRIGSAMPLES before trigger time
nleoni 0:025037057a21 173 }
nleoni 0:025037057a21 174 break;
nleoni 0:025037057a21 175 }
nleoni 0:025037057a21 176 }
nleoni 0:025037057a21 177 }
nleoni 0:025037057a21 178
nleoni 0:025037057a21 179
nleoni 0:025037057a21 180 //Processing thread
nleoni 0:025037057a21 181 void crossCorrelationThread(void const *args){
nleoni 0:025037057a21 182 int i,j,k,ndelays,delay;
nleoni 0:025037057a21 183
nleoni 0:025037057a21 184 ndelays=2*SAMPLEDELAY+1;
nleoni 0:025037057a21 185 int correlationArray[ndelays],tempLFM,tempRFM;
nleoni 0:025037057a21 186 //This thread waits for the processing signal and then perform one correlation calculation
nleoni 0:025037057a21 187 //This very simple cross correlation will for the time being have no Thread::wait....as it runs alone
nleoni 0:025037057a21 188 while(1){
nleoni 0:025037057a21 189 Thread::signal_wait(PROCESSINGSIGNAL);
nleoni 0:025037057a21 190 Max=0; //Store max computed value of correlation
nleoni 0:025037057a21 191 indexMax=0;
nleoni 0:025037057a21 192 delayMax=2*SAMPLEDELAY;//safe value to know if it did not run
nleoni 0:025037057a21 193 for(j=0;j<ndelays;j++){
nleoni 0:025037057a21 194 correlationArray[j]=0;
nleoni 0:025037057a21 195 delay=-SAMPLEDELAY+j;
nleoni 0:025037057a21 196 for(i=0;i<EVENTLENGTH;i++){
nleoni 0:025037057a21 197 //compute k
nleoni 0:025037057a21 198 k=i+delay;
nleoni 0:025037057a21 199 if(k<0) k=EVENTLENGTH+k;
nleoni 0:025037057a21 200 if(k>(EVENTLENGTH-1)) k=k-EVENTLENGTH;
nleoni 0:025037057a21 201 tempLFM=(int)FLMbuffer[i]-0x8000;
nleoni 0:025037057a21 202 tempRFM=(int)FRMbuffer[k]-0x8000;
nleoni 0:025037057a21 203 correlationArray[j]+=tempLFM*tempRFM;
nleoni 0:025037057a21 204 } //end of for i
nleoni 0:025037057a21 205 if(correlationArray[j]>Max){
nleoni 0:025037057a21 206 Max=correlationArray[j];
nleoni 0:025037057a21 207 indexMax=j;
nleoni 0:025037057a21 208 delayMax=delay;
nleoni 0:025037057a21 209 }
nleoni 0:025037057a21 210 #ifdef DEBUG//debugging printout of calculated correlation values
nleoni 0:025037057a21 211 pc.printf("Correlation[%i]=%.0f\n>",j,(double)correlationArray[j]);
nleoni 0:025037057a21 212 pc.printf("Max=%.0f\n>",(double)Max);
nleoni 0:025037057a21 213 pc.printf("delayMax=%.0f\n>",(double)delayMax);
nleoni 0:025037057a21 214 #endif
nleoni 0:025037057a21 215 }//end of for j loop
nleoni 0:025037057a21 216 pc.printf("Correlation results: delay=%i\n>",delayMax);
nleoni 0:025037057a21 217 #ifdef DEBUG
nleoni 0:025037057a21 218 dicMicState=IDLE;//processing is done set to idle until manually armed
nleoni 0:025037057a21 219 #else
nleoni 0:025037057a21 220 dicMicState=ACQUIRING; //the systems goes back to aqcuiring after finished processing
nleoni 0:025037057a21 221 audioDAQ.attach_us(&acquireISR,SAMPLINGPERIOD);
nleoni 0:025037057a21 222 #endif
nleoni 0:025037057a21 223 }//end of while loop for thread
nleoni 0:025037057a21 224 }
nleoni 0:025037057a21 225
nleoni 0:025037057a21 226
nleoni 0:025037057a21 227 int main() {
nleoni 0:025037057a21 228 pc.printf("Directional Microphone\n");
nleoni 0:025037057a21 229 audioDAQ.attach_us(&acquireISR,SAMPLINGPERIOD);
nleoni 0:025037057a21 230 ptrflm=FLMbuffer;
nleoni 0:025037057a21 231 ptrfrm=FRMbuffer;
nleoni 0:025037057a21 232 dicMicState=IDLE;
nleoni 0:025037057a21 233 #ifdef DEBUG
nleoni 0:025037057a21 234 pc.printf("State is %i\n",dicMicState);
nleoni 0:025037057a21 235 #endif
nleoni 0:025037057a21 236 Thread thread(onDAQ);
nleoni 0:025037057a21 237 onDAQTrigger=&thread;
nleoni 0:025037057a21 238 Thread thread2(crossCorrelationThread);
nleoni 0:025037057a21 239 processingCrossCorr=&thread2;
nleoni 0:025037057a21 240 Thread thread3(readTerminal);
nleoni 0:025037057a21 241
nleoni 0:025037057a21 242 while(1) {
nleoni 0:025037057a21 243
nleoni 0:025037057a21 244 }
nleoni 0:025037057a21 245 }
nleoni 0:025037057a21 246
nleoni 0:025037057a21 247 void acquireISR(void){
nleoni 0:025037057a21 248 if(dicMicState==ACQUIRING || dicMicState==TRIGGERED ){
nleoni 0:025037057a21 249 #ifdef DEBUG
nleoni 0:025037057a21 250 ISRcheck=1;
nleoni 0:025037057a21 251 #endif
nleoni 0:025037057a21 252 if(ptrflm && ptrfrm){//check if pointer not null
nleoni 0:025037057a21 253 //Note that two calls to read_u16 take overall 50 us!!!
nleoni 0:025037057a21 254 *ptrflm=FLMic.read_u16();
nleoni 0:025037057a21 255 flmLastValue=*ptrflm;
nleoni 0:025037057a21 256 #ifdef DEBUG
nleoni 0:025037057a21 257 FLMout.write_u16(*ptrflm);
nleoni 0:025037057a21 258 #endif
nleoni 0:025037057a21 259 *ptrfrm=FRMic.read_u16();
nleoni 0:025037057a21 260 frmLastValue=*ptrfrm;
nleoni 0:025037057a21 261 if( ((ptrflm-FLMbuffer)) >= (EVENTLENGTH-1) ){
nleoni 0:025037057a21 262 ptrflm=FLMbuffer;//here we should wrap the pointer around the eventlength
nleoni 0:025037057a21 263 ptrfrm=FRMbuffer;
nleoni 0:025037057a21 264 #ifdef DEBUG//Confirm that pointer wraps to beginning of array
nleoni 0:025037057a21 265 //Test passed!
nleoni 0:025037057a21 266 circularCheck=!circularCheck;
nleoni 0:025037057a21 267 #endif
nleoni 0:025037057a21 268 } else {
nleoni 0:025037057a21 269 ptrflm++;
nleoni 0:025037057a21 270 ptrfrm++;
nleoni 0:025037057a21 271 }
nleoni 0:025037057a21 272 } else {
nleoni 0:025037057a21 273 onDAQTrigger->signal_set(NULLPOINTER);
nleoni 0:025037057a21 274 exit(1);
nleoni 0:025037057a21 275 }
nleoni 0:025037057a21 276 onDAQTrigger->signal_set(COMPARESIGNAL);
nleoni 0:025037057a21 277 #ifdef DEBUG
nleoni 0:025037057a21 278 ISRcheck=0;
nleoni 0:025037057a21 279 #endif
nleoni 0:025037057a21 280 }
nleoni 0:025037057a21 281 }