// fit 2 exponential data with two exponentials

tmax = 10
ndata = 101
sum=0
double tdata[ndata], ydata[ndata]
tolerance =1e-6
proc datagenerator() {local t, y, i
	for i=0, ndata - 1 {
		t = i/(ndata-1)*tmax
		tdata[i] = t
		ydata[i] = 1.5*exp(-t) +1.5* exp(-t/4)
	}
}

datagenerator()

func model() {local t, y, i
	t = $1
	y = $2*exp(-t/$3) + $4*exp(-t/$5)
	return y
}
A1=1.5	
tau1=8	
A2=1.5	
tau2=1

double parm[4]
proc init()	{	//initial guess
	parm[0]=A1	parm[1]=tau1	parm[2]=A2	parm[3]=tau2
}
init()

proc makepanels() {
xpanel("Fitted values")
xvalue("Amp1","parm[0]",1,"",0,1)
xvalue("tau1","parm[1]",1,"",0,1)
xvalue("Amp2","parm[2]",1,"",0,1)
xvalue("tau2","parm[3]",1,"",0,1)
xvalue("fit error", "err()")
xvalue("# calls to errfun()", "iterations")
xpanel(100,600)

xpanel("Initial guesses & Control")
xvalue("Amp1","A1",1,"",0,1)
xvalue("tau1","tau1",1,"",0,1)
xvalue("Amp2","A2",1,"",0,1)
xvalue("tau2","tau2",1,"",0,1)
//xvalue("total time","tmax",1,"datagenerator()",0,1)
xbutton("run","run()")
xpanel(100,500)
} //end of makepanels

func err() { return errfun(parm[0], parm[1], parm[2], parm[3]) }
func mod() { return model($1, parm[0], parm[1], parm[2], parm[3]) }

minerr = 1e9
func errfun() { local sum, y, i
	iterations = iterations + 1
	sum = 0
	for i=0,ndata-1 {
		y = model(tdata[i], $1, $2, $3, $4) - ydata[i]
		sum = sum + y*y
	}
	if (sum < minerr) {
		minerr = sum
		doNotify()
	}
	return sum
}

objectvar g
g = new Graph()
g.size(0,tmax,0,3)
g.color(2)
g.vector(ndata, &tdata[0], &ydata[0])
g.label("Data:     1.5e-t/4 + 1.5e-t")
g.color(1)
g.addexpr("mod(t)")
g.label("Fitted with:  1.5e-t/4 + 1.5e-t")

proc run()	{init()		datagenerator()
	attr_praxis(tolerance, 1, 0)
	minerr = 1e9
	iterations = 0
	fit_praxis(4, "errfun",  &parm[0])
	g.begin()
	for i=0, ndata-1 { t= tdata[i]  g.plot(t) }
	g.flush()
}

makepanels()