summaryrefslogtreecommitdiff
path: root/macros/arburg.sci
diff options
context:
space:
mode:
Diffstat (limited to 'macros/arburg.sci')
-rw-r--r--macros/arburg.sci225
1 files changed, 181 insertions, 44 deletions
diff --git a/macros/arburg.sci b/macros/arburg.sci
index de4dcbb..ee85ac5 100644
--- a/macros/arburg.sci
+++ b/macros/arburg.sci
@@ -1,57 +1,194 @@
-function varargout = arburg( x, poles, criterion )
-//This function calculates coefficients of an autoregressive (AR) model of complex data.
+//This function calculates coefficients of an autoregressive (AR) model of complex data
+
//Calling Sequence
//a = arburg(x, poles)
//a = arburg(x, poles, criterion)
//[a, v] = arburg(...)
//[a, v, k] = arburg(...)
-//Parameters
+
+//Parameters
//x: vector of real or complex numbers, of length > 2
-//poles: positive integer value < length(x) - 2
-//criterion: string value, takes in "AKICc", "KIC", "AICc", "AIC" and "FPE", default it not using a model-selection criterion
-//a, v, k: Output variables
+//poles: positive integer value < length(x) - 2
+//criterion: string value, takes in "AKICc", "KIC", "AICc", "AIC" and "FPE", default it not using a model-selection criterion
+//a: list of P+1 autoregression coefficients.
+//v: mean square of residual noise from the whitening operation of the Burg lattice filter
+//k: reflection coefficients defining the lattice-filter embodiment of the model
+
//Description
-//This is an Octave function.
-//
//This function calculates coefficients of an autoregressive (AR) model of complex data x using the whitening lattice-filter method of Burg.
-//
//The first argument is the data sampled. The second argument is the number of poles in the model (or limit in case a criterion is supplied).
//The third parameter takes in the criterion to limit the number of poles. The acceptable values are "AIC", "AKICc", "KIC", "AICc" which are based on information theory.
-//Output variable a is a list of P+1 autoregression coefficients.
-//Output variable v is the mean square of residual noise from the whitening operation of the Burg lattice filter.
-//Output variable k corresponds to the reflection coefficients defining the lattice-filter embodiment of the model.
+
//Examples
//arburg([1,2,3,4,5],2)
-//ans =
-// 1.00000 -1.86391 0.95710
-
-funcprot(0);
-rhs = argn(2)
-lhs = argn(1)
-if(lhs>3)
-error("Wrong number of output arguments.")
-elseif(rhs<2)
-error("Wrong number of input arguments.")
-end
-
- select(lhs)
- case 1 then
- if(rhs==2)
- a = callOctave("arburg",x,poles)
- elseif(rhs==3)
- a = callOctave("arburg",x,poles,criterion)
- end
- case 2 then
- if(rhs==2)
- [a,v] = callOctave("arburg",x,poles)
- elseif(rhs==3)
- [a,v] = callOctave("arburg",x,poles,criterion)
- end
- case 3 then
- if(rhs==2)
- [a,v,k] = callOctave("arburg",x,poles)
- elseif(rhs==3)
- [a,v,k] = callOctave("arburg",x,poles,criterion)
- end
- end
+// ans =
+//
+// 1. - 1.8639053 0.9571006
+
+
+//*************************************************************************************
+//-------------------version1 (using callOctave / errored)-----------------------------
+//*************************************************************************************
+//function varargout = arburg( x, poles, criterion )
+//funcprot(0);
+//rhs = argn(2)
+//lhs = argn(1)
+//if(lhs>3)
+//error("Wrong number of output arguments.")
+//elseif(rhs<2)
+//error("Wrong number of input arguments.")
+//end
+//
+// select(lhs)
+// case 1 then
+// if(rhs==2)
+// a = callOctave("arburg",x,poles)
+// elseif(rhs==3)
+// a = callOctave("arburg",x,poles,criterion)
+// end
+// case 2 then
+// if(rhs==2)
+// [a,v] = callOctave("arburg",x,poles)
+// elseif(rhs==3)
+// [a,v] = callOctave("arburg",x,poles,criterion)
+// end
+// case 3 then
+// if(rhs==2)
+// [a,v,k] = callOctave("arburg",x,poles)
+// elseif(rhs==3)
+// [a,v,k] = callOctave("arburg",x,poles,criterion)
+// end
+// end
+//endfunction
+//
+
+//*************************************************************************************
+//-----------------------------version2 (pure scilab code)-----------------------------
+//*************************************************************************************
+
+function varargout = arburg( x, poles, criterion )
+
+ funcprot(0);
+ // Check arguments
+ [nargout nargin ] = argn() ;
+ if ( nargin < 2 )
+ error( 'arburg(x,poles): Need at least 2 args.' );
+ elseif ( ~isvector(x) | length(x) < 3 )
+ error( 'arburg: arg 1 (x) must be vector of length >2.' );
+ elseif ( ~isscalar(poles) | ~isreal(poles) | fix(poles)~=poles | poles<=0.5)
+ error( 'arburg: arg 2 (poles) must be positive integer.' );
+ elseif ( poles >= length(x)-2 )
+ // lattice-filter algorithm requires "poles<length(x)"
+ // AKICc and AICc require "length(x)-poles-2">0
+ error( 'arburg: arg 2 (poles) must be less than length(x)-2.' );
+ elseif ( nargin>2 & ~isempty(criterion) & ...
+ (~(type(criterion) == 10 ) | size(criterion,1)~=1 ) )
+ error( 'arburg: arg 3 (criterion) must be string.' );
+ else
+ //
+ // Set the model-selection-criterion flags.
+ // is_AKICc, isa_KIC and is_corrected are short-circuit flags
+ if ( nargin > 2 & ~isempty(criterion) )
+ is_AKICc = strcmp(criterion,'AKICc'); // AKICc
+ isa_KIC = is_AKICc | strcmp(criterion,'KIC'); // KIC or AKICc
+ is_corrected = is_AKICc | strcmp(criterion,'AICc'); // AKICc or AICc
+ use_inf_crit = is_corrected | isa_KIC | strcmp(criterion,'AIC');
+ use_FPE = strcmp(criterion,'FPE');
+ if ( ~use_inf_crit & ~use_FPE )
+ error( 'arburg: value of arg 3 (criterion) not recognized' );
+ end
+ else
+ use_inf_crit = 0;
+ use_FPE = 0;
+ end
+ //
+ // f(n) = forward prediction error
+ // b(n) = backward prediction error
+ // Storage of f(n) and b(n) is a little tricky. Because f(n) is always
+ // combined with b(n-1), f(1) and b(N) are never used, and therefore are
+ // not stored. Not storing unused data makes the calculation of the
+ // reflection coefficient look much cleaner :)
+ // N.B. {initial v} = {error for zero-order model} =
+ // {zero-lag autocorrelation} = E(x*conj(x)) = x*x'/N
+ // E = expectation operator
+ N = length(x);
+ k = [];
+ if ( size(x,1) > 1 ) // if x is column vector
+ f = x(2:N);
+ b = x(1:N-1);
+ v = real(x'*x) / N;
+ else // if x is row vector
+ f = x(2:N).';
+ b = x(1:N-1).';
+ v = real(x*x') / N;
+ end
+ // new_crit/old_crit is the mode-selection criterion
+ new_crit = abs(v);
+ old_crit = 2 * new_crit;
+ for p = 1:poles
+ //
+ // new reflection coeff = -2* E(f.conj(b)) / ( E(f^2)+E(b(^2) )
+ last_k= -2 * (b' * f) / ( f' * f + b' * b);
+ // Levinson-Durbin recursion for residual
+ new_v = v * ( 1.0 - real(last_k * conj(last_k)) );
+ if ( p > 1 )
+ //
+ // Apply the model-selection criterion and break out of loop if it
+ // increases (rather than decreases).
+ // Do it before we update the old model "a" and "v".
+ //
+ // * Information Criterion (AKICc, KIC, AICc, AIC)
+ if ( use_inf_crit )
+ old_crit = new_crit;
+ // AKICc = log(new_v)+p/N/(N-p)+(3-(p+2)/N)*(p+1)/(N-p-2);
+ // KIC = log(new_v)+ 3 *(p+1)/N;
+ // AICc = log(new_v)+ 2 *(p+1)/(N-p-2);
+ // AIC = log(new_v)+ 2 *(p+1)/N;
+ // -- Calculate KIC, AICc & AIC by using is_AKICc, is_KIC and
+ // is_corrected to "short circuit" the AKICc calculation.
+ // The extra 4--12 scalar arithmetic ops should be quicker than
+ // doing if...elseif...elseif...elseif...elseif.
+ new_crit = log(new_v) + is_AKICc*p/N/(N-p) + ...
+ (2+isa_KIC-is_AKICc*(p+2)/N) * (p+1) / (N-is_corrected*(p+2));
+ if ( new_crit > old_crit )
+ break;
+ end
+ //
+ // (FPE) Final prediction error
+ elseif ( use_FPE )
+ old_crit = new_crit;
+ new_crit = new_v * (N+p+1)/(N-p-1);
+ if ( new_crit > old_crit )
+ break;
+ end
+ end
+ // Update model "a" and "v".
+ // Use Levinson-Durbin recursion formula (for complex data).
+ a = [ prev_a + last_k .* conj(prev_a(p-1:-1:1)) last_k ];
+ else // if( p==1 )
+ a = last_k;
+ end
+ k = [ k; last_k ];
+ v = new_v;
+ if ( p < poles )
+ prev_a = a;
+ // calculate new prediction errors (by recursion):
+ // f(p,n) = f(p-1,n) + k * b(p-1,n-1) n=2,3,...n
+ // b(p,n) = b(p-1,n-1) + conj(k) * f(p-1,n) n=2,3,...n
+ // remember f(p,1) is not stored, so don't calculate it; make f(p,2)
+ // the first element in f. b(p,n) isn't calculated either.
+ nn = N-p;
+ new_f = f(2:nn) + last_k * b(2:nn);
+ b = b(1:nn-1) + conj(last_k) * f(1:nn-1);
+ f = new_f;
+ end
+ end
+
+ varargout(1) = [1,a];
+ varargout(2) = v;
+ if ( nargout>=3 )
+ varargout(3) = k;
+ end
+ end
+
endfunction