summaryrefslogtreecommitdiff
path: root/macros/impinvar.sci
diff options
context:
space:
mode:
Diffstat (limited to 'macros/impinvar.sci')
-rw-r--r--macros/impinvar.sci187
1 files changed, 145 insertions, 42 deletions
diff --git a/macros/impinvar.sci b/macros/impinvar.sci
index cc9aa6f..57fdb88 100644
--- a/macros/impinvar.sci
+++ b/macros/impinvar.sci
@@ -1,43 +1,146 @@
-function [b_out, a_out] = impinvar (b, a, fs, tol)
-//This function converts analog filter with coefficients b and a to digital, conserving impulse response.
-//Calling Sequence
-//[b, a] = impinvar (b, a)
-//[b, a] = impinvar (b, a, fs)
-//[b, a] = impinvar (b, a, fs, tol)
-//Parameters
-//b: real or complex valued scalar or vector
-//a: real or complex valued scalar or vector, order should be greater than b
-//fs: real or complex value, default value 1Hz
-//tol: real or complex value, default value 0.0001
-//Description
-//This is an Octave function.
-//This function converts analog filter with coefficients b and a to digital, conserving impulse response.
-//This function does the inverse of impinvar.
-//Examples
-//b = 0.0081000
-//a = [2.0000000, 0.56435378, 0.4572792, 0.00705544, 0.091000]
-//[ay,by] = impinvar(b,a,10)
-//ay =
-// 0.0000e+00 7.5293e-08 2.9902e-07 7.4238e-08
-//by =
-// 1.00000 -3.96992 5.91203 -3.91428 0.97218
-
-funcprot(0);
-rhs = argn(2)
-if(rhs<2)
-error("Wrong number of input arguments.")
-end
-
-
- select(rhs)
- case 2 then
-// [b, a] = callOctave("impinvar",b,a)
- [b_out, a_out] = callOctave("impinvar",b,a)
- case 3 then
-// [b, a] = callOctave("impinvar",b,a,fs)
- [b_out, a_out] = callOctave("impinvar",b,a,fs)
- case 4 then
-// [b, a] = callOctave("impinvar",b,a,fs,tol)
- [b_out, a_out] = callOctave("impinvar",b,a,fs,tol)
- end
+// Copyright (C) 2018 - IIT Bombay - FOSSEE
+// This file must be used under the terms of the CeCILL.
+// This source file is licensed as described in the file COPYING, which
+// you should have received as part of this distribution. The terms
+// are also available at
+// http://www.cecill.info/licences/Licence_CeCILL_V2-en.txt
+// Original Source : https://octave.sourceforge.io/signal/
+// Modifieded by: Abinash Singh , SOE CUSAT
+// Last Modified on : Feb 2024
+// Organization: FOSSEE, IIT Bombay
+// Email: toolbox@scilab.in
+
+/*
+Calling Sequence
+[b_out, a_out] = impinvar (b, a, fs, tol)
+[b_out, a_out] = impinvar (b, a, fs)
+[b_out, a_out] = impinvar (b, a)
+Converts analog filter with coefficients b and a to digital, conserving impulse response.
+
+If fs is not specified, or is an empty vector, it defaults to 1Hz.
+
+If tol is not specified, it defaults to 0.0001 (0.1%) This function does the inverse of impinvar so that the following example should restore the original values of a and b.
+
+invimpinvar implements the reverse of this function.
+
+[b, a] = impinvar (b, a);
+[b, a] = invimpinvar (b, a);
+Reference: Thomas J. Cavicchi (1996) “Impulse invariance and multiple-order poles”. IEEE transactions on signal processing, Vol 44 (9): 2344–2347
+Dependencies
+ residue
+
+
+*/
+function [b_out, a_out] = impinvar (b_in, a_in, fs , tol)
+ error("impinvar: Missing functionality .This function is not implemented yet. Will available in next release");
+endfunction
+/*
+ if (nargin <2)
+ error ("impinvar: Insufficient input arguments");
+ end
+ if nargin < 3
+ fs = 1;
+ end
+ if nargin < 4
+ tol = 0.0001;
+ end
+ // to be compatible with the matlab implementation where an empty vector can
+ // be used to get the default
+ if (isempty(fs))
+ ts = 1;
+ else
+ ts = 1/fs; // we should be using sampling frequencies to be compatible with Matlab
+ end
+
+ [r_in, p_in, k_in] = residue(b_in, a_in); // partial fraction expansion
+
+ n = length(r_in); // Number of poles/residues
+
+ if (length(k_in)>0) // Greater than zero means we cannot do impulse invariance
+ error("Order numerator >= order denominator");
+ end
+
+ r_out = zeros(1,n); // Residues of H(z)
+ p_out = zeros(1,n); // Poles of H(z)
+ k_out = 0; // Constant term of H(z)
+
+ i=1;
+ while (i<=n)
+ m = 1;
+ first_pole = p_in(i); // Pole in the s-domain
+ while (i<n && abs(first_pole-p_in(i+1))<tol) // Multiple poles at p(i)
+ i=i+1; // Next residue
+ m=m+1; // Next multiplicity
+ end
+ [r, p, k] = z_res(r_in(i-m+1:i), first_pole, ts); // Find z-domain residues
+ k_out = k_out + k; // Add direct term to output
+ p_out(i-m+1:i) = p; // Copy z-domain pole(s) to output
+ r_out(i-m+1:i) = r; // Copy z-domain residue(s) to output
+
+ i=i+1; // Next s-domain residue/pole
+ end
+
+ [b_out, a_out] = inv_residue(r_out, p_out, k_out, tol);
+ a_out = to_real(a_out); // Get rid of spurious imaginary part
+ b_out = to_real(b_out);
+
+ // Shift results right to account for calculating in z instead of z^-1
+ b_out($)=[];
endfunction
+*/
+// Convert residue vector for single and multiple poles in s-domain (located at sm) to
+// residue vector in z-domain. The variable k is the direct term of the result.
+
+function [r_out, p_out, k_out] = z_res (r_in, sm, ts)
+
+ p_out = exp(ts * sm); // z-domain pole
+ n = length(r_in); // Multiplicity of the pole
+ r_out = zeros(1,n); // Residue vector
+
+ // First pole (no multiplicity)
+ k_out = r_in(1) * ts; // PFE of z/(z-p) = p/(z-p)+1; direct part
+ r_out(1) = r_in(1) * ts * p_out; // pole part of PFE
+
+ for i=(2:n) // Go through s-domain residues for multiple pole
+ r_out(1:i) = r_out(1:i) + r_in(i) * polyrev(h1_z_deriv(i-1, p_out, ts)); // Add z-domain residues
+ end
+
+endfunction
+function p_out = polyrev (p_in)
+
+ p_out = p_in($:-1:1);
+
+
+endfunction
+function p_out = to_real(p_in)
+
+ p_out = abs(p_in) .* sign(real(p_in));
+
+ endfunction
+/*
+//test passed
+[b_out,a_out]=impinvar([1],[1 1],100);
+assert_checkalmostequal(b_out,0.01,%eps,1e-4)
+assert_checkalmostequal(a_out,[1 -0.99],%eps,1e-4)
+
+//test passed
+[b_out,a_out]=impinvar([1],[1 2 1],100)
+assert_checkalmostequal(b_out,[0 9.9005e-5],%eps,1e-4)
+assert_checkalmostequal(a_out,[1 -1.9801 0.9802],%eps,1e-4)
+
+[b_out, a_out] = impinvar([1], [1 3 3 1], 100) // test passed
+
+[b_out, a_out] = impinvar([1 1], [1 3 3 1], 100) // test passed
+
+[b_out, a_out] = impinvar([1 1 1], [1 3 3 1], 100) // test passed
+
+// FIXME : builtin filter doesn't accepts complex parameters
+// These test cases will through errors
+// [b_out, a_out] = impinvar([1], [1 0 1], 100)
+// [b_out, a_out] = impinvar([1 1], [1 0 1], 100)
+// [b_out, a_out] = impinvar([1], [1 0 2 0 1], 100)
+// [b_out, a_out] = impinvar([1 1], [1 0 2 0 1], 100)
+// [b_out, a_out] = impinvar([1 1 1], [1 0 2 0 1], 100)
+// [b_out, a_out] = impinvar([1 1 1 1], [1 0 2 0 1], 100)
+
+*/