Search code examples
matlabtimecurve-fittingdistortiontrigonometry

Fit sine wave with a distorted time-base


I want to know the best way to fit a sine-wave with a distorted time base, in Matlab.

The distortion in time is given by a n-th order polynomial (n~10), of the form t_distort = P(t).

For example, consider the distortion t_distort = 8 + 12t + 6t^2 + t^3 (which is just the power series expansion of (t-2)^3).

This will distort a sine-wave as follows:

IMG

I want to be able to find the distortion given this distorted sine-wave. (i.e. I want to find the function t = G(t_distort), but t_distort = P(t) is unknown.)


Solution

  • Here's an analytical driven route that takes asin of the signal with proper unwrapping of the angle. Then you can fit a polynomial using polyfit on the angle or using other fit methods (search for fit and see). Last, take a sin of the fitted function and compare the signal to the fitted one... see this pedagogical example:

    % generate data
    t=linspace(0,10,1e2);
    x=0.02*(t+2).^3;
    y=sin(x);
    
    % take asin^2 to obtain points of "discontinuity" where then asin hits +-1
    da=(asin(y).^2);
    [val locs]=findpeaks(da); % this can be done in many other ways too...
    
    % construct the asin according to the proper phase unwrapping
    an=NaN(size(y));
    an(1:locs(1)-1)=asin(y(1:locs(1)-1));
    for n=2:numel(locs)
        an(locs(n-1)+1:locs(n)-1)=(n-1)*pi+(-1)^(n-1)*asin(y(locs(n-1)+1:locs(n)-1));
    end
    an(locs(n)+1:end)=n*pi+(-1)^(n)*asin(y(locs(n)+1:end));
    
    r=~isnan(an);
    p=polyfit(t(r),an(r),3);
    
    figure;  
    subplot(2,1,1); plot(t,y,'.',t,sin(polyval(p,t)),'r-');
    subplot(2,1,2); plot(t,x,'.',t,(polyval(p,t)),'r-');
    title(['mean error ' num2str(mean(abs(x-polyval(p,t))))]);
    

    enter image description here

    p =
    
        0.0200    0.1200    0.2400    0.1600
    

    The reason I preallocate with NaNand avoid taking the asin at points of discontinuity (locs) is to reduce the error of the fit later. As you can see, for a 100 points between 0,10 the average error is of the order of floating point accuracy, and the polynomial coefficients are as exact as you can have them.

    The fact that you are not taking a derivative (as in the very elegant Hilbert transform) allows to be numerically exact. For the same conditions the Hilbert transform solution will have a much bigger average error (order of unity vs 1e-15).

    The only limitation of this method is that you need enough points in the regime where the asin flips direction and that function inside the sin is well behaved. If there's a sampling issue you can truncate the data and only maintain a smaller range closer to zero, such that it'll be enough to characterize the function inside the sin. After all, you don't need millions op points to fit to a 3 parameter function.