least square method for finding unknown variables - python

I need to compute two unknown variable with least square method , I have got the experimental data which are produced ( simiulated ) by a few line of code at first. so at the beginning two variable which are phase and width are known to simulate the data. in the second part these two variable are considered unknown and with the help of data and least squares method I am going to compute them. but there is a problem!. if the phase is between 0 to pi the code gives the right value and when it is between pi to 2*pi wrong value is retuned. I need to compute these two variables for any arbitrary value with high precision that is entered in the first part.
Thanks to those who would help in advance.
this is the code bellow:
from numpy import sin,cos,pi,linspace,sqrt,zeros,arccos
from scipy.special import fresnel as f
import matplotlib.pyplot as plt
from scipy.optimize import least_squares as lst
import numpy as np
# first part to simulate data
m=500
l=632.8e-9
z=.25
a=0.3e-3
b=6e-3
p=(1.7)*pi
q=sqrt(2/(l*z))
x=linspace(-b,b,m)
v2=-q*(x-a)
v1=-q*(x+a)
s,c,I=zeros(m),zeros(m),zeros(m)
for i in range(m):
s[i]=f(v2[i])[0]-f(v1[i])[0]
c[i]=f(v2[i])[1]-f(v1[i])[1]
for j in range(m):
I[j]=1+(1-cos(p))*((c[j]**2 +s[j]**2 )-(c[j]+s[j]))+sin(p)*(c[j]-s[j])
# second part to compute a and p
def model(y,x):
w=sqrt(2/(l*z))
C=f(w*(y[1]-x))[1]-f(w*(-y[1]-x))[1]
S=f(w*(y[1]-x))[0]-f(w*(-y[1]-x))[0]
return 1+(1-cos(y[0])) *(C**2 -C +S**2 -S)+sin(y[0])*(C-S)
def func(y,x,z):
return (z-model(y,x))
ExI=I
y0=np.array([0.5,50e-6])
reslm = lst(func, y0,method='lm',args=(x, ExI),verbose=2)
print('Real phase and channel width : ',p , a)
print(' lm method ')
print('Estimated phase : ' ,reslm.x[0] if reslm.x[0]>=0 else 2*pi+reslm.x[0])
print('channel width' , reslm.x[1])

Related

How to apply Particle Swarm Optimization using SKO.pso python

I find a package on the Github, it contains various algorithms about evolution. The link is below:
https://github.com/guofei9987/scikit-opt
However, I got confused when using the package. When I try to do as the example, setting the dim as one, and lower bound as zero when upper bound is ten, focusing on the non negative for x, it got wrong answer, here is my code:
def demo_func(x):
# Sphere
x1= x
return ((10-4*x1)/(4*x1+3))*x1
from sko.PSO import PSO
pso = PSO(func=demo_func, n_dim=1, pop=40, max_iter=150, lb=[0], ub=[10], w=0.8, c1=0.5, c2=0.5)
pso.run()
print('best_x is ', pso.gbest_x, 'best_y is', pso.gbest_y)
import matplotlib.pyplot as plt
plt.plot(pso.gbest_y_hist)
plt.show()
the result are below:result
best_x is [10.] best_y is [-6.97674419]
However, it is a wrong answer. the right answer for x is between 0.5 to 1. Does anybody has suggestions?
PSO optimize the minimum value of function. add a negative sign to get the max.
def demo_func(x):
x1,= x
return -((10-4*x1)/(4*x1+3))*x1
from sko.PSO import PSO
pso = PSO(func=demo_func, n_dim=1, pop=40, max_iter=150, lb=[0], ub=[10], w=0.8, c1=0.5, c2=0.5)
pso.run()
print('best_x is ', pso.gbest_x, 'best_y is', pso.gbest_y)
import matplotlib.pyplot as plt
plt.plot(pso.gbest_y_hist)
plt.show()

Plancks Law, Frequency figures

I want to plot the frequency version of planck's law. I first tried to do this independently:
import numpy as np
import matplotlib.pyplot as plt
import pandas as pd
import seaborn as sns
%matplotlib inline
# Planck's Law
# Constants
h = 6.62607015*(10**-34) # J*s
c = 299792458 # m * s
k = 1.38064852*(10**-23) # J/K
T = 20 # K
frequency_range = np.linspace(10**-19,10**19,1000000)
def plancks_law(nu):
a = (2*h*nu**3) / (c**2)
e_term = np.exp(h*nu/(k*T))
brightness = a /(e_term - 1)
return brightness
plt.plot(frequency_range,plancks_law(frequency_range))
plt.gca().set_xlim([1*10**-16 ,1*10**16 ])
plt.gca().invert_xaxis()
This did not work, I have an issue with scaling somehow. My next idea was to attempt to use this person's code from this question: Plancks Formula for Blackbody spectrum
import matplotlib.pyplot as plt
import numpy as np
h = 6.626e-34
c = 3.0e+8
k = 1.38e-23
def planck_f(freq, T):
a = 2.0*h*(freq**3)
b = h*freq/(k*T)
intensity = a/( (c**2 * (np.exp(b) - 1.0) ))
return intensity
# generate x-axis in increments from 1nm to 3 micrometer in 1 nm increments
# starting at 1 nm to avoid wav = 0, which would result in division by zero.
wavelengths = np.arange(1e-9, 3e-6, 1e-9)
frequencies = np.arange(3e14, 3e17, 1e14, dtype=np.float64)
intensity4000 = planck_f(frequencies, 4000.)
plt.gca().invert_xaxis()
This didn't work, because I got a divide by zero error. Except that I don't see where there is a division by zero, the denominator shouldn't ever be zero since the exponential term shouldn't ever be equal to one. I chose the frequencies to be the conversions of the wavelength values from the example code.
Can anyone help fix the problem or explain how I can get planck's law for frequency instead of wavelength?
You can not safely handle such large numbers; even for comparably "small" values of b = h*freq/(k*T) your float64 will overflow, e.g np.exp(709.)=8.218407461554972e+307 is ok, but np.exp(710.)=inf. You'll have to adjust your units (exponents) accordingly to avoid this!
Note that this is also the case in the other question you linked to, if you insert print( np.exp(b)[:10] ) within the definition of planck(), you can examine the first ten evaluated b's and you'll see the overflow in the first few occurrences. In any case, simply use the answer posted within the other question, but convert the x-axis in plt.plot(wavelengths, intensity) to frequency (i hope you know how to get from one to the other) :-)

customizing np.fft.fft function in python

I wish to perform a fourier transform of the function 'stress' from 0 to infinity and extract the real and imaginary parts. I have the following code that does it using a numerical integration technique:
import numpy as np
from scipy.integrate import trapz
import fileinput
import sys,string
window = 200000 # length of the array I wish to transform (number of data points)
time = np.linspace(1,window,window)
freq = np.logspace(-5,2,window)
output = [0]*len(freq)
for index,f in enumerate(freq):
visco = trapz(stress*np.exp(-1j*f*t),t)
soln = visco*(1j*f)
output[index] = soln
print 'f storage loss'
for i in range(len(freq)):
print freq[i],output[i].real,output[i].imag
This gives me a nice transformation of my input data.
Now I have an array of size 2x10^6, and using the above technique is not feasible(computation time scales as O(N^2)), so I have turned to the inbuilt fft function in numpy.
There aren't too many arguments that you can specify to change this function, and so I'm finding it difficult to customize it to my needs.
So far I have
import numpy as np
import fileinput
import sys, string
np.set_printoptions(threshold='nan')
N = len(stress)
fvi = np.fft.fft(stress,n=N)
gprime = fvi.real
gdoubleprime = fvi.imag
for i in range(len(stress)):
print gprime[i], gdoubleprime[i]
And it's not giving me accurate results.
The DFT in python is of the form A_k = summation(a_m * exp(-2*piimk/n)) where the summation is from m = 0 to m = n-1 (http://docs.scipy.org/doc/numpy-1.10.1/reference/routines.fft.html). How can I change it to the form that I have mentioned in my first code, i.e. exp(-1jfreq*t) (freq is the frequency and t is the time which have already been predefined)? Or is there a post processing of the data that I have to do?
Thanks in advance for all your help.

Optimising two arrays simultaneously with scipy optimize

I have a function that takes two m-dimensional arrays does some calculation with them (here it is very simplified) and returns one dimensional array. Also I have m-dimensional measurement data and would like to optimise those two arrays to fit the measurements. This worked fine with one arrays. I can just simply not get it to work with two arrays (or more). it always throws:
TypeError: Improper input: N=40 must not exceed M=20
Here is my Code. Thank you very much if anyone can help!
import numpy as np
from scipy import optimize
data=[np.arange(0,20.0,1),np.array([-52.368, 32.221, 40.102, 48.088, 73.106, 50.807, 52.235, 76.933, 65.737, 34.772, 94.376, 123.366, 92.71, 72.25, 165.051, 91.501, 118.92, 100.936, 56.747, 159.034])]
def line(m,b):
return m*b
guessm = np.ones(20) #initial guessed values for m
guessb = np.ones(20) #initial guesses values for b
guess = np.append(guessm,guessb)
errfunc= lambda p,y: (y-line(p[:20],p[20:]))
parameter, sucess = optimize.leastsq(errfunc, guess, args=(data[1]))
print(parameter)
plt.plot(data[0],d[1],'o')
plt.plot(data[0],line(parameter[0],parameter[1]))
plt.show()
If you want to fit a line, you should give the slope and intercept - two parameters, not 40. I suspect this is what you try to do:
import matplotlib.pyplot as plt
import numpy as np
from scipy import optimize
data=[np.arange(0,20.0,1),np.array([-52.368, 32.221, 40.102, 48.088, 73.106, 50.807, 52.235, 76.933, 65.737, 34.772, 94.376, 123.366, 92.71, 72.25, 165.051, 91.501, 118.92, 100.936, 56.747, 159.034])]
def line(m,b):
return np.arange(0, 20, 1)*m + b
guess = np.ones(2)
errfunc= lambda p,y: (y-line(p[0],p[1]))
parameter, sucess = optimize.leastsq(errfunc, guess, args=(data[1]))
print(parameter)
plt.plot(data[0],data[1],'o')
plt.plot(data[0],line(parameter[0],parameter[1]))
plt.show()

Solving nonlinear overdetermined system using python

I'm trying to find a good way to solve a nonlinear overdetermined system with python. I looked into optimization tools here http://docs.scipy.org/doc/scipy/reference/optimize.nonlin.html but I can't figure out how to use them. What I have so far is
#overdetermined nonlinear system that I'll be using
'''
a = cos(x)*cos(y)
b = cos(x)*sin(y)
c = -sin(y)
d = sin(z)*sin(y)*sin(x) + cos(z)*cos(y)
e = cos(x)*sin(z)
f = cos(z)*sin(x)*cos(z) + sin(z)*sin(x)
g = cos(z)*sin(x)*sin(y) - sin(z)*cos(y)
h = cos(x)*cos(z)
a-h will be random int values in the range 0-10 inclusive
'''
import math
from random import randint
import scipy.optimize
def system(p):
x, y, z = p
return(math.cos(x)*math.cos(y)-randint(0,10),
math.cos(x)*math.sin(y)-randint(0,10),
-math.sin(y)-randint(0,10),
math.sin(z)*math.sin(y)*math.sin(x)+math.cos(z)*math.cos(y)-randint(0,10),
math.cos(x)*math.sin(z)-randint(0,10),
math.cos(z)*math.sin(x)*math.cos(z)+math.sin(z)*math.sin(x)-randint(0,10),
math.cos(z)*math.sin(x)*math.sin(y)-math.sin(z)*math.cos(y)-randint(0,10),
math.cos(x)*math.cos(z)-randint(0,10))
x = scipy.optimize.broyden1(system, [1,1,1], f_tol=1e-14)
could you help me out a bit here?
If I understand you right, you want to find an approximate solution to the non-linear system of equations f(x) = b where b is the vector containing the random values b=[a,...,h].
In order to do this you will first need to remove the random values from the system function, because otherwise in each iteration the solver will try to solve a different equation system. Moreover, I think that the basic Broyden method only works for a system with as many unknowns as equations. Alternatively you could use scipy.optimize.leastsq. A possible solution looks like this:
# I am using numpy because it's more convenient for the generation of
# random numbers.
import numpy as np
from numpy.random import randint
import scipy.optimize
# Removed random right-hand side values and changed nomenclature a bit.
def f(x):
x1, x2, x3 = x
return np.asarray((math.cos(x1)*math.cos(x2),
math.cos(x1)*math.sin(x2),
-math.sin(x2),
math.sin(x3)*math.sin(x2)*math.sin(x1)+math.cos(x3)*math.cos(x2),
math.cos(x1)*math.sin(x3),
math.cos(x3)*math.sin(x1)*math.cos(x3)+math.sin(x3)*math.sin(x1),
math.cos(x3)*math.sin(x1)*math.sin(x2)-math.sin(x3)*math.cos(x2),
math.cos(x1)*math.cos(x3)))
# The second parameter is used to set the solution vector using the args
# argument of leastsq.
def system(x,b):
return (f(x)-b)
b = randint(0, 10, size=8)
x = scipy.optimize.leastsq(system, np.asarray((1,1,1)), args=b)[0]
I hope this is of help for you. However, note that it is extremely unlikely that you will find a solution, especially when you generate random integers in the interval [0,10] while the range of f is limited to [-2,2]

Categories