Mokus
Mokus

Reputation: 10400

How can I fit a cosine function?

I wrote a python function to get the parameters of the following cosine function: enter image description here

param = Parameters()    
param.add( 'amp', value = amp_guess, min = 0.1 * amp_guess, max = amp_guess )

param.add( 'off', value = off_guess, min = -10, max = 10 )

param.add( 'shift', value = shift_guess[0], min = 0, max = 2 * np.pi, )

fit_values = minimize( self.residual, param, args = ( azi_unique, los_unique ) )

def residual( self, param, azi, data ):
        """
        Parameters
        ----------

        Returns
        -------
        """
        amp = param['amp'].value
        off = param['off'].value
        shift = param['shift'].value
        model = off + amp * np.cos( azi - shift )
        return model - data

In Matlab how can get the amplitude, offset and shift of the cosine function?

Upvotes: 2

Views: 5428

Answers (2)

Rody Oldenhuis
Rody Oldenhuis

Reputation: 38032

My experience tells me that it's always good to depend as little as possible on toolboxes. For your particular case, the model is simple and doing it manually is pretty straightforward.

Assuming that you have the following model:

y = B + A*cos(w*x + phi)

and that your data is equally-spaced, then:

%// Create some bogus data

A   = 8;
B   = -4;
w   = 0.2;
phi = 1.8;

x = 0 : 0.1 : 8.4*pi;
y = B + A*cos(w*x + phi) + 0.5*randn(size(x));

%// Find kick-ass initial estimates
L = length(y);
N = 2^nextpow2(L);

B0 = (max(y(:))+min(y(:)))/2;

Y = fft(y-B0, N)/L;
f = 5/(x(2)-x(1)) * linspace(0,1,N/2+1);

[A0,I] = max( 2*abs(Y(1:N/2+1)) );
w0   = f(I);
phi0 = 2*imag(Y(I));

%// Refine the fit
sol = fminsearch(@(t) sum( (y(:)-t(1)-t(2)*cos(t(3)*x(:)+t(4))).^2 ), [B0 A0 w0 phi0])

Results:
 

sol = %// B was -4      A was 8       w was 0.2     phi was 1.8                
         -4.0097e+000   7.9913e+000   1.9998e-001   1.7961e+000    

Upvotes: 5

MrAzzaman
MrAzzaman

Reputation: 4768

MATLAB has a function called lsqcurvefit in the optimisation toolbox:

lsqcurvefit(fun,X0,xdata,ydata,lbound,ubound);

where fun is the function to fit, x0 is the initial parameter guess, xdata and ydata are self-explanatory, and lbound and ubound are the lower and upper bounds to the parameters. So, for instance, you might have a function:

% x(1) = amp
% x(2) = shift
% x(3) = offset
% note cosd instead of cos, because your data appears to be in degrees
cosfit = @(x,xdata) x(1) .* cosd(xdata - x(2)) + x(3);

You would then call the lsqcurvefit function as follows:

guess = [7,150,0.5];
lbound = [-10,0,-10]
ubound = [10,360,10]
fit_values = lsqcurvefit(cosfit,guess,azi_unique,los_unique,lbound,ubound);

Upvotes: 4

Related Questions