FIR Filter
Dependencies: CMSIS_DSP_401 mbed
Diff: main.cpp
- Revision:
- 1:a2238b2df415
- Parent:
- 0:5cd703c0576c
--- a/main.cpp Sat May 28 21:26:55 2016 +0000 +++ b/main.cpp Sun May 29 20:16:11 2016 +0000 @@ -1,185 +1,264 @@ +/******************************************************************************* + * main.cpp + * by Jason Shen, James Smith and Luis Sanchez + * + * Acoustic Location System Filtering + * + * This C module implements the DSP filtering of an input signal for the + * STM33F446RE Nucleo board.. The input signal will be passed in through + * on board ADC connected to a transponder that receives accoustic waves + * delivered by three transponders at 3 different frequencies. The coeffecients + * used for the filter are defined in main.h and implement bandpass filters for + * 35kHz, 40kHz and 45kHz with a pass bandwith of 500Hz. + * + * This program will output the time difference of arrival of the three + * varying frequency signals. the default for for output is: + * + * [ A vs B time difference, B vs C time difference, A vs C time difference ] + * + * Currently the algorithm will first FIR filter the data for each of the 3 + * frequencies. Then it will use an in place moving average function to + * smooth the data. Finally, it will run a peak detection function and find the + * peak of each of the 3 filtered signals which will then be placed on an output + * pin to be available for beagle bone on OpenROV. + * + * + * + * + * TODO: + * 1. Test on different location inputs from python script, + * 2. Integrate ADC and filter code + * 3. If current filtering and smoothing is innaccurate develop new algorithm + * 4. Clean up code +*******************************************************************************/ + /* Includes */ -#include <stdio.h> //fprintf, FILE -#include <stdlib.h> // -#include <math.h> //sqrt - -#include "mbed.h" #include "main.h" -//#include "arm_math.h" -//#include "math_helper.h" -#include "float.h" + -//#include "tiny_printf.c" - -#define BLOCK_SIZE (32) - +/* FIR filter variables */ static float firStateF[BLOCK_SIZE + NUM_TAPS - 1]; - unsigned int blockSize = BLOCK_SIZE; unsigned int numBlocks = NUM_SAMPLES/BLOCK_SIZE; -/* Private macro */ - - -/* Private variables */ -//float signalA[NUM_SAMPLES]; -//float signalB[NUM_SAMPLES]; -//float signalC[NUM_SAMPLES]; - -FILE* logFile; - -typedef struct coordinate { - float x; - float y; -} coord; - /* Function Prototypes */ float calculateSoundSpeedInWater(float temp, float salinity, float depth); -void createSignalsFromFile(void); - -void movingAverage(float signal[NUM_SAMPLES], float * averagedSignal[NUM_SAMPLES]); - -int singleThresholdDetection(const float sampleData[NUM_SAMPLES], int startPosition); +int singleThresholdDetection(const float sampleData[], int startPosition); -void getPositionFromSignal( - float signal[NUM_SAMPLES], coord* projCoord, - float velocity, float depth, - float xa, float ya, float za, - float xb, float yb, float zb, - float xc, float yc, float zc); +void filterAndSmooth(float signal[], float filterCoeffs[], int smoothingCoeff, float * filteredSignal); -void filterAndSmooth(float signal[NUM_SAMPLES], float filterCoeffs[NUM_TAPS], int smoothingCoeff, float * filteredSignal); +void movAvg(float signal[]); -void calculateProjectedCoordinates( - coord * projCoord, - float depth, float velocity, - float tsa, float tsb, float tsc, - float xa, float ya, float za, - float xb, float yb, float zb, - float xc, float yc, float zc); - +int findMax(float signal[]); -//------------------------------------ -// Hyperterminal configuration -// 9600 bauds, 8-bit data, no parity -//------------------------------------ - +/*------------------------------------ + * Hyperterminal configuration + * 9600 bauds, 8-bit data, no parity + ************************************/ Serial pc(SERIAL_TX, SERIAL_RX); -DigitalOut myled(LED1); +DigitalOut myled(LED1); //Debug LED int main(void) { - int i = 0; - - /* TODO - Add your application code here */ - //FILE* fp = fopen("log.txt", "w"); - //if(fp == 0) - // pc.printf("NULL\n"); - //fclose(fp); - - //createSignalsFromFile(); - + printf("---------------------------------------------------------------- "); + printf(" "); + printf(" Underwater Acoustic Location System DSP\n"); + printf(" "); + printf("---------------------------------------------------------------- "); + printf(" Running Filter... "); + printf("---------------------------------------------------------------- "); + printf(" Number of Samples: %d\n", NUM_SAMPLES); + printf(" Moving Average window: %d samples\n", MOV_AVG_WIND); + /* - float temp = TEMP; - float depth = DEPTH; - float salinity = SALINITY; - float velocity = calculateSoundSpeedInWater(temp, salinity, depth); - pc.printf("The velocity is %lf", velocity); - - - int firstPeak = singleThresholdDetection(signalA, 0); - - pc.printf("First peak found at position %d\n", firstPeak); - pc.printf("Time of first peak (in ms): %lf", firstPeak / 250.0); */ - - arm_fir_instance_f32 S; + + // Fir instance variables + arm_fir_instance_f32 S1, S2, S3; arm_status status; float32_t *input, *output; + // Fir Coefficients float coeffsA_f32[NUM_TAPS]; + float output_f32[NUM_SAMPLES]; + /* Input is the signal with all 3 frequencies present. */ input = &signalABC[0]; - /* - for(i = 0; i < NUM_TAPS; i++) { - coeffsA_f32[i] = (float) coeffsA[i]; + output = &output_f32[0]; + + /* The array of time differences to place on output pin */ + int toReturn[3]; + + /*************************************************************************** + ****************** Filtering for f = 35kHz (from buoy A) ******************* + ***************************************************************************/ + if(UALS_DEBUG) { + printf("Beginning filtering for f = 35kHz (buoy A)\n"); } - */ + + /* Initialize FIR instance structure */ + arm_fir_init_f32(&S1, NUM_TAPS, (float *) &coeffsA[0], + &firStateF[0], blockSize); - /* Initialize FIR instance structure */ - arm_fir_init_f32(&S, NUM_TAPS, (float *) &coeffsA_f32[0], &firStateF[0], blockSize); + int i = 0; /* FIR Filtering */ for( i = 0; i < numBlocks; i++) { - arm_fir_f32(&S, input + (i * blockSize), output + (i * blockSize), blockSize); + arm_fir_f32(&S1, input + (i * blockSize), + output + (i * blockSize), blockSize); } /* Take the absolute value of the filtered signal */ for(i = 0; i < NUM_SAMPLES; i++ ) { - //printf("Index: %d, Amplitude: %e\n", i, output[i]); if(output[i] < 0) { - //printf("Negative sample!\n"); + output[i] = -1 * output[i]; + } + } + + /* Print before moving average */ + printf("----------Before moving average-------------\n"); + if(UALS_DEBUG) { + for(i = 0; i < NUM_SAMPLES; i++) { + printf("%lf\n", output[i]); + } + } + + float * avgSignal[NUM_SAMPLES]; + // Calculate moving average and do peak detection; + movAvg(output); + + /* Print signal after moving average */ + printf("----------After moving average-------------\n"); + if(UALS_DEBUG) { + for(i = 0; i < NUM_SAMPLES; i++) { + printf("%lf\n", output[i]); + } + } + + /* Find the maximum value of the filtered signal */ + int maxA = findMax(output); + + /*************************************************************************** + ********************* Filtering for f = 40kHz (from buoy B) **************** + ***************************************************************************/ + if(UALS_DEBUG) { + printf("Beginning filtering for f = 40kHz (buoy B)\n"); + } + /* Initialize FIR instance structure */ + arm_fir_init_f32(&S2, NUM_TAPS, (float *) &coeffsB[0], + &firStateF[0], blockSize); + + /* FIR Filtering */ + for( i = 0; i < numBlocks; i++) { + arm_fir_f32(&S2, input + (i * blockSize), + output + (i * blockSize), blockSize); + } + + /* Take the absolute value of the filtered signal */ + for(i = 0; i < NUM_SAMPLES; i++ ) { + if(output[i] < 0) { output[i] = -1 * output[i]; } } - float * avgSignal[NUM_SAMPLES]; + /* Print before moving average */ + if(UALS_DEBUG) { + printf("----------Before moving average-------------\n"); + for(i = 0; i < NUM_SAMPLES; i++) { + printf("%lf\n", output[i]); + } + } + + + /* Perform moving average */ + movAvg(output); + + /* Print signal after moving average */ + if(UALS_DEBUG) { + printf("----------After moving average-------------\n"); + for(i = 0; i < NUM_SAMPLES; i++) { + printf("%lf\n", output[i]); + } + } - //movingAverage(output, avgSignal); + /* Find the maximum value of the filtered signal */ + int maxB = findMax(output); + + + /*************************************************************************** + ******************** Filtering for f = 45kHz (from buoy C) ***************** + ***************************************************************************/ + if(UALS_DEBUG) { + printf("Beginning filtering for f = 45kHz (buoy C)\n"); + } + /* Initialize FIR instance structure */ + arm_fir_init_f32(&S3, NUM_TAPS, (float *) &coeffsC[0], + &firStateF[0], blockSize); - q15_t max = 0; + /* FIR Filtering */ + for( i = 0; i < numBlocks; i++) { + arm_fir_f32(&S3, input + (i * blockSize), + output + (i * blockSize), blockSize); + } - for(i = 0; i < NUM_SAMPLES; i++) { - printf("%lf\n", output[i]); + /* Take the absolute value of the filtered signal */ + for(i = 0; i < NUM_SAMPLES; i++ ) { + if(output[i] < 0) { + output[i] = -1 * output[i]; + } + } + + /* Print before moving average */ + if(UALS_DEBUG) { + printf("----------Before moving average-------------\n"); + for(i = 0; i < NUM_SAMPLES; i++) { + printf("%lf\n", output[i]); + } } - //printf("Max is at %d\n", max); + - /* - for(i = 0; i < 20; i++) { - printf("%d\n", coeffsA[i]); + /* Perform moving average */ + movAvg(output); + + /* Print signal after moving average */ + if(UALS_DEBUG) { + printf("----------After moving average-------------\n"); + for(i = 0; i < NUM_SAMPLES; i++) { + printf("%lf\n", output[i]); + } } - */ + + /* Find the maximum value of the filtered signal */ + int maxC = findMax(output); + + /* The time differences to be returned */ + /* TODO: should we take the absolute value? What does TDOA take in */ + float tdAB = maxB - maxA; + float tdBC = maxB - maxC; + float tdAC = maxC - maxA; + + printf("tdAB = %f\n", tdAB); + printf("tdBC = %f\n", tdBC); + printf("tdAC = %f\n", tdAC); + + toReturn[0] = tdAB; + toReturn[1] = tdBC; + toReturn[2] = tdAC; } -void movingAverage(float signal[NUM_SAMPLES], float ** averagedSignal) { - int i = 0; - - int start = 0; - int finish = 0; - float total = 0; - - for(i = 0; i < NUM_SAMPLES; i++) { - start = i - MOV_AVG_WIND; - finish = i + MOV_AVG_WIND; - - if(start < 0) { - start = 0; - } - if(finish > NUM_SAMPLES) { - finish = NUM_SAMPLES; - } - - total = 0; - for(int j = start; j < finish; i++) { - total += signal[j]; - } - - *averagedSignal[i] = total / (finish - start); - } -} - - /* - * Function: singleThresholdDetection() - * Description: calculates the first occurrence of a value over the threshold - * value and returns it. + * Function Name: singleThresholdDetection() + * Function Declaration: int singleThresholdDetection(const float sampleData[], + int startPosition) + * Function Description: Calculates the first occurrence of a value over the + * threshold value and returns the position. * * Params: * arg1: sampleData - sample data to find position of first peak @@ -188,10 +267,10 @@ * Return Value: position where threshold is first reached * */ -int singleThresholdDetection(const float sampleData[NUM_SAMPLES], int startPosition) +int singleThresholdDetection(const float sampleData[], int startPosition) { int i; - + for(i = startPosition; i < NUM_SAMPLES; i++) { if (sampleData[i] >= DETECT_THRESH) { return i; @@ -201,99 +280,95 @@ return -1; } -/* - * Function: getPositionFromSignal() - * Description: TODO + +/* + * Function Name: movAvg(); + * Function Declaration: void movAvg(float signal[]); + * Function Description: This function takes an input signal and does an in + * place moving average algorithm. The window size is defined by MOV_AVG_WIND + * in main.h. * - * Params: TODO - * - * - * Return Value: none + * This function serves a dual purpose of finding the position of the largest + * peak and returning that position. + * + * Return Value: None * */ - /* -void getPositionFromSignal( - float signal[NUM_SAMPLES], coord* projCoord, - float velocity, float depth, - float xa, float ya, float za, - float xb, float yb, float zb, - float xc, float yc, float zc) -{ - - //TODO uncomment the following lines of code once filtering is working - //TODO can be tuned - //int smoothingCoeff = 20; - - //float extracted1[NUM_SAMPLES]; - //float extracted2[NUM_SAMPLES]; - //float extracted3[NUM_SAMPLES]; - - - //filterAndSmooth(signal, filter1Coeffs, smoothingCoeff, &extracted1); - //filterAndSmooth(signal, filter2Coeffs, smoothingCoeff, &extracted2); - //filterAndSmooth(signal, filter3Coeffs, smoothingCoeff, &extracted3); +void movAvg(float signal[]) { + int i = 0; + + int start = 0; + int finish = 0; + float total = 0; + + // Buffer to hold the most recent samples + float buffer[MOV_AVG_WIND*2]; + + // Go through signal array and calculate moving average + for(i = 0; i < NUM_SAMPLES; i++) { + start = i - MOV_AVG_WIND; + finish = i + MOV_AVG_WIND; + + if(start < 0) { + start = 0; + } - //int tsa = singleThresholdDetection(extracted1, 0); - //int tsb = singleThresholdDetection(extracted2, 0); - //int tsc = singleThresholdDetection(extracted3, 0); - - - int tsa = singleThresholdDetection(signalA, 0); - int tsb = singleThresholdDetection(signalB, 0); - int tsc = singleThresholdDetection(signalC, 0); - - if(tsa != -1 ) + if(finish > NUM_SAMPLES) { + finish = NUM_SAMPLES; + } + + total = 0; + for(int j = start; j < finish; j++) { + total += signal[j]; + } + + if(i > MOV_AVG_WIND*2 - 1) { + signal[i-(MOV_AVG_WIND*2)] = buffer[i % (MOV_AVG_WIND*2)]; + } - calculateProjectedCoordinates(projCoord, depth, velocity, tsa, tsb, tsc, - xa, ya, za, - xb, yb, zb, - xc, yc, zc); -} -*/ - -void filterAndSmooth(float signal[NUM_SAMPLES], float filterCoeffs[NUM_TAPS], int smoothingCoeff, float * filteredSignal) -{ - //Low pass filter - //arm_fir_instance_f32 * firInstance; - - //arm_fir_init_f32(firInstance, NUM_TAPS, - //Moving average - - //return signal - + // Rotating buffer to save the avg + buffer[i%(MOV_AVG_WIND*2)] = total / (finish - start); + + } + for(int i = NUM_SAMPLES-MOV_AVG_WIND*2; i < NUM_SAMPLES; i++) { + signal[i] = buffer[i %(MOV_AVG_WIND*2)]; + } + + if(UALS_DEBUG) { + for(int i = 0; i < NUM_SAMPLES; i++) { + printf("averagedSignal[i] = %f\n", signal[i]); + } + } } -/* - * Function: calculateProjectedCoordinates() - * Description: TODO - * - * Params: TODO - * - * - * Return Value: none +/* + * Function Name: findMax(); + * Function Declaration: int findMax(float signal[]); + * Function Description: This function takes an input signal and returns the + * position of the maximum valued sample. * */ -void calculateProjectedCoordinates( - coord * projCoord, - float depth, float velocity, - float tsa, float tsb, float tsc, - float xa, float ya, float za, - float xb, float yb, float zb, - float xc, float yc, float zc) -{ +int findMax(float signal[]) { + float maxVal = 0.0; + int maxPosition = -1; + int i; - float dsa = velocity * tsa; - float dsb = velocity * tsb; - float dsc = velocity * tsc; + /* Go through each element searching for maximum */ + for(i = 0; i < NUM_SAMPLES; i++) { + if(signal[i] > maxVal) { + /* We've found a new max, replace */ + maxVal = signal[i]; + maxPosition = i; + } + } - float dsaProjected = sqrt(dsa * dsa - depth * depth); - float dsbProjected = sqrt(dsb * dsb - depth * depth); - float dscProjected = sqrt(dsc * dsc - depth * depth); - - float xCoord = (dsaProjected * dsaProjected - dsbProjected * dsbProjected + xb * xb)/(2 * xb); - float yCoord = ((dsaProjected * dsaProjected - dscProjected * dscProjected + xc * xc + yc * yc)/(2 * yc)) - ((xc) / (yc)) * xCoord; - - projCoord->x = xCoord; - projCoord->y = yCoord; + if(maxPosition > 0) { + printf("Max position found at %d\n", maxPosition); + return maxPosition; + } + else { + printf("Error: no max found\n"); + return -1; + } }