Issue with a.any() or a.all() when trying to simulate a motion using a while loop

Question:

I am simulating a motion and when using a while loop, I am getting the following error "The truth value of an array with more than one element is ambiguous. Use a.any() or a.all()". The objective is to run the while loop to the point when the accelaration is 0… Any ideas of what might’ve gone wrong?


R = 0.025
B = 0.15
L = 0.2
m = 0.05
F = 1

def a(v):
    F_m = (B**2*L**2*v)/R
    sum_F = F - F_m
    aks = sum_F /m
    return aks

v = array([0,0])
t = linspace(0,11,1000)
speed = [v[0]]

dt = 0.001

while a(v)>0:
    v = v + a(v)*dt
    t = t + dt
    speed.append(v[0])
    

   
plot(t,speed, "r")
xlabel("t/s")
ylabel("v m/s")
grid()
show()```
Asked By: Aristarchus_

||

Answers:

There’s a few things here.

For those playing along at home, you’ll need to include some imports at the top:

from matplotlib.pyplot import *
from numpy import *

The specific error message that you’re getting is because v is an array of values, so a(v) is an array, and a(v) > 0 is also an array.

The while condition requires a single (scalar) value. As the error message suggests, you could change it to:

while (a(v) > 0).any():          # or .all()

That works but it’s not particularly scientifically rigorous. If your axes are perpendicular then you could use a Euclidean measure to combine the values:

while linalg.norm(a(v)) > 0:     # sqrt( sum(a(v)**2) )

This will get you into new trouble, because although the velocity gets very small, it will never actually get to zero, so your program will run forever! More useful would be to cut it off when it gets fairly small:

while linalg.norm(a(v)) > 0.1:  # for example

So, now the loop runs but we hit a new problem trying to plot:

ValueError: x and y must have same first dimension, but have shapes (1000,) and (7839,)

What’s going on? It is trying to plot t versus speed.

speed is the array built up in your while loop, which has length 7839 because that’s how many iterations it took for a(v) to drop below 0.1.

t is an array of length 1000 whose value isn’t actually used! You initialise it using linspace to contain 1000 values spread equally between 0 and 11, then increment every value in it by dt each time the loop runs, but then never use the value.

Let’s set that aside for the moment and add some new variables current_time and times which we’ll use in the loop:

current_time = 0
times = []
while linalg.norm(a(v)) > 0.1:
    v = v + a(v)*dt
    speed.append(v[0])
    current_time = current_time + dt
    times.append(current_time)

… and then plot speed against our new times array, which are constructed side by side so they have the same length.
speed versus times

So, that works. But we still have this t variable from before which isn’t being used. Presumably it contains a list of times at which we’d like to sample the velocity, so let’s get rid of current_time and times and use the values in t:

prev_time = 0
for time in t:
    dt = time - prev_time
    v = v + a(v)*dt
    speed.append(v[0])
    prev_time = time

Now we can plot speed against t because they have the same length:
speed versus t

Essentially the same plot as before, but now it is sampling using the times in t rather than "for as long as it takes for a(v) to get sufficiently small". We can verify this by reducing the number of samples, e.g.

t = linspace(0,11,11)

speed versus t with reduced samples

Answered By: motto
Categories: questions Tags: ,
Answers are sorted by their score. The answer accepted by the question owner as the best is marked with
at the top-right corner.