File Coverage

blib/lib/PDL/DSP/Fir/Simple.pm
Criterion Covered Total %
statement 38 41 92.6
branch 2 6 33.3
condition 3 8 37.5
subroutine 11 11 100.0
pod 2 2 100.0
total 56 68 82.3


line stmt bran cond sub pod time code
1             package PDL::DSP::Fir::Simple;
2              
3 1     1   247894 use 5.006;
  1         5  
4 1     1   6 use strict;
  1         2  
  1         26  
5 1     1   6 use warnings;
  1         17  
  1         58  
6              
7             our $VERSION = '0.005';
8              
9 1     1   6 use base 'Exporter';
  1         2  
  1         122  
10              
11 1     1   6 use PDL::LiteF;
  1         2  
  1         9  
12 1     1   3803 use PDL::ImageND('convolveND');
  1         4378  
  1         10  
13 1     1   192 use PDL::NiceSlice;
  1         2  
  1         10  
14              
15             # first line is compat. with older pdl.
16 1     1   2669 use constant PI => 4 * atan2(1, 1);
  1         2  
  1         88  
17             #use PDL::Constants qw(PI);
18              
19 1     1   702 use PDL::DSP::Fir;
  1         4  
  1         430  
20              
21             our @ISA = qw(Exporter);
22             our @EXPORT_OK = qw( filter testdata );
23              
24             $PDL::onlinedoc->scan(__FILE__) if $PDL::onlinedoc;
25              
26             =head1 NAME
27              
28             PDL::DSP::Simple - Simple interface to windowed sinc filters.
29              
30             =head1 SYNOPSIS
31              
32             use PDL::LiteF;
33             use PDL::DSP::Fir::Simple;
34              
35             =head1 DESCRIPTION
36              
37             At present, this module provides one filtering
38             routine. The main purpose is to provide an easy-to-use
39             lowpass filter that only requires the user to provide the
40             data and the cutoff frequency. However, the routines take
41             options to give the user more control over the
42             filtering. The module implements the filters via convolution
43             with a kernel representing a finite impulse response
44             function, either directly or with fft. The filter kernel is
45             constructed from windowed sinc functions. Available filters
46             are lowpass, highpass, bandpass, and bandreject. All window
47             functions in L are available.
48              
49             See L for a moving average filter.
50              
51             Some of this functionality is already available in the PDL core.
52             The modules L and L (time series) also have
53             filtering functions.
54              
55             Below, the word B refers to the number of elements in the filter
56             kernel. The default value is equal to the number of elements in the data
57             to be filtered.
58              
59             No functions are exported by default.
60              
61             =head1 FUNCTIONS
62              
63             =head2 filter
64              
65             $xf = filter($x, {OPTIONS});
66              
67             or
68              
69             $xf = filter($x, $kern);
70              
71             =head3 Examples
72              
73             =for example
74              
75             Apply lowpass filter to signal $x with a cutoff frequency of 90% of the
76             Nyquist frequency (i.e. 45% of the sample frequency).
77              
78             $xf = filter($x, { fc => 0.9 });
79              
80              
81             Apply a highpass filter rather than the default lowpass filter
82              
83             $xf = filter($x, {fc => 0.9 , type => 'highpass' });
84              
85              
86             Apply a lowpass filter of order 20 with a blackman window, rather than the default hamming window.
87              
88             $xf = filter($x, {fc => 0.9 , window => 'blackman' , N => 20 });
89              
90             Apply a 10 point moving average. Note that this moving averaging is implemented via
91             convolution. This is a relatively inefficient implementation.
92              
93             $xf = filter($x, {window => 'rectangular', type => 'window', N => 10 });
94              
95             Return the kernel used in the convolution.
96              
97             ($xf, $kern) = filter($x, { fc => 0.9 });
98              
99              
100             Apply a lowpass filter of order 20 with a tukey window with parameter I = 0.5.
101              
102             $xf = filter($x, {fc => 0.9 ,
103             window => { name => 'tukey', params => 0.5 } , N => 20 });
104              
105             =head3 OPTIONS
106              
107             =over
108              
109             =item N
110              
111             Order of filter. I.e. the number of points in the filter kernel.
112             If this option is not given, or is undefined, or false, or less than
113             zero, then the order of the filter is equal to the number of points
114             in the data C<$x>.
115            
116             =item kern
117              
118             A kernel to use for convolution rather than calculating a kernel
119             from other parameters.
120              
121             =item boundary
122              
123             Boundary condition passed to C. Must be one of
124             'extend', 'truncate', 'periodic'. See L.
125              
126             =back
127              
128             All other options to C are passed to the function L which creates the filter kernel.
129             L in turn passes options to L.
130             The option C is either a string giving the name of the window function, or
131             an anonymous hash of options to pass to L.
132             For example C<< { name => 'window_name', ... } >>.
133              
134             If the second argument is not a hash of options then it is interpreted as a
135             kernel C<$kern> to be convolved with the C<$data>.
136              
137             If called in a list context, the filtered data and kernel ($dataf,$kern)
138             are returned.
139              
140             =cut
141              
142             sub filter {
143 1     1 1 1429 my ($dat,$iopts) = @_;
144 1         36 my ($kern, $boundary);
145 1 50       10 if (ref $iopts eq 'HASH') {
146 1   50     14 $boundary = delete $iopts->{boundary} || 'periodic';
147 1 50 33     19 $iopts->{N} = ($iopts->{N} and $iopts->{N} > 0) ? $iopts->{N} : $dat->nelem;
148 1   33     14 $kern = $iopts->{kern} || PDL::DSP::Fir::firwin($iopts);
149             }
150             else {
151 0         0 $kern = $iopts;
152             }
153 0         0 my $fdat = convolveND($dat, $kern, { boundary => $boundary});
154 0 0       0 return wantarray ? ($fdat,$kern) : $fdat;
155             }
156              
157             # hmm, this is almost like exporting. maybe don't do it.
158             # *PDL::filter = \&filter;
159              
160             =head2 testdata
161              
162             $x = testdata($Npts, $freqs, $amps)
163              
164             For example:
165              
166             $x = testdata(1000, [5,100], [1, .1] );
167              
168             Generate a signal by summing sine functions of differing
169             frequencies. The signal has $Npts
170             elements. $freqs is an array of frequencies, and $amps an
171             array of amplitudes for each frequency. The frequencies should
172             be between 0 and 1, with 1 representing the nyquist frequency.
173              
174             =cut
175              
176             sub testdata {
177 1     1 1 11 my ($M, $f, $amp) = @_;
178 1         7 my $x = zeroes($M);
179 1         203 my $n = sequence($M);
180 1         146 foreach (@$f) {
181 3         3505 $x = $x + (shift @$amp)*sin(PI*$n*($_));
182             }
183 1         464 return $x;
184             }
185              
186             =head1 AUTHOR
187              
188             John Lapeyre, C<< >>
189              
190             =head1 LICENSE AND COPYRIGHT
191              
192             Copyright 2012 John Lapeyre.
193              
194             This program is free software; you can redistribute it and/or modify it
195             under the terms of either: the GNU General Public License as published
196             by the Free Software Foundation; or the Artistic License.
197              
198             See http://dev.perl.org/licenses/ for more information.
199              
200             =cut
201              
202             1; # End of PDL::DSP::Fir::Simple