Search code examples
parametersfixedmatlabcurve-fitting

How to fit function with fixed parameter?


I have an initial parameters for lsqcurvefit like

a0 = [value1, value2, value3];

and then

curvefitoptions = optimset('Display','final','MaxFunEvals',10000,'MaxIter',5000);
[a] = lsqcurvefit(@myfun,a0,x,y,lb,ub,curvefitoptions);

I want to be able to fix any of the initial parameters, f.ex. I'm fixing a0(1) and a0(3) at given value and optimizing only a0(2). How to do it? I was trying fixing it in ub and lb, but the same values are not allowed. Of course I can add a bit for ub, but it's not a nice way of doing it :)

Any suggestions? Thanks!


Solution

  • You can create an anonymous function that fixes the value of the first and third elements. You also need to tweak the start points (2nd argument) and the upper & lower bounds so that they only apply to the 2nd element, e.g.,

    a = lsqcurvefit( @(x, xdata) myfun([a0(1); x; a0(3)], xdata), a0(2), x, y, ...
            lb(2), ub(2), curvefitoptions );
    

    You can easily change this to fix the 2nd and 3rd elements, e.g.,

    a = lsqcurvefit( @(x, xdata) myfun([x; a0(2); a0(3)], xdata), a0(1), x, y, ...
            lb(1), ub(1), curvefitoptions );
    

    Or to fix just the 2nd element

    a = lsqcurvefit( @(x, xdata) myfun([x(1); a0(2); x(2)], xdata), a0([1,3]), x, y, ...
            lb([1,3]), ub([1,3]), curvefitoptions );
    

    To do this in general, start by defining the following (or similar) function

    function a = interlace( a, x, fix )
    a(~fix) = x;
    end
    

    You can then replace code like [a0(1); x; a0(3)] in the examples above with a call to interlace(). For example,

    fix = [1; 0; 1];
    a_free = lsqcurvefit( @(x, xdata) myfun( interlace( a0, x, fix ), xdata), ...
        a0(~fix), x, y, lb(~fix), ub(~fix), curvefitoptions );
    a = interlace( a0, a_free, fix );
    

    My testing of this is limited to the following code:

    %% A function
    myfun = @(x, xdata) x(1) + x(2)*xdata + x(3)./xdata;
    
    %% Some Data
    x = [0.036;0.14;0.42;0.49;0.66;0.68;0.76;0.79;0.8;0.85;0.92;0.93;0.96];
    y = [0.83;1;0.66;0.53;0.58;0.6;0.64;0.62;0.62;0.55;0.41;0.39;0.33];
    
    %% Initial conditions
    a0 = [1; 2; 3];
    
    %% Bounds
    lb = [-1; -2; -3];
    ub = [0.1; 0.2; 0.3];
    
    %% Fitting options
    curvefitoptions = optimset( 'Display', 'iter' );
    
    %% Fit all three parameters
    a = lsqcurvefit( myfun, a0, x, y, lb, ub, curvefitoptions )
    
    %% Fix some parameters
    fix = [1; 0; 1];
    
    a_free = lsqcurvefit( @(x, xdata) myfun( interlace( a0, x, fix ), xdata), ...
        a0(~fix), x, y, lb(~fix), ub(~fix), curvefitoptions );
    a = interlace( a0, a_free, fix );