summaryrefslogtreecommitdiff
path: root/macros/impz.sci
blob: e4e1ba495658781bd503885cc47733bd5cd73468 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
// 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/
// Modifieded by: Abinash Singh Under FOSSEE Internship
// Last Modified on : 3 Feb 2024
// Organization: FOSSEE, IIT Bombay
// Email: toolbox@scilab.in
/*
Calling Sequence
 [x, t] = impz (b) ¶
 [x, t] = impz (b, a) ¶
 [x, t] = impz (b, a, n) ¶
 [x, t] = impz (b, a, n, fs) ¶
 impz (…) ¶
Generate impulse-response characteristics of the filter. 
The filter coefficients correspond to the the z-plane rational function with numerator b and denominator a. If a is not specified, it defaults to 1. 
If n is not specified, or specified as [], it will be chosen such that the signal has a chance to die down to -120dB, or to not explode beyond 120dB, or to show five periods if there is no significant damping.
If no return arguments are requested, plot the results.
Dependencies
  fftfilt
*/
function [x_r, t_r] = impz(b, a, n, fs)

  if nargin < 1 || nargin > 4 then 
    error(" impz : Incorrect number of input arguments ")
  end
  if nargin < 2 then a = [1]; end 
  if nargin < 3 then n = [] ; end
  if nargin < 4 then fs = 1 ; end
  
  if  (~isvector(b) && ~isscalar(b)) || (~isvector(a) && ~isscalar(a) )  then
    error("impz: B and A must be vectors");
  end
  if isempty(n) && length(a) > 1 then 
    precision = 1e-6;
    r = roots(a);
    maxpole = max(abs(r));
    if (maxpole > 1+precision)     // unstable -- cutoff at 120 dB
      n = floor(6/log10(maxpole));
    elseif (maxpole < 1-precision) // stable -- cutoff at -120 dB
      n = floor(-6/log10(maxpole));
    else                           // periodic -- cutoff after 5 cycles
      n = 30;

      // find longest period less than infinity
      // cutoff after 5 cycles (w=10*pi)
      rperiodic = r(find(abs(r)>=1-precision & abs(arg(r))>0));
      if ~isempty(rperiodic)
        n_periodic = ceil(10*pi./min(abs(arg(rperiodic))));
        if (n_periodic > n)
          n = n_periodic;
        end
      end

      // find most damped pole
      // cutoff at -60 dB
      rdamped = r(find(abs(r)<1-precision));
      if ~isempty(rdamped)
        n_damped = floor(-3/log10(max(abs(rdamped))));
        if (n_damped > n)
          n = n_damped;
        end
      end
    end
    n = n + length(b);
  elseif isempty(n)
    n = length(b);
  elseif ( ~isscalar(n))
    // TODO: missing option of having N as a vector of values to
    //       compute the impulse response.
    error ("impz: N must be empty or a scalar");
  end

  if length(a) == 1 then 
    x = fftfilt(b/a, [1, zeros(1,n-1)]');
  else
    x = filter(b, a, [1, zeros(1,n-1)]');
  end
  t = [0:n-1]/fs;

  if nargout >= 1 x_r = x; end
  if nargout >= 2 t_r = t; end
  //if nargout ~= 2 then  //FIXME: fix nargout to detect 0 output arguments . till then plot it always
      title("Impulse Response");
      if (fs > 1000)
        t = t * 1000;
        xlabel("Time (msec)");
      else
        xlabel("Time (sec)");
      end
      plot(t, x,);
  //end

endfunction
/*

test case 1
assert_checkequal(size(impz (1, [1 -1 0.9], 100)), [100 1]) // passed

test case 2
// 7th order butterworth filter with fc = 0.5 //passed
B=[0.016565   0.115957   0.347871   0.579785   0.579785   0.347871   0.115957   0.016565];
A=[1.0000e+00  -5.6205e-16   9.1997e-01  -3.6350e-16   1.9270e-01  -4.3812e-17   7.6835e-03  -4.2652e-19];
impz(B, A) 

test case 3
// 
[x_r,tr]=impz([0.4 0.2 8 2] ,1,10)
assert_checkalmostequal(x_r,[ 0.4000000 0.2000000 8. 2.0000000 1.943D-16 1.388D-17 0. 0  0. 0.]',%eps,1e-4);
assert_checkalmostequal(tr,0:9,%eps,1e-4);

//test case 4 
[xr,tr]=impz([0.4 0.2],[4 5 6],3,10) 


// test case 5
B = [0.021895   0.109474   0.218948   0.218948   0.109474   0.021895];
A = [1.0000  -1.2210   1.7567  -1.3348   0.7556  -0.2560];
impz(B, A) 

 */