quadrature encoder rotation rate averaging

Hi,

I am using this quadrature encoder: "

formatting link
"

with 300 cycles per revolution / 1200 pulses per revolution. I have it hooked up to an AVR microcontroller (atmega168) using two external interrupt pins for the A and B channel (there is no index channel). This is working and I have a variable that keeps track of the encoder pulses and uses a 4state machine to check the rotation direction, so the variable goes + for forward rotation and - for reverse rotation.

I am now trying to get an averaged rotation rate for the last 1ms, 10ms,

100ms, 1s and 10s. I have an interrupt that runs every 1ms for this but the code only updates the rotation rate variables once per period, ie. once per second for the 1s variable, instead of giving a continuously updated value from the last second.

Any ideas on how to fix this? I was thinking about using a digital lowpass filter:

formatting link
for each rotation rate variable but am not sure if that is the best way to do it.

cheers, Jamie

Reply to
Jamie Morken
Loading thread data ...

What is best depends entirely on just what you want to do with the information, and what your memory resources are. The IIR filters that you'll get from that page will certainly give you effective averaging at low phase delay and low memory requirements, but they won't give exact moving averages, if that's what you really need.

--

Tim Wescott
Wescott Design Services
http://www.wescottdesign.com

Posting from Google?  See http://cfaj.freeshell.org/google/

"Applied Control Theory for Embedded Systems" came out in April.
See details at http://www.wescottdesign.com/actfes/actfes.html
Reply to
Tim Wescott

If save in a variable each 1ms the you need an accumulator for each 10ms, 1s , 10s , this will be difficult if the integers are below 16 bit.

webmaster

formatting link
Database of Web Hosting Plans, Featuring Cheap Web Hosting Plans, Ecommerce Hosting, Dedicated Hosting

Reply to
ADM

You need to store the values for each interrupt period in a circular array and do the sum on the entire array. If you have 1ms interrupts you will need to store 1000 values in the array. This is a lot of memory so you'll probably want to store values only every 10 or 100ms.

Strictly speaking it is a digital filter, only much simpler than Chebychev & al.

vic

Reply to
vic

This does not look doable, especially the longer times. So the question becomes why do you need these values and what are you doing with them? And, is there another way of accomplishing that?

Luhan

Reply to
Luhan

On Tue, 13 Jun 2006 13:32:37 +0200, vic wrote:

I can see how to do this in four circular buffers of 10 values each, and an accumulator (or two) for each circular buffer.

Requoting more of the OP:

What will be the maximum RPM of this thing? This will tell you the number of bytes to allocate for each value at each stage.

Presuming fix means rewrite:

Use a circular buffer of the last 10 1ms values. You could brute-force sum all ten values every 1ms, which may be feasible and is simpler programming, but you can find the sum much faster (presuming they start out zero when the code starts, which they really should) by using an accumulator. Subtract the 10th value from the accumulator, put the new value into the circular buffer (erasing the old 10th value you just subtracted), and add this value to the accumulator. Thus the accumulator will always have the sum of the most recent 10 values in the circular buffer. The usual caveats apply, be sure everything has enough bits for the maximum value it can hold. If you need an actual average, divide the accumulator value by 10 (and store in yet another varuable, and use THAT as the input to the next, uh, paragraph), but if you have enough bits to hold all the sums or need higher resolution on the longer averages, just continue using sums, and only use division to get the actual average values to send off somewhere. Use a circular array of the last 10 10ms values you got from the previous paragraph, and do likewise with it to get a 100ms sum or average. Continue for 100ms and 1s, giving 1s and 10s averages/sums respectively. Total operations each 1mS (not counting division to get actual averages and whatever code to send these values somewhere) is four subtracts, four adds, and eight buffer operations. The brute-force option changes that to 40 adds and and eight buffer operations. To get actual averages instead of sums, you also need to do four divides each

1mS, each by a fixed power of 10.

This is a FIR filter with 10 coeficients of value 1 each (or 0.1 if you want the output automatically divided by 10). But you don't need to know that. ;-)

Reply to
Ben Bradley

Ben Bradley scrobe on the papyrus:

All of the software is much simpler if you use an average buffer of 8 or 16 samples. Dividing by 10 is a PITA.

--
John B
Reply to
John B

ElectronDepot website is not affiliated with any of the manufacturers or service providers discussed here. All logos and trade names are the property of their respective owners.