Hi I want to plot a rocket trajectory and it gives me this error: float() argument must be a string or a number, not 'function'. I want to plot the whole trajectory of a rocket that is losing mass to gain thrust. When the fuel ends, it describes a parabolic trajectory. Data of the problem can be changed. Those are the values I put, where mo is the initial mass of the rocket, q is the flow of gasses (how mass changes over time), g is gravitational acceleration, xo is the initia position, and t is time.
My code is:
import math
import numpy as np
import matplotlib.pyplot as plt
%matplotlib inline
Data:
mo = 1500
q = 2.5
u = 6000
vo = 0
g = 9.8
x0 = 0
t = np.arange(0,1001)
t
velocity ecuation:
def v(t):
return vo + u*(math.log(mo/(mo-q*t))-g*t)
Position ecuation:
def x(t):
return x0 + vo*t - 0.5*g*t^2 + u*t*math.log(mo) + (u/q)*((mo - q*t)*math.log(mo - q*t) + q*t - mo*math.log(mo))
for t in (0,100):
plt.plot(x,t)
plt.grid()
Thanks for helping me, I really appreciate it.
There are four problems.
you need to call a function, not state it, x(t).
Don't use math when working with arrays. Instead use numpy.
A power in python is written as **, not ^.
Don't use negative values inside of logarithms.
The correct code may then look like:
import numpy as np
import matplotlib.pyplot as plt
mo = 1500
q = 2.5
u = 6000
vo = 0
g = 9.8
x0 = 0
t = np.arange(0,int(1500/2.5))
def v(t):
return vo + u*(np.log(mo/(mo-q*t))-g*t)
def x(t):
return x0 + vo*t - 0.5*g*t**2 + u*t*np.log(mo) + \
(u/q)*((mo - q*t)*np.log(mo - q*t) + q*t - mo*np.log(mo))
plt.plot(x(t),t)
plt.grid()
plt.show()
producing
It should be
plt.plot(x(t), t)
instead of
plt.plot(x, t)
What you're doing above is treating each (x,y) as a set of data. This isn't correct, since it's rather the collection of ((0, x(0)), (1, x(1))...) that is your set of data. A readable way is to have an array for your x-axis and y-axis:
x_ = np.arange(0,100)
y_ = x(x_) # available in newer versions of numpy.
plt.plot(x_, y_)
Related
I'm working on this code that requires the use of elliptic integrals to solve an equation as a function of time. Most of the code is pretty straight forward but it runs into an error on the final equation containing the elliptic integrals, reading "cannot create mpf from array". Not quite sure if there is an easy fix but any insight would be greatly appreciated. The code can be found below:
import matplotlib.pyplot as plt
import numpy as np
from scipy import integrate
from mpmath import *
G = 6.6743*10**(-11) #Gravitational Constant
M = 10*(1.988*10**30) #Mass of the Black Hole (kg)
m = 1*(1.988*10**30) #Mass of the Companion Star (kg)
Mt = M + m #Total Mass(kg)
q = m/M #Mass Ratio
c = 2.99792458*10**8 #Speed of Light (m/s)
Period = 10 #Orbital Period (Days)
P = Period*86400 #Orbital Period (Seconds)
phi = 0.01*(np.pi/(180)) #Inclination from Line-of-Sight
t0 = Period/2 #Pulse Mid-Point
a = ((P**2*G*(Mt))/(4*np.pi**2))**(1/3) #Semi-Major Axis
omega = ((G*(m + M))/a**3)**0.5 #Angular Velocity
vtran = a*omega #Transverse Velocity
Rs = (2*G*M)/c**2 #Schwarzschild Radius
Rein = (2*Rs*a)**0.5 #Einstein Radius
te = (Rein/vtran)/86400 #Einstein Time
u0 = (a/Rein)*phi #Closest Angular Approach
pstar = ((1*(6.957*10**8))/Rein)
t = np.linspace(0,P,2500000) #Time Vector
u = ((u0**2)+((((t/86400)-t0)/te))**2)**0.5 #Angular Separation
n = ((4*u*pstar)/(u + pstar)**2)
k = ((4*n)/(4 + (u - pstar)**2))**0.5
Amp = (1/(2*(np.pi)))*(((((u+pstar)/(pstar**2))*np.sqrt(4+(u-pstar)**2)*ellipe(k**2))-(((u-pstar)/(pstar**2))*(((8+u**2-pstar**2)/(np.sqrt(4+(u-pstar)**2)))*ellipk(k**2)))+(((4*(u-pstar)**2)/(pstar**2*(u+pstar)))*(((1+pstar**2)/(np.sqrt(4+(u-pstar)**2)))*ellippi(n,k**2)))))
The problem is specifically with mpmath.ellipe() and mpmath.ellipk() and mpath.ellippi().
The docs are here:
https://mpmath.org/doc/current/functions/elliptic.html#ellipe
(and similarly for ellipk and ellippi).
But in summary, as the comment has pointed out, mpmath.ellipe(*args)
Called with a single argument m, evaluates the Legendre complete elliptic integral of the second kind, E(m)
You have passed in a list.
I keep getting error messages such as invalid syntax, or something is not defined.
here I defined the dependencies
import math #Basic math library
import numpy as np #Numpy -> tools for working with arrays
import matplotlib.pyplot as plt #Matplotlib -> tools for plotting
here I defined the constants
#CONSTANTS
pi = math.pi
omega_n = 30
xi = 0.05
beta = 0.1
here I defined the functions
O = (1/((1-beta**2)**2 + (2*xi*beta)**2)) #Capital Omega defined above
omega_d = omega_n*np.sqrt(1-xi**2) #Damped natural frequency
A = (2*xi*beta*np.cos(omega_n*t)*math.e**(-xi* omega_n* t)
C = 2*omega_n*(xi**2)*beta*math.e**(-xi*omega_n*t)
D = (1-beta**2)*np.sin(omega_d*t)
E = -2*xi*beta*np.cos(omega_d*t)
tmax = 60 #(sec) The max time
delta_t = 0.001 #(sec) The timestep
nPoints = tmax/delta_t #Number of equally spaced data points
t = np.linspace(0,tmax, int(nPoints)) # Time vector
ut = O* (A + omega_d + C) #Transientresponse
us = O* (D + E) #Steady-state response
rt= ut + us
plotting
#Plotting
fig = plt.figure()
axes = fig.add_axes([0.1,0.1,2,1.5])
axes.plot(t,rt,label='Respond ratio of a damped system')
axes.set_xlim([0,tmax])
axes.set_xlabel('Time (sec)')
axes.set_ylabel('Respond ratio')
axes.set_title('Respond ratio-time history')
axes.grid()
axes.legend()
plt.show()
There are several errors here. First, you're missing a bracket in this line:
A = (2*xi*beta*np.cos(omega_n*t)*math.e**(-xi* omega_n* t))
Then you're using the variable t in the same line but you haven't defined t yet. You're defining t after this line. Similarly, you need to define tmax/delta_t before using them in nPoints
I am trying to simulate the colour changes within the solution of the Belousov-Zhabotinsky reaction by solving ODEs and to produce a graph which will demonstrate oscillations using odeint.
I have an error message 'AxisError: axis -1 is out of bounds for array of dimension 0' and I do not know why this is happening, I am very new to Python and I am struggling.
import numpy as np
import matplotlib.pyplot as plt
from scipy.integrate import odeint
# Dimensionless parameters
c1 = 10
c2 = 0.15
c3 = 0.005
c4 = 0.02
#pack 3 initial conditions with state of x,y,z into y0
y0 = [1,0,0]
k = 1
def Oregonator (t,Y):
x = Y[0]
y = Y[1]
z = Y[2]
dxdt = c1 + c2*x - x - x*y**2
dydt = (x + x*y**2 - y)/c3
dzdt = (y-z)/c4
return [dxdt,dydt,dzdt]
t = np.linspace(0, 10,100)
Y = odeint(y0,t,Oregonator)
plt.plot(t,Y)
plt.xlabel('time')
plt.ylabel('other side')
plt.show()
I am using Spyder to process the Python code.
I appreciate any help that can be given, thank you.
You need to fix the call to odeint to be conform with its documentation, here at least
Y = odeint(Oregonator,y0,t, tfirst=True)
And you need to equalize the indentation in the Oregonator function.
Then you get an oscillating graph.
Also, increase the display resolution, 100 points in an interval with over 100 oscillations is much too few. As there are sharp peaks you want at least 20 points per oscillation, better more, thus
t = np.linspace(0, 10,5000)
So what I'm doing is creating sine waves with normally distributed amplitudes and frequencies - within given ranges. Eg 5V with 2-10Hz. So my attempt at this is to get my function with the given amplitude and frequency and then run it till the first turning point. From there I calculate the next function and add the y value of the previous functions turning point (as a shift) so it starts from that point. My problem is for some of the function changes I get straight lines rather than curves. If someone could tell me where I'm going wrong I'd appreciate it. Just to note, I use 8ms increments for each value to be plotted.
import numpy as np
import matplotlib.pyplot as plt
import scipy.stats as stats
import serial
newlist = np.zeros(1)
timesnew = np.zeros(1)
volts = []
def main(amp, lowerFreq, upperFreq, time, incr):
#Creates graph and saves it in newlist and timesnew
amt = np.int(time / incr)
list = []
timels = [] # np.zeros(amt+amt)
curtime = 0
loweramp = -amp
mu, sigma = 0, 1
ybefore = 0
rand = stats.truncnorm((loweramp - mu) / sigma, (amp - mu) / sigma, loc=mu, scale=sigma)
freqr = stats.truncnorm((lowerFreq - mu) / sigma, (upperFreq - mu) / sigma, loc=mu, scale=sigma)
i = 0
while i < amt:
# get amp
thisAmp = rand.rvs()
angleFreq = 2 * np.pi * freqr.rvs()
xtp = np.arccos(0) / angleFreq #x value of turning point
yval = thisAmp * np.sin(angleFreq * xtp)
# check that yvalue(voltage) is okay to be used - is within +-amp range
while not loweramp <= yval + ybefore <= amp:
thisAmp = rand.rvs()
angleFreq = 2 * np.pi * freqr.rvs()
xtp = np.arccos(0) / angleFreq
yval = thisAmp * np.sin(angleFreq * xtp)
# now add values to list
t = 0
while t <= xtp:
ynow = thisAmp * np.sin(angleFreq * t) + ybefore
# print ynow
list.append(ynow)
curtime += incr
timels.append(curtime)
t += incr
i += 1
print i
ybefore = ynow
newlist = np.asarray(list)
timesnew = np.asarray(timels)
#a = np.column_stack((timesnew, newlist))
np.savetxt("C://foo.csv", a, delimiter=";", fmt='%.10f')
addvolts()
plt.plot(timels,list)
plt.show()
if __name__ == "__main__":
main(5, 1, 2, 25, 0.00008)
EDIT:
Basically here is the problem, after the turning point the function does not seem to be sinusodial (the line seems to be linear) and I can't understand why or atleast how to get the functions to end up being more "curvy" and not "sharp" at the turning points.
I'm thinking maybe the function changes shouldn't be too different from the previous function but then I would lose the randomness. I'd like it to "look better" but I'm not sure how to achieve that unless I ran the frequencies in order. I'm trying to emulate a "whitenoise file" that was given to me as part of a job that I applied for - the whitenoise would be sent to a digital to analog converter and be used to test equipment. Obviously I didn't get the position BUT for knowledge purposes I want to complete this.
Here is the graph of the whitenoise file I was given - 700 mins long:
From the last pic the difference between mine and the given can be seen, I think I'm going to attempt to run each function for an entire period rather than a single turning point.
True white noise is completely random, so trying to emulate white noise using some kind of function already is contradictory.
If the file you have is really supposed to be white noise than it has already undergone some kind of filtering. You can of course do the same in your program: Create some truely random numbers and use a filter function to obtain some "smoothing" effect.
For example you can use a Hann filter and colvolute the random noise with the filter. This is shown below.
import numpy as np
import scipy.signal
import matplotlib.pyplot as plt
y = np.random.rand(1600)
win = scipy.signal.hann(15)
filtered = scipy.signal.convolve(y, win, mode='same') / sum(win)
fig, (ax, ax2) = plt.subplots(nrows=2, sharex=True, sharey=True)
ax.plot(y, linestyle="-", marker=".", lw=0.3, markersize=1, color="r", alpha=0.5)
ax.set_title("random noise")
ax2.plot(y, linestyle="", marker=".", color="r", markersize=1)
ax2.plot(filtered)
ax2.set_title("filterred")
plt.show()
You might want to zoom in to better see the effect or use different parameter for the filter window.
I am trying to graph a projectile through time at various angles. The angles range from 25 to 60 and each initial angle should have its own line on the graph. The formula for "the total time the projectile is in the air" is the formula for t. I am not sure how this total time comes into play, because I am supposed to graph the projectile at various times with various initial angles. I imagine that I would need x,x1,x2,x3,x4,x5 and the y equivalents in order to graph all six of the various angles. But I am confused on what to do about the time spent.
import numpy as np
import matplotlib.pylab as plot
#initialize variables
#velocity, gravity
v = 30
g = -9.8
#increment theta 25 to 60 then find t, x, y
#define x and y as arrays
theta = np.arange(25,65,5)
t = ((2 * v) * np.sin(theta)) / g #the total time projectile remains in the #air
t1 = np.array(t) #why are some negative
x = ((v * t1) * np.cos(theta))
y = ((v * t1) * np.sin(theta)) - ((0.5 * g) * (t ** 2))
plot.plot(x,y)
plot.show()
First of all g is positive! After fixing that, let's see some equations:
You know this already, but lets take a second and discuss something. What do you need to know in order to get the trajectory of a particle?
Initial velocity and angle, right? The question is: find the position of the particle after some time given that initial velocity is v=something and theta=something. Initial is important! That's the time when we start our experiment. So time is continuous parameter! You don't need the time of flight.
One more thing: Angles can't just be written as 60, 45, etc, python needs something else in order to work, so you need to write them in numerical terms, (0,90) = (0,pi/2).
Let's see the code:
import numpy as np
import matplotlib.pylab as plot
import math as m
#initialize variables
#velocity, gravity
v = 30
g = 9.8
#increment theta 25 to 60 then find t, x, y
#define x and y as arrays
theta = np.arange(m.pi/6, m.pi/3, m.pi/36)
t = np.linspace(0, 5, num=100) # Set time as 'continous' parameter.
for i in theta: # Calculate trajectory for every angle
x1 = []
y1 = []
for k in t:
x = ((v*k)*np.cos(i)) # get positions at every point in time
y = ((v*k)*np.sin(i))-((0.5*g)*(k**2))
x1.append(x)
y1.append(y)
p = [i for i, j in enumerate(y1) if j < 0] # Don't fall through the floor
for i in sorted(p, reverse = True):
del x1[i]
del y1[i]
plot.plot(x1, y1) # Plot for every angle
plot.show() # And show on one graphic
You are making a number of mistakes.
Firstly, less of a mistake, but matplotlib.pylab is supposedly used to access matplotlib.pyplot and numpy together (for a more matlab-like experience), I think it's more suggested to use matplotlib.pyplot as plt in scripts (see also this Q&A).
Secondly, your angles are in degrees, but math functions by default expect radians. You have to convert your angles to radians before passing them to the trigonometric functions.
Thirdly, your current code sets t1 to have a single time point for every angle. This is not what you need: you need to compute the maximum time t for every angle (which you did in t), then for each angle create a time vector from 0 to t for plotting!
Lastly, you need to use the same plotting time vector in both terms of y, since that's the solution to your mechanics problem:
y(t) = v_{0y}*t - g/2*t^2
This assumes that g is positive, which is again wrong in your code. Unless you set the y axis to point downwards, but the word "projectile" makes me think this is not the case.
So here's what I'd do:
import numpy as np
import matplotlib.pyplot as plt
#initialize variables
#velocity, gravity
v = 30
g = 9.81 #improved g to standard precision, set it to positive
#increment theta 25 to 60 then find t, x, y
#define x and y as arrays
theta = np.arange(25,65,5)[None,:]/180.0*np.pi #convert to radians, watch out for modulo division
plt.figure()
tmax = ((2 * v) * np.sin(theta)) / g
timemat = tmax*np.linspace(0,1,100)[:,None] #create time vectors for each angle
x = ((v * timemat) * np.cos(theta))
y = ((v * timemat) * np.sin(theta)) - ((0.5 * g) * (timemat ** 2))
plt.plot(x,y) #plot each dataset: columns of x and columns of y
plt.ylim([0,35])
plot.show()
I made use of the fact that plt.plot will plot the columns of two matrix inputs versus each other, so no loop over angles is necessary. I also used [None,:] and [:,None] to turn 1d numpy arrays to 2d row and column vectors, respectively. By multiplying a row vector and a column vector, array broadcasting ensures that the resulting matrix behaves the way we want it (i.e. each column of timemat goes from 0 to the corresponding tmax in 100 steps)
Result: