function [y,yi_or_p] = orthofit(x,y,n,xi) %ORTHOFIT Fit polynomial to data. % YS = ORTHOFIT(X,Y,N) smooths/fits data Y(X) in a least-squares sense % using a polynomial of degree N and returns the smoothed data YS. % % [YS,YI] = ORTHOFIT(X,Y,N,XI) also returns the values YI of the fitting % polynomial at the points of a different XI array. % % YI = ORTHOFIT(X,Y,N,XI) returns only the values YI of the fitting % polynomial at the points of the XI array. % % [YS,P] = ORTHOFIT(X,Y,N) returns the polynomial coefficients P for use % with POLYVAL. % % Notes: % ----- % ORTHOFIT smooths/fits data using a polynomial of degree N developed in % a sequence of orthogonal polynomials. ORTHOFIT is more appropriate than % POLYFIT for polynomial fitting and smoothing since this method does not % involve any matrix linear system but a simple recursive procedure. % Degrees much higher than 30 could be used with orthogonal polynomials, % whereas badly conditioned matrices may appear with a classical % polynomial fitting of degree typically higher than 10. % % To avoid using unnecessarily high degrees, you may let the function % POLYDEG choose it for you. POLYDEG finds an optimal polynomial degree % according to the Akaike's information criterion (available here). % % Example: % ------- % x = linspace(0,10,300); % y = sin(x.^3/100).^2 + 0.05*randn(size(x)); % ys = orthofit(x,y,25); % plot(x,y,'.',x,ys,'k') % % try POLYFIT for comparison... % % % Automatic degree determination with POLYDEG % n = polydeg(x,y); % ys = orthofit(x,y,n); % plot(x,y,'.',x,ys,'k') % % Reference: Méthodes de calcul numérique 2. JP Nougier. Hermes Science % Publications, 2001. Section 4.7 pp 116-121 % % Damien Garcia, 09/2007, revised 01/2010 % % See also POLYDEG, POLYFIT, POLYVAL. %% Check input arguments error(nargchk(3,4,nargin)); if ~isequal(size(x),size(y)) error('MATLAB:orthofit:XYSizeMismatch',... 'X and Y must have the same size.') elseif ~isscalar(n) || n~=round(abs(n)) error('MATLAB:orthofit:WrongNValue',... 'N must be a positive integer.') elseif ~isfloat(x) || ~isfloat(y) error('MATLAB:orthofit:NonFloatingXY',... 'X and Y must be floating point arrays.') elseif nargin==4 && ~isfloat(xi) error('MATLAB:orthofit:NonFloatingXI',... 'XI must be a floating point array.') end %% Particular case: n=0 if n==0 p = mean(y(:)); y = ones(size(y))*p; if nargin<4 yi_or_p = p; elseif nargout==2 yi_or_p = ones(size(xi))*p; else y = ones(size(xi))*p; end return end %% Reshape x = x(:); siz0 = size(y); y = y(:); %% Coefficients of the orthogonal polynomials p = zeros(3,n+1); p(2,2) = mean(x); N = length(x); PL = ones(N,n+1); PL(:,2) = x-p(2,2); for i = 3:n+1 p(2,i) = sum(x.*PL(:,i-1).^2)/sum(PL(:,i-1).^2); p(3,i) = sum(x.*PL(:,i-2).*PL(:,i-1))/sum(PL(:,i-2).^2); PL(:,i) = (x-p(2,i)).*PL(:,i-1)-p(3,i)*PL(:,i-2); end p(1,:) = sum(bsxfun(@times,PL,y))./sum(PL.^2); %% ys = smoothed y if nargin<4 || (nargin==4 && nargout==2) y = sum(bsxfun(@times,PL,p(1,:)),2); y = reshape(y,siz0); end %% Coefficients of the polynomial in its final form if nargin<4 yi = zeros(n+1); yi(1,n+1) = 1; yi(2,n:n+1) = [1 -p(2,2)]; for i = 3:n+1 yi(i,:) = [yi(i-1,2:end) 0]-p(2,i).*yi(i-1,:)-p(3,i)*yi(i-2,:); end p = sum(bsxfun(@times,p(1,:).',yi),1); yi_or_p = p; return end %% yi values for a given xi siz0 = size(xi); xi = xi(:); N = length(xi); n = size(p,2); yi = ones(N,n); yi(:,2) = xi-p(2,2); for i = 3:n yi(:,i) = (xi-p(2,i)).*yi(:,i-1) - bsxfun(@times,p(3,i),yi(:,i-2)); end yi = sum(bsxfun(@times,p(1,:),yi),2); yi = reshape(yi,siz0); if nargout==2 yi_or_p = yi; else y = yi; end