// LPF.c // Runs on any microcontroller // implements seven FIR low-pass filters // Jonathan Valvano // January 15, 2020 /* This example accompanies the books "Embedded Systems: Introduction to ARM Cortex M Microcontrollers", ISBN: 978-1469998749, Jonathan Valvano, copyright (c) 2020 "Embedded Systems: Real Time Interfacing to ARM Cortex M Microcontrollers", ISBN: 978-1463590154, Jonathan Valvano, copyright (c) 2020 "Embedded Systems: Real-Time Operating Systems for ARM Cortex-M Microcontrollers", ISBN: 978-1466468863, Jonathan Valvano, copyright (c) 2020 Copyright 2020 by Jonathan W. Valvano, valvano@mail.utexas.edu You may use, edit, run or distribute this file as long as the above copyright notice remains THIS SOFTWARE IS PROVIDED "AS IS". NO WARRANTIES, WHETHER EXPRESS, IMPLIED OR STATUTORY, INCLUDING, BUT NOT LIMITED TO, IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE APPLY TO THIS SOFTWARE. VALVANO SHALL NOT, IN ANY CIRCUMSTANCES, BE LIABLE FOR SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES, FOR ANY REASON WHATSOEVER. For more information about my classes, my research, and my books, see http://users.ece.utexas.edu/~valvano/ */ #include #include "../RTOS_Labs_common/LPF.h" // Newton's method // s is an integer // sqrt(s) is an integer uint32_t sqrt2(uint32_t s){ uint32_t t; // t*t will become s int n; // loop counter to make sure it stops running t = s/10+1; // initial guess for(n = 16; n; --n){ // guaranteed to finish t = ((t*t+s)/t)/2; } return t; } #define FILTERMAX 16 //**************Low pass Digital filter************** int32_t Size1; // Size-point average, Size=2 to FILTERMAX int32_t x1[FILTERMAX]; // one copy of data in MACQ uint32_t I1; // index to oldest int32_t LPFSum1; // sum of the last Size samples int32_t sigma1; int32_t snr1; // signal to noise ratio void LPF_Init(int32_t initial, int32_t size){ int i; if(size>FILTERMAX) size=FILTERMAX; // max Size1 = size; I1 = Size1-1; LPFSum1 = Size1*initial; // prime MACQ with initial data for(i=0; iFILTERMAX) size=FILTERMAX; // max Size2 = size; I2 = Size2-1; LPFSum2 = Size2*initial; // prime MACQ with initial data for(i=0; iFILTERMAX) size=FILTERMAX; // max Size3 = size; I3 = Size3-1; LPFSum3 = Size3*initial; // prime MACQ with initial data for(i=0; iFILTERMAX) size=FILTERMAX; // max Size4 = size; I4 = Size4-1; LPFSum4 = Size4*initial; // prime MACQ with initial data for(i=0; iFILTERMAX) size=FILTERMAX; // max Size5 = size; I5 = Size5-1; LPFSum5 = Size5*initial; // prime MACQ with initial data for(i=0; iFILTERMAX) size=FILTERMAX; // max Size6 = size; I6 = Size6-1; LPFSum6 = Size6*initial; // prime MACQ with initial data for(i=0; iFILTERMAX) size=FILTERMAX; // max Size7 = size; I7 = Size7-1; LPFSum7 = Size7*initial; // prime MACQ with initial data for(i=0; iu2){ if(u2>u3){ result = u2; // u1>u2,u2>u3 u1>u2>u3 }else{ if(u1>u3){ result = u3; // u1>u2,u3>u2,u1>u3 u1>u3>u2 }else{ result = u1; // u1>u2,u3>u2,u3>u1 u3>u1>u2 } } }else{ if(u3>u2){ result = u2; // u2>u1,u3>u2 u3>u2>u1 }else{ if(u1>u3){ result = u1; // u2>u1,u2>u3,u1>u3 u2>u1>u3 } else{ result = u3; // u2>u1,u2>u3,u3>u1 u2>u3>u1 } } } return(result); } // if the ADC is sampled at 1 kHz // 60-Hz notch high-Q, IIR filter, assuming fs=2000 Hz // y(n) = (256x(n) -503x(n-1) + 256x(n-2) + 498y(n-1)-251y(n-2))/256 (2k sampling) // y(n) = (256x(n) -476x(n-1) + 256x(n-2) + 471y(n-1)-251y(n-2))/256 (1k sampling) int32_t Filter(int32_t data){ static int32_t x[6]; // this MACQ needs twice memory allocation static int32_t y[6]; static uint32_t n=3; // 3, 4, or 5 n++; if(n==6) n=3; x[n] = x[n-3] = data; // two copies of new data y[n] = (256*(x[n]+x[n-2])-476*x[n-1]+471*y[n-1]-251*y[n-2]+128)/256; y[n-3] = y[n]; // two copies of filter outputs too return y[n]; } // Independent second instance of the 60-Hz notch IIR filter (e.g. for left IR sensor) int32_t Filter2(int32_t data){ static int32_t x[6]; static int32_t y[6]; static uint32_t n=3; n++; if(n==6) n=3; x[n] = x[n-3] = data; y[n] = (256*(x[n]+x[n-2])-476*x[n-1]+471*y[n-1]-251*y[n-2]+128)/256; y[n-3] = y[n]; return y[n]; } int32_t mx7[7]; // last 7 inputs int32_t f7[7]; // found flag // 11 usec running at 80 MHz int32_t Median5(int32_t x){ int i,j; int32_t max; for(i=3; i>=0; i--){ mx7[i+1] = mx7[i]; // push into MACQ f7[i]=1; // 1 means look at it } f7[5] = 1; mx7[0] = x; max = mx7[0]; j=0; for(i=1; i<7; i++){ if(mx7[i] > max){ max = mx7[i]; j = i; } } f7[j] = 0; // 0 means ignore the max max = INT32_MIN; for(i=0; i<7; i++){ if((mx7[i] > max)&&f7[i]){ max = mx7[i]; j = i; } } f7[j] = 0; // 0 means ignore the second highest max = INT32_MIN; for(i=0; i<7; i++){ if((mx7[i] > max)&&f7[i]){ max = mx7[i]; } } return max; // median is third highest } // Independent second instance of Median5 with separate MACQ (avoids sharing mx7/f7 with Median5) int32_t mx7_2[7]; int32_t f7_2[7]; int32_t Median5_2(int32_t x){ int i,j; int32_t max; for(i=3; i>=0; i--){ mx7_2[i+1] = mx7_2[i]; f7_2[i]=1; } f7_2[5] = 1; mx7_2[0] = x; max = mx7_2[0]; j=0; for(i=1; i<7; i++){ if(mx7_2[i] > max){ max = mx7_2[i]; j = i; } } f7_2[j] = 0; max = INT32_MIN; for(i=0; i<7; i++){ if((mx7_2[i] > max)&&f7_2[i]){ max = mx7_2[i]; j = i; } } f7_2[j] = 0; max = INT32_MIN; for(i=0; i<7; i++){ if((mx7_2[i] > max)&&f7_2[i]){ max = mx7_2[i]; } } return max; } // 16 usec running at 80 MHz int32_t Median7(int32_t x){ int i,j; int32_t max; for(i=5; i>=0; i--){ mx7[i+1] = mx7[i]; // push into MACQ f7[i]=1; // 1 means look at it } f7[6] = 1; mx7[0] = x; max = mx7[0]; j=0; for(i=1; i<7; i++){ if(mx7[i] > max){ max = mx7[i]; j = i; } } f7[j] = 0; // 0 means ignore the max max = INT32_MIN; for(i=0; i<7; i++){ if((mx7[i] > max)&&f7[i]){ max = mx7[i]; j = i; } } f7[j] = 0; // 0 means ignore the second highest max = INT32_MIN; for(i=0; i<7; i++){ if((mx7[i] > max)&&f7[i]){ max = mx7[i]; j = i; } } f7[j] = 0;// 0 means ignore the third highest max = INT32_MIN; for(i=0; i<7; i++){ if((mx7[i] > max)&&f7[i]){ max = mx7[i]; } } return max; // median is fourth highest }