Well, every iteration update your variables like this:
$$ U_{i-2} \leftarrow U_{i-1}$$
$$ U_{i-1} \leftarrow U_{i}$$
$$ U_{i} \leftarrow \text{curent ADC reading}$$
$$Y_{i-2} \leftarrow Y_{i-1}$$
$$Y_{i-1} \leftarrow Y_i$$
$$Y_i \leftarrow \text{calculate current output}$$
In you code you are using double
variables for precision, but, for the Arduino Uno and other that use AVR architecture microcontrollers double is the same as float. If you intend on keep using double
, notice you will not have the desired performanceprecision.
Also, if you are using the Arduino Uno you will not be able to do many floating point operations per cycle, someone got a figure of 9 us per operation (except division), so just the part where you calculate your output \$Y_i\$ would use 5 multiplications and 5 additions, taking 90 us. Your filter is designed for 20 kHz, so you would do that operation 20,000 times per second, but:
$$20,000\cdot90 \,\mu\text{s} = 1.8 \, \text{s}$$
So you are way over your budget in frequency, if you where doing only that calculation, you would be barely able to achieve a 10 kHz frequency.
Finally, you could improve your code in two ways, first
//you do not need all those values,
//from your expression for the filter, you could use just this
//double Y_i[10] = {0,0,0,0,0,0,0,0,0,0};
//double U_i[10] = {0,0,0,0,0,0,0,0,0,0};
double Y_i[3] = {0,0,0};
double U_i[3] = {0,0,0};
//not needed, just load the values you want as initialization in the array above
//double Y_i_1 = 0;
//double Y_i_2 = 0;
//double U_i_1 = 0;
//double U_i_2 = 0;
notice that
- \$ U_{i-2}\$ =
U_i[2]
- \$ U_{i-1}\$ =
U_i[1]
- \$ U_{i}\$ =
U_i[0]
- \$Y_{i-2}\$ =
Y_i[2]
- \$Y_{i-1}\$ =
Y_i[1]
- \$Y_{i}\$ =
Y_i[0]
And that filter expression with a bunch of if
could be just
void loop() {
U_i[2] = U_i[1];
U_i[1] = U_i[0];
U_i[i] = x;
Y_i[2] = Y_i[1];
Y_i[1] = Y_i[0];
Y_i[0] = 0.144*U_i[0] + 0.2281*U_i[1] + 0.1441*U_i[2] + 0.6777*Y_i[1] - 0.254*Y_i[2];
//send or store any of the values that you need,
//Y_i[0] will always have the latest update of the filter, and so on...
//either put this filter in some non-critical interruption to execute it with the desired periodicity (best way)
//or use some precise delay here right after calculating the filter inside the loop
delayMicroseconds(50);
}