www.gusucode.com > 生物信号工具箱 > 生物信号工具箱/生物信号工具箱/Biosignal/Biosignal/Adaptive_Algorithms/harmonic_est.m

    function [varargout]=harmonic_est(x,varargin)
%
%[theta,theta_curve,b,a,err]=harmonic_est(x,P,Fs,theta,mu,r)
%
% 
% Implements harmonic frequency tracking algorithm as described in 
% IEEE Signal Processing Magazine (189) 11/09 by Tan and Jiang.
% Parameters are:
% 
% Input:
%     x     - (Nx1, required) Signal to be tracked
%     P     - (1x1, required) Order of how many harmonics (including fundamental)
%              to be estimated.
%     Fs    - (1x1, optional) Sampling frequency (Hz). If present output is returned
%             in Hertz, if absent output is returned in radians.
%     theta - (1x1, optional) Initial guess of the fundamental frequency capture range.
%     mu    - (1x1, optional) Step size of the LMS algorithm.
%     r     - (1x1, optinoal) Magnitude of the pole for the harmonic comb filter
%             (0<r<1).
%
% Output:
%     theta -       (1x1,required) Final estimate of the fundamental frequency.
%     theta_curve - (Nx1,optional) Tracking curve of the instantenous fundamental
%                                  frequency.
%     b-            (1xP,optional) b coefficients of the comb filter.
%     a-            (1xP,optional) a coefficients fo the comb filter.
% 
% 
% %Example
% clear all;close all;clc
% N=1200;
% Fs=8000;
% tm=[0:1/Fs:(N-1)/Fs]';
% t=[0:400:N]+1;
% snr=10^(-18/20);
% F=[1000 1075 975];
% x=[];
% true=[];
% for i=1:3
%     T=2*pi*F(i).*tm(t(i):t(i+1)-1);
%     sig=sin(T)+0.5*cos(T*2)+0.25*cos(T*3)+randn(N/3,1).*snr;
%     x=[x;sig];
%     true=[true;ones(N/3,1)*F(i)];
% end
% 
% [theta,theta_curve,b,a]=harmonic_est(x,3,Fs);
% subplot(211)
% plot(tm,theta_curve)
% hold on
% plot(tm,true,'r--','LineWidth',3)
% grid on
% xlabel('Time')
% ylabel('Fundamental Frequency Estimate')
% legend('Tracking','True')
% subplot(212)
% [H,F]=freqz(b,a,N,Fs);
% plot(F,log10(abs(H)))
% title('Final Comb Filter')
% xlabel('Frequency')
% ylabel('Magnitude')
% 
%
%
%
%%%  Written by Ikaro Silva, 2010 version 1.3

% 
% _______________________________________________________________________________
% Copyleft (l) 2010 by Ikaro Silva, All Rights Reserved
% Contact Ikaro Silva (ikarosilva@ieee.org)
% 
%    This library (Biosignal Toolbox) is free software; you can redistribute
%    it and/or modify it under the terms of the GNU General Public License as published by
%    the Free Software Foundation; either version 2 of the License, or
%    (at your option) any later version.
% 
%    This program is distributed in the hope that it will be useful,
%    but WITHOUT ANY WARRANTY; without even the implied warranty of
%    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
%    GNU General Public License for more details.
% 
%    You should have received a copy of the GNU General Public License
%    along with this program; if not, write to the Free Software
%    Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
%    02111-1307  USA
% 
% _______________________________________________________________________________


[N,M]=size(x);
step=500;
r= 0.85;
Fs=[];
theta=[];
mu=10^-3;


P=varargin{1}; %required
if(nargin>2 && ~isempty(varargin{2}) )
    Fs=varargin{2};
end
if(nargin>3 && ~isempty(varargin{3}) )
    theta=varargin{3};
    if(~isempty(Fs))
        %Theta is in Hz, convert to radians
        theta=2*pi*theta/Fs;
    end
end
if(nargin>4 && ~isempty(varargin{4}) )
    mu=varargin{4};
end
if(nargin>5 && ~isempty(varargin{5}) )
    r=varargin{5};
end

THETA=linspace(0,pi/P,step);
F=THETA;
Ntheta=length(THETA);
MSE=zeros(Ntheta,1);
MSE1=zeros(Ntheta,1);

%Step 1- Get frequency capture range
if(isempty(theta))
    for n=1:Ntheta
        C=2*cos([1:P].*THETA(n));
        B=[ones(P,1) -C' ones(P,1)];
        A=[ones(P,1) -r.*C' (r^2).*ones(P,1)];
        [b,a]=sos2tf([B A]);
        if(any(abs(roots(a))>1))
            MSE(n)=NaN;
        else
            ym=filter(b,a,x);
            MSE(n)=mean(ym.^2);
        end
        if(any(abs(roots(A(1,:)))>1))
            MSE1(n)=NaN;
        else
            y1=filter(B(1,:),A(1,:),x);
            MSE1(n)=mean(y1.^2);
        end
    end
    if(~isempty(Fs))
        F=F*Fs/(2*pi);
    end
    MSE(isinf(MSE))=NaN;
    DC_MSE=nanmean(MSE);
    %Get initial value for theta
    [trash,theta]=nanmax(DC_MSE-MSE1);
    theta=THETA(theta);
    
%     figure
%     plot(F,THETA.*0+DC_MSE,'k--','LineWidth',3)
%     hold on;grid on
%     plot(F,MSE1,'r')
%     plot(F,MSE,'b')
end

%Step 2 - Apply LMS to optimize Theta
beta=zeros(P+1,1);
ym=zeros(P+1,1);
theta_curve=zeros(N,1)+NaN;
ym_old=zeros(P+1,2);
beta_old=zeros(P+1,2);
ym_const=zeros(P+1,2);
ym_old(1,:)=[0 0];

err=zeros(N,1);
for n=1:N

       ym=rec_step(ym_old,ym_const,x(n),theta,P+1,r);
       beta=rec_step(beta_old,ym_old(:,1),0,theta,P+1,r);
       
       ym_old=[ym ym_old(:,1)];
       beta_old=[beta beta_old(:,1)];
       
       theta_curve(n)=theta;       
       theta= theta - 2*mu*ym(end)*beta(end);
       
       err(n)=ym(end);
       if((theta < 0) || (theta > pi))
          error(['Convergence not achieved, try reducing step size mu.'])
       end
end

if(~isempty(Fs))
    %Convert to Hz if sampling frequency is passed
    theta=theta*Fs/(2*pi);
    theta_curve=theta_curve*Fs/(2*pi);
end

if(nargout > 0)
    varargout(1)={theta};
end
if(nargout> 1)
    varargout(2)={theta_curve};
end

if(nargout > 2)
    if(~isempty(Fs))
        w=theta*2*pi/Fs;
    else
        w=theta;
    end
        
    C=2*cos([1:P].*w);
    B=[ones(P,1) -C' ones(P,1)];
    A=[ones(P,1) -r.*C' (r^2).*ones(P,1)];
    [b,a]=sos2tf([B A]);
    varargout(3)={b};
    varargout(4)={a};
    varargout(5)={err};
end



%%%%%%%%% end of main %%%%%%%%%%%%

function out = rec_step(out_old,const,init,theta,P,r)

out=zeros(P,1);
out(1)=init;

for p=2:P
    
    w=(p-1)*theta;
    out(p)= out(p-1) - 2*cos(w)*out_old(p-1,1) + ...
        2*(p-1)*sin(w)*const(p-1) + out_old(p-1,2) + ...
        2*r*cos(w)*out_old(p,1) - (r^2)*out_old(p,2) - ...
        2*r*(p-1)*sin(w)*const(p);
end