Code covered by the BSD License  

Highlights from
ARMASA

from ARMASA by Piet M T Broersen
Automatic program to estimate the power spectral density with only statistically significant details

convolrev(x,y,shift1,shift2,last)
function [z,ASAcontrol] = convolrev(x,y,shift1,shift2,last)
%CONVOLREV Convolution sum with one vector reversed
%   Z = CONVOLREV(X,Y) is the convolution sum of a flipped version of 
%   vector X with vector Y. With all vectors given as columns, this is 
%   the same as CONVOL(FLIPUD(X),Y).
%   
%   CONVOLREV(X) is the same as CONVOLREV(X,X).
%   
%   CONVOLREV(X,Y,SHIFT1,SHIFT2) or CONVOLREV(X,SHIFT1,SHIFT2) returns 
%   only the elements from SHIFT1 up to SHIFT2.
%   
%   C = CONVOLREV(X,N_LAG) can be used for computing (biased) 
%   autocovariance estimates of a series. The raw (unscaled) 
%   autocovariance sequence Z = CONVOLREV(X) is symmetric.
%   C = CONVOLREV(X,N_LAG) returns the central element of Z and N_LAG 
%   additional elements in C.
%   
%   CONVOLREV is an ARMASA main function.
%   
%   See also: CONVOL, DECONVOL, CONV.

%Header
%=============================================================================

%Declaration of variables
%------------------------

%Declare and assign values to local variables
%according to the input argument pattern
switch nargin
case 1 
   if isa(x,'struct'), ASAcontrol=x; x=[]; 
   else, ASAcontrol=[];
   end
   y=[]; shift1=[]; shift2=[];
case 2 
   if isa(y,'struct'), ASAcontrol=y; y=[];
      shift1=[]; shift2=[];
   else, ASAcontrol=[];
      if length(y)==1
         shift1=y; y=[]; shift2=[];
      else
         shift1=[]; shift2=[];
      end
   end
case 3 
   if isa(shift1,'struct')
      ASAcontrol=shift1;
      if length(y)==1
         shift1=y; y=[]; shift2=[];
      else
         shift1=[]; shift2=[];
      end
   else, ASAcontrol=[]; shift2=shift1; shift1=y; y=[];
   end
case 4
   if isa(shift2,'struct'), ASAcontrol=shift2; shift2=shift1; shift1=y; y=[];
   else, ASAcontrol=[];
   end
case 5
   if isa(last,'struct'), ASAcontrol=last;
   else, error(ASAerr(39))
   end
otherwise
   error(ASAerr(1,mfilename))
end

if isequal(nargin,1) & ~isempty(ASAcontrol)
      %ASAcontrol is the only input argument
   ASAcontrol.error_chk = 0;
   ASAcontrol.run = 0;
end

%ARMASA-function version information
%-----------------------------------

%This ARMASA-function is characterized by
%its current version,
ASAcontrol.is_version = [2000 12 6 12 17 20];
%and its compatability with versions down to,
ASAcontrol.comp_version = [2000 12 6 12 17 20];

%Checks
%------

if ~any(strcmp(fieldnames(ASAcontrol),'error_chk')) | ASAcontrol.error_chk
   %Perform standard error checks
   %Input argument format checks
   ASAcontrol.error_chk = 1;
   if ~isnum(x)
      error(ASAerr(11,'x'))
   end
   if ~isempty(y) & ~isnum(y)
      error(ASAerr(11,'y'))
   end
   if ~isempty(shift1) & (~isnum(shift1) | ...
         ~isintscalar(shift1) | shift1<0)
      error(ASAerr(17,'shift1'))
   end
   if ~isempty(shift2) & (~isnum(shift2) | ...
         ~isintscalar(shift2) | shift2<0)
      error(ASAerr(17,'shift2'))
   end
   
   %Input argument value checks
   if ~isavector(x)
      error([ASAerr(14) ASAerr(15,'x')])
   else
      l_x = length(x);
      l_y = length(x);
   end
   if ~isempty(y)
      if ~isavector(y)
         error([ASAerr(14) ASAerr(15,'y')])
      end
      l_y = length(y);
   end
   if ~isempty(shift1) & isempty(shift2) & shift1 >= l_y
      error(ASAerr(19,num2str(l_x-1)))
   elseif ~(isempty(shift1) & isempty(shift2)) & ...
         (shift1 > shift2 | shift2 > l_x+l_y-1 | ...
         shift1==0)
      error(ASAerr(20,{'shift1','shift2'}))
   end
end

if ~any(strcmp(fieldnames(ASAcontrol),'version_chk')) | ASAcontrol.version_chk
      %Perform version check
   ASAcontrol.version_chk = 1;
      
   %Make sure the requested version of this function
   %complies with its actual version
   ASAversionchk(ASAcontrol);
end

if ~any(strcmp(fieldnames(ASAcontrol),'run')) | ASAcontrol.run
      %Run the computational kernel
   ASAcontrol.run = 1;

%Main   
%========================================================================

s_x = size(x);
l_x = prod(s_x);
if isempty(y)
   s_y = s_x;
   l_y = l_x;
else
   s_y = size(y);
   l_y = prod(s_y);
end
if l_x>l_y
   l_long = l_x;
   l_short = l_y;
else
   l_long = l_y;
   l_short = l_x;
end
if isempty(shift1)&isempty(shift2)
   shift1 = 1;
   shift2 = l_long+l_short-1;
elseif isempty(shift2)
   shift2 = l_x+shift1;
   shift1 = l_x;
end
if s_x(1)==1 & s_y(1)==1
   z = zeros(1,shift2-shift1+1);
else
   z = zeros(shift2-shift1+1,1);
end

%Determination of the fastest approach
if l_long<81
   if isempty(y)
      if l_long<64
         mode=1;
      else
         mode=3;
         l_fft = nxtppow(l_long+max(shift2-l_long,l_long-shift1));
      end
   else
      mode=2;
   end
else
   if isempty(y)
      l_fft = nxtppow(l_long+max(shift2-l_long,l_long-shift1));
      t_fft = 7.3*l_fft*log(l_fft)+5*l_fft;
      thresh = min(l_long,shift2);
      t_direct = thresh^2-shift1^2+thresh+shift1;
      if shift2>thresh
         t_direct = t_direct+4*l_long*shift2-shift2^2-3*l_long^2;
      end
      if t_fft<t_direct
         mode = 3;
      else
         mode = 1;
      end
   else
      t_direct = 0;
      start = shift1;
      if shift1<l_short
         thresh = min(l_short,shift2);
         t_direct = thresh^2-shift1^2;
         start = l_short;
      end
      if start>=l_short
         thresh = min(l_long,shift2);
         t_direct = t_direct+2*l_short*max(0,(thresh-l_short));
      end
      if shift2>l_long
         t_direct = t_direct+2*l_short*(shift2-l_long)-(shift2-l_long)^2;
      end
      if shift1<l_short
         l_eff = shift2;
      else
         l_eff = shift2-shift1+l_short;  
      end
      t_filt = 0.6*l_eff*l_short+1.2*l_short^2;
      l_fft = nxtppow(l_long+l_short);
      t_fft = 14.6*l_fft*log(l_fft)+6*l_fft;
      [mode,index] = sort([t_direct t_filt t_fft]);
      mode = index(1);
   end
end

if mode==1 %Direct approach,
           %minimized number of flops
  if isempty(y)
     y = x;
  end   
  if l_x>=l_y
      if s_x(2)>1
         long = x;
      else
         long = x';
      end
      if s_y(2)>1;
         short = y';
      else
         short = y;
      end
      first = l_x+l_y-shift2;
      last = l_x+l_y-shift1;
      k = last-first+1;
      k_increm = -1;
   else
      if s_x(2)>1
         short = x';
      else
         short = x;
      end
      if s_y(2)>1;
         long = y;
      else
         long = y';
      end
      first = shift1;
      last = shift2;
      k = 1;
      k_increm = 1;
   end
   start = first;
   run_in = l_short-first;
   if run_in>0
      index_temp = run_in+1;
      i_stop = min(last-first,run_in-1);
      for i = 0:i_stop
         z(k) = long(1:first+i)*short(index_temp-i:l_short);
         k = k+k_increm;
      end
      start = l_short;
   end
   run_center = start-l_short;
   if run_center>=0
      if last<=l_long
         stop = last;
      else
         stop = l_long;
      end
      index_temp = run_center+1;
      i_stop = stop-start;
      for i=0:i_stop
         z(k) = long(index_temp+i:start+i)*short;
         k = k+k_increm;
      end
   end
   run_out = last-l_long;
   if run_out>0
      index_temp = l_long-l_short+1;
      i_start = max(1,first-l_long);
      for i = i_start:run_out
         z(k) = long(index_temp+i:l_long)*short(1:l_short-i);
         k = k+k_increm;
      end
   end
elseif mode==2 %Filter approach,
               %non-optimal in the sense of flops but sometimes
               %faster because 'filter' is a built-in function
   if isempty(y)
      y = x;
   end   
   if l_x>l_y
      if s_x(1)==1 & s_y(1)==1
         long = zeros(1,l_x+l_y-1);
         long(l_x:-1:1) = x;
      else
         long = zeros(l_x+l_y-1,1);
         long(l_x:-1:1) = x;
      end
      short = y;
   else
      if s_x(1)==1 & s_y(1)==1
         long = zeros(1,l_x+l_y-1);
         long(1:l_y) = y;
      else
         long = zeros(l_x+l_y-1,1);
         long(1:l_y) = y;
      end
      short = x(l_x:-1:1);
   end
   first = shift1;
   last = shift2;
   if first-l_short>0
      start = first-l_short+1;
      first = l_short;
   else
      start = 1;
   end
   stop = last;
   z = filter(short,1,long(start:stop));
   z = z(first:end);
elseif mode==3 %FFT approach,
               %fast for long sequences
   if ~isempty(y) %cross-convolution
      first = shift1;
      last = shift2;
      run_in = l_short-first;
      if run_in<0
         start = 1-run_in;
         first = l_short;
      else
         start = 1;
      end
      if last<l_long
         stop = last;
      else
         stop = l_long;
      end
      first = first+1;
      last = last-start+2;
      l_long = stop-start+1;
      sig_mtx = zeros(l_fft,2);
      if l_x>l_y
         start = l_long-stop+1;
         stop = l_long-start+1;
         x = x(start:stop);
         sig_mtx(l_fft-l_long+1:l_fft,1) = x(:);
         sig_mtx(1:l_y,2) = y(:);
      else
         y = y(stop:-1:start);
         sig_mtx(l_x:-1:1,2) = x(:);
         sig_mtx(l_fft-l_long+1:l_fft,1,1) = y(:);
      end
      transf_mtx = fft(sig_mtx);
      z = real(fft(transf_mtx(:,1).*conj(transf_mtx(:,2))));
      if s_x(1)==1 & s_y(1)==1
         z = z(first:last)'/l_fft;
      else
         z = z(first:last)/l_fft;
      end
   else %autocorrelation 
      l_sig = l_x;
      index2 = shift2-l_sig+1;
      index3 = l_fft-l_sig+shift1+1;
      index4 = min(l_fft,l_fft+index2);
      index1 = max(1,index3-l_fft);
      sig = zeros(l_fft,1);
      sig(1:l_x,1) = x(:);
      transf = fft(sig);
      z = real(fft(abs(transf).^2));
      if s_x(1)==1 & s_y(1)==1
         z = [z(index3:index4);z(index1:index2)]'/l_fft;
      else
         z = [z(index3:index4);z(index1:index2)]/l_fft;
      end
   end
end

%Footer
%=====================================================

else %Skip the computational kernel
   %Return ASAcontrol as the first output argument
   if nargout>1
      warning(ASAwarn(9,mfilename,ASAcontrol))
   end
   z = ASAcontrol;
   ASAcontrol = [];
end 

%Program history
%======================================================================
%
% Version                Programmer(s)          E-mail address
% -------                -------------          --------------
% [2000 12 6 12 17 20]   W. Wunderink           wwunderink01@freeler.nl

Contact us at files@mathworks.com