[Scipy-svn] r6975 - in trunk/scipy/signal: . tests

scipy-svn at scipy.org scipy-svn at scipy.org
Sun Nov 28 19:40:49 EST 2010


Author: warren.weckesser
Date: 2010-11-28 18:40:49 -0600 (Sun, 28 Nov 2010)
New Revision: 6975

Modified:
   trunk/scipy/signal/fir_filter_design.py
   trunk/scipy/signal/tests/test_fir_filter_design.py
Log:
ENH: signal: add the 'nyq' keyword argument to firwin(), to be consistent with the API of firwin2().

Modified: trunk/scipy/signal/fir_filter_design.py
===================================================================
--- trunk/scipy/signal/fir_filter_design.py	2010-11-28 23:43:20 UTC (rev 6974)
+++ trunk/scipy/signal/fir_filter_design.py	2010-11-29 00:40:49 UTC (rev 6975)
@@ -129,7 +129,8 @@
     return int(ceil(numtaps)), beta
 
 
-def firwin(numtaps, cutoff, width=None, window='hamming', pass_zero=True, scale=True):
+def firwin(numtaps, cutoff, width=None, window='hamming', pass_zero=True,
+                                                        scale=True, nyq=1.0):
     """
     FIR filter design using the window method.
     
@@ -145,25 +146,25 @@
     ----------
     numtaps : int
         Length of the filter (number of coefficients, i.e. the filter
-        order + 1).  `numtaps` must be even if a passband includes the Nyquist
-        frequency.
+        order + 1).  `numtaps` must be even if a passband includes the
+        Nyquist frequency.
 
     cutoff : float or 1D array_like
-        Cutoff frequency of filter (normalized so that 1 corresponds to
-        Nyquist or pi radians / sample) OR an array of cutoff frequencies
-        (that is, band edges). In the latter case, the frequencies in 
-        `cutoff` should be positive and monotonically increasing between
-        0 and 1.  The values 0 and 1 must not be included in `cutoff`.
+        Cutoff frequency of filter (expressed in the same units as `nyq`)
+        OR an array of cutoff frequencies (that is, band edges). In the
+        latter case, the frequencies in `cutoff` should be positive and
+        monotonically increasing between 0 and `nyq`.  The values 0 and
+        `nyq` must not be included in `cutoff`.
 
     width : float or None
-        If `width` is not None, then assume it is the approximate width of
-        the transition region (normalized so that 1 corresponds to pi)
+        If `width` is not None, then assume it is the approximate width
+        of the transition region (expressed in the same units as `nyq`)
         for use in Kaiser FIR filter design.  In this case, the `window`
         argument is ignored.
 
     window : string or tuple of string and parameter values
-        Desired window to use. See `scipy.signal.get_window` for a list of
-        windows and required parameters.
+        Desired window to use. See `scipy.signal.get_window` for a list
+        of windows and required parameters.
 
     pass_zero : bool
         If True, the gain at the frequency 0 (i.e. the "DC gain") is 1.
@@ -175,10 +176,14 @@
         That frequency is either:
             0 (DC) if the first passband starts at 0 (i.e. pass_zero
                 is True);
-            1 (Nyquist) if the first passband ends at 1 (i.e the
-                filter is a single band highpass filter);
+            `nyq` (the Nyquist rate) if the first passband ends at
+                `nyq` (i.e the filter is a single band highpass filter);
             center of first passband otherwise.
 
+    nyq : float
+        Nyquist frequency.  Each frequency in `cutoff` must be between 0
+        and `nyq`.
+
     Returns
     -------
     h : 1D ndarray
@@ -187,8 +192,8 @@
     Raises
     ------
     ValueError
-        If any value in cutoff is less than or equal to 0 or greater
-        than or equal to 1, if the values in cutoff are not strictly
+        If any value in `cutoff` is less than or equal to 0 or greater
+        than or equal to `nyq`, if the values in `cutoff` are not strictly
         monotonically increasing, or if `numtaps` is even but a passband
         includes the Nyquist frequency.
 
@@ -232,28 +237,24 @@
     # The major enhancements to this function added in November 2010 were
     # developed by Tom Krauss (see ticket #902).
 
-    cutoff = np.atleast_1d(cutoff)
-    
+    cutoff = np.atleast_1d(cutoff) / float(nyq)
+
     # Check for invalid input.
     if cutoff.ndim > 1:
         raise ValueError("The cutoff argument must be at most one-dimensional.")
     if cutoff.size == 0:
         raise ValueError("At least one cutoff frequency must be given.")
     if cutoff.min() <= 0 or cutoff.max() >= 1:
-        raise ValueError("Invalid cutoff frequency: frequencies must be greater than 0 and less than 1.")
+        raise ValueError("Invalid cutoff frequency: frequencies must be greater than 0 and less than nyq.")
     if np.any(np.diff(cutoff) <= 0):
         raise ValueError("Invalid cutoff frequencies: the frequencies must be strictly increasing.")
 
     if width is not None:
-        # A width was given.  Verify that it is a float, find the beta parameter
-        # of the Kaiser window, and set `window`.  This overrides the value of
-        # `window` passed in.
-        if isinstance(width, float):
-            atten = kaiser_atten(numtaps, width)
-            beta = kaiser_beta(atten)
-            window = ('kaiser', beta)
-        else:
-            raise ValueError("Invalid value for width: %s", width)
+        # A width was given.  Find the beta parameter of the Kaiser window
+        # and set `window`.  This overrides the value of `window` passed in.
+        atten = kaiser_atten(numtaps, float(width)/nyq)
+        beta = kaiser_beta(atten)
+        window = ('kaiser', beta)
 
     pass_nyquist = bool(cutoff.size & 1) ^ pass_zero
     if pass_nyquist and numtaps % 2 == 0:

Modified: trunk/scipy/signal/tests/test_fir_filter_design.py
===================================================================
--- trunk/scipy/signal/tests/test_fir_filter_design.py	2010-11-28 23:43:20 UTC (rev 6974)
+++ trunk/scipy/signal/tests/test_fir_filter_design.py	2010-11-29 00:40:49 UTC (rev 6975)
@@ -165,6 +165,25 @@
                 [1.0, 1.0, 1.0, 0.0, 0.0, 0.0, 1.0, 1.0, 1.0, 0.0, 0.0, 0.0],
                 decimal=5)
 
+    def test_nyq(self):
+        """Test the nyq keyword."""
+        nyquist = 1000
+        width = 40.0
+        relative_width = width/nyquist
+        ntaps, beta = kaiserord(120, relative_width)
+        taps = firwin(ntaps, cutoff=[300, 700], window=('kaiser', beta),
+                        pass_zero=False, scale=False, nyq=nyquist)
+
+        # Check the symmetry of taps.
+        assert_array_almost_equal(taps[:ntaps/2], taps[ntaps:ntaps-ntaps/2-1:-1])
+
+        # Check the gain at a few samples where we know it should be approximately 0 or 1.
+        freq_samples = np.array([0.0, 200, 300-width/2, 300+width/2, 500,
+                                700-width/2, 700+width/2, 800, 1000])
+        freqs, response = freqz(taps, worN=np.pi*freq_samples/nyquist)
+        assert_array_almost_equal(np.abs(response),
+                [0.0, 0.0, 0.0, 1.0, 1.0, 1.0, 0.0, 0.0, 0.0], decimal=5)
+
     def test_bad_cutoff(self):
         """Test that invalid cutoff argument raises ValueError."""
         # cutoff values must be greater than 0 and less than 1.
@@ -180,8 +199,10 @@
         assert_raises(ValueError, firwin, 99, [])
         # 2D array not allowed.
         assert_raises(ValueError, firwin, 99, [[0.1, 0.2],[0.3, 0.4]])               
+        # cutoff values must be less than nyq.
+        assert_raises(ValueError, firwin, 99, 50.0, nyq=40)
+        assert_raises(ValueError, firwin, 99, [10, 20, 30], nyq=25)
 
-
     def test_even_highpass_raises_value_error(self):
         """Test that attempt to create a highpass filter with an even number
         of taps raises a ValueError exception."""
@@ -190,6 +211,7 @@
 
 
 
+
 class TestFirwin2(TestCase):
 
     def test_invalid_args(self):




More information about the Scipy-svn mailing list