Writing signal processing/filtering for 6bit gforce sensor - Page 1
Forum section: electronics / general

author: Psi
author_rank: Super Contributor
timestamp: October 19, 2012, 12:30:54 am
content: Hey guys, I'm using a 6bit SPI accelerometer for a project. The 6th bit is the sign, so it's really +/- 31 (+/- 1.5G).I'd like to apply some software processing to the signal so the data a bit more stable. (Currently it jumps around +/- 2 while stationary).What i need is the stationary jitter removed but as soon as there's a significant change in g-force the processing switches off and the full resolution and response returns. Does anyone know the best approach to do this?The core issue i have is the led display for the output (influenced by the g-force value). It doesn't look very professional jumping around. I would like to filter the raw g-force data but if that isn't going to be possible without a downside i can just filter the led display and leave the internal sensor data as is.

author: nctnico
author_rank: Super Contributor
timestamp: October 19, 2012, 01:00:33 am
content: This usually works well (moving average filtering):a=sensor valueb=(b* (x-1) + a) / xIf you choose a power of 2 for x (like 2,4,8,16,.. 256 ,etc) then the division becomes a bit shift so its very fast to compute. Most modern microcontroller have a hardware multiplier. Startup may be a 'problem' but if you initialize b with the first sampled value then it should be OK.

author: Psi
author_rank: Super Contributor
timestamp: October 19, 2012, 02:13:01 am
content: The problem with a moving average is they slow down the response.

author: Mechatrommer
author_rank: Super Contributor
timestamp: October 19, 2012, 03:03:06 am
content: i believe your problem is dealing with the "noise", and you want to remove that noise (averaging is the usual and easy trick), well, just as every problem dealing with noise, afaik you'll be in trouble if your signal is closer to noise level, and i believe there's no easy trick for that. so taking an easy step, assuming your signal level is significantly larger than the noise, you can either do the averaging the entire process, or keep detecting some threshold level, ie if the reading difference is lower than this threshold, you'll assume noise and do not change the averaged data, but if its exceeding the threshold, you can stop the averaging and read instantanoues data, but i believe the noise/jitter is still there, in your "legitimate above threshold" reading, except you dont see it much since you signal overshadowing the noise. my best bet will be... continuous averaging! without the hassle to handle every possible situation, it is noise you are dealing with afterall. about the respond time, its a compromise between reading stability vs respond time, ie you use more data, it will be slow respond, but you get more stable reading, and vice versa. YMMV.

author: Bored@Work
author_rank: Super Contributor
timestamp: October 19, 2012, 06:17:01 am
content: What you are probably looking for is called a Kalman Filter. Not the easiest to do and tune.

author: Rerouter
author_rank: Super Contributor
timestamp: October 19, 2012, 06:28:37 am
content: or you use a moving average that passes straight through deviations greater than the noise,x1= sample 1x2= sample 2x3= sample 3y= readingIF(x2-x3=OR(>5,<-5),y=(x1+x2+x3)/3)ELSE(y=x3=x2=x1)or something like that, where if it deviates by more than a predetermined level it will imediatly move to it, and start averaging from that point follwing it,technically if you used timers or other methods you could make it lower that deviation limit if the last sample deviated,

author: Mechatrommer
author_rank: Super Contributor
timestamp: October 19, 2012, 11:14:35 am
content: Quote from: Bored@Work on October 19, 2012, 06:17:01 amwhy dont save a step... artificial intelligence with genetic algorithm, you remember? one guy want to do power management with itKalman filter takes data in with some "trustability" weight. in this case maybe low difference data may weigh less hence not updated/passed very well into the filter, but jeez with the whole lot of math theory, is it really necessary?

author: Psi
author_rank: Super Contributor
timestamp: October 19, 2012, 11:16:02 am
content: Some good info here, thanks guys.This will be done on an ATMega at 8Mhz so complex math is out.

author: Mechatrommer
author_rank: Super Contributor
timestamp: October 19, 2012, 11:29:52 am
content: Quote from: Psi on October 19, 2012, 11:16:02 amkalman filter if i'm not mistaken with good understanding, can be done in simple integer arithmetic, but to get a good understanding you need to read all the math behind it. its pretty much like a weighed averaging if i remember it correctly, but not exactly that. YMMV.

author: Mechatrommer
author_rank: Super Contributor
timestamp: October 19, 2012, 11:58:49 am
content: oh i forgot but not least... as far as the averaging is concerned, we can always do a quicker programming method in hardware if its feasible, just one line... add a capacitor to the sensor output or if its high impedance stuff, at the sensor's buffer output or the related ADC input

author: Psi
author_rank: Super Contributor
timestamp: October 19, 2012, 12:00:15 pm
content: Quote from: Mechatrommer on October 19, 2012, 11:58:49 amIn this case it's a SPI accelerometer, so that isn't possible.

author: Mechatrommer
author_rank: Super Contributor
timestamp: October 19, 2012, 12:06:36 pm
content: Quote from: Psi on October 19, 2012, 12:00:15 pmbut hacking the analog side of the module is possible isnt it? since you having problem with this so i guess its cheapo type? and hacking or the less likeliness of damaging it wont hurt? always a pleasure to make a cheapo performs better

author: Mechatrommer
author_rank: Super Contributor
timestamp: October 19, 2012, 12:32:35 pm
content: another method will be to discard the offending bit(s) or value altogether. since yours is ±2 (i assume decimal number) so you can lump the value say 0-4 into 2 (middle value). the psuedo will probably looks like this:Code:#define DISCARD_VAL 4remain = value % DISCARD_VAL; mod operationvalue = (value - remain) + (DISCARD_VAL / 2);of if the offender is the 1st least bitCode:val &= 254; // 8 bit valueanother compromise! though you will get the stable reading and "on the spot" response, you'll lose resolution

author: andyturk
author_rank: Frequent Contributor
timestamp: October 19, 2012, 03:40:32 pm
content: Quote from: Bored@Work on October 19, 2012, 06:17:01 amIs there an "Idiot's Guide to Kalman Filtering" somewhere? Most presentations I've seen of the subject are fairly math intensive.

author: nctnico
author_rank: Super Contributor
timestamp: October 19, 2012, 04:09:31 pm
content: Quote from: Psi on October 19, 2012, 02:13:01 amWhat is the samplerate? If you use a small value for x (like 2 or 4) then the impact is minimal.

author: andyturk
author_rank: Frequent Contributor
timestamp: October 19, 2012, 05:16:55 pm
content: Quote from: Psi on October 19, 2012, 12:30:54 amIf your circuit is built correctly, then it seems pretty strange that your 6-bit resolution sensor is functioning only as good as a 4-bit sensor. Does the datasheet say you should expect +/- 2? If not, you should probably try to find the source of that noise rather than massaging the data.Is your power supply clean? The output of the sensor is digital, but it might have analog innards that are sensitive to noise on the power rails.Does the noise you're seeing have a particular frequency? I.e., if you sample at different rates, do you still see the same level of noise? Could there be some physical explanation for what the sensor is putting out?

author: PA0PBZ
author_rank: Super Contributor
timestamp: October 19, 2012, 07:26:44 pm
content: Exactly what I was thinking. If it jumps around for 0.1G you are either doing something wrong or you need to find another sensor.

author: Psi
author_rank: Super Contributor
timestamp: October 20, 2012, 01:53:44 am
content: Most of the jitter is the LSB, so +/- 1. Occasional you get a 2 though. This is correct according to the datasheet.QuoteThe chip is a MMA7660http://www.freescale.com.cn/files/sensors/doc/data_sheet/MMA7660FC.pdfThe sensor is 6 bit digital and internally takes 3846 samples/s and filters them to selectable 120/s, 64/s, 32/s, 16/s etc. Which you can read over SPI. There is no way to get at the analog side, it's internal.Because it can detect both directions you only get 5 bits of actual G data, bit 6 is the sign.So there are 31 steps from 0G to 1.5G, so 1 step = 0.048G.Most of the issue is, as you say, the sensor is a bit cheap, it's really meant for cellphones to detect orientation and pretty basic realtime measurements. That's why the resolution is low. It's only $1 when other sensors are $5I probably should be using a better sensor but this one is real cheap and it does work ok currently, I'm just trying to tidy it up and make it more professional.What i'm looking at currently is a running averagewhich changes its length in realtimebased on the signal rate of change.The idea is the running average is really long while the signal is stable but as soon as big changes occur the number of samples reduces to minimal so the response is fast.

author: nctnico
author_rank: Super Contributor
timestamp: October 20, 2012, 09:54:54 am
content: Quote from: Psi on October 20, 2012, 01:53:44 amYou may not want that. When reading sensors there is always the possibility of a false reading. A signal processing algorithm should ignore / filter such readings.

author: Psi
author_rank: Super Contributor
timestamp: October 20, 2012, 10:20:32 am
content: The filtering won't be reduced to zero in the event of a big signal change, just to a minimum level.A running average of 4 samples seems to work quite well in general.I'm currently getting it to switch between a 4 sample running average and a 32sample one, with a few stages in-between, depending on the change in data over a 8 sample period.

author: Psi
author_rank: Super Contributor
timestamp: October 20, 2012, 11:07:12 am
content: ok, so i have the code written and running. It's actually working very well, i'm quite happy with it.Automatically moves between a 4 and 128 running average based on the change between the current value and the value 8 samples agoQuote

author: andyturk
author_rank: Frequent Contributor
timestamp: October 21, 2012, 07:41:23 pm
content: Quote from: Psi on October 20, 2012, 01:53:44 amWell, the chip does have separate analog and digital supplies, which probably means you want to keep the analog rails clean. They're at the same voltage, so you can tie them together and get data out, but connecting analog parts up to a digital supply can cause problems. SPI in particular seems to dump a lot of noise back into the supply rails.As for the code, what does your filter code do when there are fewer than eight samples? Similarly, what happens if it wants to switch to a longer filter length, but doesn't actually have the data yet?It also looks like the average is recomputed for each sample. That's a lot of extra processing. A running sum would produce the same result with one addition operation (and one subtraction) per sample as long as the filter length hasn't changed. If the filter length changes, then you'd need to recompute. Better yet, just keep four running sums (one for each filter length) and then the cost of switching drops to zero. This gives you very predictable execution times which are nice to have in interrupt routines.

author: mrflibble
author_rank: Super Contributor
timestamp: October 21, 2012, 09:13:19 pm
content: Quote from: andyturk on October 21, 2012, 07:41:23 pmGets my vote. You simply have your ringbuffer of size N=128. Then an accumulator for every tap you are interested in, so in this case for 4, 8, 32 and 64. And since you're doing the shift in software, I'd do the shift after the select. Saves you 3 shift operations.So 4 adds and 4 subtracts per update, and then 1 select + 1 shift for each usage. Deterministic timings are indeed nice.Other than that, if all this isn't caused by your power rail .. that seems to be one hell of a noisy part. O_oUpdate:On second thought.... do the shift during the update phase, right after you did the add/subtract. Keeps the code simpler AND since you have the result in a register already might be about as fast...

author: Psi
author_rank: Super Contributor
timestamp: October 22, 2012, 02:19:06 am
content: Quote from: andyturk on October 21, 2012, 07:41:23 pmYeah, output is only valid once the ringbuffer is full, but that isn't a problem for the application.Quote from: mrflibble on October 21, 2012, 09:13:19 pmYep, that is definitely a better solution.Now that i have the concept working i will start optimizing it.I've already discovered that the line " if (y_filterlength < gfsarraylen) y_filterlength++; " really needs to happen less often, about once in every 5-10 samples, otherwise the buffer expands back too quick and skews the data a little

author: Kremmen
author_rank: Super Contributor
timestamp: October 22, 2012, 09:03:33 am
content: Quote from: andyturk on October 19, 2012, 03:40:32 pmIdiot's Guide? Probably not, unfortunately this is not a topic for rookies. I quickly checked my library and actual textbook material on the theory of Kalman filtering was suprprisingly sparse. I do have one at least that i can recommend with reservations:Grewal, Mohinder S. and Andrews, Angus P.; "Kalman Filtering: Theory and Practice Using Matlab"; Wiley & Sons; ISBN 0-471-26638-8The reservations are that it is relatively math intensive because there is no way around that fact. Perhaps a picture from that book's intro illuminates why:In a way, a concept like Kalman filtering stands on the shoulders of a number of disciplines that must be understood for it to make sense. You cannot begin from the top, so to say.