Skip to content

Commit

Permalink
Merge pull request #6483 from endolith/odd_periodic
Browse files Browse the repository at this point in the history
BUG: Allow odd-length windows to be periodic ("DFT-even") too
  • Loading branch information
e-q committed Jan 21, 2017
2 parents 2f7ee77 + 09ac528 commit c9c0e04
Show file tree
Hide file tree
Showing 3 changed files with 54 additions and 34 deletions.
24 changes: 12 additions & 12 deletions scipy/signal/tests/test_spectral.py
Original file line number Diff line number Diff line change
Expand Up @@ -230,8 +230,8 @@ def test_real_onesided_odd(self):
x[8] = 1
f, p = welch(x, nperseg=9)
assert_allclose(f, np.arange(5.0)/9.0)
q = np.array([0.15958227, 0.24193957, 0.24145224, 0.24100919,
0.24377353])
q = np.array([0.12477455, 0.23430933, 0.17072113, 0.17072113,
0.17072113])
assert_allclose(p, q, atol=1e-7, rtol=1e-7)

def test_real_twosided(self):
Expand Down Expand Up @@ -270,8 +270,8 @@ def test_integer_onesided_odd(self):
x[8] = 1
f, p = welch(x, nperseg=9)
assert_allclose(f, np.arange(5.0)/9.0)
q = np.array([0.15958227, 0.24193957, 0.24145224, 0.24100919,
0.24377353])
q = np.array([0.12477455, 0.23430933, 0.17072113, 0.17072113,
0.17072113])
assert_allclose(p, q, atol=1e-7, rtol=1e-7)

def test_integer_twosided(self):
Expand Down Expand Up @@ -424,8 +424,8 @@ def test_real_onesided_odd_32(self):
x[8] = 1
f, p = welch(x, nperseg=9)
assert_allclose(f, np.arange(5.0)/9.0)
q = np.array([0.15958227, 0.24193957, 0.24145224, 0.24100919,
0.24377353], 'f')
q = np.array([0.12477458, 0.23430935, 0.17072113, 0.17072116,
0.17072113], 'f')
assert_allclose(p, q, atol=1e-7, rtol=1e-7)
assert_(p.dtype == q.dtype)

Expand Down Expand Up @@ -532,8 +532,8 @@ def test_real_onesided_odd(self):
x[8] = 1
f, p = csd(x, x, nperseg=9)
assert_allclose(f, np.arange(5.0)/9.0)
q = np.array([0.15958227, 0.24193957, 0.24145224, 0.24100919,
0.24377353])
q = np.array([0.12477455, 0.23430933, 0.17072113, 0.17072113,
0.17072113])
assert_allclose(p, q, atol=1e-7, rtol=1e-7)

def test_real_twosided(self):
Expand Down Expand Up @@ -572,8 +572,8 @@ def test_integer_onesided_odd(self):
x[8] = 1
f, p = csd(x, x, nperseg=9)
assert_allclose(f, np.arange(5.0)/9.0)
q = np.array([0.15958227, 0.24193957, 0.24145224, 0.24100919,
0.24377353])
q = np.array([0.12477455, 0.23430933, 0.17072113, 0.17072113,
0.17072113])
assert_allclose(p, q, atol=1e-7, rtol=1e-7)

def test_integer_twosided(self):
Expand Down Expand Up @@ -749,8 +749,8 @@ def test_real_onesided_odd_32(self):
x[8] = 1
f, p = csd(x, x, nperseg=9)
assert_allclose(f, np.arange(5.0)/9.0)
q = np.array([0.15958227, 0.24193957, 0.24145224, 0.24100919,
0.24377353], 'f')
q = np.array([0.12477458, 0.23430935, 0.17072113, 0.17072116,
0.17072113], 'f')
assert_allclose(p, q, atol=1e-7, rtol=1e-7)
assert_(p.dtype == q.dtype)

Expand Down
51 changes: 36 additions & 15 deletions scipy/signal/tests/test_windows.py
Original file line number Diff line number Diff line change
Expand Up @@ -60,6 +60,10 @@ class TestBlackman(object):
def test_basic(self):
assert_allclose(signal.blackman(6, sym=False),
[0, 0.13, 0.63, 1.0, 0.63, 0.13], atol=1e-14)
assert_allclose(signal.blackman(7, sym=False),
[0, 0.09045342435412804, 0.4591829575459636,
0.9203636180999081, 0.9203636180999081,
0.4591829575459636, 0.09045342435412804], atol=1e-8)
assert_allclose(signal.blackman(6),
[0, 0.2007701432625305, 0.8492298567374694,
0.8492298567374694, 0.2007701432625305, 0],
Expand All @@ -73,6 +77,10 @@ class TestBlackmanHarris(object):
def test_basic(self):
assert_allclose(signal.blackmanharris(6, False),
[6.0e-05, 0.055645, 0.520575, 1.0, 0.520575, 0.055645])
assert_allclose(signal.blackmanharris(7, sym=False),
[6.0e-05, 0.03339172347815117, 0.332833504298565,
0.8893697722232837, 0.8893697722232838,
0.3328335042985652, 0.03339172347815122])
assert_allclose(signal.blackmanharris(6),
[6.0e-05, 0.1030114893456638, 0.7938335106543362,
0.7938335106543364, 0.1030114893456638, 6.0e-05])
Expand Down Expand Up @@ -211,25 +219,13 @@ def test_cheb_even_low_attenuation(self):
(4, 2, 1.0, False): array([0.1353352832366127, 0.36787944117144233, 1.,
0.36787944117144233]),
(4, 2, 1.0, True): None,
(5, None, 0.2, False):
array([4.53999297624848542e-05,
6.73794699908546700e-03, 1.00000000000000000e+00,
6.73794699908546700e-03, 4.53999297624848542e-05]),
(5, None, 0.2, True):
array([4.53999297624848542e-05,
6.73794699908546700e-03, 1.00000000000000000e+00,
6.73794699908546700e-03, 4.53999297624848542e-05]),
(5, None, 1.0, False): array([0.1353352832366127, 0.36787944117144233, 1.,
0.36787944117144233, 0.1353352832366127]),
(5, None, 1.0, True): array([0.1353352832366127, 0.36787944117144233, 1.,
0.36787944117144233, 0.1353352832366127]),
(5, 2, 0.2, False):
array([4.53999297624848542e-05, 6.73794699908546700e-03,
1.00000000000000000e+00, 6.73794699908546700e-03,
4.53999297624848542e-05]),
(5, 2, 0.2, True): None,
(5, 2, 1.0, False): array([0.1353352832366127, 0.36787944117144233, 1.,
0.36787944117144233, 0.1353352832366127]),
(5, 2, 1.0, True): None
}

Expand All @@ -249,6 +245,11 @@ def test_basic(self):
assert_allclose(signal.flattop(6, sym=False),
[-0.000421051, -0.051263156, 0.19821053, 1.0,
0.19821053, -0.051263156])
assert_allclose(signal.flattop(7, sym=False),
[-0.000421051, -0.03684078115492348,
0.01070371671615342, 0.7808739149387698,
0.7808739149387698, 0.01070371671615342,
-0.03684078115492348])
assert_allclose(signal.flattop(6),
[-0.000421051, -0.0677142520762119, 0.6068721525762117,
0.6068721525762117, -0.0677142520762119,
Expand Down Expand Up @@ -284,6 +285,10 @@ class TestHamming(object):
def test_basic(self):
assert_allclose(signal.hamming(6, False),
[0.08, 0.31, 0.77, 1.0, 0.77, 0.31])
assert_allclose(signal.hamming(7, sym=False),
[0.08, 0.2531946911449826, 0.6423596296199047,
0.9544456792351128, 0.9544456792351128,
0.6423596296199047, 0.2531946911449826])
assert_allclose(signal.hamming(6),
[0.08, 0.3978521825875242, 0.9121478174124757,
0.9121478174124757, 0.3978521825875242, 0.08])
Expand All @@ -296,6 +301,10 @@ class TestHann(object):
def test_basic(self):
assert_allclose(signal.hann(6, sym=False),
[0, 0.25, 0.75, 1.0, 0.75, 0.25])
assert_allclose(signal.hann(7, sym=False),
[0, 0.1882550990706332, 0.6112604669781572,
0.9504844339512095, 0.9504844339512095,
0.6112604669781572, 0.1882550990706332])
assert_allclose(signal.hann(6, True),
[0, 0.3454915028125263, 0.9045084971874737,
0.9045084971874737, 0.3454915028125263, 0])
Expand Down Expand Up @@ -334,6 +343,10 @@ def test_basic(self):
assert_allclose(signal.nuttall(6, sym=False),
[0.0003628, 0.0613345, 0.5292298, 1.0, 0.5292298,
0.0613345])
assert_allclose(signal.nuttall(7, sym=False),
[0.0003628, 0.03777576895352025, 0.3427276199688195,
0.8918518610776603, 0.8918518610776603,
0.3427276199688196, 0.0377757689535203])
assert_allclose(signal.nuttall(6),
[0.0003628, 0.1105152530498718, 0.7982580969501282,
0.7982580969501283, 0.1105152530498719, 0.0003628])
Expand Down Expand Up @@ -469,9 +482,15 @@ def test_windowfunc_basics():
for window_name, params in window_funcs:
window = getattr(signal, window_name)
with warnings.catch_warnings(record=True): # window is not suitable...
w1 = window(7, *params, sym=True)

# Check symmetry for odd and even lengths
w1 = window(8, *params, sym=True)
w2 = window(7, *params, sym=False)
assert_array_almost_equal(w1, w2)
assert_array_almost_equal(w1[:-1], w2)

w1 = window(9, *params, sym=True)
w2 = window(8, *params, sym=False)
assert_array_almost_equal(w1[:-1], w2)

# Check that functions run and output lengths are correct
assert_equal(len(window(6, *params, sym=True)), 6)
Expand Down Expand Up @@ -503,9 +522,11 @@ def test_windowfunc_basics():
assert_array_less(window(9, *params, sym=True), 1.01)
assert_array_less(window(9, *params, sym=False), 1.01)

# Check periodic spectrum
# Check that DFT-even spectrum is purely real for odd and even
assert_allclose(fftpack.fft(window(10, *params, sym=False)).imag,
0, atol=1e-14)
assert_allclose(fftpack.fft(window(11, *params, sym=False)).imag,
0, atol=1e-14)


def test_needs_params():
Expand Down
13 changes: 6 additions & 7 deletions scipy/signal/windows.py
Original file line number Diff line number Diff line change
Expand Up @@ -22,8 +22,7 @@ def _len_guards(M):

def _extend(M, sym):
"""Extend window by 1 sample if needed for DFT-even symmetry"""
odd = M % 2
if not sym and not odd:
if not sym:
return M + 1, True
else:
return M, False
Expand Down Expand Up @@ -1727,13 +1726,13 @@ def get_window(window, Nx, fftbins=True):
--------
>>> from scipy import signal
>>> signal.get_window('triang', 7)
array([ 0.25, 0.5 , 0.75, 1. , 0.75, 0.5 , 0.25])
array([ 0.125, 0.375, 0.625, 0.875, 0.875, 0.625, 0.375])
>>> signal.get_window(('kaiser', 4.0), 9)
array([ 0.08848053, 0.32578323, 0.63343178, 0.89640418, 1. ,
0.89640418, 0.63343178, 0.32578323, 0.08848053])
array([ 0.08848053, 0.29425961, 0.56437221, 0.82160913, 0.97885093,
0.97885093, 0.82160913, 0.56437221, 0.29425961])
>>> signal.get_window(4.0, 9)
array([ 0.08848053, 0.32578323, 0.63343178, 0.89640418, 1. ,
0.89640418, 0.63343178, 0.32578323, 0.08848053])
array([ 0.08848053, 0.29425961, 0.56437221, 0.82160913, 0.97885093,
0.97885093, 0.82160913, 0.56437221, 0.29425961])
"""
sym = not fftbins
Expand Down

0 comments on commit c9c0e04

Please sign in to comment.