summaryrefslogtreecommitdiff
path: root/macros/freqz.sci
diff options
context:
space:
mode:
Diffstat (limited to 'macros/freqz.sci')
-rw-r--r--macros/freqz.sci316
1 files changed, 246 insertions, 70 deletions
diff --git a/macros/freqz.sci b/macros/freqz.sci
index dc71b75..4579da3 100644
--- a/macros/freqz.sci
+++ b/macros/freqz.sci
@@ -1,71 +1,247 @@
-function [H, W] = freqz(B, varargin)
-//This function returns the complex frequency response H of the rational IIR filter whose numerator and denominator coefficients are B and A, respectively.
-//Calling Sequence
-//[H, W] = freqz(B, A, N, "whole")
-//[H, W] = freqz(B)
-//[H, W] = freqz(B, A)
-//[H, W] = freqz(B, A, N)
-//H = freqz(B, A, W)
-//[H, W] = freqz(..., FS)
-//freqz(...)
-//Parameters
-//B, A, N: Integer or Vector
-//Description
-// Return the complex frequency response H of the rational IIR filter whose numerator and denominator coefficients are B and A, respectively.
-//
-//The response is evaluated at N angular frequencies between 0 and 2*pi.
-//
-//The output value W is a vector of the frequencies.
-//
-//If A is omitted, the denominator is assumed to be 1 (this corresponds to a simple FIR filter).
-//
-//If N is omitted, a value of 512 is assumed. For fastest computation, N should factor into a small number of small primes.
-//
-//If the fourth argument, "whole", is omitted the response is evaluated at frequencies between 0 and pi.
-//
-// 'freqz (B, A, W)'
-//
-//Evaluate the response at the specific frequencies in the vector W. The values for W are measured in radians.
-//
-// '[...] = freqz (..., FS)'
-//
-//Return frequencies in Hz instead of radians assuming a sampling rate FS. If you are evaluating the response at specific frequencies W, those frequencies should be requested in Hz rather than radians.
-//
-// 'freqz (...)'
-//
-//Plot the magnitude and phase response of H rather than returning them.
-//Examples
-//H = freqz([1,2,3], [4,3], [1,2,5])
-//ans =
-// 0.4164716 - 0.5976772i - 0.4107690 - 0.2430335i 0.1761948 + 0.6273032i
-funcprot(0);
-rhs=argn(2);
-lhs=argn(1);
-if(rhs<2 | rhs>4) then
- error("Wrong number of input arguments.");
-end
-if (lhs<1 | lhs>2)
- error("Wrong number of output arguments.");
-end
-if (lhs==1) then
-select(rhs)
-case 1 then
- H = callOctave("freqz",B);
-case 2 then
- H = callOctave("freqz",B, varargin(1));
-case 3 then
- H = callOctave("freqz",B, varargin(1), varargin(2));
-end
-elseif (lhs==2) then
- select(rhs)
-case 1 then
- [H, W] = callOctave("freqz",B);
-case 2 then
- [H, W] = callOctave("freqz",B, varargin(1));
-case 3 then
- [H, W] = callOctave("freqz",B, varargin(1), varargin(2));
-case 4 then
- [H, W] = callOctave("freqz", B, varargin(1), varargin(2), varargin(3));
-end
-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 , Under FOSSEE Internship
+// Last Modified on : 3 Feb 2024
+// Organization: FOSSEE, IIT Bombay
+// Email: toolbox@scilab.in
+
+// Example usage of freqz in different formats:
+// [h, w] = freqz (b, a, n, "whole")
+// [h, w] = freqz (b)
+// [h, w] = freqz (b, a)
+// [h, w] = freqz (b, a, n)
+// h = freqz (b, a, w)
+// [h, w] = freqz (…, Fs)
+// freqz (...)
+
+/*
+Return the complex frequency response `h` of the rational IIR filter whose
+numerator and denominator coefficients are `b` and `a`, respectively.
+
+The response is evaluated at `n` angular frequencies between 0 and 2*pi.
+
+The output value `w` is a vector of the frequencies.
+
+If `a` is omitted, the denominator is assumed to be 1 (this corresponds to a simple FIR filter).
+
+If `n` is omitted, a value of 512 is assumed. For fastest computation, `n` should factor into a small number of small primes.
+
+If the fourth argument, "whole", is omitted, the response is evaluated at frequencies between 0 and pi.
+
+freqz (b, a, w)
+
+Evaluate the response at the specific frequencies in the vector `w`. The values for `w` are measured in radians.
+
+[...] = freqz (…, Fs)
+
+Return frequencies in Hz instead of radians assuming a sampling rate `Fs`. If you are evaluating the response at specific frequencies `w`, those frequencies should be requested in Hz rather than radians.
+
+freqz (...)
+
+Plot the magnitude and phase response of `h` rather than returning them.
+*/
+// Dependencies
+// fft1 unwrap2 postpad
+function [h_r, f_r] = freqz (b, a, n, region, Fs)
+
+ if (nargin < 1)
+ error("Invalid numbers of inputs");
+ elseif (nargin == 1)
+ // Response of an FIR filter.
+ a = [];
+ n = [];
+ region =[];
+ Fs = [];
+ elseif (nargin == 2)
+ // Response of an IIR filter
+ n = [];
+ region = [];
+ Fs = [];
+ elseif (nargin == 3)
+ region =[];
+ Fs = [];
+ elseif (nargin == 4)
+ Fs = [];
+ if (~ (type(region)==10) && ~ isempty(region))
+ Fs = region;
+ region = [];
+ end
+ end
+
+ if (isempty (b))
+ b = 1;
+ elseif (~ isvector (b))
+ error ("freqz: B must be a vector");
+ end
+ if (isempty (a))
+ a = 1;
+ elseif (~ isvector (a))
+ error ("freqz: A must be a vector");
+ end
+ if (isempty (n))
+ n = 512;
+ elseif (isscalar (n) && n < 1)
+ error ("freqz: N must be a positive integer");
+ end
+ if (isempty (region))
+ if (isreal (b) && isreal (a))
+ region = "half";
+ else
+ region = "whole";
+ end
+ end
+ if (isempty (Fs))
+ freq_norm = %t;
+ if (nargout == 1)
+ Fs = 2;
+ else
+ Fs = 2*%pi;
+ end
+ else
+ freq_norm = %f;
+ end
+ // FIXME : nargout != 0 even if no output parameter is used
+ // FIXME : problem in argn() or nargin function
+ //plot_output = (nargout == 0);
+ plot_output = (nargout == 1) // temp fix
+ whole_region = ~strcmp (region, "whole");
+
+ a = a(:);
+ b = b(:);
+
+ if (~ isscalar (n))
+ // Explicit frequency vector given
+ w = n;
+ f = n;
+ if (nargin == 4)
+ // Sampling rate Fs was specified
+ w = 2*%pi*f/Fs;
+ end
+ k = max (length (b), length (a));
+ hb = polyval (postpad (b, k), exp (%i*w));
+ ha = polyval (postpad (a, k), exp (%i*w));
+ else
+ // polyval(fliplr(P),exp(jw)) is O(p n) and fft(x) is O(n log(n)),
+ // where p is the order of the polynomial P. For small p it
+ // would be faster to use polyval but in practice the overhead for
+ // polyval is much higher and the little bit of time saved isn't
+ // worth the extra code.
+ k = max (length (b), length (a));
+ if (k > n/2 && nargout == 0)
+ // Ensure a causal phase response.
+ n = n * 2 .^ ceil (log2 (2*k/n));
+ end
+
+ if (whole_region)
+ N = n;
+ if (plot_output)
+ f = Fs * (0:n).' / N; // do 1 more for the plot
+ else
+ f = Fs * (0:n-1).' / N;
+ end
+ else
+ N = 2*n;
+ if (plot_output)
+ n = n + 1;
+ end
+ f = Fs * (0:n-1).' / N;
+ end
+
+ pad_sz = N*ceil (k/N);
+ b = postpad (b, pad_sz);
+ a = postpad (a, pad_sz);
+
+ hb = zeros (n, 1);
+ ha = zeros (n, 1);
+
+ for i = 1:N:pad_sz
+ fftresult = fft1 (postpad (b(i:i+N-1), N))(1:n);
+ if size(fftresult,1) == 1 then fftresult = fftresult';end
+ hb = hb + fftresult ;
+ tempfftresult=fft1 (postpad (a(i:i+N-1), N))(1:n);
+ if size(tempfftresult,1) == 1 then tempfftresult = tempfftresult';end
+ ha = ha + tempfftresult;
+ end
+
+ end
+
+ h = hb ./ ha;
+
+ if (plot_output)
+ // Plot and don't return values.
+ if (whole_region && isscalar (n))
+ h($+1) = h(1); // Solution is periodic. Copy first value to end.
+ end
+ freqz_plot (f, h, freq_norm);
+ end
+ // Return values and don't plot.
+ h_r = h;
+ f_r = f;
+
+
endfunction
+function freqz_plot (w, h, freq_norm)
+ if (nargin < 2)
+ error("Invalid numbers of inputs");
+ end
+
+ if nargin < 3 then
+ freq_norm = %f
+ end
+ n = size(max(w));
+ mag = 20 * log10 (abs (h));
+ phase = unwrap2 (angle (h));
+
+ if (freq_norm)
+ x_label = 'Normalized Frequency (\times\pi rad/sample)';
+ else
+ x_label = "Frequency (Hz)";
+ end
+ subplot (2, 1, 1);
+ plot (w, mag);
+ xgrid;
+ xlabel (x_label);
+ ylabel ("Magnitude (dB)");
+
+ subplot (2, 1, 2);
+ plot (w, phase*360/(2*%pi));
+ xgrid;
+ xlabel (x_label);
+ ylabel ("Phase (degrees)");
+
+endfunction
+/*
+// passed
+testif HAVE_FFTW # correct values and fft-polyval consistency
+ // butterworth filter, order 2, cutoff pi/2 radians
+ b = [0.292893218813452 0.585786437626905 0.292893218813452];
+ a = [1 0 0.171572875253810];
+ [h,w] = freqz (b,a,32);
+
+//passed
+testif HAVE_FFTW # whole-half consistency
+ b = [1 1 1]/3;
+ [h,w] = freqz (b,1,32,"whole");
+
+ [h2,w2] = freqz (b,1,16,"half");
+
+
+//passed
+testif HAVE_FFTW # Sampling frequency properly interpreted
+ b = [1 1 1]/3; a = [1 0.2];
+ [h,f] = freqz (b,a,16,320);
+
+ [h2,f2] = freqz (b,a,[0:15]*10,320);
+
+ [h3,f3] = freqz (b,a,32,"whole",320);
+
+
+// Test input validation
+// FIXME: Need to put tests here and simplify input validation in the main code.
+
+*/