Teensy Digital Filter Implementation - Using coefficients

Status
Not open for further replies.

Deadp1xels

Well-known member
I know how to design digital filters in Matlab but now I'm looking at using them on my Teensy.

Because I have no access to Matlab at home, for ease of use I used:
http://www-users.cs.york.ac.uk/~fisher/mkfilter/trad.html

And made a low pass filter to quickly get:
Code:
#define NZEROS 1
#define NPOLES 1
#define GAIN   1.324919696e+00

static float xv[NZEROS+1], yv[NPOLES+1];

static void filterloop()
  { for (;;)
      { xv[0] = xv[1]; 
        xv[1] = next input value / GAIN;
        yv[0] = yv[1]; 
        yv[1] =   (xv[0] + xv[1])
                     + ( -0.5095254495 * yv[0]);
        next output value = yv[1];
      }
  }

How do I modify this code to filter a specific analog signal?

I want to filter a signal at A1 and then store that new smoother signal in a variable to use but I'm not sure how to utilize this new piece of code
 
you have to substitute "next input value" with the vlaue read from A1,
and your own varname instead of "next output" value.
You can use loop() instead of this function to test it... keep timing!
This examples will only filter correct in whole uS steps!: only 100k, 50k, 33.3k, 25k, 12.5 are valid samplerates for it..

Code:
#define NZEROS 1
#define NPOLES 1
#define GAIN   1.324919696e+00

static float xv[NZEROS+1], yv[NPOLES+1];
int sampleRate=50000;
elapsedMicros microCount;
int microsPerSample =1000000/sampleRate; 

void setup()
{          
  analogWriteResolution(12);             // max resolution on the output
  analogReadResolution(12);             // same on input
}
int myOutput=2048;
void loop()
{
       analogWrite(A14,myOutput);
        float myInput= analogRead(A1) - 2048;  //512=10 bit DC level adjust!   12 bit = 2048

        xv[0] = xv[1]; 
        xv[1] = myInput / GAIN;
        yv[0] = yv[1]; 
        yv[1] =   (xv[0] + xv[1])+ ( -0.5095254495 * yv[0]);     //coefficient is here...

         myOutput = 2048 + int(yv[1]); //dc offset + output filter
  
  while(microCount<microsPerSample){}     // fill our timing budget
  microCount-=microsPerSample;            // keep pace 
}
 
Last edited:
Note1: ofcourse you can use other samplerates in this example but they have to be divisions of 1000000, because of the uS timer used.
Note2: this is Teensy3.1 code, you have to use another output on other Teensies for monitoring with PWM on another pin..
 
Last edited:
Thanks, face palmed when I noticed I completely overlooked that...

I'm using the digital filter on an accelerometer so I don't need to output it on the ADC just filter so I can control MIDI parameters
 
Thank you Deadp1xels, because I needed a filter too, and I completely overlooked this mkfilter thing. So I made this example primairily for myself, and shared it with you and other people with the same question, I've learned a lot on this forum and I like to do my part.

Thanks, face palmed when I noticed I completely overlooked that...

I'm using the digital filter on an accelerometer so I don't need to output it on the ADC just filter so I can control MIDI parameters
 
Its a lot quicker than Matlab :) I'm glad we've managed to help each other!

Ran into a slight snag, the current filter I was using works great

However, I want to implement a filter I design so when I show my lecturer he can see my reasoning behind the filter rather than "Smooth data" When I implement any filter its worse than what I already have.

I'm using an ADXL335 Accelerometer and by the nature of the device its noisey because of vibration! I just want to smooth it slighty, I read the datasheet and it says the noise extends at 500Hz so I decided to filter anything above 500Hz out.

No big benefit so I tried 400Hz still no major changes to see, I set my sample rate at 1600Hz and cutoff at 500Hz maybe its just the device is particularly noisey? would really like to design a filter from scratch to solve the problem.
 
you'll have to use a higher order filter (I suggest simple butterworth with 2nd order), and I suggest at least testing it with higher samplerate. You're know crossing the border of 1/2 nyquist, my guts say that that will deteriorate your performance..
You have to put the -3db point an octave lower than where you want your real cuttoff point (250hz in this case), and raise the order. First use a higher samplerate for safety: if it works allright, you lower the samplerate for efficiency (with different coefficients ofcourse)
And it's a good idea to look at the output of your accelerometer: it should'nt be noisy at all! In fact, i've seen an demo with this accelerometer a a 3d transducer for guitar! And it was hifi. Check the powersupply, big chance the turmoil comes from there, it should 3v3 and well regulated.
 
Thanks for the tips,

I've been trying different orders, higher sampling rate and my accelerometer is defiantly 3.3v regulated

I mapped both my input and output filtered signal and used them to control two separate faders in Midi software and I saw almost no difference...

Not sure where I'm going wrong.

I admit I'm no expert in DSP at a long shot but I thought I would at least see a decent change, thing that's weird is my bare input signal is actually quite good once its mapped... which is weird I know the sparkfun breakout has analog filtering onboard via caps but still.
 
HI Deadp1xels, you could share the code if you like..

Code:
#define NZEROS 3
#define NPOLES 3
#define GAIN   3.450423889e+02

static float xv[NZEROS+1], yv[NPOLES+1];
void setup() {
  // put your setup code here, to run once:

}

void loop() {
 int input=analogRead(A0);
xv[0] = xv[1]; xv[1] = xv[2]; xv[2] = xv[3]; 
        xv[3] = input / GAIN;
        yv[0] = yv[1]; yv[1] = yv[2]; yv[2] = yv[3]; 
        yv[3] =   (xv[0] + xv[3]) + 3 * (xv[1] + xv[2])
                     + (  0.5320753683 * yv[0]) + ( -1.9293556691 * yv[1])
                     + (  2.3740947437 * yv[2]);
        int output = yv[3];
        
        output=map(output,609,404,127,0);
         input=map(input,609,404,127,0);
        
        usbMIDI.sendControlChange(1,output,1);
        usbMIDI.sendControlChange(2,input,1);
        
        
  Serial.print(" | Input: ");
  Serial.print(input);
  Serial.print(" | Output: ");
  Serial.println(output);
}

Here it is, I've kept it simple just till I get an appropriate filter working
 
it is too simple Im afraid, but it is easy to fix..
Your fault: where do you define the samplerate? nowhere!.. so the filter wont work..
So, look at my example above,
these lines define the speed:
int sampleRate=10000; // beware, this method only supports 1 uS steps for your period time
elapsedMicros microCount;
int microsPerSample =1000000/sampleRate; //REAL samplerate: use this samplerate in mkfilter!!

the 2 lines in loop() keep pace:
while(microCount<microsPerSample){} // fill our timing budget
microCount-=microsPerSample; // keep pace

Without a definition of your samplespeed no filter will work!

Secondly, your flooding your usb with midimessages, to send only changed data allready would be a nice improvement.
This flooding can lead to artefacts like added delays that will trouble your samplerate.
 
Last edited:
Status
Not open for further replies.
Back
Top