Chief Delphi

Chief Delphi (http://www.chiefdelphi.com/forums/index.php)
-   C/C++ (http://www.chiefdelphi.com/forums/forumdisplay.php?f=183)
-   -   Unexpected results from Encoder::GetRate() (http://www.chiefdelphi.com/forums/showthread.php?t=82171)

vamfun 20-04-2010 15:30

Re: Unexpected results from Encoder::GetRate()
 
Quote:

Originally Posted by jhersh (Post 955993)
What's a proper count? If the lines did it, it gets decoded. It seems unreasonable for the decoder to make assumptions about what the sensor meant to encode. The way I've implemented it allows you to read the true position at any point independent of the rate calculation.

I suspect the accuracy of both approaches would be comparable, just have max errors occurring at different locations in the resolution cycle. On a change of direction, yours would be off by a count initially but be more accurate just prior to the next edge count. Mine would be more accurate on the initial reversal and off by a count just prior to the next count. Probably needs a simulation to verify.


Quote:

I then address the concern you have for the rate measurement independently by ignoring any count that has changed direction for the purposes of calculating rate

Here you have disconnected the rate from the position signal temporarily. This is why I like Kevin's or my approach .. since it doesn't require this and yet maintains the same accuracy if what I said above is true.



Quote:

Because I'm using an FPGA, I can afford to implement the decoder correctly without regard for shortcuts in interrupt handling
. No argument there.... just so we know what you are doing.
Please, please, please put these algorithms in the code documentation at the nearest opportunity. I don't want to spend the rest of my retirement slowly extracting this information on our CD threads:)

vamfun 23-04-2010 03:09

Re: Unexpected results from Encoder::GetRate()
 
Quote:

Note to Joe H: For your 1x, I don't like your algorithm because the count oscillates when stuck with an oscillating A edge over a BHigh or Blow state. I believe this can really aggravate the GetRate() noise.

You count up or down on the A edge transition if Bhigh so you oscillate between +1 and -1 increments. My 1x non-oscillating scheme and Kevin's will not do this. Mine will allow a single proper count in the normal direction and no change on the oscillatory reversal. Kevin's will not allow any count until B changes sign.
Quote:

Originally Posted by jhersh View Post
What's a proper count? If the lines did it, it gets decoded. It seems unreasonable for the decoder to make assumptions about what the sensor meant to encode. The way I've implemented it allows you to read the true position at any point independent of the rate calculation.
Quote:

Originally Posted by vamfun (Post 956019)
I suspect the accuracy of both approaches would be comparable, just have max errors occurring at different locations in the resolution cycle. On a change of direction, yours would be off by a count initially but be more accurate just prior to the next edge count. Mine would be more accurate on the initial reversal and off by a count just prior to the next count. Probably needs a simulation to verify.

The more I think about this the stronger I believe that you are doing the wrong thing by decrementing on the reversal. The encoder knows it is the same edge so it is sure that it has not moved since the last edge. Before the reversal, the encoder knew that it was on a new edge so the increment was valid and warranted. Any other situation there is a 1 count uncertainty.

By allowing the oscillation in position, you are penalizing those who derive rate from position with unwarranted errors that you corrected for in your GetRate().


Quote:

Here you have disconnected the rate from the position signal temporarily. This is why I like Kevin's or my approach ..
As a user , I want the rate to be the time derivative of the position. Here the position is moving and the rate is not. In this case, the rate is correct because it recognizes that the encoder has not changed position and should have a zero rate.

It seems reasonable therefore to simply apply the same logic to the position as you apply to GetRate() and force the position to match the rate.



Aside: I was only partially correct a while back when I said that the x2 and x4 were not edge oscillation sensitive.... they will not increment continuously but they will oscillate between increment and decrement as the x1 case because of the way your algorithm works. Right?




Users who are listening... is this a bug in your minds?

jhersh 23-04-2010 17:10

Re: Unexpected results from Encoder::GetRate()
 
Quote:

Originally Posted by vamfun (Post 957061)
The more I think about this the stronger I believe that you are doing the wrong thing by decrementing on the reversal. The encoder knows it is the same edge so it is sure that it has not moved since the last edge. Before the reversal, the encoder knew that it was on a new edge so the increment was valid and warranted. Any other situation there is a 1 count uncertainty.

I don't understand why introducing phase error between forward and reverse is preferable. I have an encoder on a shaft because I want a specific angular range on that shaft to be represented by a number in my software. Why would I want the range that a number represents to be different based on the direction that the shaft was last rotating? I believe the answer is that I would not.

Quote:

Originally Posted by vamfun (Post 957061)
By allowing the oscillation in position, you are penalizing those who derive rate from position with unwarranted errors that you corrected for in your GetRate().

I'm not clear on what algorithm you are using to compute the rate in software. Depending on what you are using, this may or may not be a moot point or have other issues. Please describe what you are using.

Quote:

Originally Posted by vamfun (Post 957061)
As a user , I want the rate to be the time derivative of the position. Here the position is moving and the rate is not. In this case, the rate is correct because it recognizes that the encoder has not changed position and should have a zero rate.

This is not an accurate statement. A rate is a difference in timing between two events. As such the first event can not have a "rate" associated with it because there is no reference as to when that motion began. That is why the first edge in a given direction can not calculate a rate.

-Joe

vamfun 23-04-2010 19:07

Re: Unexpected results from Encoder::GetRate()
 
Quote:

Originally Posted by jhersh (Post 957277)
Why would I want the range that a number represents to be different based on the direction that the shaft was last rotating?

Simply to be more accurate for the edge oscillation case.
Your scheme and mine will both have 1 count ambiguity...it just occurs at different times. I am interested in the best estimate of angle not just the count. I am showing a preference to have the best estimate at edge reversal rather than a count later. I can do this because of B channel information.
Lets take a simple 1 deg resolution encoder. We start with 0 angle, rotate to 1.1 deg and reverse to .99 and continue back to .1 and eventually back to 0. Error = true - encoder
Angle..joe count/chris count... joe error/chris error

0.0..0/0....0/0
1.1..1/1... 0.1/0.1*****tie
0.9..0/1...0.9/-0.1*****chris wins
0.5..0/1...0.5/-0.5*****tie.
0.1..0/1....0.1/-0.9*****joe wins
0.0..0/0.....0/0******tie

So if we are oscillating in a band about the 1 deg edge [.9 to 1.1], my algorithm will give a better estimate of angle position on reversal and we are the same going forward past 1. My rate will be zero without special compensation when oscillating in band, yours needs compensation to avoid huge rates with high frequency small amplitude oscillations (see Edit). Likewise, if we oscillate about the 0 deg edge or any edge.

So the reason for introducing the hysteresis is to avoid the rate spikes associated with the edge oscillation without giving up anything on accuracy. I.e. both have the same maximum error , just shifted in the cycle.

Edit:
Refer back to the above example and assume a small oscillation about the 1 deg edge with .1 deg amplitude at 10 rad/s. The truth rate amplitude should be 1 deg/s. Mine will be 0 yours will be (1*10) deg/s. The error in rate estimate for mine will in general be A*w , yours will be (1-A)*w where w is the frequency (rps) and A is the angle displacement amplitude. The ratio between our errors (joe/chris) is roughly 1/A for small A. Therefore , very small amplitude vibrations can cause very large differences in accuracy. E.g. A =.01 ... your error can be 100 times mine. In absolute terms, my error will be equal to the truth amplitude (100%) , while yours will be 100%/A. This you know and that's why you compensated for this effect in GetRate(). Using the hysteresis scheme, this is automatically compensated for in the GetDistance() count hence no compensation is required in GetRate() if you just divide the count by the count period.


Quote:

I'm not clear on what algorithm you are using to compute the rate in software. Depending on what you are using, this may or may not be a moot point or have other issues. Please describe what you are using.
Lets assume its just (new-old)/dt without special filtering. If my dt spans multiple counts, then it is moot...but if I'm rocking on an edge like Alan mentioned...it can lead to trouble unless we do some compensation somewhere with your algorithm.


Quote:

This is not an accurate statement. A rate is a difference in timing between two events. As such the first event can not have a "rate" associated with it because there is no reference as to when that motion began. That is why the first edge in a given direction can not calculate a rate.
We have two events.... crossing same edge in forward and reverse directions.
-Joe

Alan Anderson 24-04-2010 12:33

Re: Unexpected results from Encoder::GetRate()
 
Quote:

Originally Posted by vamfun (Post 957313)
Your scheme and mine will both have 1 count ambiguity...it just occurs at different times.

I don't believe that is true. Yours has the ambiguity; a true quadrature decoder does not.

Quote:

Lets take a simple 1 deg resolution encoder. We start with 0 angle, rotate to 1.1 deg and reverse to .99 and continue back to .1 and eventually back to 0. Error = true - encoder
Angle..joe count/chris count... joe error/chris error

0.0..0/0....0/0
1.1..1/1... 0.1/0.1*****tie
0.9..0/1...0.9/-0.1*****chris wins
0.5..0/1...0.5/-0.5*****tie.
0.1..0/1....0.1/-0.9*****joe wins
0.0..0/0.....0/0******tie
That range seems chosen especially to favor your scheme, and you ignored the fractional information that a quadrature encoder can provide. Depending on what "1 deg resolution" means, a quadrature decoder will give at least twice the resolution of an edge-triggered up/down counter, and can give four times as much.

You also left out all of the samples that would reveal that yours gives different values for the same position depending on where it came from. For measuring position, I do not believe hysteresis is a positive attribute.

vamfun 24-04-2010 14:35

Re: Unexpected results from Encoder::GetRate()
 
Quote:

Originally Posted by Alan Anderson (Post 957496)
I don't believe that is true. Yours has the ambiguity; a true quadrature decoder does not.

Don't follow you here. All encoders have a resolution ambiguity. The 4x quadrature decoder is 1/4 of 1x but there still exists the ambiguity within the resolution deadband.



Good to hear from you Alan. I am primarily addressing the 1x decoding of a quadrature encoder. So we have two channels to make the best 1x estimate. We are using 1x to minimize the rate errors associated with extra edge phase noise found with 2x and 4x decoding. So please evaluate my comments in this regard. The 1 deg resolution is identical to the kit 360 count encoders.

The comparison is between Joe's 1x and my 1x. The example doesn't favor either but is designed to illustrate the differences in the two approaches, so it focuses on the edge reversal. If there isn't an edge reversal, then the two schemes are identical. You can start anywhere on the cycle... at the exact point where the edge reverses, Joe's error will have a max 1 count error (ambiguity) and mine will be zero. As the reversal continues toward the next edge, Joe's estimate gets better and mine gets worse. If you look at the example carefully, you will notice that the max distance error is the same for both and will not exceed the resolution.

If the Kevin W. algorithm was implemented as I discussed earlier in the thread , I believe it would produce the same output as my 1x case. So I thought I was arguing in your favor.

Quote:

You also left out all of the samples that would reveal that yours gives different values for the same position depending on where it came from. For measuring position, I do not believe hysteresis is a positive attribute.
In my example, I am 0 going up to 1.1 and 1 returning so this is exactly what is illustrated. But , I claim this is the best estimate you can make when a reversal on the same edge is detected. If at the reversal, I ask you where you are and you tell me that you are 1 count further away than just before the reversal... then I know you can do better than that. My algorithm lets you say that you are in the same position that created your last count, hence it gives a more accurate guess at that point. Continuing in the reverse direction , if you happen to move close to the next edge... I will be reporting a 1 count error while Joe would be spot on. Users of either scheme cannot claim any better accuracy than 1 count after an event has been registered. But, in the neighborhood of the reversal event I can claim better accuracy hence I report better rate performance in the presence of your oscillating wheel phenomenon which triggers that event. This is a very subtle point and that's why I'm belaboring it.

Let's nix that "hysteresis" word, since it only applies to same edge reversals not all reversals and may be confusing.

Alan Anderson 24-04-2010 19:59

Re: Unexpected results from Encoder::GetRate()
 
Quote:

Originally Posted by vamfun (Post 957532)
Don't follow you here. All encoders have a resolution ambiguity. The 4x quadrature decoder is 1/4 of 1x but there still exists the ambiguity within the resolution deadband.

We obviously have a different understanding of the word "ambiguity". I'm using it to mean that a specific measured value can indicate different things. You seem to be using it as a synonym of "precision" instead.

Quote:

Let's nix that "hysteresis" word, since it only applies to same edge reversals not all reversals and may be confusing.
I thought you were only looking at transitions on one channel to determine when to change counts. With that assumption, it looks to me like "same edge reversals" are the only kind you would see.

vamfun 24-04-2010 21:04

Re: Unexpected results from Encoder::GetRate()
 
Quote:

Originally Posted by Alan Anderson (Post 957624)
We obviously have a different understanding of the word "ambiguity". I'm using it to mean that a specific measured value can indicate different things. You seem to be using it as a synonym of "precision" instead.
I thought you were only looking at transitions on one channel to determine when to change counts. With that assumption, it looks to me like "same edge reversals" are the only kind you would see.

I have the same definition of ambiguity... I just see it as caused by the precision round off.

You are right.. they are the only kind... But the hysteresis is cleared up as soon as the next count comes in without another reversal. In a normal hysteresis, this doesn't happen. This is what I meant by possible confusion.


Do you still feel that the value should be the same going up as down for the 1x case as discussed in post 51? If so .. can you think of a counter example that illustrates your concerns with my logic? This goes for Joe too.

Alan Anderson 24-04-2010 22:38

Re: Unexpected results from Encoder::GetRate()
 
Quote:

Originally Posted by vamfun (Post 957636)
But the hysteresis is cleared up as soon as the next count comes in without another reversal.

I don't see how. The last line in your table of states looks wrong -- in order for your scheme to return to 0, there has to have been a transition, right? The true quadrature decoding would see that transition and go to -1. Your values will continue to be off by one compared to a quadrature decoder when going in reverse. The term hysteresis seems perfectly appropriate to me.

Quote:

Do you still feel that the value should be the same going up as down for the 1x case as discussed in post 51? If so .. can you think of a counter example that illustrates your concerns with my logic? This goes for Joe too.
Yes, of course the values should be the same for a given position, no matter which direction one gets there from. I don't know what example you want to see countered.

vamfun 25-04-2010 01:04

Re: Unexpected results from Encoder::GetRate()
 
Quote:

Originally Posted by Alan Anderson (Post 957659)
I don't see how. The last line in your table of states looks wrong -- in order for your scheme to return to 0, there has to have been a transition, right? The true quadrature decoding would see that transition and go to -1. Your values will continue to be off by one compared to a quadrature decoder when going in reverse.

Yes, thank you.. I forgot to decrement Joe. Here is a revised and expanded table:
1x Decoding example of a quadrature encoder
Lets take a simple 1 deg resolution encoder. We start with 0 angle, rotate to 1.1 deg and reverse to -.9 and then reverse again and go forward back to 0.
Error = true - encoder
Angle..joe count/chris count... joe error/chris error
fwd
0.0..0/0....0/0********tie
0.5..0/0....0/0********tie
1.0..1/1... 0/0 New edge event (joe and chris increment)****tie note:joe and chris in sync
1.1..1/1... 0.1/0.1*****tie
bkwd
1.0..0/1... 1/0 Same edge event (joe decrement, chris no) ****chris wins note:joe and chris out of sync by 1
0.9..0/1...0.9/-0.1*****chris wins
0.5..0/1...0.5/-0.5*****tie.
0.1..0/1....0.1/-0.9*****joe wins
0.0..-1/0....1.0/0 New edge event(joe and chris decrement) ******chris wins
-0.5..-1/0...0.5/-.5*****tie
-.9...-1/0....0.1/-.9*****joe wins
fwd
-.5... -1/0...0.5/-.5*****tie
0.0...0/0....0/0 Same edge event(joe increment,chris no) ***tie note: back in sync here
0.5...0/0.... 0/0********tie

Quote:

The term hysteresis seems perfectly appropriate to me.
Sort of... If joe and I are in sync going up, I will lag going down. But at each transition, I will have zero error. This is not typical of a hysteresis band which has either plus or minus error equal to half the band.

Quote:

Yes, of course the values should be the same for a given position, no matter which direction one gets there from. I don't know what example you want to see countered.
This type of comment doesn't help.. please refer to a flawed statement in my logic as you did above. I have corrected the table...and I see no reason to adopt joes algorithm since it is a less accurate predictor in position when an event occurs. At the time an event occurs, the best you can do is have zero error at that time... which is what my algorithm does. Anything better than this must rely on some future assumed behavior, e.g. moving to an angle where joe's error is zero and staying there. If all angles are equally likely, then mine would be the optimal estimator at the time the estimate is updated.

Here is another analogy: A climber must report his position to base camp as either (ground or top). The climber reaches the top of a mountain and reports (top) to base camp. He then turns around and takes one step down and then updates his position to base camp. What is his best estimate? Alan/joe might say..of course... he must report a ground position. I say no... he has knowledge that he is at the top on his last report and he that he is still there... so his best estimate must be his last reported position which is top.

vamfun 26-04-2010 03:22

Re: Unexpected results from Encoder::GetRate()
 
Quote:

Originally Posted by vamfun (Post 957679)

This type of comment doesn't help.. please refer to a flawed statement in my logic as you did above. I have corrected the table...and I see no reason to adopt joes algorithm since it is a less accurate predictor in position when an event occurs. At the time an event occurs, the best you can do is have zero error at that time... which is what my algorithm does. Anything better than this must rely on some future assumed behavior, e.g. moving to an angle where joe's error is zero and staying there. If all angles are equally likely, then mine would be the optimal estimator at the time the estimate is updated.

Ok, allow me Alan. The flaw in the logic is what happens between events. I finally put my controls hat on instead of my optimal estimation hat. The added one unit of hysteresis with my algorithm does cause major headaches when trying to do closed loop feedback control of position. This is what was bothering Alan and Joe. If I had to control position, I would certainly choose Joe's algorithm since one can control to a sharp edge without phase lag. Although it is accurate, my algorithm creates a control dead zone with a width of + or -1 precision unit centered on the last event. That is a big price to pay for the improved rate noise from an oscillating edge.

So Joe has reached a compromise position by providing a GetDistance() that is control friendly but sensitive to oscillating edges and a GetRate() that is insensitive to oscillating edges.

I still need to study Kevin's solution since it appears to have the hysteresis in it.... yet Alan found it acceptable for his control problem. Perhaps Alan can describe what type of control they were doing at that time.

jhersh 26-04-2010 14:14

Re: Unexpected results from Encoder::GetRate()
 
Quote:

Originally Posted by vamfun (Post 957313)
Your scheme and mine will both have 1 count ambiguity...it just occurs at different times. I am interested in the best estimate of angle not just the count.
...
Error = true - encoder

So if we are oscillating in a band about the 1 deg edge [.9 to 1.1], my algorithm will give a better estimate of angle position on reversal and we are the same going forward past 1.

Aside from the fact that your algorithm has a different value at the same position depending on the direction of approach, I must also point out that the mapping of "true to encoder" is arbitrary and is chosen to optimize for accuracy. What I mean by this is you have chosen that the code "1" represents true [1 .. 2) where as I would argue that the code "1" represents true [0.5 .. 1.5). Hence my algorithm is more accurate than yours given that definition.

Quote:

Originally Posted by vamfun (Post 957313)
We have two events.... crossing same edge in forward and reverse directions.

Again, I contend that the definition of speed is distance per time. Distance is the difference between two positions. If the encoder reverses directions, then the only thing I know about the distance is that it is somewhere between (0 .. 2) counts of the encoder. I effectively have no (known) distance. How, then, can I claim to compute a speed with no distance?

Therefore, I say again that I do not have two events... I have one. As such, I do not report an invalid rate. It is not a patch to the algorithm, it is fundamentally accurate and required.

-Joe

jhersh 26-04-2010 14:25

Re: Unexpected results from Encoder::GetRate()
 
Quote:

Originally Posted by vamfun (Post 957679)
Here is another analogy: A climber must report his position to base camp as either (ground or top). The climber reaches the top of a mountain and reports (top) to base camp. He then turns around and takes one step down and then updates his position to base camp. What is his best estimate? Alan/joe might say..of course... he must report a ground position. I say no... he has knowledge that he is at the top on his last report and he that he is still there... so his best estimate must be his last reported position which is top.

Then I would say that my encoder ticks halfway up the mountain... anywhere above half way, and I am at the top (best estimate given 2 choices); anywhere below, and I'm at the ground.

Your algorithm would say ground when starting, then after crossing half way, you are at the top... then you come back down all the way to the ground, and you still report that you are at the TOP!

-Joe

jhersh 26-04-2010 14:30

Re: Unexpected results from Encoder::GetRate()
 
Quote:

Originally Posted by vamfun (Post 957974)
Although it is accurate, my algorithm creates a control dead zone with a width of + or -1 precision unit centered on the last event. That is a big price to pay for the improved rate noise from an oscillating edge.

How can you call it accurate and then describe how it is inaccurate?

See post 58.

Quote:

Originally Posted by vamfun (Post 957974)
So Joe has reached a compromise position by providing a GetDistance() that is control friendly but sensitive to oscillating edges and a GetRate() that is insensitive to oscillating edges.

What did I compromise? It simply doesn't report invalid measurements.

-Joe

Alan Anderson 26-04-2010 15:12

Re: Unexpected results from Encoder::GetRate()
 
Joe figured out what the disconnect was.

A proper quadrature decoder has a sawtooth-shaped error. This is typical of any digital measurement of a continuous value. Usually, one chooses the interpretation of the actual value to be between the transitions rather than right at them. This places the "zero error" level midway up the sawtooth, yielding a quantization error of +/- half the precision. The hysterical scheme :) instead puts the "zero error" level at the bottom of the sawtooth when traveling in one direction, and at the top when traveling in the other. The quantization error is either between 0 and 1, or between 0 and -1. Such a scheme strikes me as less desireable in every way but one -- that one way being ease of implementation when the only tool is an inflexible edge detector.

Any scheme with a one-count lag when changing direction can not give the same answer at both the beginning and the end of a round trip. If it says you're at the bottom of the mountain when you start, and you go far enough for it to say you're at the top, it will still say you're at the top after you return to the bottom. Trying to measure the position at the transition is always problematic. Once you choose which side of the discontinuity you want to compare things on, the advantages of each scheme become much more clear...and I see no obvious advantages to the scheme with the lag on direction reversal.


All times are GMT -5. The time now is 12:29.

Powered by vBulletin® Version 3.6.4
Copyright ©2000 - 2017, Jelsoft Enterprises Ltd.
Copyright © Chief Delphi