software trick to stabilize noisy sensor

Go To Last Post
12 posts / 0 new
Author
Message
#1
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Hi, I have a very noisy 3-axis digital accelerometer, lis302dl. It's like, even though my accelerometer is in complete rest, the three registers of each axis fluctuate so much. So I've been trying to write a software trick that can check if the value of the XYZ register is stable or not.

I have a counter set to increment if the value of a register is less than the threshold I had set but decrement if the value is greater than. But since the accelerometer is still way to noisy, the counter still does not fix the noisiness.

Here is my current code that does that software trick I'm trying:

while(1)
{
	_delay_us(10);
	PORTC = 0x00;
	data1 = readaccel(_X);
	if(data1<0)
	{
		cnt1++;
		prdata1 = data1;
	}
	else
		cnt1--;
	if(cnt1 >1000)
	{
		PORTC |= 0b00000001;
		cnt1=0;
		_delay_ms(100);
	}
}
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

software filter it. This is generally what i use as a filter

unsigned int ReadAccelerometer(void) {
	static unsigned int totalX;
	unsigned int averageX;
	
	totalX += readaccel(_X);
	averageX = totalX >> 4;
	totalX -= averageX;
	
	return averageX;
}

can also add this line if you want;

unsigned int ReadAccelerometer(void) {
	static unsigned int totalX;
	unsigned int averageX;
	
	if (!totalX) totalX = readaccel(_X) << 4;
	else totalX += readaccel(_X);
	averageX = totalX >> 4;
	totalX -= averageX;
	
	return averageX;
}
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Or how about a first order low pass filter? No tricks involved.

long ltmp;
static long x_filt;
unsigned int flt;
unsigned char coeff; //value between 0 and 255 to vary the filtering
//
// apply some filtering to smooth things out a little
//
// flt has the raw input
// x_filt has the filtered output
ltmp = (((long)flt * (long)coeff) + ((long)x_filt * (255L - (long)coeff))) >> 8;
x_filt = ltmp;

//x_filt has the filtered output

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

You probably have something wrong with the PCB design if the readings are excessively noisy. Is the chip decoupled properly as described in the data sheet?

Leon

Leon Heller G1HSM

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

dual wrote:
Hi, I have a very noisy 3-axis digital accelerometer, lis302dl. It's like, even though my accelerometer is in complete rest, the three registers of each axis fluctuate so much.

I've used the LIS302DL in several designs. While far from perfect, it is not *that* noisy. Something else is wrong. How clean is your power supply? High ripple will look like movement. One of ST's newest part addresses this by building in the regulator. In the design for the STM32 Primer2 the accelerometer has its own power supply.

Also these MEMS based parts are more sensitive that you might expect, so check for environmental factors like trucks going down the road outside, the air conditioner vibrating your desk etc.

"Digital Filter and Motion Estimation Algorithm"
http://www.signalquest.com/datasheets/Digital%20Filter%20and%20Motion%20Estimation%20Algorithm.pdf
is worth a look on filtering.

One of the VTI App. Notes actually tells you that if you get the same reading from their device for more than couple of reads, the device is broken. The VTI parts are even more sensitive than the ST parts.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Well, first of all, this is how I have it connected.
I use the breakout board from Sparkfun and I have MISO connected to MISO, MOSI connected to MOSI, VCC connected to 3.3V, GND connected to ground, CS connected to SS, SCK connected to SCK.. I have 1K isolation resistors in between the connections since I use MKII ISP to program it.

I use SPI to interface with it and I can read the WHO_AM_I register correctly. I can read values from the XYZ registers but like I said, they fluctuate alot. My control registers except CTRL1 is set to default, while CTRL1 has been set to do Active Mode, X enable, Y enable, and Z enable.

And my first basic concern that I could never find anywhere is, if anyone has used this sensor, what are the default values of each XYZ register, minimum and maximum, and are the values signed or unsigned?

Here is a webpage that contains the datasheet, schematic, and even a sample PIC code that I based my code into.

If anyone who's a veteran with this sensor can tell me those values then that would be so amazing.

Thanks in advance.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Quote:
If anyone who's a veteran with this sensor can tell me those values then that would be so amazing.

Eight other threads mention "lis302dl" - perhaps a PM to the authors?

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

If it's noise out of nothing use a median filter
a normal filter will 'remember' the noise.

Jens

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Quote:
I could never find anywhere is, if anyone has used this sensor, what are the default values of each XYZ register, minimum and maximum, and are the values signed or unsigned?

AN2335 is what you are looking for:

http://www.st.com/stonline/products/literature/an/12215.pdf

"9.3 Understanding acceleration data

The measured acceleration data are sent into OUTX, OUTY and OUTZ registers. The acceleration values are expressed as a 2’s complement number. When the full-scale is set to 2g, each LSB corresponds to 18mg."

Here is the code I use to initialize the LIS302DL, and the header file for symbolic names [PetPeeve of mine is looking at code filled with 'magic numbers' like 0b1000111, always use symbols].

/*
 * Initialization code for LIS302DL connected to XMega128A1.
 * Note that the Who_Am_I value on the LIS302DL returns 0xFF when PD is zero,
 * and the proper 0x3B value when PD is one.  Why don't chip designers
 * ever see this kind of problem coming?
 */

enum Accel_Status{
  Accel_OK,             /**< Accelerometer powered up with no error **/
  Accel_WhoAmI_Error,   /**< Accelerometer did not correctly identify itself at power up **/
  Accel_TimeOut_Error   /**< Accelerometer did not respond when trying to initilize it **/
};
#include "lis302dlreg.h" /* Hardware registers for the ST LIS302DL Accelerometer */
uint8_t accel_initialize( void )
{
  uint8_t  value_u8;
  uint16_t loop_u16, timeout_u16 = 0;
  int8_t  x_i8, y_i8, z_i8;
  AVR_ENTER_CRITICAL_REGION();

  PR.PRPE &= (uint8_t) ~(PR_SPI_bm); /* Power up the SPI module */

  /* Initialize SPI master on port E: */
  SPI_MasterInit(&spiMasterE, /* Data Structure */
                 &SPIE,                 /* Module */
                 &PORTE,                /* Port */
                 false,                 /* lsbFirst */
                 SPI_MODE_3_gc,         /* Mode */
                 SPI_INTLVL_OFF_gc,     /* IRQ Level */
                 false,                 /* Clk2X */
                 SPI_PRESCALER_DIV4_gc); /* Clock Division */

  delay_5ms();          /* 3 ms, minimum, power up delay, and reset watchdog */

  ACCEL_CS_ASSERT();
  (void) SPI_MasterTransceiveByte( &spiMasterE, (AUTO_INCREMENT|WRITE|Ctrl_Reg1) );
  (void) SPI_MasterTransceiveByte( &spiMasterE, Ctrl1_PD );                               /* Power up, enable axises later */
  (void) SPI_MasterTransceiveByte( &spiMasterE, Ctrl2_Boot );                             /* Reboot the calibration constants, not all of the registers */
  ACCEL_CS_DEASSERT();

  do{/* If we are not who we think we are then abort with error return: */

    ACCEL_CS_ASSERT();
    (void) SPI_MasterTransceiveByte( &spiMasterE, (READ|Who_Am_I) );
    value_u8 = SPI_MasterTransceiveByte( &spiMasterE, ACCEL_DUMMY_BYTE );
    ACCEL_CS_DEASSERT();

    if( WhoAmIvalue != value_u8 )
      {
        AVR_LEAVE_CRITICAL_REGION();
        return( Accel_WhoAmI_Error );                                      /* Return non-zero to indicate the accelerometer is broken */
      }

    ACCEL_CS_ASSERT();
    (void) SPI_MasterTransceiveByte( &spiMasterE, (READ|Ctrl_Reg2) );      /* Read the Boot bit, when returns to zero, boot is done */
    value_u8 = SPI_MasterTransceiveByte( &spiMasterE, ACCEL_DUMMY_BYTE );
    ACCEL_CS_DEASSERT();

    if( 0 == ++timeout_u16 )
      {
        AVR_LEAVE_CRITICAL_REGION();
        return( Accel_TimeOut_Error );          /* Return non-zero to indicate the accelerometer is broken */
      }

  }while( (0 != (value_u8 & Ctrl2_Boot)) );     /* Wait for Accelerometer Reboot to be over, about 3 ms */

  ACCEL_CS_ASSERT();

  (void) SPI_MasterTransceiveByte( &spiMasterE, (AUTO_INCREMENT|WRITE|Ctrl_Reg1) );         /* CTRL1 Write */
  (void) SPI_MasterTransceiveByte( &spiMasterE, (Ctrl1_PD|Ctrl1_Xen|Ctrl1_Yen|Ctrl1_Zen) ); /* Power Up, Enable X/Y/Z @ 100 Hz */

  /* Hardware output on data availability: */
  (void) SPI_MasterTransceiveByte( &spiMasterE, 0 );               /* CTRL2 write, default value [Only for advancing the address in this case] */
  (void) SPI_MasterTransceiveByte( &spiMasterE, (IHL|I1CFGMODE4) );/* CTRL3 write, Active Low Data/IRQ Outputs.  Output is Data Ready */

  ACCEL_CS_DEASSERT();

  delay_5ms();

  /*
   * Read X/Y/Z to clear the overrun flags.
   */
  ACCEL_CS_ASSERT();

  (void) SPI_MasterTransceiveByte( &spiMasterE, (AUTO_INCREMENT|READ|Out_X) );

  x_i8 = (int8_t) SPI_MasterTransceiveByte( &spiMasterE, ACCEL_DUMMY_BYTE ); /* Read axis */
  (void) SPI_MasterTransceiveByte( &spiMasterE, ACCEL_DUMMY_BYTE );        /* Skip unused byte */

  y_i8 = (int8_t) SPI_MasterTransceiveByte( &spiMasterE, ACCEL_DUMMY_BYTE );
  (void) SPI_MasterTransceiveByte( &spiMasterE, ACCEL_DUMMY_BYTE );

  z_i8 = (int8_t) SPI_MasterTransceiveByte( &spiMasterE, ACCEL_DUMMY_BYTE );

  ACCEL_CS_DEASSERT();

  /* XMega IRQ setup: */
  ACCEL_IRQ_PORT.INTCTRL           = PORT_INT0LVL_LO_gc;
  ACCEL_IRQ_PORT.INT0MASK          = ACCEL_IRQ1_bm;
  ACCEL_IRQ_PORT.ACCEL_IRQ_PINCTRL = PORT_ISC_FALLING_gc;

  AVR_LEAVE_CRITICAL_REGION();

  /* Use X/Y/Z values from above to initialize any averaging here */

  return( Accel_OK );
}
/* lis302dlreg.h Hardware registers for the ST LIS302DL Accelerometer */
#ifndef _LIS302DL_H_
#define _LIS302DL_H_ (1)

#if defined(__cplusplus) && __cplusplus
 extern "C" {
#endif

/* LIS302DL register definitions: */
#define ACCEL_DUMMY_BYTE  ((uint8_t) 0) /* Arbitrary value sent out on SPI when we don't care about the value, so we can read in a SPI value */

#define Who_Am_I         (0x0F) /* (R) Always reads 0x3B as device identifier, but only when PD=1, else reads 0xFF when PD=0 */
#define WhoAmIvalue      ((uint8_t)(0x3B))

#define Ctrl_Reg1        (0x20) /* (RW) */
#define Ctrl1_DR         (0x80) /* 0=100 Hz sample rate, 1=400 Hz sample rate */
#define Ctrl1_PD         (0x40) /* 0=Power Down, 1=Active */
#define Ctrl1_Zen        (0x04) /* Z axis enabled */
#define Ctrl1_Yen        (0x02) /* Y axis enabled */
#define Ctrl1_Xen        (0x01) /* X axis enabled */

#define Ctrl_Reg2        (0x21) /* (RW) */

#define Ctrl2_FDSoff     (0x00) /* Filtered Data Sent to output when non-zero */
#define Ctrl2_FDSon      (0x10) /* Filtered Data Sent to output when non-zero */
#define Ctrl2_HP_FF_WU1on  (0x04) /* High Pass filter enabled for Free-Fall/Wake-Up #1. Default value: 0 */
#define Ctrl2_HP_FF_WU1off (0x00)
#define Ctrl2_Boot        (0x40) /* BOOT bit is used to refresh the content of internal registers stored in the flash memory block. */

#define Ctrl_Reg3        (0x22) /* (RW) */
#define IHL              (0x80) /* Active Low Data/IRQ outputs */
#define I1CFGMODE0       (0x00) /* GND */
#define I1CFGMODE1       (0x01) /* FF_WU_1 */
#define I1CFGMODE2       (0x02) /* FF_WU_2 */
#define I1CFGMODE3       (0x03) /* FF_WU_1 or FF_WU_2 */
#define I1CFGMODE4       (0x04) /* Dataready */
#define I1CFGMODE7       (0x0E) /* Click Interrupt */
#define I2CFGMODE0       (0x00) /* GND */
#define I2CFGMODE1       (0x08) /* FF_WU_1 */
#define I2CFGMODE2       (0x10) /* FF_WU_2 */
#define I2CFGMODE3       (0x18) /* FF_WU_1 or FF_WU_2 */
#define I2CFGMODE4       (0x20) /* Dataready */
#define I2CFGMODE7       (0x38) /* Click Interrupt */

#define HP_filter_reset  (0x23) /* (R)  */

#define Status_Reg       (0x27) /* (R)  */
#define Status_ZYXDA     (0x08) /* 1=XYZ all have data available */

#define Out_X            (0x29) /* (R)  */
#define Out_Y            (0x2B) /* (R)  */
#define Out_Z            (0x2D) /* (R)  */

#define FF_WU_CFG_1      (0x30) /* (RW) */
#define CFG_AOI          (0x80) /* 0=OR, 1=AND */
#define CFG_LIR          (0x40) /* 1=Latched IRQ */
#define CFG_ZHIE         (0x20) /* 1=Z high Event */
#define CFG_ZLIE         (0x10) /* 1=Z low  Event */
#define CFG_YHIE         (0x08) /* 1=Y high Event */
#define CFG_YLIE         (0x04) /* 1=Y low  Event */
#define CFG_XHIE         (0x02) /* 1=X high Event */
#define CFG_XLIE         (0x01) /* 1=X low  Event */

#define FF_WU_SRC_1      (0x31) /* (R) ACK1 */
#define SRC_IA           (0x40) /* 1=IRQ Active */
#define SRC_ZH           (0x20) /* 1=Z high Event */
#define SRC_ZL           (0x10) /* 1=Z low  Event */
#define SRC_YH           (0x08) /* 1=Y high Event */
#define SRC_YL           (0x04) /* 1=Y low  Event */
#define SRC_XH           (0x02) /* 1=X high Event */
#define SRC_XL           (0x01) /* 1=X low  Event */

#define FF_WU_THS_1      (0x32) /* (RW) */
#define THS_DCRM_RESET     (0x00) /* 0=Reset Duration timer immediately whenever the internal inertial event programmed is not active */
#define THS_DCRM_DECREMENT (0x80) /* 1=Decrement Duration timer to filter out spurious spikes which might impair the recognition and validation of inertial events */
#define FF_WU_DURATION_1 (0x33) /* (RW) */

#define FF_WU_CFG_2      (0x34) /* (RW) */
#define FF_WU_SRC_2      (0x35) /* (R) ACK2 */
#define FF_WU_THS_2      (0x36) /* (RW) */
#define FF_WU_DURATION_2 (0x37) /* (RW) */

#define AUTO_INCREMENT   (0x40)
#define READ             (0x80)
#define WRITE            (0x00)


#if defined(__cplusplus) && __cplusplus
 }
#endif

#endif /* _LIS302DL_H_ */
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

dual wrote:
Hi, I have a very noisy 3-axis digital accelerometer, lis302dl. It's like, even though my accelerometer is in complete rest, the three registers of each axis fluctuate so much. So I've been trying to write a software trick that can check if the value of the XYZ register is stable or not.

I have written on this before, but it's been scattered and I can't find the threads that I was on about with it.

After playing with sensors where the signal to noise ratio is quite high, it can be really difficult moving to motion sensors where the devices are noisy and subject to fluctuation.

Q: Why are these sensors so noisy?:

A: In short, if you're expecting a clean signal (and "clean" means different things to different people) from an accelerometer (or gyroscope), you'll need to spend thousands (or worse, tens or even hundreds of thousands) of dollars per axis. For everyone else, you'll have to settle for the chips of offer from the likes of VTI, ST, Freescale, Bosch, ADI, ...

So what do I mean by clean?

My original training is in aerospace, but I'm firmly ground-based these days and I dabble in these types of sensors as part of my job from time to time. As such, I tend to view these sensors through three main classes of applications:
* Motion detection (e.g. hard disk falling, pedometer)
* Attitude measurement (e.g. flight control, chassis stability, robotic arms)
* Inertial Navigation (e.g. airliners, military jets)

Each one requires a full order of magnitude (or more) better performance out of the sensor with a multiple order of magnitude cost difference.

Motion detection tends to be the simplest: A high pass filter, integrator and threshold tends to be sufficient - many chips (like the OP's device) even have such algorithms built into the chip. Noisy devices in this class are very common, because all they're really doing is looking for deviations from a steady-state value of the sensor.

Attitude measurement relies on the accelerometer detecting the gravity vector - simple trigonometry can resolve the measurements into pitch and roll angles. Any noise or bias on the measurements directly corresponds to noisy attitude estimates, with a rule of thumb of about 1 milliradian of angular error per milli-g of error (noise/bias).

Inertial Navigation is by far the most demanding on these sensors - the purpose is that you're trying to integrate acceleration **twice** to get an estimate of position. Therefore, any bias will quadratically increase error with time, and any noise will turn into a doubly integrated random walk. Given a flight can easily last 8 hours or more, you can see why they demand precision!

--------

Q: So can't I just filter it for a long time to clean up the signal?

A: Well, Yes and No, depending on your application. If you're you're a non-static application, then quite clearly you can't average for seconds at a time!

Even if you've got a static application, it's not just a matter of averaging/low pass filtering forever. The reason being that there's not just white noise acting on the device.

In addition to white noise (which most people on this site would have encountered at some point in their electronics career/dabbling), there are several other types of noises not always seen or cared about in the electronics world. I'll limit myself to a couple of these, which tend to dominate low-cost devices:
* Turn-on bias
* Temperature bias
* Bias Instability ("Flicker Noise", "Correlated Noise")
* Bias Random Walk
* Scale Factor error.

In general, you'll only need to start worrying about these errors when doing something needing precision, like attitude measurement.

Turn-on bias is a constant offset that changes every time that the device is turned on - not too much different from having to zero a pair of digital scales.

Temperature bias is a change in the bias of these devices as a function of temperature. After all, MEMS sensors are just little machines in silicon and temperature will expand/contract the structures inside the device. This is particularly dominant - especially if your device is exposed outdoors.

Bias instability (it has a specific meaning, but I'll talk generally) refers to random changes in the bias of these devices just because they feel like it, or because they're having a bad day. It happens very slowly and like white noise, you can't predict it (although you can statistically characterise it)

Random Walk Bias also refers to random fluctuations to the bias, but one that follows a "random walk process". See http://en.wikipedia.org/wiki/Ran...

The result is, after averaging for a period of time, the standard deviation of your average actually increases because of the slow fluctuations in bias listed. We generally use a tool known as an Allan Variance chart to analyse the bias performance of these sensors.

I've used the word "bias" a lot. It's pretty much as you'd expect - a constant (or slowly moving) offset from the true measurement. Because it moves very slowly, it's actually quite difficult to deal with - you just can't average it away like you can with white noise!

So, back to your original question, if you're looking to get a stable value, sorry, you're out of luck. You'll need to work out in your application what level of instability is necessary and choose a device based on this criteria.

Unfortunately, because none of the low-cost datasheet publishes any of the standard errors (there's an IEEE standard), you'll have a lot of testing ahead of you if you decide that the ST device isn't suitable.

-- Damien.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Actually, I just posted this same problem in the website where I bought the device, SparkFun.com.
I found that the value does not really fluctuate so much.

I was reading values ranging from like, 0x01, 0xFF, 0x00, 0x02. etc... I'm sure you notice the relationship, that I did not notice before, and since the datasheet offered by the website had not mentioned this.

The device I'm using transmits SIGNED data, in other words, the default value, when there is 0g on my accelerometer is 0x00, and since it's SIGNED, the value can go from (int)[..,-2,-1,0,1,2,..], the values that it gives when the accelerometer is resting in the axis I'm reading... in signed HEX!

Those values are actually what I was reading..

My application is mainly Motion Detection and I have tested that my accelerometer actually works pretty well, many many thanks for all your advises.

I will let you know how my project goes, my project is due this coming thursday and when it's done, I'll try to post a video and show you the results of all of you helping me out.

Thanks alot!

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

damien_d wrote:
dual wrote:
Hi, I have a very noisy 3-axis digital accelerometer, lis302dl. It's like, even though my accelerometer is in complete rest, the three registers of each axis fluctuate so much. So I've been trying to write a software trick that can check if the value of the XYZ register is stable or not.

I have written on this before, but it's been scattered and I can't find the threads that I was on about with it.

After playing with sensors where the signal to noise ratio is quite high, it can be really difficult moving to motion sensors where the devices are noisy and subject to fluctuation.

Thank you for those details.

I'll add this one:

"Accelerometers - Fantasy and Reality":
http://www.analog.com/library/analogdialogue/archives/43-05/accelerometer.html