Problem of False Positive for vertical motion with Accelerometer

I am working on a project to calculate speed (Velocity when I get an IMU) of finger taps and then to apply them for further applications like music, hand gesture recognition etc. I have been able to work the integration well enough due to the short time spaces between hand/finger movements.

But, I was getting an unwanted delay and false velocity in opposite directions when the finger reached the end of one vertical movement, i.e. Top/summit to bottom/tabletop and vice versa. I expect to get positive acceleration with downward motion as per my program, attached below. I get correct readings until I hit the tabletop which results in an amplified or equal and opposite acceleration. Similar but reversed phenomenon for the upwards motion and stopping at a summit. Graphs attached.

The first phenomenon of "false negative" during downwards motion doesn't affect my program and hence is categorized as benign. But, it is useful for analysis.

The second phenomenon of "false positive" during upwards motion does affect my program and hence is categorized as Negative effect/Unwanted effect.

I am using an ADXL335 accelerometer and the datasheet is also attached.

My core program with the integration is beyond the scope of this problem and not a cause, therefore not attached here.

Kindly ignore the smoothening snippets of the code as they did not help with this issue. I can however compile the data with graphs for those snippets, if it will help the error analysis. I used a 100ms delay and 50Hz BW for the third datasheet/graph. The program I used to get the data and graphs below:

# define Xpin 0
# define Ypin 1
# define Zpin 2

const byte LED = 12;  // Calibration in process or not.
const byte BUTTON = 3;  // Press to calibrate.

const int Axis = 3;

const float ZeroPoint[] = { 1.64, 1.64 , 1.655};  // Calculated practically.
const float Sensitivity = 0.33;

float GravCorrection = 1.0;

float R_Curr = 0; float R_Prev = 0;
int Sign = +1;

volatile boolean CaliFlag = false;

/*
 *  Interrupt to notice Calibration request from digital switch. Later built in Android. etc.:
 *  Set the caliFlag when switch on. Off otherwise.
 */
void switchPressed ()
{
  if ( digitalRead (BUTTON) == LOW )
  {
    digitalWrite (LED, HIGH);
    CaliFlag = true;
  }
  else
  {
    digitalWrite (LED, LOW);
    CaliFlag = false;
  }
}

void setup() {
  // put your setup code here, to run once:
  Serial.begin(115200);
  analogReference(EXTERNAL);
  pinMode (LED, OUTPUT); // So we can update the LED
  pinMode (BUTTON, INPUT_PULLUP);  // Internal pull-up resistor
  attachInterrupt (digitalPinToInterrupt (BUTTON), switchPressed, CHANGE);  // Attach interrupt handler.
}

void loop() {
  // put your main code here, to run repeatedly:
  float Rx = 0; float Ry = 0; float Rz = 0;
  float R = 0;

  if ( CaliFlag == true )  // To calculate the gravitational acceleration to be removed.
  { 
    Serial.println ("Calibration will begin in one second. Keep the device flat on play surface.");
    delay(1000);
    GravCorrection = getR ( xlRation(analogRead( Xpin ), ZeroPoint[Xpin]), xlRation(analogRead( Ypin ), ZeroPoint[Ypin]), xlRation(analogRead( Zpin ), ZeroPoint[Zpin]) );
    Serial.println ("Moving to play mode.");
    Serial.print ("Gravity Correction detected = " );
    Serial.println (GravCorrection);
    
    return;
  }

  Rx = xlRation ( analogRead(Xpin), ZeroPoint[Xpin] );
  Ry = xlRation ( analogRead(Ypin), ZeroPoint[Ypin] );
  Rz = xlRation ( analogRead(Zpin), ZeroPoint[Zpin] );
  
  //Test for cumulative Acceleration, R:
  
  // Acceleration in Gs without Gravity Correction
  R = getR ( Rx, Ry, Rz );

  R_Curr = GravCorrection - R; // Corrected for gravity.
  
  Serial.print("R_Curr = ");  
  Serial.println(R_Curr);

  //delay(100);
  R_Prev = R_Curr;
}

float xlRation ( int AdcReading, float ZeroPoint )
{
  return ((( AdcReading * 3.3/1023 ) - ZeroPoint )/Sensitivity );
}

float getR ( float Rx, float Ry, float Rz )  //Calibrate for each new position to set gravity correction 
                                                          //value, i.e. NIC.
{
  float R = 0.0;
  
  if ( Rz <= 0 )  // Sign to signify downwards and upwards acceleration respectively.
    Sign = -1;  // Downwards as in normal equations.
  else
    Sign = +1;  // Upwards as in normal equations.
  
  R = Sign * sqrt( sq(Rx) + sq(Ry) + sq(Rz) );
 
  return R;
}

Possible reasons:

  1. My first reaction and theory was that this is due to noise but various denoising methods did not help. It still might be.
  2. My second theory was that this is due to Newton's third law: Every action has an equal and opposite reaction. As it occurs for both upwards and downwards motion, it seems to be the likeliest cause.

Can someone definitively tell me what the reason is? And maybe how I can work on fixing/removing it?

That maximum delay per loop I can allow is 166ms which results in 6 beats per seconds. Ideally, I want to be able to process double of that.

And no, I did not move the accelerometer in the opposite direction. For the first, It goes down and then hits the table to a stop. For the second, it goes up and I stop and keep it still for a while.

adxl335_DataSheet.pdf (427 KB)

But, I was getting an unwanted delay and false velocity in opposite directions when the finger reached the end of one vertical movement, i.e. Top/summit to bottom/tabletop and vice versa. I expect to get positive acceleration with downward motion as per my program, attached below. I get correct readings until I hit the tabletop which results in an amplified or equal and opposite acceleration. Similar but reversed phenomenon for the upwards motion and stopping at a summit. Graphs attached.

Go back to your physics book, if an object has some velocity and is slowed down you get an acceleration in the opposite direction. If that results in a false velocity in the opposite direction you either did the math wrong or your integration doesn't use small enough steps.

Your description of the setup is unclear. Please post a picture. Is the accelerometer attached to a finger?

In the first posted graph (titled "acceleration"), what does the Y axis actually represent ?

Kindly ignore the smoothening snippets of the code

Kindly remove them. All the junk makes your code hard to read.

pylon:
Go back to your physics book, if an object has some velocity and is slowed down you get an acceleration in the opposite direction. If that results in a false velocity in the opposite direction you either did the math wrong or your integration doesn't use small enough steps.

Thank you for affirming the 2nd theory that it is the equal and opposite force/acceleration to stop the motion. It gives an error of +/- 0.1 m/s without the bandpass filter to remove noise and drift. And that too, at really high accelerations so it's not a problem that I can't solve. The problem I can't solve is the 230-300ms of unwanted delay caused by it.

jremington:
Your description of the setup is unclear. Please post a picture. Is the accelerometer attached to a finger?

In the first posted graph (titled "acceleration"), what does the Y axis actually represent ?
Kindly remove them. All the junk makes your code hard to read.

The accelerometer is mounted on a bread board for now, but will be attached on the finger when testing is complete. The Z axis is horizontal. Cleaned the code. Y axis stands for acceleration, X axis stands for time in "Seconds.MilliSeconds" format

So, are you tapping a breadboard with accelerometer on the table?

Thank you for affirming the 2nd theory that it is the equal and opposite force/acceleration to stop the motion

You misunderstand Newton's Third Law. "Equal and opposite" does not apply to the effect you see. The Third Law tells you that if you push on a wall, the wall pushes back with an equal and opposite force.

jremington:
So, are you tapping a breadboard with accelerometer on the table?
You misunderstand Newton's Third Law. "Equal and opposite" does not apply to the effect you see.

The Third Law tells you that if you push on a wall, the wall pushes back with an equal and opposite force.

I'm sorry that's how I made sense of it. I thought its the opposite force/acceleration (as mass is constant if i'm not wrong) caused by the tabletop, in the first case of downward motion. Or the hand is exerting external force to stop the movement in the second case of upward motion, so that would be the first law of motion. Can you correct me and tell me what it is otherwise?

Different acceleration profiles can cause different velocity profiles (acceleration is the slope of the velocity), with the same overall result: an object starts from rest, speeds up, slows down and stops.

Plot illustrating this below, from https://www.teachengineering.org/lessons/view/uno_gaitway_lesson01

velocity_accel.png

I don't think you need to care about the exact nature of the forces responsible for the motion, you just need to discriminate between different types of motion.

Why do you think calculating the speed is helpful or required? This will become very difficult and perhaps impossible, when you face the problem of subtracting the gravity component of acceleration for an arbitrary orientation. See this tutorial explaining the problem: http://www.chrobotics.com/library/accel-position-velocity

velocity_accel.png

jremington:
Different acceleration profiles can cause different velocity profiles (acceleration is the slope of the velocity), with the same overall result: an object starts from rest, speeds up, slows down and stops.

Plot illustrating this below, from https://www.teachengineering.org/lessons/view/uno_gaitway_lesson01

velocity_accel.png

I don't think you need to care about the exact nature of the forces responsible for the motion, you just need to discriminate between different types of motion.

Why do you think calculating the speed is helpful or required? This will become very difficult and perhaps impossible, when you face the problem of subtracting the gravity component of acceleration for an arbitrary orientation. See this tutorial explaining the problem: http://www.chrobotics.com/library/accel-position-velocity

Yes, you're right. The exact nature of the force is trivial for the application but, I just want to be sure my inference of the problem is correct. I need to reduce the delay caused by that "Reactive force". The lower that delay, the better. 230 ms+ pause in a program is way too high for an instantaneous stop.

For the gravitation correction, I don't think it is that big a problem for my needs:

  1. Because my device will not rotate. There's no Yaw, pitch or roll to account for yet. For full-proofing, I'll add a higher quality gyroscope to make it an IMU and get better gravity readings. In any case, bigger problem there is fluctuations of gravitational acceleration with time and location which is accounted for by the manual calibration for now.
  2. I'll do a frequency response analysis sometime in the future. I think the gravitational acceleration should be a very low frequency, if so I'll use a bandpass circuit to take it out of picture. I don't know if it'll work yet. But, it would deal with drift and noise errors as well. Along with "sleep mode" during adc reading and ADC interrupts, It should cover the bases to give an accurate enough velocity at a +/-0.5 m/s error at maximum.
  3. Also, I wanted to try if an external integrator amplifier circuit would give me a cleaner velocity and position result.

And yes, yes I am tapping a "breadboard with accelerometer" on the table.

bigger problem there is fluctuations of gravitational acceleration with time and location

I see why you chose that user name.