Exponential curve fitting

We use linear least squares fitting to observe the exponential behaviour in the voltage of a capacitor as it charges or discharges in an RC circuit as a function of time.

The fitting of an exponential function can be accomplished through linear least squares (LLSQ) after taking the logarithm of the data.

> with(plots):

We define a linear least squares procedure: (developed in the worksheet DataAnalysis.mws )

> addme:=arg->evalf(Sum(arg[_i],_i=1..nops(arg)));

[Maple Math]

> addpr:=(arg1,arg2)->evalf(Sum(arg1[_i]*arg2[_i],_i=1..nops(arg1)));

[Maple Math]

> LLSQ:=proc(xv,yv) local _i,N,a,b,c,d,Delta,A,B,sq,sigsq,dA,dB;

> N:=nops(xv);

> if nops(yv)<N then RETURN(`Mismatch in sizes of xv and yv`); fi;

> c:=addpr(xv,xv);

> d:=addme(xv);

> a:=addpr(xv,yv);

> b:=addme(yv);

> Delta:=evalf(N*c-d^2);

> A:=(c*b-d*a)/Delta;

> B:=(N*a-d*b)/Delta;

> sq:=[]; _i:='_i': for _i from 1 to N do:

> sq:=[op(sq),evalf(yv[_i]-A-B*xv[_i])]: od:

> sigsq:=addpr(sq,sq)/(N-2);

> dA:=sigsq*c/Delta;

> dB:=evalf(N*sigsq)/Delta;

> print(`[A,B,sigma,dA,dB]`);

> [A,B,evalf(sqrt(sigsq),4),evalf(sqrt(dA),4),evalf(sqrt(dB),4)];

> end:

>

The time at which the capacitor voltage was measured (in seconds):

> Times:=[]:

> for i from 1 to 21 do:

> Time:=(i-1)*10: Times:=[op(Times),Time]: od:

> Times;

[Maple Math]

The voltage across a big electrolytic capacitor while being connected to 8.1 Volts through a 1000 Ohm resistor at these times was measured to be:

> V_Cchg:=[0.025,0.555,1.04,1.47,1.85,2.16,2.43,2.66,2.83,3.05,3.22,3.38,3.52,3.66,3.79,3.9,3.97,4.15,4.25,4.34,4.43];

[Maple Math]

The battery voltage was 8.1 Volts. The capacitor charged maximally to 7.4 Volts when fed through a 1000 Ohm resistor! A leaking current of 0.7 mA accounting for the voltage drop across the resistor in the steady-state regime was observed for the electrolytic capacitor. A non-ideal world after all...

We generate a graph of the data points. First for the charging regime, then for the discharge.

> i:='i': PL_c:=[seq([Times[i],V_Cchg[i]],i=1..nops(Times))]:

> P_c:=plot(PL_c,style=point,symbol=cross,color=red): display(P_c);

[Maple Plot]

The capacitor was discharged through the same resistor. We reset time to zero and use the same time interval as before.

> V_Cdis:=[4.29,3.96,3.67,3.42,3.19,2.98,2.79,2.62,2.45,2.3,2.15,2.02,1.9,1.78,1.67,1.57,1.47,1.39,1.3,1.23,1.15];

[Maple Math]

> i:='i': PL_d:=[seq([Times[i],V_Cdis[i]],i=1..nops(Times))]:

> P_d:=plot(PL_d,style=point,symbol=cross,color=green):

> display(P_d);

[Maple Plot]

The discharge regime is easy to analyze, we have an exponential decay. Taking the log of the data allows to extract the decay constant using LLSQ fitting:

> ln_of_V_Cdis:=map(ln,V_Cdis);

[Maple Math]
[Maple Math]
[Maple Math]

> i:='i': PL_dl:=[seq([Times[i],ln_of_V_Cdis[i]],i=1..nops(Times))]:

> P_dl:=plot(PL_dl,style=point,symbol=cross,color=blue):

> display(P_dl);

[Maple Plot]

This looks perfectly linear, and thus we have confidence in the fit.

> i:='i': sol_d:=LLSQ(Times,ln_of_V_Cdis);

[Maple Math]

[Maple Math]

> tau:=-1/sol_d[2];

[Maple Math]

We discharged the capacitor with a 1 kOhm resistor.

> evalf(tau/1000);

[Maple Math]

> evalf(%*10^6);

[Maple Math]

The capacitor was actually rated at 110 000 microFarads. We graph the fit together with the original voltage measurements:

> y_d:=exp(sol_d[1]+sol_d[2]*t);

[Maple Math]

> P_dfit:=plot(y_d,t=0..200,color=black):

> display({P_d,P_dfit},scaling=unconstrained);

[Maple Plot]

The charging regime is described by the expression

[Maple Math]

To analyze the charging data we need a map that first divides out the final voltage (the one reached for asymptotic times, which in our case is 7.4V and not the battery voltage due to the leakage) from the datapoints, and computes the difference to 1. Then we take the logarithm of the voltages. The real part in the map below is taken to avoid a wrong complex-valued choice of branch.

> myfun:=x->Re(ln(1-x/7.4));

[Maple Math]

> ln_of_V_Cchg:=map(myfun,V_Cchg);

[Maple Math]
[Maple Math]
[Maple Math]

> i:='i': PL_cl:=[seq([Times[i],ln_of_V_Cchg[i]],i=1..nops(Times))]:

> P_cl:=plot(PL_cl,style=point,symbol=cross,color=blue):

> display(P_cl,scaling=unconstrained);

[Maple Plot]

We observe that the data points behave linearly for the first third, and then turn over to a different slope. Thus, we pick out a part of the data set for the fitting.

> nops(Times);

[Maple Math]

> Times1:=[seq(Times[i],i=1..7)]: ln_of_V_Cchg1:=[seq(ln_of_V_Cchg[i],i=1..7)]:

> sol_c:=LLSQ(Times1,ln_of_V_Cchg1);

[Maple Math]

[Maple Math]

> tau_c:=-1/sol_c[2];

[Maple Math]

> C_c:=evalf(tau_c/1000);

[Maple Math]

> evalf(C_c*10^6*mu*F);

[Maple Math]

The value of the capacitance is apparently quite close to the one obtained from the discharge cycle.

Exercise:

Use the uncertainty on the slopes for the charge and discharge cycles to determine whether the two determinations of the capacitance are consistent with each other.

Exercise:

Use Maple's built-in LLSQ procedure (use ?fit to determine its usage) to perform a fit for which the intercept is fixed as A =0 (only the slope is determined from the fit). Compare your results for the capacitance.

Systematic Error

If we had used all the data points from the charging cycle, we would have obtained a smaller slope in the linear fit, and as a result a substantially larger capacitance

(about 30% higher, but also a much larger uncertainty). To use such a fit blindly (without checking whether the data to be fitted look like a straight line with statistical scatter) would result in the introduction of a systematic error. The physical reason for this systematic error is the strange behaviour in the charge cycle, whereby the capacictor never charges up to the full voltage, and a leakage current persists in the asymptotic time regime. The capacitor we used was an old specimen (garage sale purchase), and is likely to be faulty, i.e., probably performed better when it was new.

We compare the fit result with the data over the full charge time that was observed.

> y_c:=7.4*(1-exp(-t/tau_c));

[Maple Math]

> P_cfit:=plot(y_c,t=0..200,color=black):

> display({P_cfit,P_c});

[Maple Plot]

>