Smoothly make a number approach zero
I have 开发者_JAVA技巧a floating point value X which is animated. When in rest it's at zero, but at times an outside source may change it to somewhere between -1 and 1.
If that happens I want it to go smoothly back to 0. I currently do something like
addToXspeed(-x * FACTOR); // below is out of my control function addToXspeed(bla) { xspeed += bla; x += xspeed; }
every step in the animation, but that only causes X to oscillate. I want it to rest on 0 however.
(I've explained the problem in abstracts. The specific thing I'm trying to do is make a jumping game character balance himself upright in the air by applying rotational force)
Interesting problem. What you are asking for is the stabilization of the following discrete-time linear system:
| x(t+1)| = | 1 dt | | x(t)| + | 0 | u(t)
|xspeed(t+1)| | 0 1 | |xspeed(t)| | 1 |
where dt
is the sampling time and u(t)
is the quantity you addToXspeed()
. (Further, the system is subject to random disturbances on the first variable x
, which I don't show in the equation above.) Now if you "set the control input equal to a linear feedback of the state", i.e.
u(t) = [a b] | x(t)| = a*x(t) + b*xspeed(t)
|xspeed(t)|
then the "closed-loop" system becomes
| x(t+1)| = | 1 dt | | x(t)|
|xspeed(t+1)| | a b+1 | |xspeed(t)|
Now, in order to obtain "asymptotic stability" of the system, we stipulate that the eigenvalues of the closed-loop matrix are placed "inside the complex unit circle", and we do this by tuning a
and b
. We place the eigenvalues, say, at 0.5.
Therefore the characteristic polynomial of the closed-loop matrix, which is
(s - 1)(s - (b+1)) - a*dt = s^2 -(2+b)*s + (b+1-a*dt)
should equal
(s - 0.5)^2 = s^2 - s + 0.25
This is easily attained if we choose
b = -1 a = -0.25/dt
or
u(t) = a*x(t) + b*xspeed(t) = -(0.25/dt)*x(t) - xspeed(t)
addToXspeed(u(t))
which is more or less what appears in your own answer
targetxspeed = -x * FACTOR;
addToXspeed(targetxspeed - xspeed);
where, if we are asked to place the eigenvalues at 0.5, we should set FACTOR = (0.25/dt)
.
x = x*FACTOR
This should do the trick when factor is between 0 and 1.
The lower the factor the quicker you'll go to 0.
Why don't you define a fixed step to be decremented from x
?
You just have to be sure to make it small enough so that the said person doesn't seem to be traveling at small bursts at a time, but not small enough that she doesn't move at a perceived rate.
Writing the question oftens results in realising the answer.
targetxspeed = -x * FACTOR; addToXspeed(targetxspeed - xspeed); // below is out of my control function addToXspeed(bla) { xspeed += bla; x += xspeed; }
So simple too
If you want to scale it but can only add, then you have to figure out which value to add in order to get the desired scaling:
Let's say x = 0.543
, and we want to cause it to rapidly go towards 0, i.e. by dropping it by 95%.
We want to do:
scaled_x = x * (1.0 - 0.95);
This would leave x at 0.543 * 0.05, or 0.02715
. The difference between this value and the original is then what you need to add to get this value:
delta = scaled_x - x;
This would make delta equal -0,51585
, which is what you need to add to simulate a scaling by 5%.
精彩评论