pure imaginary part fitting implemented
This commit is contained in:
parent
6b84d6da95
commit
9da511b92a
44
QDS.py
44
QDS.py
@ -10,7 +10,7 @@ from PyQt4.QtGui import *
|
||||
import matplotlib
|
||||
from Container import Conductivity, PowerComplex, Static, Peak, YAFF
|
||||
|
||||
from mathlib import fit_anneal, fit_lbfgsb, fit_odr_cmplx, FunctionRegister, FitRoutine
|
||||
from mathlib import FunctionRegister, FitRoutine
|
||||
|
||||
matplotlib.use('agg')
|
||||
|
||||
@ -26,11 +26,8 @@ import QDSMain
|
||||
from data import Data
|
||||
import pyqtgraph as pg
|
||||
|
||||
#import yaff
|
||||
from ContainerWidgets import ParameterWidget
|
||||
|
||||
from ContainerWidgets import ParameterWidget, YaffWidget
|
||||
|
||||
USE_CROSSH=False
|
||||
|
||||
class AppWindow(QMainWindow):
|
||||
|
||||
@ -73,16 +70,6 @@ class AppWindow(QMainWindow):
|
||||
self.ui.pgPlotWidget_imag.addItem(self.data.fitted_curve_imag)
|
||||
self.ui.pgPlotWidget_real.addItem(self.data.fitted_curve_real)
|
||||
|
||||
# cross hair
|
||||
if USE_CROSSH:
|
||||
#self.poslabel = pg.LabelItem(justify='right')
|
||||
self.horizontalLine = pg.InfiniteLine(angle=0)
|
||||
self.verticalLine = pg.InfiniteLine(angle=90)
|
||||
|
||||
#self.ui.pgPlotWidget_imag.plotItem.addItem(self.poslabel)
|
||||
self.ui.pgPlotWidget_imag.addItem(self.horizontalLine)
|
||||
self.ui.pgPlotWidget_imag.addItem(self.verticalLine)
|
||||
|
||||
self.ui.pgPlotWidget_imag.addItem(self.fit_boundary_imag)
|
||||
self.ui.pgPlotWidget_real.addItem(self.fit_boundary_real)
|
||||
|
||||
@ -144,21 +131,15 @@ class AppWindow(QMainWindow):
|
||||
# fitting methods
|
||||
fitMenu = self.menuBar().addMenu("Standard Fits")
|
||||
# lm
|
||||
fit_lmAction = QAction("&Levenberg-Marquardt", self)
|
||||
fit_lmAction = QAction("Complex NLS", self)
|
||||
fit_lmAction.setShortcut(QKeySequence("Ctrl+F"))
|
||||
fitMenu.addAction(fit_lmAction)
|
||||
# lbfgsb
|
||||
fit_lbfgsbAction = QAction("&L-BFGS-B", self)
|
||||
fit_lbfgsbAction = QAction("NLS (Imag.)", self)
|
||||
fitMenu.addAction(fit_lbfgsbAction)
|
||||
# Simulated Annealing
|
||||
fit_annealAction = QAction("&Simulated Annealing", self)
|
||||
fitMenu.addAction(fit_annealAction)
|
||||
# YAFF
|
||||
yaffMenu = self.menuBar().addMenu("YAFF")
|
||||
start_yaff = QAction("&Startparam.", self)
|
||||
yaffMenu.addAction(start_yaff)
|
||||
fit_yaff = QAction("&Fit", self)
|
||||
yaffMenu.addAction(fit_yaff)
|
||||
|
||||
self.signalMapper = QSignalMapper(self)
|
||||
for i, fit_action in enumerate([fit_lmAction, fit_lbfgsbAction, fit_annealAction
|
||||
@ -179,17 +160,11 @@ class AppWindow(QMainWindow):
|
||||
else:
|
||||
pos = QPointF(0.0, 0.0)
|
||||
self.last_pos = pos
|
||||
if USE_CROSSH:
|
||||
self.horizontalLine.setBounds([self.data.frequency.min(), self.data.frequency.max()])
|
||||
self.horizontalLine.setPos(pos.y())
|
||||
self.verticalLine.setPos(pos.x())
|
||||
|
||||
def mousePress(self, evt):
|
||||
data_pos = self.last_pos
|
||||
|
||||
mouse_in_imag = self.ui.pgPlotWidget_imag.underMouse()
|
||||
mouse_in_real = self.ui.pgPlotWidget_real.underMouse()
|
||||
|
||||
msgBox = QMessageBox()
|
||||
|
||||
if self.ui.actionAdd_Peak.isChecked():
|
||||
@ -396,7 +371,13 @@ class AppWindow(QMainWindow):
|
||||
self.updatePlot()
|
||||
|
||||
def fitData_start(self, method):
|
||||
fit_methods = [fit_odr_cmplx, fit_lbfgsb, fit_anneal]
|
||||
print method
|
||||
#fit_methods = [fit_odr_cmplx, fit_odr_imag, fit_lbfgsb, fit_anneal]
|
||||
|
||||
fit_method = [
|
||||
self._fit_method.fit_odr_cmplx,
|
||||
self._fit_method.fit_odr_imag,
|
||||
][method]
|
||||
|
||||
# build function list
|
||||
p0,funcs,fixed_params = [],[],[]
|
||||
@ -408,7 +389,8 @@ class AppWindow(QMainWindow):
|
||||
_freq, _fit = self.data.get_data()
|
||||
|
||||
if not self._fit_thread.isRunning():
|
||||
self._fit_method.fit_odr_cmplx(_freq, _fit, p0, fixed_params, funcs)
|
||||
#self._fit_method.fit_odr_cmplx(_freq, _fit, p0, fixed_params, funcs)
|
||||
fit_method(_freq, _fit, p0, fixed_params, funcs)
|
||||
self._fit_thread.start()
|
||||
self.ui.statusbar.showMessage("Fitting ...")
|
||||
else:
|
||||
|
409
mathlib.py
409
mathlib.py
@ -11,6 +11,217 @@ from scipy import optimize as opt, odr
|
||||
import libyaff
|
||||
|
||||
|
||||
|
||||
def id_to_color(id):
|
||||
colors = [
|
||||
QColor(54,22,115),
|
||||
QColor(160,16,36),
|
||||
QColor(45,142,15),
|
||||
QColor(168,149,17),
|
||||
QColor(36,10,85),
|
||||
QColor(118,8,23),
|
||||
QColor(31,105,7),
|
||||
QColor(124,109,8),
|
||||
]
|
||||
return colors[id % len(colors)]
|
||||
|
||||
|
||||
|
||||
class FitFunctionCreator(QObject):
|
||||
new_data = pyqtSignal(np.ndarray, np.ndarray)
|
||||
|
||||
def __init__(self):
|
||||
super(FitFunctionCreator,self).__init__()
|
||||
self.data = None
|
||||
self.functions = Functions()
|
||||
|
||||
|
||||
def fitfcn(self, p0, x, *funcs):
|
||||
if x.ndim == 2:
|
||||
self.data = np.zeros( x.shape )
|
||||
else:
|
||||
self.data = np.zeros( (2,x.size) )
|
||||
ndx = 0
|
||||
for fn in funcs: # loop over functions and add the results
|
||||
f, num_p = fn.function, fn.param_number
|
||||
p = p0[ndx:ndx + num_p]
|
||||
if x.ndim == 2:
|
||||
x = x[0]
|
||||
result = f(p, x)
|
||||
self.data += result # fit functions take only 1-dim x
|
||||
ndx += num_p
|
||||
self.new_data.emit(x, self.data)
|
||||
return self.data
|
||||
|
||||
def fitfcn_imag(self, p0, x, *funcs):
|
||||
if x.ndim == 2:
|
||||
self.data = np.zeros( x.shape )
|
||||
else:
|
||||
self.data = np.zeros( (2,x.size) )
|
||||
ndx = 0
|
||||
for fn in funcs: # loop over functions and add the results
|
||||
f, num_p = fn.function, fn.param_number
|
||||
p = p0[ndx:ndx + num_p]
|
||||
if x.ndim == 2:
|
||||
x = x[0]
|
||||
result = f(p, x)
|
||||
self.data += result # fit functions take only 1-dim x
|
||||
ndx += num_p
|
||||
self.new_data.emit(x, self.data)
|
||||
return self.data[1]
|
||||
|
||||
|
||||
class FitRoutine(QObject):
|
||||
finished_fit = pyqtSignal()
|
||||
data_ready = pyqtSignal(np.ndarray, np.ndarray)
|
||||
def __init__(self):
|
||||
super(FitRoutine,self).__init__()
|
||||
self.f = FitFunctionCreator()
|
||||
self.f.new_data.connect(self.data_ready.emit)
|
||||
self._fitter = self.fit_odr_cmplx
|
||||
self._odr_fit = None
|
||||
|
||||
@property
|
||||
def fitter(self):
|
||||
return self._fitter
|
||||
|
||||
@fitter.setter
|
||||
def fitter(self, f):
|
||||
self._fitter = f
|
||||
|
||||
def fit_odr_cmplx(self, x, y, p0, fixed, fcns):
|
||||
#if x.ndim < 2:
|
||||
# x = N.resize(x, (2,x.size))
|
||||
if np.iscomplexobj(y) and y.ndim == 1:
|
||||
weights = 1/np.abs(y)**2
|
||||
we = np.resize(weights, (2, weights.size))
|
||||
#we = 1/N.array([y.real**2, y.imag**2])
|
||||
y = np.array([y.real, y.imag])
|
||||
else:
|
||||
raise NotImplementedError, "need complex input for now"
|
||||
dat = odr.Data(x, y, we=we)
|
||||
mod = odr.Model(self.f.fitfcn, extra_args=fcns)
|
||||
self._odr_fit = odr.ODR(dat, mod, p0, ifixx=(0,), ifixb=fixed, maxit=800)
|
||||
|
||||
def fit_odr_imag(self, x, y, p0, fixed, fcns):
|
||||
if np.iscomplexobj(y) and y.ndim == 1:
|
||||
we = 1/np.imag(y)**2
|
||||
else:
|
||||
raise NotImplementedError, "need complex input for now"
|
||||
dat = odr.Data(x, y.imag, we=we)
|
||||
mod = odr.Model(self.f.fitfcn_imag, extra_args=fcns)
|
||||
self._odr_fit = odr.ODR(dat, mod, p0, ifixx=(0,), ifixb=fixed, maxit=800)
|
||||
|
||||
@pyqtSlot()
|
||||
def fit(self):
|
||||
#print "TID in FitRoutine", QThread.thread()
|
||||
self._odr_fit.run()
|
||||
self.finished_fit.emit()
|
||||
|
||||
def result(self):
|
||||
return self._odr_fit.output
|
||||
|
||||
|
||||
class FunctionRegister:
|
||||
def __init__(self):
|
||||
self.registry = {}
|
||||
|
||||
def register_function(self, obj):
|
||||
#print "FR: Registering:",obj
|
||||
id_string = obj.id_label
|
||||
if self.registry.has_key(obj):
|
||||
raise AssertionError,"The object is already registered! This should NOT happen"
|
||||
self.registry[obj]=id_string
|
||||
#print "FR: ",self.registry
|
||||
|
||||
def unregister_function(self, obj):
|
||||
#print "FR: UnRegistering:",obj
|
||||
if self.registry.has_key(obj):
|
||||
self.registry.pop(obj)
|
||||
else:
|
||||
obj.deleteLater()
|
||||
raise AssertionError,"The object is not in the registry! This should NOT happen"
|
||||
#print "FR: ",self.registry
|
||||
|
||||
def get_registered_functions(self):
|
||||
return self.registry
|
||||
|
||||
|
||||
|
||||
############## deprecated #####################
|
||||
def fit_odr_cmplx(x, y, p0, fixed, fcns):
|
||||
f = FitFunctionCreator()
|
||||
#if x.ndim < 2:
|
||||
# x = N.resize(x, (2,x.size))
|
||||
if np.iscomplexobj(y) and y.ndim == 1:
|
||||
weights = 1/np.abs(y)**2
|
||||
we = np.resize(weights, (2, weights.size))
|
||||
#we = 1/N.array([y.real**2, y.imag**2])
|
||||
y = np.array([y.real, y.imag])
|
||||
else:
|
||||
raise NotImplementedError, "need complex input for now"
|
||||
dat = odr.Data(x, y, we=we)
|
||||
mod = odr.Model(f.fitfcn, extra_args=fcns)
|
||||
fit = odr.ODR(dat, mod, p0, ifixx=(0,), ifixb=fixed, maxit=8000)
|
||||
fit.run()
|
||||
#print fit.output.pprint()
|
||||
return fit.output
|
||||
|
||||
### define funcs here
|
||||
class Functions(QObject):
|
||||
def __init__(self):
|
||||
super(Functions,self).__init__()
|
||||
self.list = {
|
||||
# provides functions: "id_string":(function, number_of_parameters)
|
||||
"hn":(self.hn_cmplx, 4),
|
||||
"conductivity":(self.cond_cmplx, 3),
|
||||
"power":(self.power_cmplx, 2),
|
||||
"static":(self.static_cmplx, 1),
|
||||
"yaff":(self.yaff, 8)
|
||||
}
|
||||
self.YAFF = libyaff.Yaff()
|
||||
|
||||
def hn_cmplx(self, p, x):
|
||||
om = 2*np.pi*x
|
||||
#hn = om*1j
|
||||
eps,t,a,b = p
|
||||
hn = eps/(1+(1j*om*t)**a)**b
|
||||
cplx = np.array([hn.real, -hn.imag])
|
||||
return cplx
|
||||
|
||||
def cond_cmplx(self, p, x):
|
||||
om = 2*np.pi*x
|
||||
sgma, isgma, n = p
|
||||
cond = sgma/(om**n) + isgma/(1j*om**n) # Jonscher (Universal Dielectric Response: e",e' prop sigma/omega**n
|
||||
cplx = np.array([cond.real, -cond.imag])
|
||||
return cplx
|
||||
|
||||
def power_cmplx(self, p, x):
|
||||
om = 2*np.pi*x
|
||||
sgma,n = p
|
||||
power = sgma/(om*1j)**n
|
||||
cplx = np.array([power.real, -power.imag])
|
||||
return cplx
|
||||
|
||||
def static_cmplx(self, p, x):
|
||||
eps_inf = p[0]
|
||||
static = np.ones( (2,x.size) )*eps_inf
|
||||
static[1,:] *= 0 # set imag part zero
|
||||
#cplx = N.array([static.real, static.imag])
|
||||
return static
|
||||
|
||||
def yaff(self,p,x):
|
||||
ya = self.YAFF.yaff(p[:8],x)
|
||||
cplx = np.array([ya.imag, ya.real])
|
||||
return cplx
|
||||
|
||||
def get(self,name):
|
||||
return self.list[name]
|
||||
|
||||
def get_function(self,name):
|
||||
return self.list[name][0]
|
||||
|
||||
|
||||
def fit_anneal(x, y, p0, fixed, funcs):
|
||||
raise NotImplementedError
|
||||
bounds = [(0, 1e14), (0, 1)]
|
||||
@ -85,19 +296,6 @@ def hn(p, nu):
|
||||
return e_loss # 2* oder nicht?
|
||||
|
||||
|
||||
def id_to_color(id):
|
||||
colors = [
|
||||
QColor(54,22,115),
|
||||
QColor(160,16,36),
|
||||
QColor(45,142,15),
|
||||
QColor(168,149,17),
|
||||
QColor(36,10,85),
|
||||
QColor(118,8,23),
|
||||
QColor(31,105,7),
|
||||
QColor(124,109,8),
|
||||
]
|
||||
return colors[id % len(colors)]
|
||||
|
||||
|
||||
def mini_func(p, x, y):
|
||||
res = y - multi_hn(p, x)
|
||||
@ -133,188 +331,3 @@ def tau_peak(f, a, b):
|
||||
|
||||
|
||||
|
||||
|
||||
### define funcs here
|
||||
class Functions(QObject):
|
||||
def __init__(self):
|
||||
super(Functions,self).__init__()
|
||||
self.list = {
|
||||
# provides functions: "id_string":(function, number_of_parameters)
|
||||
"hn":(self.hn_cmplx, 4),
|
||||
"conductivity":(self.cond_cmplx, 3),
|
||||
"power":(self.power_cmplx, 2),
|
||||
"static":(self.static_cmplx, 1),
|
||||
"yaff":(self.yaff, 8)
|
||||
}
|
||||
self.YAFF = libyaff.Yaff()
|
||||
|
||||
def hn_cmplx(self, p, x):
|
||||
om = 2*np.pi*x
|
||||
#hn = om*1j
|
||||
eps,t,a,b = p
|
||||
hn = eps/(1+(1j*om*t)**a)**b
|
||||
cplx = np.array([hn.real, -hn.imag])
|
||||
return cplx
|
||||
|
||||
def cond_cmplx(self, p, x):
|
||||
om = 2*np.pi*x
|
||||
sgma, isgma, n = p
|
||||
cond = sgma/(om**n) + isgma/(1j*om**n) # Jonscher (Universal Dielectric Response: e",e' prop sigma/omega**n
|
||||
cplx = np.array([cond.real, -cond.imag])
|
||||
return cplx
|
||||
|
||||
def power_cmplx(self, p, x):
|
||||
om = 2*np.pi*x
|
||||
sgma,n = p
|
||||
power = sgma/(om*1j)**n
|
||||
cplx = np.array([power.real, -power.imag])
|
||||
return cplx
|
||||
|
||||
def static_cmplx(self, p, x):
|
||||
eps_inf = p[0]
|
||||
static = np.ones( (2,x.size) )*eps_inf
|
||||
static[1,:] *= 0 # set imag part zero
|
||||
#cplx = N.array([static.real, static.imag])
|
||||
return static
|
||||
|
||||
def yaff(self,p,x):
|
||||
ya = self.YAFF.yaff(p[:8],x)
|
||||
cplx = np.array([ya.imag, ya.real])
|
||||
return cplx
|
||||
|
||||
def get(self,name):
|
||||
return self.list[name]
|
||||
|
||||
def get_function(self,name):
|
||||
return self.list[name][0]
|
||||
|
||||
|
||||
class FitFunctionCreator(QObject):
|
||||
new_data = pyqtSignal(np.ndarray, np.ndarray)
|
||||
|
||||
def __init__(self):
|
||||
super(FitFunctionCreator,self).__init__()
|
||||
self.data = None
|
||||
self.functions = Functions()
|
||||
|
||||
|
||||
def fitfcn(self, p0, x, *funcs):
|
||||
if x.ndim == 2:
|
||||
self.data = np.zeros( x.shape )
|
||||
else:
|
||||
self.data = np.zeros( (2,x.size) )
|
||||
ndx = 0
|
||||
for fn in funcs: # loop over functions and add the results
|
||||
f, num_p = fn.function, fn.param_number
|
||||
p = p0[ndx:ndx + num_p]
|
||||
if x.ndim == 2:
|
||||
x = x[0]
|
||||
result = f(p, x)
|
||||
self.data += result # fit functions take only 1-dim x
|
||||
ndx += num_p
|
||||
self.new_data.emit(x, self.data)
|
||||
return self.data
|
||||
|
||||
def _fitfcn(self, p0, x, *funcs):
|
||||
if x.ndim == 2:
|
||||
self.data = np.zeros( x.shape )
|
||||
else:
|
||||
self.data = np.zeros( (2,x.size) )
|
||||
ndx = 0
|
||||
for fn in funcs: # loop over functions and add the results
|
||||
f,num_p = self.functions.get(fn)
|
||||
p = p0[ndx:ndx + num_p]
|
||||
if x.ndim == 2:
|
||||
x = x[0]
|
||||
result = f(p, x)
|
||||
self.data += result # fit functions take only 1-dim x
|
||||
ndx += num_p
|
||||
self.new_data.emit(x, self.data)
|
||||
return self.data
|
||||
|
||||
|
||||
def fit_odr_cmplx(x, y, p0, fixed, fcns):
|
||||
f = FitFunctionCreator()
|
||||
#if x.ndim < 2:
|
||||
# x = N.resize(x, (2,x.size))
|
||||
if np.iscomplexobj(y) and y.ndim == 1:
|
||||
weights = 1/np.abs(y)**2
|
||||
we = np.resize(weights, (2, weights.size))
|
||||
#we = 1/N.array([y.real**2, y.imag**2])
|
||||
y = np.array([y.real, y.imag])
|
||||
else:
|
||||
raise NotImplementedError, "need complex input for now"
|
||||
dat = odr.Data(x, y, we=we)
|
||||
mod = odr.Model(f.fitfcn, extra_args=fcns)
|
||||
fit = odr.ODR(dat, mod, p0, ifixx=(0,), ifixb=fixed, maxit=8000)
|
||||
fit.run()
|
||||
#print fit.output.pprint()
|
||||
return fit.output
|
||||
|
||||
class FitRoutine(QObject):
|
||||
finished_fit = pyqtSignal()
|
||||
data_ready = pyqtSignal(np.ndarray, np.ndarray)
|
||||
def __init__(self):
|
||||
super(FitRoutine,self).__init__()
|
||||
self.f = FitFunctionCreator()
|
||||
self.f.new_data.connect(self.data_ready.emit)
|
||||
self._fitter = self.fit_odr_cmplx
|
||||
self._odr_fit = None
|
||||
|
||||
@property
|
||||
def fitter(self):
|
||||
return self._fitter
|
||||
|
||||
@fitter.setter
|
||||
def fitter(self,f):
|
||||
self._fitter = f
|
||||
|
||||
def fit_odr_cmplx(self, x, y, p0, fixed, fcns):
|
||||
#if x.ndim < 2:
|
||||
# x = N.resize(x, (2,x.size))
|
||||
if np.iscomplexobj(y) and y.ndim == 1:
|
||||
weights = 1/np.abs(y)**2
|
||||
we = np.resize(weights, (2, weights.size))
|
||||
#we = 1/N.array([y.real**2, y.imag**2])
|
||||
y = np.array([y.real, y.imag])
|
||||
else:
|
||||
raise NotImplementedError, "need complex input for now"
|
||||
|
||||
dat = odr.Data(x, y, we=we)
|
||||
mod = odr.Model(self.f.fitfcn, extra_args=fcns)
|
||||
self._odr_fit = odr.ODR(dat, mod, p0, ifixx=(0,), ifixb=fixed, maxit=10)
|
||||
|
||||
@pyqtSlot()
|
||||
def fit(self):
|
||||
#print "TID in FitRoutine", QThread.thread()
|
||||
self._odr_fit.run()
|
||||
self.finished_fit.emit()
|
||||
|
||||
def result(self):
|
||||
return self._odr_fit.output
|
||||
|
||||
|
||||
|
||||
class FunctionRegister:
|
||||
def __init__(self):
|
||||
self.registry = {}
|
||||
|
||||
def register_function(self, obj):
|
||||
#print "FR: Registering:",obj
|
||||
id_string = obj.id_label
|
||||
if self.registry.has_key(obj):
|
||||
raise AssertionError,"The object is already registered! This should NOT happen"
|
||||
self.registry[obj]=id_string
|
||||
#print "FR: ",self.registry
|
||||
|
||||
def unregister_function(self, obj):
|
||||
#print "FR: UnRegistering:",obj
|
||||
if self.registry.has_key(obj):
|
||||
self.registry.pop(obj)
|
||||
else:
|
||||
obj.deleteLater()
|
||||
raise AssertionError,"The object is not in the registry! This should NOT happen"
|
||||
#print "FR: ",self.registry
|
||||
|
||||
def get_registered_functions(self):
|
||||
return self.registry
|
||||
|
Loading…
Reference in New Issue
Block a user