Is this sampling frequency right?

I designed a Butterworth second order bandstop filter on Matlab with the following parameters:

• Notch frequency: 150 Hz (the frequency I want to remove)
• Bandwidth = 8 Hz, that is
• Fc1=146 Hz
• Fc2=154 Hz
• Fs (sampling frequency) = 10,000 Hz

According to Nyquist Criterion, 0.5xFs > Fm where Fm is my signal’s highest frequency. Let's say that my signal frequency ranges from 0 to 3 kHz, so my sampling frequency should be 6 kHz or higher. As you saw, I chose a samplig frequency of 10 kHz.

MATLAB gave me the filter coefficients for my difference equation, that is

y[n]=b0x[n]+b1x[n−1]+b2x[n−2]−a1y[n−1]−a2y[n−2] (IIR Filter).

I implemented this equation in a STM32F767 Nucleo Board. The input signal goes to the ADC, the signal is processed and then go to the DAC for output. I used a timer interrupt every 100 us for this. I mean, the process takes place in the timer interrupt loop.

**

The problem is this: My filter works, but it's no filtering the frequency I chose to filter. I wanted to remove the 150Hz, but it's removing a frequency of 298~300Hz.

**

What could be happening here? Does the sampling frequency have to do with this? Should I choose a lower sampling frequency? If it's needed I can attach my C code as well as the MATLAB design. But this is the basic idea:

struct difference_equation
{
// coefficients
double b0;
double b1;
double b2;
double a1;
double a2;
// input history
double x1;
double x2;
// output history
double y1;
double y2;

double process(double x0)
{
double y0 = b0 * x0 + b1 * x1 + b2 * x2
- a1 * y1 - a2 * y2;

x2 = x1;
x1 = x0;

y2 = y1;
y1 = y0;

return y0;
}
}


• That is not C, that is C++; in C, structs cannot have methods. – Marcus Müller Feb 17 '18 at 10:36
• Just for understanding, you want two filter functionalities: 1. you want to filter out all that's not between 146 and 154 Hz, and you 2. want to remove a signal component at 150 Hz, right? – Marcus Müller Feb 17 '18 at 10:38
• Hi @MarcusMüller. I'm not using "struct". I just pointed out the way I'm implementing the formula within interrupt loop. I want to remove 150Hz. That's why I chose a Bandwidth of 8Hz to make sure 150 Hz is eliminated. I'm new designing filters so I hope I'm expressing my ideas successfully. 1. you want to filter out all that's not between 146 and 154 Hz, and you 2. want to remove a signal component at 150 Hz, right? – Blue_Electronx Feb 17 '18 at 13:06
• Any update with this? Has it been resolved? – A_A Feb 27 '18 at 11:01
• @A_A I modified the sampling frequency without telling Matlab. That is, I designed the filter in Matlab for a sampling frequency of 10 kHz, but in my microcontroller I used 5 kHz instead of 10 kHz and it worked. I still don't know what happens here. – Blue_Electronx Feb 28 '18 at 13:13

The STM32 is a 32bit micro-controller and all of your processing seems to be taking place over a double precision data type.

Doubles are 64bit "numbers" but not in the straightforward sense that 64bit integers are. Therefore, mathematical operations on doubles can take some additional steps (see page 47 onwards) on CPUs that are not equipped with special hardware to handle floating point operations. If the CPU does not have an FPU then mathematical operations are handled in software which means that they take more CPU cycles to complete (For example, you can try double precision multiplications on an Arduino (like Uno), it's going to be fun).

The STM32F767 does have (see page 13) a Floating Point Unit, which means that it can potentially perform double precision operations faster than when these operations are implemented in software and take up CPU cycles. Notice that the FPU is better than not having it but it still has its own limits, for indicative timings see page 16 on this document

Therefore, my guess is that your interrupt routine is striving to fire at the intended 10kHz but it doesn't complete before $\frac{1}{10000}$ seconds. So, your effective sampling frequency is not 10kHz and the whole system is transposed to a different frequency range.

You might want to check if the FPU is enabled at double precision or move to fixed point numbers which every CPU will happily crunch. With fixed point numbers, you have another problem which is that your filter might go out of spec because of the rounding that is inevitable due to the reduction in precision. But these are aspects that you have to manage in your solution.

Hope this helps.

• One way to check is to set b0 = 1.0, set the other coefficients to 0.0, (i.e., make a filter with 1.0 gain and no phase shift) and feed a simple signal like a sine wave in. You should get the same sine wave out. Besides processing speed, this will also check if your double is converted back to whatever the DAC expects correctly. – mtrw Feb 17 '18 at 12:44
• @mtrw You might want to leave this as a comment to the person who asked the question, optionally quoting this answer (?) – A_A Feb 17 '18 at 12:50
• Hi all. Thanks for your comments. I find them very useful. What I'm going to do now is to check if my FPU is enabled and then try again. I will let you know what's going on, – Blue_Electronx Feb 17 '18 at 13:02
• @XavierPachecoPaulino Thanks for letting me know but please note that this board's functionality is different than that of a forum. If you have additional data later that may be affecting your question it will be better to update your original question. Otherwise we are likely to lose the plot on what is mentioned where and what the exact problem and its solution is. – A_A Feb 17 '18 at 13:04
• @A_A I realized that FPU was enabled. So that's not the problem. Something that I noticed is that when I lower the sampling frequency, I approach a bit to the target frequency. I still don't understand what could be happening. – Blue_Electronx Feb 17 '18 at 19:07