changeset 2751:fc1806b425d5 octave-forge

fix for complex autocorrelation, and transposed vectors. Add argument checking and adjust variance for rounding errors (For Peter Lanspeary)
author adb014
date Tue, 07 Nov 2006 20:48:32 +0000
parents 81c03b030836
children 25e8cf25709e
files main/signal/inst/levinson.m
diffstat 1 files changed, 34 insertions(+), 12 deletions(-) [+]
line wrap: on
line diff
--- a/main/signal/inst/levinson.m	Mon Nov 06 19:41:46 2006 +0000
+++ b/main/signal/inst/levinson.m	Tue Nov 07 20:48:32 2006 +0000
@@ -43,31 +43,53 @@
 ## TODO: What is the difference between aryule, levinson, 
 ## TODO:    ac2poly, ac2ar, lpc, etc.?
   
+## Changes (Peter Lanspeary, 6 Nov 2006):
+##  Add input sanitising;
+##  avoid using ' (conjugate transpose) to force a column vector;
+##  take direct solution from Kay & Marple Eqn (2.39), code is now same
+##        as the theory;
+##  take Durbin-Levinson recursion from Kay & Marple Eqns (2.42-2.46),
+##        now works for complex data, code is now same as the theory;
+##  force real variance (get rid of imaginary part due to rounding error);
+##
+## REFERENCE
+## [1] Steven M. Kay and Stanley Lawrence Marple Jr.:
+##   "Spectrum analysis -- a modern perspective",
+##   Proceedings of the IEEE, Vol 69, pp 1380-1419, Nov., 1981
+
 function [a, v, ref] = levinson (acf, p)
-  
-  if( columns (acf) > 1 ) acf=acf'; endif
+if ( nargin<1 )
+  error( 'usage: [a,v,ref]=levinson(acf,p)\n', 1);
+elseif( ~isvector(acf) || length(acf)<2 )
+  error( 'levinson: arg 1 (acf) must be vector of length >1\n', 1);
+elseif ( nargin>1 && ( ~isscalar(p) || fix(p)~=p || p>length(acf)-2 ) )
+  error( 'aryule: arg 2 (p) must be integer >0 and <length(acf)-1\n', 1);
+else
   if (nargin == 1) p = length(acf) - 1; endif
+  if( columns(acf)>1 ) acf=acf(:); endif      # force a column vector
 
   if nargout < 3 && p < 100
     ## direct solution [O(p^3), but no loops so slightly faster for small p]
+    ##   Kay & Marple Eqn (2.39)
     R = toeplitz(acf(1:p), conj(acf(1:p)));
     a = R \ -acf(2:p+1);
-    a = [ 1, a' ];
-    v = sum(a'.*acf(1:p+1));
+    a = [ 1, a.' ];
+    v = real( a*conj(acf(1:p+1)) );
   else
     ## durbin-levinson [O(p^2), so significantly faster for large p]
-    ref = zeros (1, p);
-    g = acf(2) / acf(1);
+    ##   Kay & Marple Eqns (2.42-2.46)
+    ref = zeros(p,1);
+    g = -acf(2)/acf(1);
     a = [ g ];
-    v = ( 1 - g^2 ) * acf(1);
+    v = real( ( 1 - g*conj(g)) * acf(1) );
     ref(1) = g;
     for t = 2 : p
-      g = (acf(t+1) - a * acf(2:t)) / v;
-      a = [ g,  a-g*a(t-1:-1:1) ];
-      v = v * ( 1 - g^2 ) ;
+      g = -(acf(t+1) + a * acf(t:-1:2)) / v;
+      a = [ a+g*conj(a(t-1:-1:1)), g ];
+      v = v * ( 1 - real(g*conj(g)) ) ;
       ref(t) = g;
     endfor
-    a = [1, -a(p:-1:1)];
+    a = [1, a];
   endif
-    
+endif    
 endfunction