3
|
24305 Views
|
12 Replies
|
21 Total Likes
View groups...
Share
GROUPS:

# Problem using optimization for modeling

Posted 11 years ago
 I'm trying use NMinimize to determine the parameters of a model, but I'm having problems using OutputResponse as part of the objective function. The model represents lithium-ion cells used to power an autonomous underwater vehicle. I can measure a real cell's voltage response to changes in output current, and I want to compare that output to the output of my model for a given set of model circuit parameters. If I can minimize the difference between the output of my model and the output of a real cell, then my model will be correct. In general, I'm trying to minimize the difference between two curves.I use OutputResponse to generate the output of my model. My problem is that OutputResponse can't simulate the response of a system that contains symbolic parameters. But my model parameters have to be symbolic so NMinimize can vary them. Here is my code (sorry for the long posting):Write the transfer function of the circuit that models the complex impedance of the cell.tf = (Rser + Rfast/((Rfast s Cfast) + 1) + Rslow/((Rslow s Cslow) + 1));Convert the tf into a transfer function model.tfm = TransferFunctionModel[{{tf}}, s];Generate a battery current profile.Ibatt = UnitStep[t - 1] - UnitStep[t - 5];Plot[Ibatt, {t, 0, 10}, Exclusions -> None]Assign values to the circuit parameters.vals = {Rser -> 0.1, Rfast -> 0.05, Cfast -> 10, Rslow -> 0.01, Cslow -> 100};Voc = 4.2;Find the output response for these circuit values and current profile.y = OutputResponse[tfm /. vals, Ibatt, {t, 10}];Plot[Voc - y, {t, 0, 10}]Define some different circuit values to get a different response and plot both responses.dvals = {Rser -> 0.06, Rfast -> 0.08, Cfast -> 15, Rslow -> 0.015, Cslow -> 50};dy = OutputResponse[tfm /. dvals, Ibatt, {t, 10}];Plot[{Voc - y, Voc - dy}, {t, 0, 10}]Find the area of the difference between the two responses.Plot[Abs[y - dy], {t, 0, 10}]NIntegrate[Abs[y - dy], {t, 0, 10}]{0.156543}I now have an objective function and can try modeling. Given only the first response curve as a template, find the circuit values that produced that response as a test of the modeling algorithm. Do this by minimizing the difference between the template and the output of a model whose circuit values are adjusted by NMinimize. In this case I already know the answer, but if it works then I can use measurements of an actual cell as my template. NMinimize[  NIntegrate[   Abs[    OutputResponse[tfm, Ibatt, {t, 0, 10}] - y   ], {t, 0, 10}  ], {Rser, Rfast, Cfast, Rslow, Cslow} ]  OutputResponse::symbs: Cannot simulate response of system StateSpaceModel[{{{0,1},{-(1/(Cfast Cslow Rfast Rslow)),-((Cfast Rfast+Cslow Rslow)/(Cfast Cslow Rfast Rslow))}},{{0},{1}},{{-(Rser/(Cfast Cslow Rfast Rslow))+(Rfast+Rser+Rslow)/(Cfast Cslow Rfast Rslow),-((Rser (Cfast Rfast+Cslow Rslow))/(Cfast Cslow Rfast Rslow))+(<<1>>+<<2>>+<<1>>)/<<1>>}},{{Rser}}},<<18>>->None] that contains symbolic parameter(s). >>As you can see, OutputResponse can't produce an output because it has symbolic parameters.How do I get NMinimize to set the values of the parameters before OutputResponse uses them? Will NMinimize work at all with this type of objective function?Thanks for any help,Paul
12 Replies
Sort By:
Posted 11 years ago
 Though not recomended, you can still use NMinimize or FindMinimum in this way. Here is a piece of code that should work regardless of problematic numeric performance: Define the system and input: tf[Rser_, Rfast_, Cfast_, Rslow_, Cslow_, s_] := (Rser + Rfast/((Rfast s Cfast) + 1) + Rslow/((Rslow s Cslow) + 1)) tfm[Rser_, Rfast_, Cfast_, Rslow_, Cslow_, s_] :=    TransferFunctionModel[{{tf[Rser, Rfast, Cfast, Rslow, Cslow, s]}}, s] Ibatt = UnitStep[t - 1] - UnitStep[t - 5];Define responce y and responce f with parametery = OutputResponse[tfm[0.1, 0.05, 10, 0.01`, 100, t], Ibatt, {t, 10}]; f[Rser_?NumericQ, Rfast_?NumericQ, Cfast_?NumericQ, Rslow_?NumericQ, Cslow_?NumericQ] :=    First@NIntegrate[         Abs[OutputResponse[tfm[Rser, Rfast, Cfast, Rslow, Cslow, t],Ibatt, {t, 0, 10}] - y],         {t, 0, 10},         Method -> {"LocalAdaptive", "SymbolicProcessing" -> 0, Method -> {"TrapezoidalRule"}} ]You can use the optimization function here to find the close result: and use a dynamic variable to track the process: FindMinimum[         f[Rser, Rfast, Cfast, Rslow, Cslow],         {{Rser, 0.05}, {Rfast, 0.08}, {Cfast, 5}, {Rslow, 1/10}, {Cslow, 50}}, StepMonitor :> (x = Cslow)]Dynamic[x]The result I have for this set of value is not bad even though it halted due to poor convergence: During evaluation of In[30]:= FindMinimum::sdprec: Line search unable to find a sufficient decrease in the function value with MachinePrecision digit precision. >>Out[30]= {0.173594, {Rser -> 0.0555499, Rfast -> 0.0593808, Cfast -> 5., Rslow -> 0.0779124, Cslow -> 50.}}For this type of non-linear system, you may want to find some heuristical values first before you go ahead. Proper start value and boundaries for the parameters are very helpful in general.
Posted 11 years ago
 After evaluating all but your last block of code I look at the followingIn[14]:= tfmOut[14]= TransferFunctionModel[{{{Rfast + Rser + Rslow + Cfast*Rfast*Rser*s + Cfast*Rfast*Rslow*s + Cslow*Rfast*Rslow*s + Cslow*Rser*Rslow*s + Cfast*Cslow*Rfast*Rser*Rslow*s^2}}, (1 + Cfast*Rfast*s)*(1 + Cslow*Rslow*s)}, s]Thus I change your last block of code to be In[15]:= f[{Rse_?NumericQ, Rfa_?NumericQ, Cfa_?NumericQ, Rsl_?NumericQ, Csl_?NumericQ}] :=  (Print[{tfm /. {Rser -> Rse, Rfast -> Rfa, Cfast -> Cfa, Rslow -> Rsl, Cslow -> Csl}}]];    NIntegrate[Abs[OutputResponse[tfm/.{Rser->Rse,Rfast->Rfa,Cfast->Cfa,Rslow->Rsl,Cslow->Csl}, Ibatt, {t,0,10}]-y], {t,0,10}]  ); NMinimize[f[{Rser, Rfast, Cfast, Rslow, Cslow}], {Rser, Rfast, Cfast, Rslow, Cslow}]  During evaluation of In[16]:={TransferFunctionModel[{{{1.07688+0.15247*s-0.02527*s^2}},(1-0.07403*s)*(1+0.34557*s)},s]}  During evaluation of In[16]:= {TransferFunctionModel[{{{1.07688+0.15247*s-0.02527*s^2}},(1-0.07403*s)*(1+0.34557*s)},s]}During evaluation of In[16]:= NMinimize::nnum: The function value {1.19169*10^51} is not a number at{Cfast,Cslow,Rfast,Rser,Rslow} = {0.989531,0.284773,0.349234,0.987641,-0.259993}. >>Out[17]= NMinimize[f[{Rser, Rfast, Cfast, Rslow, Cslow}], {Rser, Rfast, Cfast, Rslow, Cslow}]I make some of those changes based on looking at your use of OutputResponse in a previous code block and the rest based on experimentation.By introducing a dummy function f and using ?NumericQ on each of the arguments I forced everything to be numeric to satisfy NIntegrate.By using :=(Print[],NIntegrate[]); I get a look at your integrand every time f is called.The error message from NMinimize blowing up may be because I've misused part of your code.Hopefully something in this will give you the needed clue to get to the next step.
Posted 11 years ago
 This is officially implemented via the HoldAll attribute of NMinimize and its siblings.NMinimize does not have the HoldAll attribute. FindMinimum does, but all that means is that the argument is not evaluated before being passed to function. Then, to quote the documentation, FindMinimum "first localizes the values of all variables, then evaluates f with the variables being symbolic, and then repeatedly evaluates the result numerically". The use of a black box objective function f (defined using _?NumericQ) prevents the symbolic evaluation step by keeping f unevaluated for non-numeric arguments.
Posted 11 years ago
 Bill - I really like your approach of using a dummy function. I don't understand how adding the pattern test to the function arguments forces them to be numbers. I thought that adding those qualifiers to function arguments tests the arguments and rejects them if they don't match, but it doesn't force them to be anything. Oh well, there's a lot about Mma I don't understand...I defined my dummy function as follows f[{Rse_?NumericQ, Rfa_?NumericQ, Cfa_?NumericQ, Rsl_?NumericQ, Csl_?NumericQ}] :=  (error =     NIntegrate[     Abs[OutputResponse[        tfm /. {Rser -> Rse, Rfast -> Rfa, Cfast -> Cfa, Rslow -> Rsl,           Cslow -> Csl}, Ibatt, {t, 0, 10}] - y     ], {t, 0, 10}    ];   Print[error, " ", Rser, " ", Rfast, " ", Cfast, " ", Rslow, " ", Cslow];)Unfortunately, when I run the minimization, even adding constraints, I getNMinimize[{f[{Rser, Rfast, Cfast, Rslow, Cslow}], Rser > 0,   Rser < 0.5, Rfast > 0, Rfast < 0.5, Cfast > 10, Cfast < 100,   Rslow > 0, Rslow < 0.5, Cslow > 50, Cslow < 200}, {Rser, Rfast, Cfast, Rslow, Cslow}]{1.74048} 0.485254 0.301249 93.0382 0.148942 135.54{1.74048} 0.485254 0.301249 93.0382 0.148942 135.54{1.74048} Rser Rfast Cfast Rslow CslowNMinimize::nnum: The function value Null is not a number at {Cfast,Cslow,Rfast,Rser,Rslow} = {93.0382,135.54,0.301249,0.485254,0.148942}. >>The good news is that NMinimize is working with numeric arguments. The bad news is that the arguments don't seem to change and then it fails after just two iterations. I'm not sure what's going on but will play with it some more. Thanks again for looking at it for me.Shenghui - Thank you also for taking the time to help with this. I'm going to try your suggestions tomorrow. Perhaps your method will work with constraints.
Posted 11 years ago
 @Bill, you are right:This often happens because something like NMinimize or Integrate might call your function first with just symbols instead of beginning with numeric values. The guess is that NMinimize or Integrate is "probing" or testing your function, to see if it can get a symbolic result back and save a lot of time testing with numerics.This is officially implemented via the HoldAll attribute of NMinimize and its siblings.
Posted 11 years ago
Posted 11 years ago
 It might be possible to get a close enough answer by searching the whole parameter space (in the spirit of Stephen Wolfram's "A New Kind of Science")This code will take a while, but it will finish in an overnight run.data = Table[f[{Rser, Rfast, Cfast, Rslow, Cslow}], {Rser, 0, .5, .1}, {Rfast, 0, .5, .1}, {Cfast, 10, 100, 10}, {Rslow, 0, .5, .1}, {Cslow, 50, 200, 30}]; {Min[data], Position[data, Min[data]]}That way you can get a better sense for what is going on by studying data, and also you get an answer with some feeling for its correctness.
Posted 11 years ago
 Progress update: I've managed to successfully run my test case, minimizing the error between my model output and my test output.Timing[NMinimize[{f[{Rser, Rfast, Cfast, Rslow, Cslow}],    0 < Rser < 0.5, 0 < Rfast < 0.5, 10 < Cfast < 100, 0 < Rslow < 0.5,    50 < Cslow < 200}, {Rser, Rfast, Cfast, Rslow, Cslow},   Method -> "DifferentialEvolution"]]{23648.140956, {0.00278763, {Rser -> 0.104464, Rfast -> 0.0426679,    Cfast -> 14.1031, Rslow -> 0.0126952, Cslow -> 50.}}}The process is pretty slow, taking over 6.5 hours to run, but at least it produced a decent result. Just to remind you, the correct values arevals = {Rser -> 0.1, Rfast -> 0.05, Cfast -> 10, Rslow -> 0.01,   Cslow -> 100}The resistor values are pretty close, but the capacitor values are 40% high and 50% low. However, if I compare the output of the optimized result with the correct output, it's not too bad.Plot[{Voc - y, Voc - yopt}, {t, 0, 10}]Plot[Abs[y - yopt], {t, 0, 10}, PlotRange -> All]Perhaps I can speed up the process using Todd's method above, which searches the whole parameter space. My algorithm was searching about two solutions per second. Todd's approach would need to look at 6 x 6 x 10 x 6 x 6 = 12,960 solutions, which would take about 1.8 hours. This might get me close to the optimum parameters, after which I could let NMinimize take over (assuming the parameter space is well enough behaved). This will be more important as a I attempt to model a real cell and don't know a priori what the correct model values are. I'll attempt to model some real test data next.
Posted 11 years ago
 Paul, How are things going with your project?Besides using a uniform search to give a good seed to NMinimize, it can give a you a bunch of information about the error function and about the result the NMinimize gives.  For example,ListLinePlot[Flatten[data]]You can use data to answer the simplest questions like would there be lots of choices near the minimum? or are there nearly optimal choices far from the absolute minimum?There are lots of other things you can plug the data into like the descriptive statistics functions in Mathematica or the upload at Wolfram Alpha Pro
Posted 11 years ago
 Back to the implementation, it might speed things to discretize all the domains.  Above I suggested computing data as a uniform search of the parameter space, but you can also try storing the values of the OutputResponses for a finite set of values.   Then for each y you can just run it without recalculating the model functions.  (an alternative to this is to store the model functions as data).Instead of tfm you would haveOutputValues[Rser_, Rfast_, Cfast_, Rslow_, Cslow_] := OutputResponse[tfm[Rser, Rfast, Cfast, Rslow, Cslow, t], Ibatt, {t, 0, 10}] /. Table[{t -> i}, {i, 0, 10}]tfmdata=Table[OutputValues[Rser, Rfast, Cfast, Rslow, Cslow], {Rser, 0, .5, .1}, {Rfast, 0, .5, .1}, {Cfast, 10, 100, 10}, {Rslow, 0, .5, .1}, {Cslow, 50, 200, 30}];Note that instead of y you would have yvals sampled at the same values of t.Instead of f you would havefx[Rser_Integer, Rfast_, Cfast_, Rslow_, Cslow_, yvals_] := Total[tfmdata[[Rser, Rfast, Cfast, Rslow, Cslow]] - yvals]Instead of data you would havedatax[yvals_]:= Table[fx[Rser, Rfast, Cfast, Rslow, Cslow,yvals], {Rser, 6}, {Rfast, 6}, {Cfast, 11}, {Rslow, 6}, {Cslow,6}];then e.g.,datay=datax[Table[y[i],{i,0,10}][/i]
Posted 11 years ago