Arduino UNO and Teensy 3.2: same code but different behaviours for fixed-point math

Status
Not open for further replies.

frodojedi

Member
Hello,
I am running the code below to filter an analog sensor. The code implements (if I have not done any coding error) an exponential moving average filter. I run the very same code on and Arduino UNO and a Teensy 3.2. On the Teensy the algorithm work as expected, while on the Arduino UNO not really: the behaviour is not consistent (with some spikes happening here and there rather than following always the original signal) and there is a strange negative offset:

ERROR_ARDUINO.jpg

I am very surprised, I can't explain why this happen. Any idea? Both the Arduino UNO and the Teensy 3.2 do not have a floating point unit. So the same code should lead to exactly the same output.
The issue is independent of the sensor in input, I tested with a FSR and an accelerometer, the behaviour persist.


Code:
#define PERIOD_MICROSECS 1000

static unsigned long lastRead = 0;

     

int analog_pin = 0;   

int analog_input0 = 0;        
int analog_input0_filtered_fixed_point = 0;



//For fixed point I need to approximate the alpha using integer arithmetics 
// The general process is alpha * 2^EMA_multiplication_factor_fixed_point : e.g. for a wanted alpha = 0.26: 0.26*2^7 =~ 33
int EMA_multiplication_factor_fixed_point = 7;
int EMA_alpha_fixed_point = 33; // 0.26 = 33/128 = 33 >> 7 





//Fixed-point implementation
int low_pass_EMA_fixed_point(int x, int y, int alpha_fixed_point, int EMA_multiplication_factor_fixed_point){

  y = y << EMA_multiplication_factor_fixed_point;
  x = x << EMA_multiplication_factor_fixed_point;
  y += (x - y) * alpha_fixed_point >> EMA_multiplication_factor_fixed_point;
  return y >> EMA_multiplication_factor_fixed_point;
}





// ************************* //

void setup() {
  
  Serial.begin(115200);
  analog_input0_filtered_fixed_point = analogRead(analog_pin); //set EMA y for t=1
}



void loop() {
  
  if (micros() - lastRead >= PERIOD_MICROSECS) {
        lastRead += PERIOD_MICROSECS;

        analog_input0 = analogRead(analog_pin);  // read the input pin
        analog_input0_filtered_fixed_point = low_pass_EMA_fixed_point(analog_input0, analog_input0_filtered_fixed_point, EMA_alpha_fixed_point, EMA_multiplication_factor_fixed_point); 
  
        //Check the original and filtered signals with the serial plotter
        Serial.print(analog_input0); 
        Serial.print(" ");
        Serial.println(analog_input0_filtered_fixed_point); 
  } 
}
 
Not sure if int is the same size on 8bit UNO and 32bit Teensy.

I'd try to declare every variable explicitly, using for example int32_t and uint32_t instead of int and unsigned long, to avoid compiler confusion.

Edit: Paul was quicker...
 
Status
Not open for further replies.
Back
Top