Suggestions for lowering accelerometer noise

I've been creating a seismograph project. Central Nexus Seismograph Project

It currently uses the ADXL345 accelerometer with the Arduino Duemilanove, but it's a little noisy. It also occasionally misreads a few times a day. It samples at a rate of about 200Hz. I'm using the I²C protocol.

I'm currently working on replacing it with the Bosch Sensortec BMA180 accelerometer with an Arduino Uno. Even though it has higher resolution, the noise floor is only slightly better. It seems to be about 20% better. Using a capacitor between 3.3V and ground doesn't seem to help the noise level. I found out that if I attach the ground wire to real ground (e.g. the enclosure) in addition to the Arduino's ground pin, the signal spikes a little less, which gives me about an additional 20% less noise.

So my questions are:

  • Is it safe to attach the sensor to a real ground in addition to the Arduino's ground pin?
  • Are there other suggestions on reducing the accelerometer noise?

BTW the earthquakes I want to measure are magnitudes 2 through 9, which equates to about 0.17%-100% gravity. The revised configuration's noise floor is about 1% gravity, which is about a 3.5 magnitude earthquake. So I can't reliably detect anything less than that. So far, the current version has only be able to record a 4.1 magnitude earthquake.

Are there other suggestions on reducing the accelerometer noise?

Normally I would take multiple readings and do some averaging (or use the median to remove outliers) but with eartquakes? if the processor has some idle time or you the frequency may be lowered this might be an option.

BTW the earthquakes I want to measure are magnitudes 2 through 9, which equates to about 0.17%-100% gravity. The revised configuration's noise floor is about 1% gravity, which is about a 3.5 magnitude earthquake. So I can't reliably detect anything less than that. So far, the current version has only be able to record a 4.1 magnitude earthquake.

IIRC there are many things that start making noise before a quake (glasses, dogs etc) so maybe other sensors are more sensible? :wink:

robtillaart:
Normally I would take multiple readings and do some averaging (or use the median to remove outliers) but with eartquakes? if the processor has some idle time or you the frequency may be lowered this might be an option.

Actually, reducing the read frequency should be able to do that. I believe this chip automatically has the ability to average it, but I'm looking for sampling it at about 200Hz. This makes it easier to distinguish between something going thump or the low rumble of an earthquake over many seconds.

robtillaart:
IIRC there are many things that start making noise before a quake (glasses, dogs etc) so maybe other sensors are more sensible? :wink:

Yes, but those are easy to distinguish from earthquakes. Trash cans dropping on the floor make short spikes. Circular saws and other motors make a steady high frequency buzz in a specific direction. All sensors have this issue. Even seismographs from the USGS have to contend with cows or other large animals walking near or on the sensors. Correct placement helps with those types of temporary issues.

I've thought about polling multiple accelerometers too, but if the problem is due to noise in the circuit, I'd figure the sensor noise would affect both sensors equally. If I could use one with SPI and the other with I²C, that might decouple the circuits. Unfortunately, I haven't had any luck using SPI at 3.3 volts with the Arduino. So I'm hoping for something easier.

Try feeding the BMA180 with 2.4V -- check the specs. That is their nominal voltage.

I put 220 Ohm to +3.3 and the 1k2 Ohm to ground and took the voltage off the midpoint -- 2.3V as measure with my fancy VOM.

In particular the Z output -- which should read 8192 (mid point) at 1g now reads 8162 I think it was 7964 before... and that is close enough for most work.

I suppose a .01 uF cap to ground alongside the resistor might help. I may put a scope on that later.

WillR:
Try feeding the BMA180 with 2.4V -- check the specs. That is their nominal voltage.

Thanks. I didn't think about using a voltage divider. I got it down to 2.5V, and the noise seems to be reduced now. I'll have to try other voltages too.

The capacitor seems to be beneficial now too.

Check out this: http://www.analog.com/static/imported-files/application_notes/AN-1063.pdf
(Oversampling technique to improve the ADXL345 output resolution)

Sorry, but oversampling and averaging aren't helpful in this case. The bigger spikes lasted too many few samples, and some of the frequencies won't come out right by using that technique. If I were normally dealing with larger changes in acceleration that is distinguishable from the noise without regards to the frequency, oversampling and averaging would make more sense.

After adding a few resistors and capacitors, the noise floor now seems to be around 0.75% gravity. I tried using 2.2V and 1.8V to see if that helped. Unfortunately the chip wouldn't respond. I don't think the Arduino liked talking I²C at that voltage.

The BMA 180 also has four Modes -- 0 through three.

The noise depends on the mode setting. It also shifts the output "zero point" for some inexplicable reading.

In short with the BMA 180 you need to consider three things...

The Bandpass filter,
The Sensitivity and
The Mode...

Mode 0 is noisy by comparison to others.

If you want minimal Z noise -- use mode 2 (The third mode)
If you want minimal XY noise (at the expense of a slight in crease in Z noise) use mode three. The increase in Z noise is minor ... imnsho...

I did two minute sample runs and did a noise evaluation with the BMA180. Those were the results. If able, I will post details later.

I did Sample counts, min, max average and SD (Standard Deviation).

However, what I cannot convey without the graphs is that the character of the noise changes as you move between modes. This is something that BOSCH should publish with the rest of their "book" on the sensor. It's a good sensor. This is not a complaint -- except about the documents.

hth

After adding a few resistors and capacitors, the noise floor now seems to be around 0.75% gravity. I tried using 2.2V and 1.8V to see if that helped. Unfortunately the chip wouldn't respond. I don't think the Arduino liked talking I²C at that voltage.

You need a logic level converter for using it when going down 2.5 Volts.. A 5 Volts Arduino will take everything >= 2.5 Volts as logical high, so it will work without an LLC.. but once you goes down below 2.5 you absolutely need that.

WillR:
The BMA 180 also has four Modes -- 0 through three.

Duh! :blush: (Smacks my head) This is my second BM180. I fiddled with those settings the first time, but they didn't do anything. Bosch Sensortec recommended I return it to get the latest revision, and the revised one worked much better. I forgot to bring that code back. Changing it to mode 01 brings the noise level below 0.5% gravity. :slight_smile:

I'll have to fiddle with the mode and bandwidth settings.

Yeah, I'll have to revisit that. It wasn't working the first time I tried it.

See my stats in this thread.
http://arduino.cc/forum/index.php/topic,52688.0.html

The graphics are too big to post -- I tried...

The modes behave differently on the the different axes...

DiamondSky:

[quote author=Fabio Varesano link=topic=53062.msg380871#msg380871 date=1298494110]
You need a logic level converter for using it when going down 2.5 Volts.. A 5 Volts Arduino will take everything >= 2.5 Volts as logical high, so it will work without an LLC.. but once you goes down below 2.5 you absolutely need that.

Yeah, I'll have to revisit that. It wasn't working the first time I tried it.
[/quote]

I was able to use the logic level converter (BOB-08745) from Spark Fun, and it made the noise much worse. I think the signal was spiking about 4 times per second. So scratch that idea.

Lowering the bandwidth significantly improved the noise level, but I really need a sample rate of at least 150Hz, which is the default. 150Hz can detect thumps and chairs rolling, but not below that sampling rate. So changing the bandwidth is out of the question too. This is like oversampling.

Changing the mode_config was the best option for me. Though for some of the modes, I had to recalibrate the sensor by changing the offset. I hope I don't have to recalibrate the temperature offset too. This calibration also changed the relative % acceleration for the noise level.

BTW by default each axis is suppose to be about -4096~+4096 in range by default. According to the documentation the first bit (2^0) is status and the second (2^1) is always 0.

Upon further review, my math is a little off. It looks like the noise is close to the specified level defined by the datasheet. Changing the mode did help though.

Adding resistors, diodes and changing the voltage didn't seem to help. It appears that the capacitors and the time of day affects the reading more than anything else. Any given axis spikes every couple of seconds. The spikes seem to be more frequent during the day time.

DS:

Your results are consistent with mine.

I have now tested at 1g, 1.5g and 2g and have test runs where I recorded all the data through my UDP programs to a database -- now I can evaluate at my leisure. I can produce up to 3X 1.2M Samples every couple of hours -- so it makes for an interesting data collection system... I typically get about 4GB of data after an 8 hour run...

Assuming the sensor is ""level". You are collecting in 14 Bit mode... then you choice a "noise" mode.

AT 1g -- the Y sensor should read about +8192 -- mine reads "close" there is an offset...
At 1.5 G the Y Sensor should read about 5400 -- mine reads 5600
At 2 G the Y sensor should read about 4096 -- at least I'm close...

To explain the 5400.... 0-8192 is the range... so 1G is 2/3 of that so 2/3 * 8192 == 5461.3 the spec sheets says 5400 -- close enough...

I am currently set at 1.5G mode three (3) so the noise is not bad....
In 1G sensitivity, mode 2 is a little better for Y and Mode 3 is s little less noisy for X-Z

First you do your design, then.... Bottom line -- you have to do calibration runs like I am doing and then choose "the least worst" settings for your need. This is "engineering" at its finest. Dealing with practicalities is engineering.

Here are some "ambient noise" readings:
Settings 150Hz BW, 1.5g Mode 3

I will give a "band" that most of the noise occupies then outlier spikes...

X : -6 to -20 spikes down to -90 up to + 50
Y : -260 to -200 spikes down to -320 up to -130
Z : 5970 to 6040 spikes down to 5940 and up to 6090.

The sensor is installed on a breadboard I installed connector pins that are inserted into the bread board.

Leveling the bread board changes readings in a minor way, so I assume that one is to "level" the sensor using offsets somehow after determining the minimum noise settings desired.

Changing the bandwidth increases samples per second at 150HZ i can collect 75SPS

I will comment on 300HHz if I can get the system to re-load and run with the new settings. The Wiznet Ethernet board or the software is not that reliable.... Sometimes it starts -- sometimes it doesn't... eventually yes.

WillR:
I can produce up to 3X 1.2M Samples every couple of hours -- so it makes for an interesting data collection system... I typically get about 4GB of data after an 8 hour run...

At ~200 samples per second with 16 bits per axis, my system currently logs about 103MB uncompressed per day. It's a binary format that I cam up with. When it's written to disk, it averages around 23MB (lossless compression) per day. The time stamp is located every 5 seconds. When I summarize it in a png file to post on my web site, the png file comes out at about 80KB. :slight_smile:

WillR:
I will give a "band" that most of the noise occupies then outlier spikes...

X : -6 to -20 spikes down to -90 up to + 50
Y : -260 to -200 spikes down to -320 up to -130
Z : 5970 to 6040 spikes down to 5940 and up to 6090.

That looks like 1.5G mode. I was calculating absolute G at 150Hz using ultra-low noise 2G mode. Every 5 seconds I calculated the following.

Average deviation: 8.5~9.5
90th percentile band amplitude: 20~26
Largest spike amplitude: 60~70

Statistically, we're probably not that much different.

WillR:
Leveling the bread board changes readings in a minor way, so I assume that one is to "level" the sensor using offsets somehow after determining the minimum noise settings desired.

Yes, I noticed that too. So every time you pick up the board to modify it, and put it down on an uneven surface, the variability changed ever so slightly.

Here is my setup routine...

NOTE: The sample skipping... That gives a pretty dramatic noise reduction...

I have found modes 1 & 2 to be useless in some respects as they offset X-Y -- I forget which does which... So it's noisy mode Zero (0) or Somewhat OK Mode three (3) that doesn't muck up too much...

I also believe that the ISR on Pin2 might be interfering with something else -- can't figure out what though... It is now on Pin 3 Interrupt (ISR 1)... Maybe it is simply that I was driving it with 3.3 V... I need to hook up another level converter I guess...

I will probably stick with 1.5G and possibly 1G for my work.

This used the library by Jurgen... (Jayduino?)

// Best seetings F15HZ0 and Mode 3
// Also F300HZ and Mode 2

/* Filter settings
   F10HZ=0,F20HZ=1,F75HZ,F15HZ0,F300HZ,F600HZ,F1200HZ,HPPLUS1,BP300}FILTER;

*/
  bma180.setFilter(bma180.F300HZ);
  /* G Sensitivity
      G1=0,1.G15=1,G2,G3,G4,G8,G16  ... enumerated type, 1, 1.5,2,3,4,8,16 g settings
  */
  bma180.setGSensitivity(bma180.G15); // lets put 1.5 G maximum, not doing tests in a space shuttle
  //setRegValue(int regAdr, int val, int maskPreserve)
/*  MODE  -- for 1, 1.5 and 2g
    0x00=LowNoise,       BW=1200 Noise 150 ug/rt
    0x01 Ultra Low Noise BW=472  Noise 150 ug/rt 
    0x02 Low Noise Low Power BW= 236  Samp/Sec =1200 Noise 200 ug/rt
    0X03 Low Power       BW=600                      Noise 200 ug/rt
    Must see Page 28 section 7.7.3 for full info
*/
  bma180.setRegValue(0x30,0x03,0xFC); 
  
  // digital pin 3= ISR1  ---  ISR 0 = Dig Pin 2  ISR0 gave problems????
  attachInterrupt(1, BMAISR, RISING);
  // +++++++++++++++++++++++++++++++  -- note this

  // sample skipping reduces noise sonsiderably... not sure of count...
  bma180.setSMPSkip(); // allow sample skipping to reduce load...

  bma180.setISRMode(); // allow interrupt on (connect to Dig. Pin 3)


  bma180.disableWrite(); //parametrs are set so disallow further changes
  delay(2000);  //just a wait till thinggs settle and readings stabilize...


// End BMA180 Setup +++++++++++++++++++

 Serial.println("Starting..."); 
 SendPackets = false;
 flipflop = 0;

} //end setup

// End Setup
//*****************************************

Have fun...

WillR:
I have found modes 1 & 2 to be useless in some respects as they offset X-Y

I had to recalibrate the sensor to use mode 1. I found that you can modify the offset registers, and I used a level to find the right values. I got it so that the given axis should be perpendicular to the gravity, and so that axis should be 0. I noted the offset from zero to figure what to add to the registers. Unfortunately, I never quite figured out how to permanently write those values to the EEPROM registers. So if there is ever a short that causes the BMA180 to reset, the default values come back.

Even the other modes can need recalibration depending on what you put on the circuit, but the recalibration is not as significant for mode 0 and 3.

DiamondSky:

WillR:
I have found modes 1 & 2 to be useless in some respects as they offset X-Y

I had to recalibrate the sensor to use mode 1. I found that you can modify the offset registers, and I used a level to find the right values. I got it so that the given axis should be perpendicular to the gravity, and so that axis should be 0. I noted the offset from zero to figure what to add to the registers. Unfortunately, I never quite figured out how to permanently write those values to the EEPROM registers. So if there is ever a short that causes the BMA180 to reset, the default values come back.

Even the other modes can need recalibration depending on what you put on the circuit, but the recalibration is not as significant for mode 0 and 3.

This might be a good reason to store the values in the Arduino EEPROM....

If the sensor chips had UUID's it would even be possible to pick the right one through lookup... (Like the DALLAS Temp Chips.)

WillR:
This might be a good reason to store the values in the Arduino EEPROM....

It is stored in the Arduino EEPROM. I'm talking about the BMA180 EEPROM. The documentation suggests that it can be written to, I just haven't figured it out. It talks about the low level details about how it works, but there aren't specific steps or an example included.

I made a discovery. I found out that this BMA180 accelerometer works differently from the ADXL345. The vibration bandwidth frequency really is decoupled from the sampling frequency. So even though I want to measure frequencies in the 0.001–50 Hz range (0.1-10 Hz for the stronger ground motion), I can sample at 200 samples per second. The ADXL345 would flatline between two samples when the bandwidth went below the sampling frequency. The BMA180 actually gives a nice slope. So I set the bandwidth filter to 40Hz and sample at 200sps. This cut the noise floor in half again. :slight_smile:

BTW the bandwidth filters 0x8 and 0x9 are quite interesting. They cancel out gravity, which would seem quite helpful in other usage scenarios. They have an interesting fading effect on the tricolor LED I'm using. I guess gravity has a frequency of 0Hz because it's normally constant. It's unfortunate that the documentation doesn't advertise the purpose of those modes. :frowning: