I am trying to create a program that solves the mass-spring-damper system using backward differentiating, the only problem is that I am running into an index error that I am not sure how to solve:
import numpy as np
import matplotlib.pyplot as plt
def MSD_Solver(m,b,K):
#input: m = mass, b = damping ratio, K = spring constant
#output: (t,x) time vs position
tinitial = 0
tfinal = 15
step = .005
t = np.linspace(tinitial,tfinal,step)
x = np.zeros_like(t)
x[0]=0
x[1]=0
for k in range (len(t)-1): # extra element so subtract by 1
x[k] = (t**2)/((m+b)*t+(t**2)*k) + (x[k-2](-m))/((m+b)*t+(t**2)*k) + (x[k-1]((2*m)+(b*t)))/((m+b)*t+(t**2)*k)
return plt.plot(t,x)
print(MSD_Solver(1,.5,5)),MSD_Solver(1,1,5),MSD_Solver(1,2,5)
plt.show()
The linspace doc shows that the third argument is the number of items, not the step. Your step value got truncated to 0, so the returned array for t was empty. As a result, x has no elements, and x[0] is out of range.
Try this:
tinitial = 0
tfinal = 15
step = .005
num = (tfinal - tinitial) / step + 1
t = np.linspace(tinitial,tfinal,num)
This will get you to the semantic errors in your complex computation.
You want, probably(?), use first and second order difference quotients to discretize
m*x''(t) + b*x'(t) + K*x(t) = 1
to
m*(x[j+1]-2*x[j]+x[j-1]) + 0.5*dt*b*(x[j+1]-x[j-1]) + dt^2*K*x[j] = dt**2
so that
x[j+1] = ( dt**2 + (2*m-K*dt**2)*x[j] - (m-0.5*dt*b)*x[j-1] ) / (m+0.5*dt*b)
In code
def MSD_Solver(m,b,K):
#input: m = mass, b = damping ratio, K = spring constant
#output: (t,x) time vs position
tinitial = 0
tfinal = 15
step = .005
t = np.arange(tinitial,tfinal,step)
x = np.zeros_like(t)
dt = t[1]-t[0] # use the actual time step
x[0:2] = [ 0, 0]
for j in range(1,len(t)-1):
x[j+1] = ( dt**2 + (2*m-K*dt**2)*x[j] - (m-0.5*dt*b)*x[j-1] ) / (m+0.5*dt*b)
return t,x
t,x = MSD_Solver(1,.5,5)
plt.plot(t,x); plt.show();
Related
I'm new to python so the code may not be the best. I'm trying to find the minimum Total Cost (TotalC) and the corresponding m,k and xM values that go with this minimum cost. I'm not sure how to do this. I have tried using min(TotalC) however this gives an error within the loop or outside the loop only returns the value of TotalC and not the corresponding m, k, and xM values. Any help would be appreciated. This section is at the end of the code, I have included my entire code.
I have tried using
minIndex = TotalC.argmin()
but I'm not sure how to use it and it only returns 0 each time.
import numpy as np
import matplotlib.pyplot as plt
def Load(x):
Fpeak = (1000 + (9*(x**2) - (183*x))) *1000 #Fpeak in N
td = (20 - ((0.12)*(x**2)) + (4.2*(x))) / 1000 #td in s
return Fpeak, td
#####################################################################################################
####################### Part 2 ########################
def displacement(m,k,x,dt): #Displacement function
Fpeak, td = Load(x) #Load Function from step 1
w = np.sqrt(k/m) # Natural circular frequency
T = 2 * np.pi /w #Natural period of blast (s)
time = np.arange(0,2*T,0.001) #Time array with range (0 - 2*T) with steps of 2*T/100
zt = [] #Create a lsit to store displacement values
for t in time:
if (t <= td):
zt.append((Fpeak/k) * (1 - np.cos(w*t)) + (Fpeak/(k*td)) * ((np.sin(w*t)/w) - t))
else:
zt.append((Fpeak/(k*w*td)) * (np.sin(w*t) - np.sin(w*(t-td))) - ((Fpeak/k) * np.cos(w*t)))
zmax=max(zt) #Find the max displacement from the list of zt values
return zmax #Return max displacement
k = 1E6
m = 200
dt = 0.0001
x = 0
z = displacement(m,k,x,dt)
###################################################################################
############### Part 3 #######################
# k = 1E6 , m = 200kg , Deflection = 0.1m
k_values = np.arange(1E6, 7E6, ((7E6-1E6)/10)) #List of k values between min and max (1E6 and 7E6).
m_values = np.arange(200,1200,((1200-200)/10)) #List of m values between min and max 200kg and 1200kg
xM = []
for k in k_values: # values of k
for m in m_values: # values of m within k for loop
def bisector(m,k,dpoint,dt): #dpoint = decimal point accuracy
xL = 0
xR = 10
xM = (xL + xR)/2
zmax = 99
while round(zmax, dpoint) !=0.1:
zmax = displacement(m,k,xM,dt)
if zmax > 0.1:
xL = xM
xM = (xL + xR)/2
else:
xR = xM
xM = (xL + xR)/2
return xM
xM = bisector(m, k, 4, 0.001)
print('xM value =',xM)
#####################################################
#######Step 4
def cost (m,k,xM):
Ck = 900 + 825*((k/1E6)**2) - (1725*(k/1E6))
Cm = 10*m - 2000
Cx = 2400*((xM**2)/4)
TotalC = Ck + Cm + Cx
minIndex = TotalC.argmin(0)
print(minIndex)
return TotalC
TotalC = cost(m, k, xM)
minIndex = TotalC.argmin()
print(minIndex)
print([xM, m, k, TotalC])
argmin() returns the index of a minimum value. If you are looking for the minimum itself, try using .min(). There is also a possibility that 0 is the lowest value in Your array so bear that in mind
In my following code i m running a lorentz chaotic equation from which i will get random numbers in terms of xs , ys and zs
import numpy as np
def lorenz(x, y, z, a=10,b=8/3,c=28 ):
x_dot = a*(y -x)
y_dot = - y +c*x - x*z
z_dot = -b*z + x*y
return x_dot, y_dot, z_dot
dt = 0.01
num_steps = 10000
# Need one more for the initial values
xs = np.empty(num_steps + 1)
ys = np.empty(num_steps + 1)
zs = np.empty(num_steps + 1)
# Set initial values
xs[0], ys[0], zs[0]= (1,1,1)
# Step through "time", calculating the partial derivatives at the current point
# and using them to estimate the next point
for i in range(num_steps):
x_dot, y_dot, z_dot= lorenz(xs[i], ys[i], zs[i])
xs[i + 1] = xs[i] + (x_dot * dt)
ys[i + 1] = ys[i] + (y_dot * dt)
zs[i + 1] = zs[i] + (z_dot * dt)
I am actually trying to test the xs, ys and zs value for random number generating test via NIST 800 by using the code below
from __future__ import print_function
import math
from fractions import Fraction
from scipy.special import gamma, gammainc, gammaincc
# from gamma_functions import *
import numpy
import cmath
import random
#ones_table = [bin(i)[2:].count('1') for i in range(256)]
def count_ones_zeroes(bits):
ones = 0
zeroes = 0
for bit in bits:
if (bit == 1):
ones += 1
else:
zeroes += 1
return (zeroes,ones)
def runs_test(bits):
n = len(bits)
zeroes,ones = count_ones_zeroes(bits)
prop = float(ones)/float(n)
print(" prop ",prop)
tau = 2.0/math.sqrt(n)
print(" tau ",tau)
if abs(prop-0.5) > tau:
return (False,0.0,None)
vobs = 1.0
for i in range(n-1):
if bits[i] != bits[i+1]:
vobs += 1.0
print(" vobs ",vobs)
p = math.erfc(abs(vobs - (2.0*n*prop*(1.0-prop)))/(2.0*math.sqrt(2.0*n)*prop*(1-prop) ))
success = (p >= 0.01)
return (success,p,None)
print(runs_test(xs))
#%%
from __future__ import print_function
import math
def count_ones_zeroes(bits):
ones = 0
zeroes = 0
for bit in bits:
if (bit == 1):
ones += 1
else:
zeroes += 1
return (zeroes,ones)
def monobit_test(bits):
n = len(bits)
zeroes,ones = count_ones_zeroes(bits)
s = abs(ones-zeroes)
print(" Ones count = %d" % ones)
print(" Zeroes count = %d" % zeroes)
p = math.erfc(float(s)/(math.sqrt(float(n)) * math.sqrt(2.0)))
success = (p >= 0.01)
return (success,p,None)
print(runs_test(xs))
the output which i m getting is false i.e
output:
prop 0.00019998000199980003
tau 0.01999900007499375
(False, 0.0, None)
what should i do now?
The Lorenz system is chaotic, not random. You implemented the differential equation solver well, but it seems that count_ones_zeroes doesn't do what its name implies, at least, not on the data you provide. on xs, it returns that (zeroes, ones) = (9999, 2), which is not what you want. The code checks the value within the xs array, i.e. an x value (e.g. 8.2) against 1, but x is a float between -20 and 20, so it will be usually non1, and will be counted as 0. Only x==1 will be counted as ones.
In python, int/int results in float, so there is no need to cast it to float, in contrast to e.g. C or C++, so instead of prop = float(ones)/float(n), you can write prop = ones/n Similar statements hold for +,- and *
I am struggling with understanding why this while loop (below in the code) terminates after 2 iterations only.
It is from an adative-step size RungeKutta45 Fehlberg Method (https://www.uni-muenster.de/imperia/md/content/physik_tp/lectures/ss2017/numerische_Methoden_fuer_komplexe_Systeme_II/rkm-1.pdf) page 10/11.
The below results in this output:
$ python3 runge_kutta_45_adaptive_optimalstepsizes.py
error at this step: 0.0
error at this step: 1.6543612251060553e-24
no of iterations of the while loop was: 2
last time t was: 0.001
import numpy as np
import os
import matplotlib
from matplotlib import pyplot as plt
# using current y_n and t_n, finds the largest possible dt_new such that the TRUNCATION ERROR
# after 1 integration step with timestep = this new dt_new (the one we want to settle upon)
# REMAINS below some given desired accuracy epsilon_0
# ADAPTIVE STEP-SIZE CONTROL
# always change dt to dt = h_new (optimal timestep change)
rhs_of_diff_Eq_str = "3 * t ** 2"
def first_derivative(t, y): # the first derivative of the function y(t)
first_derivative_value = 3 * t ** 2
return first_derivative_value
def get_RKF4_approx(t, y, dt):
k1 = first_derivative(t, y )
k2 = first_derivative(t + dt/4. , y + dt*( (1./4.)*k1 ) )
k3 = first_derivative(t + dt*(3./8.) , y + dt*( (3./32.)*k1 + (9./32.)*k2 ) )
k4 = first_derivative(t + dt*(12./13.) , y + dt*( (1932./2197.)*k1 - (7200./2197.)*k2 + (7296./2197.)*k3 ) )
k5 = first_derivative(t + dt, y + dt*( (439./216.)*k1 - 8.*k2 + (3680./513.)*k3 - (845./4104)*k4 ) )
RKF4 = y + dt * ( (25./216)*k1 + (1408/2565.)*k3 + (2197./4104.)*k4 - (1./5.)*k5 )
return np.array([RKF4, k1, k2, k3, k4, k5])
def get_RKF5_approx_efficiently(t, y, dt, ks): # efficient ! re-uses derivative evaluations from RKF4 (previous) calculation.
# ks is a numpy array
# ks[0] is K1, ks[1] is K2, ... , ks[4] is K5
k6 = first_derivative(t + dt*(1./2.), y + dt*(-(8./27.)*ks[0] + 2.*ks[1] - (3544./2565.)*ks[2] + (1859./4104.)*ks[3] - (11./40.)*ks[4]) )
RKF5 = y + dt * ( (16./135.)*ks[0] + (6656./12825.)*ks[2] + (28561./56430.)*ks[3] - (9./50.)*ks[4] +(2./55.)*k6 )
return RKF5 # a number
ts = []
ys = []
tfinal = 10.0
nmax = 10**6
epsilon_0 = 10**(-6)
contor = 0
dt = 0.001
beta = 0.9
t = 0.0 # initial condition
y = 0.0 # initial condition
while (t < tfinal and contor < nmax):
contor += 1
container_from_RKF4method = get_RKF4_approx(t, y, dt)
RKF4 = container_from_RKF4method[0] # the RKF4 method's approximation for y_{n+1}
ks = container_from_RKF4method[1:]
RKF5 = get_RKF5_approx_efficiently(t, y, dt, ks)
error_at_this_step = abs(RKF5 - RKF4)
print("error at this step: {}".format(error_at_this_step))
if (error_at_this_step < epsilon_0 and error_at_this_step != 0.0):
# yes, step accepted! need optimal timestep
dt_new = beta * dt * (epsilon_0/error_at_this_step)**(0.25)
ts.append(t)
t += dt_new
dt = dt_new
y_new = RKF5
ys.append(y_new)
y = y_new
else:
if (error_at_this_step == 0.0): # it's perfect! keep carrying on with this timestep which gives 0 error.
ts.append(t)
t += dt
y_new = RKF5
ys.append(y_new)
y = y_new
else: # means that error_at_this_step > epsilon_0 and that error_at_this_step != 0
# no, step not accepted. reiterate step using a lower timestep
dt_new = beta * dt * (epsilon_0/error_at_this_step)**(0.2)
dt = dt_new
# no changes made to time t and y
# repeat this step (reiterate step)
# HERE THE PROBLEM SHALL BE! I DON'T KNOW WHY THE ABOVE 2 instructions are bad!
print("no of iterations of the while loop was: {}".format(contor))
ts = np.array(ts)
print("last time t was: {}".format(ts[-1]))
ys = np.array(ys)
plt.figure()
plt.plot(ts, ys, label='y values', color='red')
plt.xlabel('t')
plt.ylabel('y')
plt.title("RK45 adaptive step-size (optimal step-size always chosen) integration for dy/dt = f(y,t) \n" + "f(y,t) = " + rhs_of_diff_Eq_str)
plt.savefig("RK45_adaptive_step_size_optimal_step_size_results.pdf", bbox_inches='tight')
I have tried to look at instructions execution with breakpoint() and pressing n and/or s.
It seems that the while-loop literally stops after the 2nd iteration.
Do you see why this is the case?
Time t doesn't reach tfinal or contor=10**6-1=nmax!
The bit of the pdb debugging which shows the problem is:
> /mnt/c/Users/iusti/Desktop/runge_kutta_45_adaptive_optimalstepsizes.py(46)<module>()
-> while (t < tfinal and contor < nmax):
(Pdb) s
> /mnt/c/Users/iusti/Desktop/runge_kutta_45_adaptive_optimalstepsizes.py(79)<module>()
-> print("no of iterations of the while loop was: {}".format(contor))
(Pdb) s
[2]+ Stopped python3 runge_kutta_45_adaptive_optimalstepsizes.py
Thanks!
In the second iteration, try to print dt_new before the line t += dt_new in this block:
if (error_at_this_step < epsilon_0 and error_at_this_step != 0.0):
# yes, step accepted! need optimal timestep
dt_new = beta * dt * (epsilon_0/error_at_this_step)**(0.25)
ts.append(t)
t += dt_new
dt = dt_new
y_new = RKF5
ys.append(y_new)
y = y_new
I guess the dt_new value would be so big that adding it to t will cause t to be >= tfinal hence the while condition on the third iteration will not hold anymore which causes the termination.
I am trying to implement the S1 measure (Spectral Measure of Sharpness - Section III-A) from this paper. Here we have to calculate slope (alpha) of the magnitude spectrum for an image in order to measure sharpness. I am able to write the other part of the algorithm, but unable to calculate the slope. Here is my code. Function 'alpha' is where I calculate the magnitude_spectrum and I think using this we can calculate the slope but am not sure how to do that -
def aplha(image_block):
img_float32 = np.float32(image_block)
dft = cv2.dft(img_float32, flags = cv2.DFT_COMPLEX_OUTPUT)
dft_shift = np.fft.fftshift(dft)
magnitude_spectrum = 20*np.log(cv2.magnitude(dft_shift[:,:,0],dft_shift[:,:,1]))
return output (??)
Rest of the code:
def S1_calc(alpha):
tou1 = -3
tou2 = 2
output = 1 - (1 / (1 + np.exp(tou1 * (alpha - tou2))))
return output
def lx(image_block):
b = 0.7656
k = 0.0364
y = 2.2
return np.power((b + k * image_block), y)
def contrast(lx_val):
T1 = 5
T2 = 2
max_val = np.max(lx_val)
min_val = np.min(lx_val)
mean_val = np.mean(lx_val)
return (((max_val - min_val) < T1) or (mean_val < T2))
def image_gray(image_RGB):
output = (0.2989 * image_RGB[:,:,0] +
0.5870 * image_RGB[:,:,1] +
0.1140 * image_RGB[:,:,2])
return output
def S1(gray_image, m = 32, d = 24):
### SPECTRAL MEASURE OF SHARPNESS ###
# m = each block size
# d = overlapping pixels of neighbouring blocks
h,w = gray_image.shape
output = gray_image.copy()
row = 0
while (row < h):
col = 0
while (col < w):
top = row
bottom = min(row + m, h)
left = col
right = min(col + m, w)
image_block = gray_image[top : bottom, left : right]
lx_val = lx(image_block)
contrast_bool = contrast(lx_val)
if contrast_bool==True:
output[top : bottom, left : right] = 0
else:
alpha_val = aplha(image_block)
output[top : bottom, left : right] = S1_calc(alpha_val)
col = col + m - d
row = row + m - d
return output
Am using jupyter notebook, python 3.6
You could check this MATLAB code. See also another MATLAB code.
According to the latter one, we need to know freq and power value, and then we could fit these two var with a linear function, the slope of the line is what we need. We could get the slope with np.polyfit.
Now, our question is how to get the freq of a image, you could do this:
from skimage.data import camera
import numpy as np
image = camera()
height, width = image.shape
u, v = np.meshgrid(np.arange(height // 2), np.arange(width // 2))
freq = np.round(np.sqrt(u**2 + v**2)).astype(np.int64)
Now freq should be the same shape as fft transform of the input image. You need to sum all value of the magnitude_spectrum where they have the same freq, like this:
freq_uniq = np.unique(freq.flatten())
y = []
for value in f_uniq:
y.append(magnitude_spectrum[f == value].sum())
y = np.array(y)
Finally, you could just fit freq_uniq and y and get the slope. You might need to scale them with np.log first.
I want to find pattern in some spectra.
Spectrum image
Pattern should look like 2 in gray circles on picture, all data looks similarly. Light blue line is the original data, dotted dark blue line - average over 6 points. I was trying to do window with some size and scan data and check whether the y-flux value drops/rise below 60 ish % but that seems to find other regions and the one that I want, or only this I don't want.
The width of pattern is not always the same in spectra that I have. There is a picture of spectrum with pattern black dashed line but my program didn't found it.
not found picture
I tried changing size of window but it doesn't help. Can I use some pattern recognition algorithm to find this patterns? Could somebody point me in some direction? Or explain in easy way since I'm kinda lost in this, please?
That's my code:
import numpy as np
import matplotlib.pyplot as plt
from astropy.io import ascii
import glob
def reading(file_name):
data = ascii.read(file_name)
lam = data['col0'][1:-1]
#data offset *10**17 + 5
flux = data['col1'][1:-1]*10**17 + 5
return lam, flux
def percentChange(startPoint,currentPoint):
return abs(((currentPoint-startPoint)/startPoint))*100.00
def window(data, size):
n = len(data)
out = []
wind = data[0 : size]
i = size
while i + size/2 < n:
wind = data[i - size/2 : i + size/2]
tmp = percentChange(wind[0], wind[-1])
if tmp > 50.:
out.append([tmp, i - size/2, i + size/2])
i = i + size
return out
def window2(data, size):
n = len(data)
out = []
wind = data[0 : size]
i = size
while i + size/2 < n:
wind = data[i - size/2 : i + size/2]
tmp = percentChange(wind[0], wind[len(wind)/2])
if tmp > 50.:
out.append([tmp, i - size/2, i + size/2])
i = i + size
return out
def plotting(lamb, flux):
plt.rcParams['font.family'] = 'freeserif'
plt.rcParams['font.size'] = 12
plt.rcParams['axes.labelsize'] = 15
plt.rcParams['xtick.labelsize'] = 12
plt.rcParams['ytick.labelsize'] = 12
plt.rcParams['legend.fontsize'] = 12
plt.rcParams['figure.titlesize'] = 12
plt.rcParams['xtick.minor.visible'] = True
plt.rcParams['ytick.minor.visible'] = True
plt.plot(lamb, flux)
plt.xlabel("wavelenght [A]")
plt.ylabel("flux [erg/cm^2/s/A]")
def averaging(lamb, flux, param):
end = 1480
bin_flux_1 = [np.mean(flux[i : i + param]) for i in range(0, end, param)]
bin_lam_1 = [np.mean(lamb[i : i + param]) for i in range(0, end, param)]
return bin_lam_1, bin_flux_1
def main():
param = 6
stack = 6
for name in glob.glob('TRAIN/*.dat'):
print name
lamb, flux = reading(name)
lamb_a, flux_a = averaging(lamb, flux, param)
plotting(lamb, flux)
plotting(lamb_a, flux_a)
change = window(flux_a, stack)
change2 = window2(flux_a, stack)
minim = flux_a.index(min(flux_a))
for i in range(len(change)):
plt.axvline(lamb_a[change[i][1]], color='r', linestyle='--',linewidth=1)
plt.axvline(lamb_a[change[i][2]], color='r', linestyle='--',linewidth=1)
for i in range(len(change2)):
plt.axvline(lamb_a[change2[i][1]], color='y', linestyle='-',linewidth=1)
plt.axvline(lamb_a[change2[i][2]], color='y', linestyle='-',linewidth=1)
plt.axvline(lamb_a[minim], color='k', linestyle='--',linewidth=1)
plt.show()
if __name__ == "__main__":
main()
You can do it by using Knuth–Morris–Pratt algorithm in linear O(n + m) time complexity where n and m are the lengths of text and pattern.
KMP algorithm is basically a pattern matching algorithm (finding the starting position of a needle in haystack) which works on character string.
def kmp_matcher(t, d):
n=len(t)
m=len(d)
pi = compute_prefix_function(d)
q = 0
i = 0
while i < n:
if d[q]==t[i]:
q=q+1
i = i + 1
else:
if q != 0:
q = pi[q-1]
else:
i = i + 1
if q == m:
print "pattern occurs with shift "+str(i-q)
q = pi[q-1]
def compute_prefix_function(p):
m=len(p)
pi =range(m)
k=1
l = 0
while k < m:
if p[k] <= p[l]:
l = l + 1
pi[k] = l
k = k + 1
else:
if l != 0:
l = pi[l-1]
else:
pi[k] = 0
k = k + 1
return pi
t = 'brownfoxlazydog'
p = 'lazy'
kmp_matcher(t, p)