1

I am trying to model the rotation of a coin. One full rotation is modeled as a change of one parameter from 1 to -1 back to 1, 1 being the straight coin and -1 being the coin upside down. The coin should decelerate progressively. The arguments of the function are the number of half-turns that the coin is meant to make before stopping, the number of frames the movement should take, and the initial speed the coin is rotating at (half rotations per frame).

First I calculate the value of the deceleration with the formula 2*(displacement - initial_v*time) / time*time. Then I create a list with the distance values for each frame. Here something goes wrong since the values go really really high. (I am omitting the part of the code which restricts the position values between 1 and -1 since something goes wrong before getting to that point).

def animate_rotation(n_half_turns, n_frames, speed):
    """
    First I calculate the appropriate deceleration given distance d, initial velocity t_0, and time t
    Then I find the position value per frame by calculating the distance given the found acceleration
    """

    displacement = n_half_turns   # every half turn is a movement from 1 to -1, i.e. 2 units
    v = speed                   # this is the initial speed, i.e. n of half turns per frame
    time = n_frames
    position = 1

    deceleration = 2 * (displacement - v * time) / time*time

    #distance traveled from initial position for each frame
    frame_distance = []
    for i in range(n_frames):
        position += v
        frame_distance.append(position)
        v += deceleration

    #the rest of the code transforms the values so that they are between 1 and -1. I eliminated this part because things go wrong before it.

animate_rotation(1, 10, 1)

I would like the new_dist list to get to the n_half_turns value in n_frames number of frames (the length of new_dist list) starting from a certain speed and decelerating appropriately. What I get when running the code however is more like a parable: first the position increases, then it goes beyond n_half_turns, and then goes back to it. The new_dist list is:

[1, 1.8200000000000003, 2.4600000000000004, 2.9200000000000004, 3.2, 3.3000000000000007, 3.2200000000000006, 2.960000000000001, 2.520000000000001, 1.9000000000000012]
whatamess
  • 243
  • 2
  • 12

1 Answers1

0

Probably a partial answer (there may be other problems) but at least this formula is wrong:

2 * (displacement - v * time) / time*time

because division has precedence over multiplication, so it's equivalent to

2 * (displacement - v * time)

when you wanted it to be:

2 * (displacement - v * time) / (time*time)

Quick demo:

>>> 1/4*4
1.0
>>> 1/(4*4)
0.0625

Also, more a physics thing, in your loop:

for i in range(n_frames):
    position += position * v
    frame_distance.append(position)
    v += v * deceleration

doesn't make sense. Each iteration is the elapsing time if I understand correctly. So you apply the speed to the position by just adding the speed, not the product of the speed with the position, which explains why your positions skyrocket.

Same goes for the speed variation. My proposal:

for i in range(n_frames):
    position += v
    frame_distance.append(position)
    v += deceleration

with all those fixes I get a good looking set of values, not sure they're OK but the look better:

[1.0, 1.0984, 1.1952, 1.2904, 1.384, 1.476, 1.5664, 1.6552, 1.7424, 1.8279999999999998, 1.912, 1.9943999999999997, 2.0751999999999997, 2.1544, 2.2319999999999998, 2.308, 2.3823999999999996, 2.4551999999999996, 2.5263999999999993, 2.595999999999999, 2.6639999999999993, 2.730399999999999, 2.795199999999999, 2.8583999999999987, 2.9199999999999986, 2.9799999999999986, 3.0383999999999984, 3.0951999999999984, 3.1503999999999985, 3.2039999999999984, 3.2559999999999985, 3.3063999999999982, 3.355199999999998, 3.4023999999999983, 3.447999999999998, 3.491999999999998, 3.534399999999998, 3.575199999999998, 3.614399999999998, 3.651999999999998, 3.687999999999998, 3.7223999999999977, 3.7551999999999977, 3.7863999999999978, 3.8159999999999976, 3.8439999999999976, 3.8703999999999974, 3.8951999999999973, 3.918399999999997, 3.9399999999999973, 3.959999999999997, 3.9783999999999966, 3.9951999999999965, 4.010399999999997, 4.023999999999997, 4.035999999999996, 4.046399999999997, 4.055199999999996, 4.062399999999997, 4.067999999999996, 4.071999999999996, 4.074399999999995, 4.075199999999995, 4.074399999999995, 4.071999999999996, 4.067999999999996, 4.062399999999995, 4.055199999999996, 4.046399999999995, 4.035999999999996, 4.023999999999996, 4.010399999999995, 3.9951999999999948, 3.978399999999995, 3.959999999999995, 3.9399999999999946, 3.9183999999999943, 3.8951999999999942, 3.8703999999999943, 3.843999999999994, 3.815999999999994, 3.786399999999994, 3.755199999999994, 3.722399999999994, 3.687999999999994, 3.651999999999994, 3.614399999999994, 3.575199999999994, 3.534399999999994, 3.4919999999999938, 3.4479999999999937, 3.402399999999994, 3.3551999999999937, 3.306399999999994, 3.2559999999999936, 3.2039999999999935, 3.1503999999999936, 3.0951999999999935, 3.0383999999999936, 2.9799999999999933]
Jean-François Fabre
  • 137,073
  • 23
  • 153
  • 219
  • Oh right, that makes a lot of sense. The new_dist in the updated code still goes up to 6933.400093777868 though, where I would like it to go up to 2. – whatamess Mar 11 '17 at 21:12
  • `position += position * v` ? are you sure? it adds position*v to existing position. Don't you want to add elapsed time * speed to position? same goes for `v += v * deceleration` – Jean-François Fabre Mar 11 '17 at 21:15
  • `position += v` would make more sense, actually (not a physics expert, but I coded a few games). – Jean-François Fabre Mar 11 '17 at 21:16
  • Oh yes, it's definitely looking much better now. The edits make sense. It still does not behave as expected for some reason - in particular, the position gets beyond the intended number and then back to it. For instance, when running animate_rotation(1, 10, 0.5), the positions are [1.0, 1.42, 1.7599999999999998, 2.0199999999999996, 2.1999999999999993, 2.2999999999999994, 2.3199999999999994, 2.2599999999999993, 2.119999999999999, 1.899999999999999]. This seems more realistic than before, since it's a parable, but it's not what I meant it to be. – whatamess Mar 11 '17 at 21:29