views:

134

answers:

5

I have 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)

+1  A: 

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.

Thirler
I think that'll work, but I have the following problem: I can't really assign x, I can only call a function addToX(bla). Working on transforming the statement...
Bart van Heukelom
Actually I wrongly wrote down what happens. I edited my question.
Bart van Heukelom
A: 

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.

foliveira
A: 

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

Bart van Heukelom
A: 

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%.

unwind
+1  A: 

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).

Federico Ramponi
And now in programming-speak...
Clark Gaebel
Hihi, sorry I couldn't resist. Besides, I think that if you choose FACTOR too big you may actually _destabilize_ the system, i.e. the particle gets farther and farther from zero. And I also think that the oscillatory behavior of his previous policy can be explained in this framework...
Federico Ramponi
Wow...extensive. Next time I have something like this but more complex I'll go back and read this answer in depth :)
Bart van Heukelom