pure imaginary part fitting implemented

This commit is contained in:
Markus Rosenstihl 2014-04-14 15:47:16 +02:00
parent 6b84d6da95
commit 9da511b92a
2 changed files with 224 additions and 229 deletions

44
QDS.py
View File

@ -10,7 +10,7 @@ from PyQt4.QtGui import *
import matplotlib import matplotlib
from Container import Conductivity, PowerComplex, Static, Peak, YAFF 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') matplotlib.use('agg')
@ -26,11 +26,8 @@ import QDSMain
from data import Data from data import Data
import pyqtgraph as pg import pyqtgraph as pg
#import yaff from ContainerWidgets import ParameterWidget
from ContainerWidgets import ParameterWidget, YaffWidget
USE_CROSSH=False
class AppWindow(QMainWindow): class AppWindow(QMainWindow):
@ -73,16 +70,6 @@ class AppWindow(QMainWindow):
self.ui.pgPlotWidget_imag.addItem(self.data.fitted_curve_imag) self.ui.pgPlotWidget_imag.addItem(self.data.fitted_curve_imag)
self.ui.pgPlotWidget_real.addItem(self.data.fitted_curve_real) 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_imag.addItem(self.fit_boundary_imag)
self.ui.pgPlotWidget_real.addItem(self.fit_boundary_real) self.ui.pgPlotWidget_real.addItem(self.fit_boundary_real)
@ -144,21 +131,15 @@ class AppWindow(QMainWindow):
# fitting methods # fitting methods
fitMenu = self.menuBar().addMenu("Standard Fits") fitMenu = self.menuBar().addMenu("Standard Fits")
# lm # lm
fit_lmAction = QAction("&Levenberg-Marquardt", self) fit_lmAction = QAction("Complex NLS", self)
fit_lmAction.setShortcut(QKeySequence("Ctrl+F")) fit_lmAction.setShortcut(QKeySequence("Ctrl+F"))
fitMenu.addAction(fit_lmAction) fitMenu.addAction(fit_lmAction)
# lbfgsb # lbfgsb
fit_lbfgsbAction = QAction("&L-BFGS-B", self) fit_lbfgsbAction = QAction("NLS (Imag.)", self)
fitMenu.addAction(fit_lbfgsbAction) fitMenu.addAction(fit_lbfgsbAction)
# Simulated Annealing # Simulated Annealing
fit_annealAction = QAction("&Simulated Annealing", self) fit_annealAction = QAction("&Simulated Annealing", self)
fitMenu.addAction(fit_annealAction) 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) self.signalMapper = QSignalMapper(self)
for i, fit_action in enumerate([fit_lmAction, fit_lbfgsbAction, fit_annealAction for i, fit_action in enumerate([fit_lmAction, fit_lbfgsbAction, fit_annealAction
@ -179,17 +160,11 @@ class AppWindow(QMainWindow):
else: else:
pos = QPointF(0.0, 0.0) pos = QPointF(0.0, 0.0)
self.last_pos = pos 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): def mousePress(self, evt):
data_pos = self.last_pos data_pos = self.last_pos
mouse_in_imag = self.ui.pgPlotWidget_imag.underMouse() mouse_in_imag = self.ui.pgPlotWidget_imag.underMouse()
mouse_in_real = self.ui.pgPlotWidget_real.underMouse() mouse_in_real = self.ui.pgPlotWidget_real.underMouse()
msgBox = QMessageBox() msgBox = QMessageBox()
if self.ui.actionAdd_Peak.isChecked(): if self.ui.actionAdd_Peak.isChecked():
@ -396,7 +371,13 @@ class AppWindow(QMainWindow):
self.updatePlot() self.updatePlot()
def fitData_start(self, method): 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 # build function list
p0,funcs,fixed_params = [],[],[] p0,funcs,fixed_params = [],[],[]
@ -408,7 +389,8 @@ class AppWindow(QMainWindow):
_freq, _fit = self.data.get_data() _freq, _fit = self.data.get_data()
if not self._fit_thread.isRunning(): 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._fit_thread.start()
self.ui.statusbar.showMessage("Fitting ...") self.ui.statusbar.showMessage("Fitting ...")
else: else:

View File

@ -11,6 +11,217 @@ from scipy import optimize as opt, odr
import libyaff 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): def fit_anneal(x, y, p0, fixed, funcs):
raise NotImplementedError raise NotImplementedError
bounds = [(0, 1e14), (0, 1)] bounds = [(0, 1e14), (0, 1)]
@ -85,19 +296,6 @@ def hn(p, nu):
return e_loss # 2* oder nicht? 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): def mini_func(p, x, y):
res = y - multi_hn(p, x) 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