Using Optimization Toolbox to Fit a Piecewise Curve

37 views (last 30 days)
Hey guys,
I was recently given the problem of fitting a curve that is piecewise (a linear section, an exponential section, and another linear section) continuous specifically using the Optimization Toolbox. I didn't have access to the actual data, so I interpolated the following points:
x = 1:0.01:1.25;
y = [0 0 0 0 0 0 0 0 0 0 0 0 0.0010 0.0025 0.0040 0.0050 0.0100 0.0150 0.0200 0.0300 0.0500 0.0700 0.0900 0.1100 0.1350 0.1600];
I attempted to use the lsqcurvefit function, but was given the error of "User supplied objective function must return a scalar value."
My objective function was as follows:
f = ...
(c(1)*xx).*(1<=xx & xx<=1.12)+...
(c(2)+c(3)*exp(xx)).*(1.12<xx & xx<=1.2)+...
(c(4)*xx).*(1.2<xx & xx<=1.25);
Likewise, my constraints are as follows:
c(1) = 1.12*c(3)*exp(1.12)
1.2*c(3)*exp(1.2) = c(4)
c(1)*1.12 = c(2)+c(3)*exp(1.12)
c(4)*1.2 = c(2)+c(3)*exp(1.2)
I have them defined as the following Aeq:
Aeq = [-1 0 1.12*exp(1.12) 0; 0 0 1.2*exp(1.2) -1; -1.12 1 exp(1.12) 0; 0 1 exp(1.2) -1.2]
Such that Aeq*c = [0 0 0 0]', meaning Beq = [0 0 0 0]'
The first two are to equate the slopes of the functions where they meet, and the second two are to equate the values where they meet.
I may be going about this the completely wrong way, I may have something defined wrong, I don't know. I watched about 2 hours of the Optimization Toolbox Webinar, and did a ton of research online, but couldn't find any examples or previous questions about someone doing what I was.
This was originally for homework, which I obviously didn't get correct, but I have the feeling that this will come up again, and I really want to understand this. To anyone who can help, I really appreciate it. If you have any questions, I'd love to help clarify what I was doing. Likewise, if you could walk me through what you would do as well, I'd again appreciate it.
Signed, Frustrated and Sleep-Deprived
EDIT--------- I have a function for my objective:
function f = objecfun(c,xx)
f = ...
(c(1)*xx)*(0<=xx & xx<=1.12)+...
(c(2)+c(3)*exp(xx))*(1.12<xx & xx<=1.2)+...
(c(4)*xx)*(1.2<xx & xx<=1.25);
Variables defined above for x and y, as well as:
xx = 1:0.001:1.25;
xx = xx'
For my actual fit, I was just planning on plugging in:
answer = lsqcurvefit(objecfun,1,x,y);
I'm assuming this isn't right, then, since I can't even start to apply any constraints.
  4 Comments
Walter Roberson
Walter Roberson on 19 Jan 2012
The f you show is an expression, not a function.
We are going to need the actual call to lsqcurvefit and the definition of the objective functions (and any auxiliary functions you use to define it.)
Like actual code, not mathematical approximations of it. Details are important in this matter.

Sign in to comment.

Answers (2)

Andrew Newell
Andrew Newell on 19 Jan 2012
You're getting the error because you are doing element-by-element multiplication ( .* ) in your objective function. That will return a vector. Assuming xx is a column vector, try
(c(1)*xx).'*(1<=xx & xx<=1.12)+...
(c(2)+c(3)*exp(xx)).'*(1.12<xx & xx<=1.2)+...
(c(4)*xx).'*(1.2<xx & xx<=1.25);
To make sure xx is a column vector, put
xx = xx(:);
near the top of the function.
  2 Comments
Derek Roberts
Derek Roberts on 19 Jan 2012
Now I'm getting a too many input arguments answer. Should I maybe use a different fit tool?
Walter Roberson
Walter Roberson on 19 Jan 2012
We need actual code to answer your questions. Details are important.

Sign in to comment.


Walter Roberson
Walter Roberson on 19 Jan 2012
The line
answer = lsqcurvefit(objecfun,1,x,y);
calls objecfun once, hopes to get a function handle as a result, and tries to lsqcurvefit on that returned value.
Perhaps you are using
answer = lsqcurvefit(@objecfun,1,x,y);
which constructs the function handle from objecfun instead of calling objecfun?
This is the sort of point where details are important.
You give a definition for xx which is with a step size of 0.001 where your x is a step size of 0.01 . But you pass x in to lsqcurvefit() in the xdata slot, where it will become the second parameter to your objective function, xx . So we have to ask about the naming conflicts and the size conflicts.
Your x0 is a scalar, and the objective function is required to accept a vector or matrix first parameter, the one you have named c. I see no reason why exactly 4 values might happen to be passed in. I would speculate that you should expect length(y) by length(x0) as your first parameter, but I cannot test that at the moment, and the example on the doc page suggests that the first parameter will be the same as the size of your x0 and thus a scalar in your case.
I do not at the moment see why it would say the objective function should return a scalar, since the documentation does indicate it should return something the same size as y, which would be 26 elements in your case.
I am getting the impression that really your c(1) to c(4) are constants that you should be passing in as extra parameters; see http://www.mathworks.com/help/toolbox/optim/ug/brhkghv-7.html
  1 Comment
Derek Roberts
Derek Roberts on 19 Jan 2012
I'm using lsqcurvefit without a function handle for objecfun. It tells me that 'c' is undefined. 'c' would be undefined, since those are parameters which I need solved for via curve fitting, so your last statement is correct. When watching the webinar series online, the speaker used an anonymous function, as so:
answer = lsqcurvefit(@(c) objecfun(c,xx), [1 1 1 1], x, y)
You're completely right about x0 needing to be a vector, so thanks for pointing that out.
I was under the impression that lsqcurvefit returned a vector of "solved" parameters to fit the curve, which in my case would hopefully be the vector 'c'.

Sign in to comment.

Categories

Find more on Get Started with Optimization Toolbox in Help Center and File Exchange

Products

Community Treasure Hunt

Find the treasures in MATLAB Central and discover how the community can help you!

Start Hunting!