annotate main/signal/fir1.m @ 0:6b33357c7561 octave-forge

Initial revision
author pkienzle
date Wed, 10 Oct 2001 19:54:49 +0000
parents
children 76e981d75af3
Ignore whitespace changes - Everywhere: Within whitespace: At end of lines:
rev   line source
0
6b33357c7561 Initial revision
pkienzle
parents:
diff changeset
1 ## Copyright (C) 2000 Paul Kienzle
6b33357c7561 Initial revision
pkienzle
parents:
diff changeset
2 ##
6b33357c7561 Initial revision
pkienzle
parents:
diff changeset
3 ## This program is free software; you can redistribute it and/or modify
6b33357c7561 Initial revision
pkienzle
parents:
diff changeset
4 ## it under the terms of the GNU General Public License as published by
6b33357c7561 Initial revision
pkienzle
parents:
diff changeset
5 ## the Free Software Foundation; either version 2 of the License, or
6b33357c7561 Initial revision
pkienzle
parents:
diff changeset
6 ## (at your option) any later version.
6b33357c7561 Initial revision
pkienzle
parents:
diff changeset
7 ##
6b33357c7561 Initial revision
pkienzle
parents:
diff changeset
8 ## This program is distributed in the hope that it will be useful,
6b33357c7561 Initial revision
pkienzle
parents:
diff changeset
9 ## but WITHOUT ANY WARRANTY; without even the implied warranty of
6b33357c7561 Initial revision
pkienzle
parents:
diff changeset
10 ## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
6b33357c7561 Initial revision
pkienzle
parents:
diff changeset
11 ## GNU General Public License for more details.
6b33357c7561 Initial revision
pkienzle
parents:
diff changeset
12 ##
6b33357c7561 Initial revision
pkienzle
parents:
diff changeset
13 ## You should have received a copy of the GNU General Public License
6b33357c7561 Initial revision
pkienzle
parents:
diff changeset
14 ## along with this program; if not, write to the Free Software
6b33357c7561 Initial revision
pkienzle
parents:
diff changeset
15 ## Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
6b33357c7561 Initial revision
pkienzle
parents:
diff changeset
16
6b33357c7561 Initial revision
pkienzle
parents:
diff changeset
17 ## usage: b = fir1(n, w [, type] [, window] [, noscale])
6b33357c7561 Initial revision
pkienzle
parents:
diff changeset
18 ##
6b33357c7561 Initial revision
pkienzle
parents:
diff changeset
19 ## Produce an order n FIR filter with the given frequency cutoff,
6b33357c7561 Initial revision
pkienzle
parents:
diff changeset
20 ## returning the n+1 filter coefficients in b.
6b33357c7561 Initial revision
pkienzle
parents:
diff changeset
21 ##
6b33357c7561 Initial revision
pkienzle
parents:
diff changeset
22 ## n: order of the filter (1 less than the length of the filter)
6b33357c7561 Initial revision
pkienzle
parents:
diff changeset
23 ## w: band edges
6b33357c7561 Initial revision
pkienzle
parents:
diff changeset
24 ## strictly increasing vector in range [0, 1]
6b33357c7561 Initial revision
pkienzle
parents:
diff changeset
25 ## singleton for highpass or lowpass, vector pair for bandpass or
6b33357c7561 Initial revision
pkienzle
parents:
diff changeset
26 ## bandstop, or vector for alternating pass/stop filter.
6b33357c7561 Initial revision
pkienzle
parents:
diff changeset
27 ## type: choose between pass and stop bands
6b33357c7561 Initial revision
pkienzle
parents:
diff changeset
28 ## 'high' for highpass filter, cutoff at w
6b33357c7561 Initial revision
pkienzle
parents:
diff changeset
29 ## 'stop' for bandstop filter, edges at w = [lo, hi]
6b33357c7561 Initial revision
pkienzle
parents:
diff changeset
30 ## 'DC-0' for bandstop as first band of multiband filter
6b33357c7561 Initial revision
pkienzle
parents:
diff changeset
31 ## 'DC-1' for bandpass as first band of multiband filter
6b33357c7561 Initial revision
pkienzle
parents:
diff changeset
32 ## window: smoothing window
6b33357c7561 Initial revision
pkienzle
parents:
diff changeset
33 ## defaults to hamming(n+1) row vector
6b33357c7561 Initial revision
pkienzle
parents:
diff changeset
34 ## returned filter is the same shape as the smoothing window
6b33357c7561 Initial revision
pkienzle
parents:
diff changeset
35 ## noscale: choose whether to normalize or not
6b33357c7561 Initial revision
pkienzle
parents:
diff changeset
36 ## 'scale': set the magnitude of the center of the first passband to 1
6b33357c7561 Initial revision
pkienzle
parents:
diff changeset
37 ## 'noscale': don't normalize
6b33357c7561 Initial revision
pkienzle
parents:
diff changeset
38 ##
6b33357c7561 Initial revision
pkienzle
parents:
diff changeset
39 ## To apply the filter, use the return vector b:
6b33357c7561 Initial revision
pkienzle
parents:
diff changeset
40 ## y=filter(b,1,x);
6b33357c7561 Initial revision
pkienzle
parents:
diff changeset
41 ##
6b33357c7561 Initial revision
pkienzle
parents:
diff changeset
42 ## Examples:
6b33357c7561 Initial revision
pkienzle
parents:
diff changeset
43 ## freqz(fir1(40,0.3));
6b33357c7561 Initial revision
pkienzle
parents:
diff changeset
44 ## freqz(fir1(15,[0.2, 0.5], 'stop')); # note the zero-crossing at 0.1
6b33357c7561 Initial revision
pkienzle
parents:
diff changeset
45 ## freqz(fir1(15,[0.2, 0.5], 'stop', 'noscale'));
6b33357c7561 Initial revision
pkienzle
parents:
diff changeset
46
6b33357c7561 Initial revision
pkienzle
parents:
diff changeset
47 ## TODO: Consider using exact expression (in terms of sinc) for the
6b33357c7561 Initial revision
pkienzle
parents:
diff changeset
48 ## TODO: impulse response rather than relying on fir2.
6b33357c7561 Initial revision
pkienzle
parents:
diff changeset
49 ## TODO: Find reference to the requirement that order be even for
6b33357c7561 Initial revision
pkienzle
parents:
diff changeset
50 ## TODO: filters that end high. Figure out what to do with the
6b33357c7561 Initial revision
pkienzle
parents:
diff changeset
51 ## TODO: window in these cases---duplicating the central value
6b33357c7561 Initial revision
pkienzle
parents:
diff changeset
52 ## TODO: like I currently do seems very reasonable.
6b33357c7561 Initial revision
pkienzle
parents:
diff changeset
53 function b = fir1(n, w, ftype, window, scale)
6b33357c7561 Initial revision
pkienzle
parents:
diff changeset
54
6b33357c7561 Initial revision
pkienzle
parents:
diff changeset
55 if nargin < 2 || nargin > 5
6b33357c7561 Initial revision
pkienzle
parents:
diff changeset
56 usage("b = fir1(n, w [, type] [, window] [, noscale])");
6b33357c7561 Initial revision
pkienzle
parents:
diff changeset
57 endif
6b33357c7561 Initial revision
pkienzle
parents:
diff changeset
58
6b33357c7561 Initial revision
pkienzle
parents:
diff changeset
59 ## interpret arguments
6b33357c7561 Initial revision
pkienzle
parents:
diff changeset
60 if nargin==2
6b33357c7561 Initial revision
pkienzle
parents:
diff changeset
61 ftype=[]; window=[]; scale=[];
6b33357c7561 Initial revision
pkienzle
parents:
diff changeset
62 elseif nargin==3
6b33357c7561 Initial revision
pkienzle
parents:
diff changeset
63 window=[]; scale=[];
6b33357c7561 Initial revision
pkienzle
parents:
diff changeset
64 if !isstr(ftype), window=ftype; ftype=[]; endif
6b33357c7561 Initial revision
pkienzle
parents:
diff changeset
65 elseif nargin==4
6b33357c7561 Initial revision
pkienzle
parents:
diff changeset
66 scale=[];
6b33357c7561 Initial revision
pkienzle
parents:
diff changeset
67 if isstr(window), scale=window; window=[]; endif
6b33357c7561 Initial revision
pkienzle
parents:
diff changeset
68 if !isstr(ftype), window=ftype; ftype=[]; endif
6b33357c7561 Initial revision
pkienzle
parents:
diff changeset
69 endif
6b33357c7561 Initial revision
pkienzle
parents:
diff changeset
70
6b33357c7561 Initial revision
pkienzle
parents:
diff changeset
71 ## If single band edge, the first band defaults to a pass band
6b33357c7561 Initial revision
pkienzle
parents:
diff changeset
72 ## to create a lowpass filter. If multiple band edges, assume
6b33357c7561 Initial revision
pkienzle
parents:
diff changeset
73 ## the first band is a stop band, so that the two band case defaults
6b33357c7561 Initial revision
pkienzle
parents:
diff changeset
74 ## to a band pass filter. Ick.
6b33357c7561 Initial revision
pkienzle
parents:
diff changeset
75 ftype = tolower(ftype);
6b33357c7561 Initial revision
pkienzle
parents:
diff changeset
76 if isempty(ftype), ftype = length(w)==1;
6b33357c7561 Initial revision
pkienzle
parents:
diff changeset
77 elseif strcmp(ftype, 'low'), ftype = 1;
6b33357c7561 Initial revision
pkienzle
parents:
diff changeset
78 elseif strcmp(ftype, 'high'), ftype = 0;
6b33357c7561 Initial revision
pkienzle
parents:
diff changeset
79 elseif strcmp(ftype, 'pass'), ftype = 0;
6b33357c7561 Initial revision
pkienzle
parents:
diff changeset
80 elseif strcmp(ftype, 'stop'), ftype = 1;
6b33357c7561 Initial revision
pkienzle
parents:
diff changeset
81 elseif strcmp(ftype, 'dc-0'), ftype = 0;
6b33357c7561 Initial revision
pkienzle
parents:
diff changeset
82 elseif strcmp(ftype, 'dc-1'), ftype = 1;
6b33357c7561 Initial revision
pkienzle
parents:
diff changeset
83 elseif isstr(ftype)
6b33357c7561 Initial revision
pkienzle
parents:
diff changeset
84 error(["fir1 invalid filter type ", ftype]);
6b33357c7561 Initial revision
pkienzle
parents:
diff changeset
85 else
6b33357c7561 Initial revision
pkienzle
parents:
diff changeset
86 error("fir1 filter type should be a string");
6b33357c7561 Initial revision
pkienzle
parents:
diff changeset
87 endif
6b33357c7561 Initial revision
pkienzle
parents:
diff changeset
88
6b33357c7561 Initial revision
pkienzle
parents:
diff changeset
89 ## scale the magnitude by default
6b33357c7561 Initial revision
pkienzle
parents:
diff changeset
90 if isempty(scale) || strcmp(scale, 'scale'), scale = 1;
6b33357c7561 Initial revision
pkienzle
parents:
diff changeset
91 elseif strcmp(scale, 'noscale'), scale=0;
6b33357c7561 Initial revision
pkienzle
parents:
diff changeset
92 else error("fir1 scale must be 'scale' or 'noscale'");
6b33357c7561 Initial revision
pkienzle
parents:
diff changeset
93 endif
6b33357c7561 Initial revision
pkienzle
parents:
diff changeset
94
6b33357c7561 Initial revision
pkienzle
parents:
diff changeset
95 ## use fir2 default filter
6b33357c7561 Initial revision
pkienzle
parents:
diff changeset
96 if isempty(window) && isempty(scale), window = []; endif
6b33357c7561 Initial revision
pkienzle
parents:
diff changeset
97
6b33357c7561 Initial revision
pkienzle
parents:
diff changeset
98 ## build response function according to fir2 requirements
6b33357c7561 Initial revision
pkienzle
parents:
diff changeset
99 bands = length(w)+1;
6b33357c7561 Initial revision
pkienzle
parents:
diff changeset
100 f = zeros(1,2*bands);
6b33357c7561 Initial revision
pkienzle
parents:
diff changeset
101 f(1) = 0; f(2*bands)=1;
6b33357c7561 Initial revision
pkienzle
parents:
diff changeset
102 f(2:2:2*bands-1) = w;
6b33357c7561 Initial revision
pkienzle
parents:
diff changeset
103 f(3:2:2*bands-1) = w;
6b33357c7561 Initial revision
pkienzle
parents:
diff changeset
104 m = zeros(1,2*bands);
6b33357c7561 Initial revision
pkienzle
parents:
diff changeset
105 m(1:2:2*bands) = rem([1:bands]-(1-ftype),2);
6b33357c7561 Initial revision
pkienzle
parents:
diff changeset
106 m(2:2:2*bands) = m(1:2:2*bands);
6b33357c7561 Initial revision
pkienzle
parents:
diff changeset
107
6b33357c7561 Initial revision
pkienzle
parents:
diff changeset
108 ## Increment the order if the final band is a pass band. Something
6b33357c7561 Initial revision
pkienzle
parents:
diff changeset
109 ## about having a nyquist frequency of zero causing problems.
6b33357c7561 Initial revision
pkienzle
parents:
diff changeset
110 if rem(n,2)==1 && m(2*bands)==1,
6b33357c7561 Initial revision
pkienzle
parents:
diff changeset
111 warning("n must be even for highpass and bandstop filters. Incrementing.");
6b33357c7561 Initial revision
pkienzle
parents:
diff changeset
112 n=n+1;
6b33357c7561 Initial revision
pkienzle
parents:
diff changeset
113 if !isempty(window),
6b33357c7561 Initial revision
pkienzle
parents:
diff changeset
114 if rows(window) == 1
6b33357c7561 Initial revision
pkienzle
parents:
diff changeset
115 window = [window(1:n/2), window(n/2:n-1)];
6b33357c7561 Initial revision
pkienzle
parents:
diff changeset
116 else
6b33357c7561 Initial revision
pkienzle
parents:
diff changeset
117 window = [window(1:n/2); window(n/2:n-1)];
6b33357c7561 Initial revision
pkienzle
parents:
diff changeset
118 endif
6b33357c7561 Initial revision
pkienzle
parents:
diff changeset
119 endif
6b33357c7561 Initial revision
pkienzle
parents:
diff changeset
120 endif
6b33357c7561 Initial revision
pkienzle
parents:
diff changeset
121
6b33357c7561 Initial revision
pkienzle
parents:
diff changeset
122 ## compute the filter
6b33357c7561 Initial revision
pkienzle
parents:
diff changeset
123 b = fir2(n, f, m, 512, 2, window);
6b33357c7561 Initial revision
pkienzle
parents:
diff changeset
124
6b33357c7561 Initial revision
pkienzle
parents:
diff changeset
125 ## normalize filter magnitude
6b33357c7561 Initial revision
pkienzle
parents:
diff changeset
126 if scale == 1
6b33357c7561 Initial revision
pkienzle
parents:
diff changeset
127 ## find the middle of the first band edge
6b33357c7561 Initial revision
pkienzle
parents:
diff changeset
128 if m(1) == 1, w_o = (f(2)-f(1))/2;
6b33357c7561 Initial revision
pkienzle
parents:
diff changeset
129 else w_o = f(3) + (f(4)-f(3))/2;
6b33357c7561 Initial revision
pkienzle
parents:
diff changeset
130 endif
6b33357c7561 Initial revision
pkienzle
parents:
diff changeset
131
6b33357c7561 Initial revision
pkienzle
parents:
diff changeset
132 ## compute |h(w_o)|^-1
6b33357c7561 Initial revision
pkienzle
parents:
diff changeset
133 renorm = 1/abs(polyval(b, exp(-1i*pi*w_o)));
6b33357c7561 Initial revision
pkienzle
parents:
diff changeset
134
6b33357c7561 Initial revision
pkienzle
parents:
diff changeset
135 ## normalize the filter
6b33357c7561 Initial revision
pkienzle
parents:
diff changeset
136 b = renorm*b;
6b33357c7561 Initial revision
pkienzle
parents:
diff changeset
137 endif
6b33357c7561 Initial revision
pkienzle
parents:
diff changeset
138 endfunction
6b33357c7561 Initial revision
pkienzle
parents:
diff changeset
139
6b33357c7561 Initial revision
pkienzle
parents:
diff changeset
140 %!demo
6b33357c7561 Initial revision
pkienzle
parents:
diff changeset
141 %! freqz(fir1(40,0.3));
6b33357c7561 Initial revision
pkienzle
parents:
diff changeset
142 %!demo
6b33357c7561 Initial revision
pkienzle
parents:
diff changeset
143 %! freqz(fir1(15,[0.2, 0.5], 'stop')); # note the zero-crossing at 0.1
6b33357c7561 Initial revision
pkienzle
parents:
diff changeset
144 %!demo
6b33357c7561 Initial revision
pkienzle
parents:
diff changeset
145 %! freqz(fir1(15,[0.2, 0.5], 'stop', 'noscale'));