Calculating next y using previous y element using numpy - python

I want to calculate the speed of a vehicle, to plot a graph with time in seconds on x axis, and speed in km/h on y axis. To do that, I need to get the previous calculated y value.
Example: y[x] = y[x-1] * a
a = 0,11768
x = np.arange(0, 100, 1) # 0 to 100 seconds
y = a * y[x-1] ??
plt.plot(x, y)
plt.show()
Is that possible with numpy, or should I do a loop to iterate over all indexes?

v=v0+at Assuming your acceleration is constant and v0=0there's no need to do what you want simply:
import numpy as np
import matplotlib.pyplot as plt
a = 0.11768 #is it in m/s^2? I've used m/s^2...
v=[] #velocity at a given time ‹
x = np.arange(0, 100, 1) # 0 to 100 seconds
for i in x: # ‹
v.append(i*a) #read it as a*t, in fact is t...use i*a*3.6 if you want km/h ‹
fig = plt.figure()
ax = fig.add_subplot(111)
ax.plot(x,v,)
plt.plot(x, v)
plt.ylabel(r'Velocity $(m/sec )$') #note if you want km/h use v.append(i*a*3.6) above
plt.xlabel(r'Time $(sec)$')
plt.show()
This is the result:
EDIT:
As suggest by Joe in his comment you should use v=a*x delating the lines marked with ‹in my code, for a more efficient way to do that!

Your calculation for y is wrong. Instead of multiplying the previous speed with the acceleration, you have to add the acceleration to that speed. An alternative way would be to multiply the acceleration with the time and add that to some initial speed. This way, you can use a simple list comprehension for y.
a = 0.11768 # acceleration (note the dot instead of comma!)
y0 = 0 # initial speed at time x = 0
X = numpy.arange(0, 100, 1)
Y = numpy.array([y0 + a * x for x in X])
When using Numpy, there's an even simpler way -- thanks to #JoeKington for pointing this out:
Y = y0 + a * X # multiplies each value of X with a and adds y0

I don't know if it's possible in numpy but I know how you can easily achieve it using pandas:
import pandas as pd
import numpy as np
a=0.11768
df = pd.DataFrame(np.arange(0, 100, 1),columns=['X'])
df['Y'] = a*df['X'].shift(1)

a = 0.11768
x = np.arange(0, 100, 1)
y = [1]
for i in range(1, len(x)-1):
y.append(a * y[i-1])

Related

Is there a more elegant way to apply complicated functions to meshgrid?

My goal is to plot the function $f(x,y) = 3^{\min\{x,2\}}t_0 y$
where $t_0$
is the smallest solution of $2t^x-3t-1=0$ (it's just a MWE; I didn't check the existence of the root(s). )
I did it. But in somehow an ugly way.
My approach is to apply the function element-wise. Here is my code:
import numpy as np
import matplotlib.pyplot as plt
from scipy.optimize import fsolve
def equ(t,*data): # 2t^x - 3t -1
x = data
return 2*(t ** x) - 3*t - 1
def t0(t): # call fslove to solve the equation
return fsolve(equ, 1.5, args=(t))[0] # 1.5 is randomly choosed
xx = np.linspace(1,3,50) # range of x
yy = np.linspace(1,3,50) # range of y
ff = [] # the value of f at each (x, y)
# compute the value of f element-wise
for x in xx:
for y in yy:
f = (3 ** np.minimum(x, 2)) * t0(x) * y
ff.append(f)
fv = np.split(np.array(ff), np.size(xx)) # split ff to make it conform with meshgrid
xv, yv = np.meshgrid(xx, yy)
plt.pcolormesh(xv, yv, fv)
plt.colorbar()
plt.show()
But I think the elegancy of numpy is to avoid writing loops manually and to manipulate lists as a whole. So, is there a more elegant way to do that?

I am getting two plots for one data set in python

I am working through example 8.1 titled Euler's Method from Mark Newman's book Computational Physics. I rewrote the example as a method with Numpy arrays but when I plot it I get two plots on the same figure not sure how to correct it. Also is there better way to convert my 2 1D arrays into 1 2D array to use for plotting in Matplotlib, thanks.
Newman's example :
from math import sin
from numpy import arange
from pylab import plot,xlabel,ylabel,show
def f(x,t):
return -x**3 + sin(t)
a = 0.0 # Start of the interval
b = 10.0 # End of the interval
N = 1000 # Number of steps
h = (b-a)/N # Size of a single step
x = 0.0 # Initial condition
tpoints = arange(a,b,h)
xpoints = []
for t in tpoints:
xpoints.append(x)
x += h*f(x,t)
plot(tpoints,xpoints)
xlabel("t")
ylabel("x(t)")
show()
My modifications:
from pylab import plot,show,xlabel,ylabel
from numpy import linspace,exp,sin,zeros,vstack,column_stack
def f(x,t):
return (-x**(3) + sin(t))
def Euler(f,x0,a,b):
N=1000
h = (b-a)/N
t = linspace(a,b,N)
x = zeros(N,float)
y = x0
for i in range(N):
x[i] = y
y += h*f(x[i],t[i])
return column_stack((t,x)) #vstack((t,x)).T
plot(Euler(f,0.0,0.0,10.0))
xlabel("t")
ylabel("x(t)")
show()
The reason you get two lines is that t as well as x are plotted against their index, instead of x plotted against t
I don't see why you'd want to stack the two arrays. Just keep then separate, which will also solve the problem of the two plots.
The following works fine.
import numpy as np
import matplotlib.pyplot as plt
f = lambda x,t: -x**3 + np.sin(t)
def Euler(f,x0,a,b):
N=1000
h = (b-a)/N
t = np.linspace(a,b,N)
x = np.zeros(N,float)
y = x0
for i in range(N):
x[i] = y
y += h*f(x[i],t[i])
return t,x
t,x = Euler(f,0.0,0.0,10.0)
plt.plot(t,x)
plt.xlabel("t")
plt.ylabel("x(t)")
plt.show()

ask for help for a sum (sigma) function

need help to calculate this:
so, the total number of y is equal to number of x, and each y is calculated with one x and several a.
My code list below, it gives the correct results for a0. what is a simple way to calculate this? maybe a different version can also verify the results.
Thanks a lot.
import numpy as np
import matplotlib.pyplot as plt
a = np.array([1,2,3,4],float) # here we can give several a
b = np.asarray(list(enumerate(a)))
x = np.linspace(0.0,1.0,10)
y1 = []
for r in x:
y1.append(np.exp(np.sum((1-r)**2*a*((2*b[:,0]+1)*r-1+r)*(r-1+r)**(b[:,0]-1))))
y1=np.asarray(y1)
You can write almost literally the same in numpy:
def f(x, a):
x, a = np.asanyarray(x), np.asanyarray(a)
x = x[:, None] # create new dimension to sum along
i = np.arange(len(a)) # create counter
return np.sum((1-x)**2 * a * ((2*i + 1) * x - (1-x)) * (x - (1-x))**(i-1), axis=-1)
As a side note: there are obvious algebraic simplifications you could take advantage of.

Smooth circular data

I have an array of data Y such that Y is a function of an independent variable X (another array).
The values in X vary from 0 to 360, with wraparound.
The values in Y vary from -180 to 180, also with wraparound.
(That is, these values are angles in degrees around a circle.)
Does anyone know of any function in Python (in numpy, scipy, etc.) capable of low-pass filtering my Y values as a function of X?
In case this is at all confusing, here's a plot of example data:
Say you start with
import numpy as np
x = np.linspace(0, 360, 360)
y = 5 * np.sin(x / 90. * 3.14) + np.random.randn(360)
plot(x, y, '+');
To perform a circular convolution, you can do the following:
yy = np.concatenate((y, y))
smoothed = np.convolve(np.array([1] * 5), yy)[5: len(x) + 5]
This uses, at each point, the cyclic average with the previous 5 points (inclusive). Of course, there are other ways of doing so.
>>> plot(x, smoothed)
Here is a solution using pandas to do a moving average. First unwrap the data (need to convert to radians and back), so there are no discontinuities (e.g., jump from 180 to -179). Then compute the moving average and finally convert back to wrapped data if desired. Also, check out this numpy cookbook recipe using np.convolve().
import numpy as np
import pandas as pd
# generate random data
X = pd.Series([(x + 5*np.random.random())%360 for x in range(-100, 600, 15)])
Y = pd.Series([(y + 5*np.random.random())%360 - 180 for y in range(-200, 500, 15)])
# 'unwrap' the angles so there is no wrap around
X1 = pd.Series(np.rad2deg(np.unwrap(np.deg2rad(Y))))
Y1 = pd.Series(np.rad2deg(np.unwrap(np.deg2rad(Y))))
# smooth the data with a moving average
# note: this is pandas 17.1, the api changed for version 18
X2 = pd.rolling_mean(X1, window=3)
Y2 = pd.rolling_mean(Y1, window=3)
# convert back to wrapped data if desired
X3 = X2 % 360
Y3 = (Y2 + 180)%360 - 180
You can use convolve2D from scipy.signal. Here is a function, which applies smoothing to a numpy array a. If a has more than one dimension smoothing is applied to the innermost (fastest) dimension.
import numpy as np
from scipy import signal
def cyclic_moving_av( a, n= 3, win_type= 'boxcar' ):
window= signal.get_window( win_type, n, fftbins=False ).reshape( (1,n) )
shp_a= a.shape
b= signal.convolve2d( a.reshape( ( np.prod( shp_a[:-1], dtype=int ), shp_a[-1] ) ),
window, boundary='wrap', mode='same' )
return ( b / np.sum( window ) ).reshape( shp_a )
For instance it can be used like
import matplotlib.pyplot as plt
x = np.linspace(0, 360, 360)
y1 = 5 * np.sin(x / 90. * 3.14) + 0.5 * np.random.randn(360)
y2 = 5 * np.cos(0.8 * x / 90. * 3.14) + 0.5 * np.random.randn(360)
y_av= cyclic_moving_av( np.stack((y1,y2)), n=10 ) #1
plt.plot(x, y1, '+')
plt.plot(x, y2, '+')
plt.plot(x, y_av[0])
plt.plot(x, y_av[1])
plt.show()
This results in
Line #1 is equivalent to
y_av[0]= cyclic_moving_av( y1, n=10 )
y_av[1]= cyclic_moving_av( y2, n=10 )
win_type= 'boxcar' results in averaging over neighbors with equal weights. See signal.get_window for other options.

Create a 2D array that is the product of two functions

I am working on a visualization and trying to create a 2D array that is the product of a normalized Gaussian function on the X axis and a normalized exponential function on the Y axis (using Python).
I would use NumPy for this. You can use np.meshgrid to create the (X, Y) axes and use NumPy's vectorized functions to create the function on these coordinates. The array f below is your two-dimensional array, here containing the product of exp(-X/4) and exp(-((Y-2)/1.5)**2). (Substitute your own normalized functions here.)
import matplotlib.pyplot as plt
import numpy as np
x = np.linspace(0,10,100)
y = np.linspace(0,5,100)
X, Y = np.meshgrid(x, y)
f = np.exp(-X/4.) * np.exp(-((Y-2)/1.5)**2)
fig = plt.figure()
ax = fig.add_subplot(111)
ax.imshow(f)
plt.show()
If you can't or don't want to use NumPy, you'll have to loop by hand and use conventional math functions:
import math
dx, dy = 0.1, 0.05
nx, ny = 101, 101
f = [[None]*nx for i in range(ny)]
for ix in range(nx):
x = xmin + dx*ix
for iy in range(ny):
y = ymin + dy*iy
f[iy][ix] = math.exp(-x/4.) * math.exp(-((y-2)/1.5)**2)
I would use numpy for this, because numpy makes it very simple to do what you want. If you can't use it, then something like the following should work:
import math
def gauss(x, mu=0.0, sigma=1.0):
return 1.0 / math.sqrt(2.0*math.pi*sigma**2) * math.exp(-0.5*(x-mu)**2/sigma**2)
def exponential(x, lam=1.0):
return lam * math.exp(-lam * x)
# X values from -10 to 10 with 0.01 step size
xvals = [x * 0.01 for x in range(-1000, 1001)]
# Y values from 0 to 10 with 0.01 step size
yvals = [y * 0.01 for y in range(0, 1001)]
# Calculate your function at the grid points
f = [[gauss(x)*exponential(y) for x in xvals] for y in yvals]

Categories

Resources