diff m-toolbox/classes/+utils/@math/vdfit.m @ 0:f0afece42f48

Import.
author Daniele Nicolodi <nicolodi@science.unitn.it>
date Wed, 23 Nov 2011 19:22:13 +0100
parents
children
line wrap: on
line diff
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/m-toolbox/classes/+utils/@math/vdfit.m	Wed Nov 23 19:22:13 2011 +0100
@@ -0,0 +1,674 @@
+% VDFIT: Fit discrete models to frequency responses
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% DESCRIPTION:
+% 
+%     Fits a discrete model to a frequency response using relaxed z-domain
+%     vector fitting algorithm [1 - 3]. The function is able to fit more
+%     than one frequency response per time. In case that more than one
+%     frequency response is passed as input, they are fitted with a set of
+%     common poles. Model functions are expanded in partial fractions:
+% 
+%                r1                  rN
+%     f(z) = ----------- + ... + ----------- + d
+%            1-p1*z^{-1}         1-pN*z^{-1}
+% 
+% CALL:
+% 
+%     [res,poles,dterm,mresp,rdl,mse] = vdfit(y,f,poles,weight,fitin)
+% 
+% INPUTS:
+% 
+%     - y: Is a vector with the frequency response data.
+%     - f: Is the frequency vector in Hz.
+%     - poles: are a set of starting poles.
+%     - weight: are a set of weights used in the fitting procedure.
+%     - fitin: is a struct containing fitting options and parameters. fitin
+%     fields are:
+%       - fitin.stable = 0; fit without forcing poles to be stable.
+%       - fitin.stable = 1; force poles to be stable flipping unstable
+%       poles in the unit circle. z -> 1/z*.
+%       - fitin.dterm = 0; fit with d = 0.
+%       - fitin.dterm = 1; fit with d different from 0.
+%       - fitin.fs = fs; input the sampling frequency in Hz (default value
+%       is 1 Hz).
+%       - fitin.polt = 0; fit without plotting results.
+%       - fitin.plot = 1; plot fit results in loglog scale.
+%       - fitin.plot = 2; plot fit results in semilogx scale.
+%       - fitin.plot = 3; plot fit results in semilogy scale.
+%       - fitin.plot = 4; plot fit results in linear xy scale.
+%       - fitin.ploth = #; a plot handle to define the figure target for
+%       plotting. Default: [1]
+% 
+% OUTPUT:
+% 
+%     - res: vector or residues.
+%     - poles: vector of poles.
+%     - dterm: direct term d.
+%     - mresp: frequency response of the fitted model
+%     - rdl: residuals y - mresp
+%     - mse: normalized men squared error
+% 
+% EXAMPLES:
+% 
+%     - Fit on a single transfer function:
+% 
+%       INPUT
+%       y is a (Nx1) or (1xN) vector
+%       f is a (Nx1) or (1xN) vector
+%       poles is a (Npx1) or (1xNp) vector
+%       weight is a (Nx1) or (1xN) vector
+% 
+%       OUTPUT
+%       res is a (Npx1) vector
+%       poles is a (Npx1) vector
+%       dterm is a constant
+%       mresp is a (Nx1) vector
+%       rdl is a (Nx1) vector
+%       mse is a constant
+% 
+%       - Fit Nt transfer function at the same time:
+% 
+%       INPUT
+%       y is a (NxNt) or (NtxN) vector
+%       f is a (Nx1) or (1xN) vector
+%       poles is a (Npx1) or (1xNp) vector
+%       weight is a (NxNt) or (NtxN) vector
+% 
+%       OUTPUT
+%       res is a (NpxNt) vector
+%       poles is a (Npx1) vector
+%       dterm is a (1xNt) vector
+%       mresp is a (NxNt) vector
+%       rdl is a (NxNt) vector
+%       mse is a (1xNt) vector
+% 
+% REFERENCES:
+% 
+%     [1] B. Gustavsen and A. Semlyen, "Rational approximation of frequency
+%         domain responses by Vector Fitting", IEEE Trans. Power Delivery
+%         vol. 14, no. 3, pp. 1052-1061, July 1999.
+%     [2] B. Gustavsen, "Improving the Pole Relocating Properties of Vector
+%         Fitting", IEEE Trans. Power Delivery vol. 21, no. 3, pp.
+%         1587-1592, July 2006.
+%     [3] Y. S. Mekonnen and J. E. Schutt-Aine, "Fast broadband
+%         macromodeling technique of sampled time/frequency data using
+%         z-domain vector-fitting method", Electronic Components and
+%         Technology Conference, 2008. ECTC 2008. 58th 27-30 May 2008 pp.
+%         1231 - 1235.
+% 
+% 
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% HISTORY:     12-09-2008 L Ferraioli
+%                 Creation
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% VERSION: '$Id: vdfit.m,v 1.12 2009/08/06 09:57:37 miquel Exp $';
+% 
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+function [res,poles,dterm,mresp,rdl,mse] = vdfit(y,f,poles,weight,fitin)
+
+  warning off all
+  %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+  % Collecting inputs
+
+  % Default input struct
+  defaultparams = struct('stable',0, 'dterm',0, 'fs',1, 'plot',0, 'ploth',1,...
+    'regout',-1, 'idsamp',1e3, 'idamp', 1e-3);
+
+  names = {'stable','dterm','fs','plot','ploth','regout','idsamp','idamp'};
+
+  % collecting input and default params
+  if ~isempty(fitin)
+    for jj=1:length(names)
+      if isfield(fitin, names(jj)) && ~isempty(fitin.(names{1,jj}))
+       defaultparams.(names{1,jj}) = fitin.(names{1,jj});
+      end
+    end
+  end
+
+  stab = defaultparams.stable; % Enforce pole stability is is 1
+  dt = defaultparams.dterm; % 1 to fit with direct term
+  fs = defaultparams.fs; % sampling frequency
+  plotting = defaultparams.plot; % set to 1 if plotting is required
+  plth = defaultparams.ploth; % set the figure target
+  regout = defaultparams.regout; % set the strategy for complex plane fitting
+  idsamp = defaultparams.idsamp; % number of samples to define impulse response
+  idamp = defaultparams.idamp; % maximum aplitude of impulse response adimtted at idsamp
+  
+  %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+  % Inputs in row vectors
+
+  [a,b] = size(y);
+  if a > b % shifting to row
+    y = y.';
+  end
+
+  [a,b] = size(f);
+  if a > b % shifting to row
+    f = f.';
+  end
+
+  [a,b] = size(poles);
+  if a > b % shifting to row
+    poles = poles.';
+  end
+
+  clear w
+  w = weight;
+  [a,b] = size(w);
+  if a > b % shifting to row
+    w = w.';
+  end
+
+  N = length(poles); % Model order
+
+  if dt
+    dl = 1; % Fit with direct term
+  else
+    dl = 0; % Fit without direct term
+  end
+
+  % definition of z
+  z = cos(2.*pi.*f./fs)+1i.*sin(2.*pi.*f./fs);
+
+  Nz = length(z);
+
+  [Nc,Ny] = size(y);
+  if Ny ~= Nz
+    error('### The number of data points is different from the number of frequency points.')
+  end
+
+  %Tolerances used by relaxed version of vector fitting
+  TOLlow=1e-8;
+  TOLhigh=1e8;
+  
+  %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+  % Normalizing y
+
+    for nn = 1:Nc
+      y(nn,:) = y(nn,:)./z;
+    end
+
+  %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+  % Marking complex and real poles
+
+  % cindex = 1; pole is complex, next conjugate pole is marked with cindex
+  % = 2. cindex = 0; pole is real
+  cindex=zeros(1,N);
+  for m=1:N 
+    if imag(poles(m))~=0  
+      if m==1 
+        cindex(m)=1;
+      else
+        if cindex(m-1)==0 || cindex(m-1)==2
+          cindex(m)=1; cindex(m+1)=2; 
+        else
+          cindex(m)=2;
+        end
+      end 
+    end
+  end
+
+  %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+  % Augmented problem
+  %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+  % Matrix initialinzation
+  BA = zeros(Nc*Nz+1,1);
+  Ak=zeros(Nz,N+1);
+  AA=zeros(Nz*Nc+1,(N+dl)*Nc+N+1);
+  nf = zeros(1,Nc*(N+dl)+N+1); % Normalization factor
+
+  % Defining Ak
+  for jj = 1:N
+    if cindex(jj) == 1 % conjugate complex couple of poles
+      Ak(:,jj) = 1./(z-poles(jj)) + 1./(z-conj(poles(jj)));
+      Ak(:,jj+1) = 1i./(z-poles(jj)) - 1i./(z-conj(poles(jj)));
+    elseif cindex(jj) == 0 % real pole
+      Ak(:,jj) = 1./(z-poles(jj));
+    end
+  end
+
+  Ak(1:Nz,N+1) = 1;
+
+  % Scaling factor
+  sc = 0;
+  for mm = 1:Nc
+    sc = sc + (norm(w(mm,:).*y(mm,:)))^2;
+  end
+  sc=sqrt(sc)/Nz; 
+
+  for nn = 1:Nc
+
+    wg = w(nn,:).'; % Weights
+
+    ida=(nn-1)*Nz+1;
+    idb=nn*Nz;
+    idc=(nn-1)*(N+dl)+1;
+
+    for mm =1:N+dl % Diagonal blocks
+      AA(ida:idb,idc-1+mm) = wg.*Ak(1:Nz,mm);
+    end
+    for mm =1:N+1 % Last right blocks
+      AA(ida:idb,Nc*(N+dl)+mm) = -wg.*(Ak(1:Nz,mm).*y(nn,1:Nz).');
+    end
+
+  end
+
+  % setting the last row of AA and BA for the relaxion condition
+  for qq = 1:N+1
+    AA(Nc*Nz+1,Nc*(N+dl)+qq) = real(sc*sum(Ak(:,qq)));
+  end
+
+  AA = [real(AA);imag(AA)];
+
+  % Last element of the solution vector
+  BA(Nc*Nz+1) = Nz*sc;
+
+  xBA = real(BA);
+  xxBA = imag(BA);
+  
+  Nrow = Nz*Nc+1;
+  
+  BA = zeros(2*Nrow,1);
+  
+  BA(1:Nrow,1) = xBA;
+  BA(Nrow+1:2*Nrow,1) = xxBA;
+
+  % Normalization factor
+  % nf = zeros(2*N+dl+1,1);
+  for pp = 1:length(AA(1,:))
+    nf(pp) = norm(AA(:,pp),2); % Euclidean norm
+    AA(:,pp) = AA(:,pp)./nf(pp); % Normalization
+  end
+
+  %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+  % Solving augmented problem
+
+%   XA = pinv(AA)*BA;
+  % XA = inv((AA.')*AA)*(AA.')*BA;
+
+  % XA = AA.'*AA\AA.'*BA;
+
+  XA = AA\BA;
+
+  XA = XA./nf.'; % renormalization
+  
+  %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+  % Checking the tolerance
+  
+  if abs(XA(end))<TOLlow || abs(XA(end))>TOLhigh
+    
+    if XA(end)==0
+      Dnew=1;
+    elseif abs(XA(end))<TOLlow
+      Dnew=sign(XA(end))*TOLlow;
+    elseif abs(XA(end))>TOLhigh
+      Dnew=sign(XA(end))*TOLhigh;
+    end
+
+    for pp = 1:length(AA(1,:))
+      AA(:,pp) = AA(:,pp).*nf(pp); %removing previous scaling
+    end
+
+    ind=length(AA(:,1))/2; %index to additional row related to relaxation
+    
+    AA(ind,:)=[]; % removing relaxation term
+    
+    BA=-Dnew*AA(:,end);  %new right side
+    
+    AA(:,end)=[];
+    
+    nf(end)=[];
+    
+    for pp = 1:length(AA(1,:))
+      nf(pp) = norm(AA(:,pp),2); % Euclidean norm
+      AA(:,pp) = AA(:,pp)./nf(pp); % Normalization
+    end
+          
+    % XA=(AA.'*AA)\(AA.'*BA); % using normal equation
+      
+    XA=AA\BA;
+    
+    XA = XA./nf.'; % renormalization
+    
+    XA=[XA;Dnew];
+    
+  end
+
+  %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+  % Finding zeros of sigma
+
+  lsr = XA((N+dl)*Nc+1:(N+dl)*Nc+N,1); % collect the least square results
+
+  D = XA(end); % direct term of sigma
+  
+  CPOLES = diag(poles);
+  B = ones(N,1);
+  C = lsr.';
+  
+  for kk = 1:N
+    if cindex(kk) == 1
+      CPOLES(kk,kk)=real(poles(kk));
+      CPOLES(kk,kk+1)=imag(poles(kk));
+      CPOLES(kk+1,kk)=-1*imag(poles(kk));
+      CPOLES(kk+1,kk+1)=real(poles(kk));
+      B(kk,1) = 2;
+      B(kk+1,1) = 0;
+    end
+  end
+  
+  H = CPOLES-B*C/D;
+  
+  szeros=eig(H);
+  
+  %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+  % Exclude a region of the complex plane
+  switch regout
+    case -1
+      % do nothing
+    case 0
+      % do nothing
+    case 1
+      % set the maximum admitted value for stable poles
+      target_pole = (idamp)^(1/idsamp);
+      % get stable poles outside the fixed limit
+      uptgr = ((abs(szeros) > target_pole) & (abs(szeros) <= 1) & (imag(szeros)==0));
+      uptgi = ((abs(szeros) > target_pole) & (abs(szeros) <= 1) & (imag(szeros)~=0));
+      % get unstable polse smaller than minimum value
+      lwtgr = ((abs(szeros) < 1/target_pole) & (abs(szeros) > 1) & (imag(szeros)==0));
+      lwtgi = ((abs(szeros) < 1/target_pole) & (abs(szeros) > 1) & (imag(szeros)~=0));
+      % get the maximum shift needed
+      ushiftr = max(abs(abs(szeros(uptgr))-target_pole));
+      ushifti = max(abs(abs(szeros(uptgi))-target_pole));
+      lshiftr = max(abs(abs(szeros(lwtgr))-1/target_pole));
+      lshifti = max(abs(abs(szeros(lwtgi))-1/target_pole));
+      % shifting inside
+      szeros(uptgr) = (abs(szeros(uptgr))-ushiftr).*sign(szeros(uptgr));
+      szeros(uptgi) = (abs(szeros(uptgi))-ushifti).*exp(1i.*angle(szeros(uptgi)));
+      % shifting outside
+      szeros(lwtgr) = (abs(szeros(lwtgr))+lshiftr).*sign(szeros(lwtgr));
+      szeros(lwtgi) = (abs(szeros(lwtgi))+lshifti).*exp(1i.*angle(szeros(lwtgi)));
+  end
+      
+
+  %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+  % Ruling out unstable poles
+
+  % This option force the poles of f to stay inside the unit circle
+  if stab
+    unst = abs(szeros) > 1;
+    szeros(unst) = 1./conj(szeros(unst));
+  end
+  szeros = sort(szeros);
+  N = length(szeros);
+
+  %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+  % Separating complex poles from real poles and ordering
+
+  rnpoles = [];
+  inpoles = [];
+  for tt = 1:N
+    if imag(szeros(tt)) == 0
+      % collecting real poles
+      rnpoles = [rnpoles; szeros(tt)];
+    else
+      % collecting complex poles
+      inpoles = [inpoles; szeros(tt)];
+    end
+  end
+
+  % Sorting complex poles in order to have them in the expected order a+jb
+  % and a-jb a>0 b>0
+  inpoles = sort(inpoles);
+  npoles = [rnpoles;inpoles];
+  npoles = npoles - 2.*1i.*imag(npoles);
+
+  %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+  % Marking complex and real poles
+
+  cindex=zeros(N,1);
+  for m=1:N 
+    if imag(npoles(m))~=0  
+      if m==1 
+        cindex(m)=1;
+      else
+        if cindex(m-1)==0 || cindex(m-1)==2
+          cindex(m)=1; cindex(m+1)=2; 
+        else
+          cindex(m)=2;
+        end
+      end 
+    end
+  end
+
+  %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+  % Direct problem
+  %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+  % Matrix initialinzation
+  nB(1:Nz,1:Nc) = real(w.*y).';
+  nB(Nz+1:2*Nz,1:Nc) = imag(w.*y).';
+
+  B = zeros(2*Nz,1);
+  nAD = zeros(Nz,N+dl);
+  AD = zeros(2*Nz,N+dl);
+  Ak = zeros(Nz,N+dl);
+
+  for jj = 1:N
+    if cindex(jj) == 1 % conjugate complex couple of poles
+      Ak(:,jj) = 1./(z-npoles(jj)) + 1./(z-npoles(jj+1));
+      Ak(:,jj+1) = 1i./(z-npoles(jj)) - 1i./(z-npoles(jj+1));
+    elseif cindex(jj) == 0 % real pole
+      Ak(:,jj) = 1./(z-npoles(jj));
+    end
+  end
+
+  if dt
+  %   Ak(1:Nz,N+dl) = ones(Nz,1); % considering the direct term
+    Ak(1:Nz,N+dl) = 1./z;
+  end
+
+  XX = zeros(Nc,N+dl);
+  for nn = 1:Nc
+
+    % Defining AD
+    for m=1:N+dl
+      nAD(1:Nz,m) = w(nn,:).'.*Ak(1:Nz,m); 
+    end 
+
+    B(1:2*Nz,1) = nB(1:2*Nz,nn);
+
+    AD(1:Nz,:) = real(nAD);
+    AD(Nz+1:2*Nz,:) = imag(nAD);
+
+    % Normalization factor
+    nf = zeros(N+dl,1);
+    for pp = 1:N+dl
+      nf(pp,1) = norm(AD(:,pp),2); % Euclidean norm
+      AD(:,pp) = AD(:,pp)./nf(pp,1); % Normalization
+    end
+
+    % Solving direct problem
+
+    % XD = inv((AD.')*AD)*(AD.')*B;
+    % XD = AD.'*AD\AD.'*B;
+%     XD = pinv(AD)*B;
+    XD = AD\B;
+
+    XD = XD./nf; % Renormalization
+    XX(nn,1:N) = XD(1:N).';
+
+  end
+
+  %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+  % Final residues and poles of f
+
+  lsr = XX(:,1:N);
+
+  res = zeros(N,Nc);
+  % Real poles have real residues, complex poles have comples residues
+  for nn = 1:Nc
+    for tt = 1:N
+      if cindex(tt) == 1 % conjugate complex couple of poles
+        res(tt,nn) = lsr(nn,tt)+1i*lsr(nn,tt+1);
+        res(tt+1,nn) = lsr(nn,tt)-1i*lsr(nn,tt+1);
+      elseif cindex(tt) == 0 % real pole
+        res(tt,nn) = lsr(nn,tt);
+      end
+    end
+  end
+
+  poles = npoles;
+
+  if dt
+    dterm = XX(:,N+dl).';
+  else
+    dterm = zeros(1,Nc);
+  end
+
+  %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+  % Calculating responses and residuals
+
+  mresp = zeros(Nz,Nc);
+  rdl = zeros(Nz,Nc);
+  yr = zeros(Nz,Nc);
+  mse = zeros(1,Nc);
+
+  for nn = 1:Nc
+    % freq resp of the fit model
+    r = res(:,nn);
+    p = poles;
+    d = dterm(:,nn);
+
+    Nf = length(f);
+    N = length(p);
+
+    % Defining normalized frequencies
+    fn = f./fs;
+
+    rsp = zeros(Nf,1);
+    indx = 0:length(d)-1;
+    for ii = 1:Nf
+      for jj = 1:N
+        rsptemp = exp(1i*2*pi*fn(ii))*r(jj)/(exp(1i*2*pi*fn(ii))-p(jj));
+        rsp(ii) = rsp(ii) + rsptemp;
+      end
+      % Direct terms response
+      rsp(ii) = rsp(ii) + sum(((exp((1i*2*pi*f(ii))*ones(length(d),1))).^(-1.*indx)).*d);
+    end
+
+    % Model response
+    mresp(:,nn) = rsp;
+
+    % Residual
+    yr(:,nn) = (y(nn,:).*z).';
+    rdl(:,nn) = yr(:,nn) - rsp;
+    
+    % RMS error
+%     rmse(:,nn) = sqrt(sum((abs(rdl(:,nn)./yr(:,nn)).^2))/(Nf-N));
+    
+    % Chi Square or mean squared error
+    % Note that this error is normalized to the input data in order to
+    % comparable between different sets of data
+    mse(:,nn) = sum((rdl(:,nn)./yr(:,nn)).*conj((rdl(:,nn)./yr(:,nn))))/(Nf-N);
+    
+  end
+
+  %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+  % Plotting response
+  nf = f./fs;
+
+  switch plotting
+
+    case 0
+      % No plot
+
+    case 1
+      % LogLog plot for absolute value
+      figure(plth)
+      subplot(2,1,1);
+      p1 = loglog(nf,abs(yr),'k');
+      hold on
+      p2 = loglog(nf,abs(mresp),'r');
+      p3 = loglog(nf,abs(rdl),'b');
+      xlabel('Normalized Frequency [f/fs]')
+      ylabel('Amplitude')
+      legend([p1(1) p2(1) p3(1)],'Original', 'VDFIT','Residual')
+      hold off
+
+      subplot(2,1,2);
+      p4 = semilogx(nf,(180/pi).*unwrap(angle(yr)),'k');
+      hold on
+      p5 = semilogx(nf,(180/pi).*unwrap(angle(mresp)),'r');
+      xlabel('Normalized Frequency [f/fs]')
+      ylabel('Phase [Deg]')
+      legend([p4(1) p5(1)],'Original', 'VDFIT')
+      hold off
+
+    case 2
+      % Semilogx plot for absolute value
+      figure(plth)
+      subplot(2,1,1);
+      p1 = semilogx(nf,abs(yr),'k');
+      hold on
+      p2 = semilogx(nf,abs(mresp),'r');
+      p3 = semilogx(nf,abs(rdl),'b');
+      xlabel('Normalized Frequency [f/fs]')
+      ylabel('Amplitude')
+      legend([p1(1) p2(1) p3(1)],'Original', 'VDFIT','Residual')
+      hold off
+
+      subplot(2,1,2);
+      p4 = semilogx(nf,(180/pi).*unwrap(angle(yr)),'k');
+      hold on
+      p5 = semilogx(nf,(180/pi).*unwrap(angle(mresp)),'r');
+      xlabel('Normalized Frequency [f/fs]')
+      ylabel('Phase [Deg]')
+      legend([p4(1) p5(1)],'Original', 'VDFIT')
+      hold off
+
+    case 3
+      % Semilogy plot for absolute value
+      figure(plth)
+      subplot(2,1,1);
+      p1 = semilogy(nf,abs(yr),'k');
+      hold on
+      p2 = semilogy(nf,abs(mresp),'r');
+      p3 = semilogy(nf,abs(rdl),'b');
+      xlabel('Normalized Frequency [f/fs]')
+      ylabel('Amplitude')
+      legend([p1(1) p2(1) p3(1)],'Original', 'VDFIT','Residual')
+      hold off
+
+      subplot(2,1,2);
+      p4 = semilogy(nf,(180/pi).*unwrap(angle(yr)),'k');
+      hold on
+      p5 = semilogy(nf,(180/pi).*unwrap(angle(mresp)),'r');
+      xlabel('Normalized Frequency [f/fs]')
+      ylabel('Phase [Deg]')
+      legend([p4(1) p5(1)],'Original', 'VDFIT')
+      hold off
+
+    case 4
+      % Linear plot for absolute value
+      figure(plth)
+      subplot(2,1,1);
+      p1 = plot(nf,abs(yr),'k');
+      hold on
+      p2 = plot(nf,abs(mresp),'r');
+      p3 = plot(nf,abs(rdl),'b');
+      xlabel('Normalized Frequency [f/fs]')
+      ylabel('Amplitude')
+      legend([p1(1) p2(1) p3(1)],'Original', 'VDFIT','Residual')
+      hold off
+
+      subplot(2,1,2);
+      p4 = plot(nf,(180/pi).*unwrap(angle(yr)),'k');
+      hold on
+      p5 = plot(nf,(180/pi).*unwrap(angle(mresp)),'r');
+      xlabel('Normalized Frequency [f/fs]')
+      ylabel('Phase [Deg]')
+      legend([p4(1) p5(1)],'Original', 'VDFIT')
+      hold off
+
+  end
\ No newline at end of file