test_spectral.py 52 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464
  1. from __future__ import division, print_function, absolute_import
  2. import numpy as np
  3. from numpy.testing import (assert_, assert_approx_equal,
  4. assert_allclose, assert_array_equal, assert_equal,
  5. assert_array_almost_equal_nulp)
  6. import pytest
  7. from pytest import raises as assert_raises
  8. from scipy._lib._numpy_compat import suppress_warnings
  9. from scipy import signal, fftpack
  10. from scipy.signal import (periodogram, welch, lombscargle, csd, coherence,
  11. spectrogram, stft, istft, check_COLA, check_NOLA)
  12. from scipy.signal.spectral import _spectral_helper
  13. class TestPeriodogram(object):
  14. def test_real_onesided_even(self):
  15. x = np.zeros(16)
  16. x[0] = 1
  17. f, p = periodogram(x)
  18. assert_allclose(f, np.linspace(0, 0.5, 9))
  19. q = np.ones(9)
  20. q[0] = 0
  21. q[-1] /= 2.0
  22. q /= 8
  23. assert_allclose(p, q)
  24. def test_real_onesided_odd(self):
  25. x = np.zeros(15)
  26. x[0] = 1
  27. f, p = periodogram(x)
  28. assert_allclose(f, np.arange(8.0)/15.0)
  29. q = np.ones(8)
  30. q[0] = 0
  31. q *= 2.0/15.0
  32. assert_allclose(p, q, atol=1e-15)
  33. def test_real_twosided(self):
  34. x = np.zeros(16)
  35. x[0] = 1
  36. f, p = periodogram(x, return_onesided=False)
  37. assert_allclose(f, fftpack.fftfreq(16, 1.0))
  38. q = np.ones(16)/16.0
  39. q[0] = 0
  40. assert_allclose(p, q)
  41. def test_real_spectrum(self):
  42. x = np.zeros(16)
  43. x[0] = 1
  44. f, p = periodogram(x, scaling='spectrum')
  45. g, q = periodogram(x, scaling='density')
  46. assert_allclose(f, np.linspace(0, 0.5, 9))
  47. assert_allclose(p, q/16.0)
  48. def test_integer_even(self):
  49. x = np.zeros(16, dtype=int)
  50. x[0] = 1
  51. f, p = periodogram(x)
  52. assert_allclose(f, np.linspace(0, 0.5, 9))
  53. q = np.ones(9)
  54. q[0] = 0
  55. q[-1] /= 2.0
  56. q /= 8
  57. assert_allclose(p, q)
  58. def test_integer_odd(self):
  59. x = np.zeros(15, dtype=int)
  60. x[0] = 1
  61. f, p = periodogram(x)
  62. assert_allclose(f, np.arange(8.0)/15.0)
  63. q = np.ones(8)
  64. q[0] = 0
  65. q *= 2.0/15.0
  66. assert_allclose(p, q, atol=1e-15)
  67. def test_integer_twosided(self):
  68. x = np.zeros(16, dtype=int)
  69. x[0] = 1
  70. f, p = periodogram(x, return_onesided=False)
  71. assert_allclose(f, fftpack.fftfreq(16, 1.0))
  72. q = np.ones(16)/16.0
  73. q[0] = 0
  74. assert_allclose(p, q)
  75. def test_complex(self):
  76. x = np.zeros(16, np.complex128)
  77. x[0] = 1.0 + 2.0j
  78. f, p = periodogram(x, return_onesided=False)
  79. assert_allclose(f, fftpack.fftfreq(16, 1.0))
  80. q = 5.0*np.ones(16)/16.0
  81. q[0] = 0
  82. assert_allclose(p, q)
  83. def test_unk_scaling(self):
  84. assert_raises(ValueError, periodogram, np.zeros(4, np.complex128),
  85. scaling='foo')
  86. def test_nd_axis_m1(self):
  87. x = np.zeros(20, dtype=np.float64)
  88. x = x.reshape((2,1,10))
  89. x[:,:,0] = 1.0
  90. f, p = periodogram(x)
  91. assert_array_equal(p.shape, (2, 1, 6))
  92. assert_array_almost_equal_nulp(p[0,0,:], p[1,0,:], 60)
  93. f0, p0 = periodogram(x[0,0,:])
  94. assert_array_almost_equal_nulp(p0[np.newaxis,:], p[1,:], 60)
  95. def test_nd_axis_0(self):
  96. x = np.zeros(20, dtype=np.float64)
  97. x = x.reshape((10,2,1))
  98. x[0,:,:] = 1.0
  99. f, p = periodogram(x, axis=0)
  100. assert_array_equal(p.shape, (6,2,1))
  101. assert_array_almost_equal_nulp(p[:,0,0], p[:,1,0], 60)
  102. f0, p0 = periodogram(x[:,0,0])
  103. assert_array_almost_equal_nulp(p0, p[:,1,0])
  104. def test_window_external(self):
  105. x = np.zeros(16)
  106. x[0] = 1
  107. f, p = periodogram(x, 10, 'hann')
  108. win = signal.get_window('hann', 16)
  109. fe, pe = periodogram(x, 10, win)
  110. assert_array_almost_equal_nulp(p, pe)
  111. assert_array_almost_equal_nulp(f, fe)
  112. win_err = signal.get_window('hann', 32)
  113. assert_raises(ValueError, periodogram, x,
  114. 10, win_err) # win longer than signal
  115. def test_padded_fft(self):
  116. x = np.zeros(16)
  117. x[0] = 1
  118. f, p = periodogram(x)
  119. fp, pp = periodogram(x, nfft=32)
  120. assert_allclose(f, fp[::2])
  121. assert_allclose(p, pp[::2])
  122. assert_array_equal(pp.shape, (17,))
  123. def test_empty_input(self):
  124. f, p = periodogram([])
  125. assert_array_equal(f.shape, (0,))
  126. assert_array_equal(p.shape, (0,))
  127. for shape in [(0,), (3,0), (0,5,2)]:
  128. f, p = periodogram(np.empty(shape))
  129. assert_array_equal(f.shape, shape)
  130. assert_array_equal(p.shape, shape)
  131. def test_empty_input_other_axis(self):
  132. for shape in [(3,0), (0,5,2)]:
  133. f, p = periodogram(np.empty(shape), axis=1)
  134. assert_array_equal(f.shape, shape)
  135. assert_array_equal(p.shape, shape)
  136. def test_short_nfft(self):
  137. x = np.zeros(18)
  138. x[0] = 1
  139. f, p = periodogram(x, nfft=16)
  140. assert_allclose(f, np.linspace(0, 0.5, 9))
  141. q = np.ones(9)
  142. q[0] = 0
  143. q[-1] /= 2.0
  144. q /= 8
  145. assert_allclose(p, q)
  146. def test_nfft_is_xshape(self):
  147. x = np.zeros(16)
  148. x[0] = 1
  149. f, p = periodogram(x, nfft=16)
  150. assert_allclose(f, np.linspace(0, 0.5, 9))
  151. q = np.ones(9)
  152. q[0] = 0
  153. q[-1] /= 2.0
  154. q /= 8
  155. assert_allclose(p, q)
  156. def test_real_onesided_even_32(self):
  157. x = np.zeros(16, 'f')
  158. x[0] = 1
  159. f, p = periodogram(x)
  160. assert_allclose(f, np.linspace(0, 0.5, 9))
  161. q = np.ones(9, 'f')
  162. q[0] = 0
  163. q[-1] /= 2.0
  164. q /= 8
  165. assert_allclose(p, q)
  166. assert_(p.dtype == q.dtype)
  167. def test_real_onesided_odd_32(self):
  168. x = np.zeros(15, 'f')
  169. x[0] = 1
  170. f, p = periodogram(x)
  171. assert_allclose(f, np.arange(8.0)/15.0)
  172. q = np.ones(8, 'f')
  173. q[0] = 0
  174. q *= 2.0/15.0
  175. assert_allclose(p, q, atol=1e-7)
  176. assert_(p.dtype == q.dtype)
  177. def test_real_twosided_32(self):
  178. x = np.zeros(16, 'f')
  179. x[0] = 1
  180. f, p = periodogram(x, return_onesided=False)
  181. assert_allclose(f, fftpack.fftfreq(16, 1.0))
  182. q = np.ones(16, 'f')/16.0
  183. q[0] = 0
  184. assert_allclose(p, q)
  185. assert_(p.dtype == q.dtype)
  186. def test_complex_32(self):
  187. x = np.zeros(16, 'F')
  188. x[0] = 1.0 + 2.0j
  189. f, p = periodogram(x, return_onesided=False)
  190. assert_allclose(f, fftpack.fftfreq(16, 1.0))
  191. q = 5.0*np.ones(16, 'f')/16.0
  192. q[0] = 0
  193. assert_allclose(p, q)
  194. assert_(p.dtype == q.dtype)
  195. class TestWelch(object):
  196. def test_real_onesided_even(self):
  197. x = np.zeros(16)
  198. x[0] = 1
  199. x[8] = 1
  200. f, p = welch(x, nperseg=8)
  201. assert_allclose(f, np.linspace(0, 0.5, 5))
  202. q = np.array([0.08333333, 0.15277778, 0.22222222, 0.22222222,
  203. 0.11111111])
  204. assert_allclose(p, q, atol=1e-7, rtol=1e-7)
  205. def test_real_onesided_odd(self):
  206. x = np.zeros(16)
  207. x[0] = 1
  208. x[8] = 1
  209. f, p = welch(x, nperseg=9)
  210. assert_allclose(f, np.arange(5.0)/9.0)
  211. q = np.array([0.12477455, 0.23430933, 0.17072113, 0.17072113,
  212. 0.17072113])
  213. assert_allclose(p, q, atol=1e-7, rtol=1e-7)
  214. def test_real_twosided(self):
  215. x = np.zeros(16)
  216. x[0] = 1
  217. x[8] = 1
  218. f, p = welch(x, nperseg=8, return_onesided=False)
  219. assert_allclose(f, fftpack.fftfreq(8, 1.0))
  220. q = np.array([0.08333333, 0.07638889, 0.11111111, 0.11111111,
  221. 0.11111111, 0.11111111, 0.11111111, 0.07638889])
  222. assert_allclose(p, q, atol=1e-7, rtol=1e-7)
  223. def test_real_spectrum(self):
  224. x = np.zeros(16)
  225. x[0] = 1
  226. x[8] = 1
  227. f, p = welch(x, nperseg=8, scaling='spectrum')
  228. assert_allclose(f, np.linspace(0, 0.5, 5))
  229. q = np.array([0.015625, 0.02864583, 0.04166667, 0.04166667,
  230. 0.02083333])
  231. assert_allclose(p, q, atol=1e-7, rtol=1e-7)
  232. def test_integer_onesided_even(self):
  233. x = np.zeros(16, dtype=int)
  234. x[0] = 1
  235. x[8] = 1
  236. f, p = welch(x, nperseg=8)
  237. assert_allclose(f, np.linspace(0, 0.5, 5))
  238. q = np.array([0.08333333, 0.15277778, 0.22222222, 0.22222222,
  239. 0.11111111])
  240. assert_allclose(p, q, atol=1e-7, rtol=1e-7)
  241. def test_integer_onesided_odd(self):
  242. x = np.zeros(16, dtype=int)
  243. x[0] = 1
  244. x[8] = 1
  245. f, p = welch(x, nperseg=9)
  246. assert_allclose(f, np.arange(5.0)/9.0)
  247. q = np.array([0.12477455, 0.23430933, 0.17072113, 0.17072113,
  248. 0.17072113])
  249. assert_allclose(p, q, atol=1e-7, rtol=1e-7)
  250. def test_integer_twosided(self):
  251. x = np.zeros(16, dtype=int)
  252. x[0] = 1
  253. x[8] = 1
  254. f, p = welch(x, nperseg=8, return_onesided=False)
  255. assert_allclose(f, fftpack.fftfreq(8, 1.0))
  256. q = np.array([0.08333333, 0.07638889, 0.11111111, 0.11111111,
  257. 0.11111111, 0.11111111, 0.11111111, 0.07638889])
  258. assert_allclose(p, q, atol=1e-7, rtol=1e-7)
  259. def test_complex(self):
  260. x = np.zeros(16, np.complex128)
  261. x[0] = 1.0 + 2.0j
  262. x[8] = 1.0 + 2.0j
  263. f, p = welch(x, nperseg=8, return_onesided=False)
  264. assert_allclose(f, fftpack.fftfreq(8, 1.0))
  265. q = np.array([0.41666667, 0.38194444, 0.55555556, 0.55555556,
  266. 0.55555556, 0.55555556, 0.55555556, 0.38194444])
  267. assert_allclose(p, q, atol=1e-7, rtol=1e-7)
  268. def test_unk_scaling(self):
  269. assert_raises(ValueError, welch, np.zeros(4, np.complex128),
  270. scaling='foo', nperseg=4)
  271. def test_detrend_linear(self):
  272. x = np.arange(10, dtype=np.float64) + 0.04
  273. f, p = welch(x, nperseg=10, detrend='linear')
  274. assert_allclose(p, np.zeros_like(p), atol=1e-15)
  275. def test_no_detrending(self):
  276. x = np.arange(10, dtype=np.float64) + 0.04
  277. f1, p1 = welch(x, nperseg=10, detrend=False)
  278. f2, p2 = welch(x, nperseg=10, detrend=lambda x: x)
  279. assert_allclose(f1, f2, atol=1e-15)
  280. assert_allclose(p1, p2, atol=1e-15)
  281. def test_detrend_external(self):
  282. x = np.arange(10, dtype=np.float64) + 0.04
  283. f, p = welch(x, nperseg=10,
  284. detrend=lambda seg: signal.detrend(seg, type='l'))
  285. assert_allclose(p, np.zeros_like(p), atol=1e-15)
  286. def test_detrend_external_nd_m1(self):
  287. x = np.arange(40, dtype=np.float64) + 0.04
  288. x = x.reshape((2,2,10))
  289. f, p = welch(x, nperseg=10,
  290. detrend=lambda seg: signal.detrend(seg, type='l'))
  291. assert_allclose(p, np.zeros_like(p), atol=1e-15)
  292. def test_detrend_external_nd_0(self):
  293. x = np.arange(20, dtype=np.float64) + 0.04
  294. x = x.reshape((2,1,10))
  295. x = np.rollaxis(x, 2, 0)
  296. f, p = welch(x, nperseg=10, axis=0,
  297. detrend=lambda seg: signal.detrend(seg, axis=0, type='l'))
  298. assert_allclose(p, np.zeros_like(p), atol=1e-15)
  299. def test_nd_axis_m1(self):
  300. x = np.arange(20, dtype=np.float64) + 0.04
  301. x = x.reshape((2,1,10))
  302. f, p = welch(x, nperseg=10)
  303. assert_array_equal(p.shape, (2, 1, 6))
  304. assert_allclose(p[0,0,:], p[1,0,:], atol=1e-13, rtol=1e-13)
  305. f0, p0 = welch(x[0,0,:], nperseg=10)
  306. assert_allclose(p0[np.newaxis,:], p[1,:], atol=1e-13, rtol=1e-13)
  307. def test_nd_axis_0(self):
  308. x = np.arange(20, dtype=np.float64) + 0.04
  309. x = x.reshape((10,2,1))
  310. f, p = welch(x, nperseg=10, axis=0)
  311. assert_array_equal(p.shape, (6,2,1))
  312. assert_allclose(p[:,0,0], p[:,1,0], atol=1e-13, rtol=1e-13)
  313. f0, p0 = welch(x[:,0,0], nperseg=10)
  314. assert_allclose(p0, p[:,1,0], atol=1e-13, rtol=1e-13)
  315. def test_window_external(self):
  316. x = np.zeros(16)
  317. x[0] = 1
  318. x[8] = 1
  319. f, p = welch(x, 10, 'hann', nperseg=8)
  320. win = signal.get_window('hann', 8)
  321. fe, pe = welch(x, 10, win, nperseg=None)
  322. assert_array_almost_equal_nulp(p, pe)
  323. assert_array_almost_equal_nulp(f, fe)
  324. assert_array_equal(fe.shape, (5,)) # because win length used as nperseg
  325. assert_array_equal(pe.shape, (5,))
  326. assert_raises(ValueError, welch, x,
  327. 10, win, nperseg=4) # because nperseg != win.shape[-1]
  328. win_err = signal.get_window('hann', 32)
  329. assert_raises(ValueError, welch, x,
  330. 10, win_err, nperseg=None) # win longer than signal
  331. def test_empty_input(self):
  332. f, p = welch([])
  333. assert_array_equal(f.shape, (0,))
  334. assert_array_equal(p.shape, (0,))
  335. for shape in [(0,), (3,0), (0,5,2)]:
  336. f, p = welch(np.empty(shape))
  337. assert_array_equal(f.shape, shape)
  338. assert_array_equal(p.shape, shape)
  339. def test_empty_input_other_axis(self):
  340. for shape in [(3,0), (0,5,2)]:
  341. f, p = welch(np.empty(shape), axis=1)
  342. assert_array_equal(f.shape, shape)
  343. assert_array_equal(p.shape, shape)
  344. def test_short_data(self):
  345. x = np.zeros(8)
  346. x[0] = 1
  347. #for string-like window, input signal length < nperseg value gives
  348. #UserWarning, sets nperseg to x.shape[-1]
  349. with suppress_warnings() as sup:
  350. sup.filter(UserWarning, "nperseg = 256 is greater than input length = 8, using nperseg = 8")
  351. f, p = welch(x,window='hann') # default nperseg
  352. f1, p1 = welch(x,window='hann', nperseg=256) # user-specified nperseg
  353. f2, p2 = welch(x, nperseg=8) # valid nperseg, doesn't give warning
  354. assert_allclose(f, f2)
  355. assert_allclose(p, p2)
  356. assert_allclose(f1, f2)
  357. assert_allclose(p1, p2)
  358. def test_window_long_or_nd(self):
  359. assert_raises(ValueError, welch, np.zeros(4), 1, np.array([1,1,1,1,1]))
  360. assert_raises(ValueError, welch, np.zeros(4), 1,
  361. np.arange(6).reshape((2,3)))
  362. def test_nondefault_noverlap(self):
  363. x = np.zeros(64)
  364. x[::8] = 1
  365. f, p = welch(x, nperseg=16, noverlap=4)
  366. q = np.array([0, 1./12., 1./3., 1./5., 1./3., 1./5., 1./3., 1./5.,
  367. 1./6.])
  368. assert_allclose(p, q, atol=1e-12)
  369. def test_bad_noverlap(self):
  370. assert_raises(ValueError, welch, np.zeros(4), 1, 'hann', 2, 7)
  371. def test_nfft_too_short(self):
  372. assert_raises(ValueError, welch, np.ones(12), nfft=3, nperseg=4)
  373. def test_real_onesided_even_32(self):
  374. x = np.zeros(16, 'f')
  375. x[0] = 1
  376. x[8] = 1
  377. f, p = welch(x, nperseg=8)
  378. assert_allclose(f, np.linspace(0, 0.5, 5))
  379. q = np.array([0.08333333, 0.15277778, 0.22222222, 0.22222222,
  380. 0.11111111], 'f')
  381. assert_allclose(p, q, atol=1e-7, rtol=1e-7)
  382. assert_(p.dtype == q.dtype)
  383. def test_real_onesided_odd_32(self):
  384. x = np.zeros(16, 'f')
  385. x[0] = 1
  386. x[8] = 1
  387. f, p = welch(x, nperseg=9)
  388. assert_allclose(f, np.arange(5.0)/9.0)
  389. q = np.array([0.12477458, 0.23430935, 0.17072113, 0.17072116,
  390. 0.17072113], 'f')
  391. assert_allclose(p, q, atol=1e-7, rtol=1e-7)
  392. assert_(p.dtype == q.dtype)
  393. def test_real_twosided_32(self):
  394. x = np.zeros(16, 'f')
  395. x[0] = 1
  396. x[8] = 1
  397. f, p = welch(x, nperseg=8, return_onesided=False)
  398. assert_allclose(f, fftpack.fftfreq(8, 1.0))
  399. q = np.array([0.08333333, 0.07638889, 0.11111111,
  400. 0.11111111, 0.11111111, 0.11111111, 0.11111111,
  401. 0.07638889], 'f')
  402. assert_allclose(p, q, atol=1e-7, rtol=1e-7)
  403. assert_(p.dtype == q.dtype)
  404. def test_complex_32(self):
  405. x = np.zeros(16, 'F')
  406. x[0] = 1.0 + 2.0j
  407. x[8] = 1.0 + 2.0j
  408. f, p = welch(x, nperseg=8, return_onesided=False)
  409. assert_allclose(f, fftpack.fftfreq(8, 1.0))
  410. q = np.array([0.41666666, 0.38194442, 0.55555552, 0.55555552,
  411. 0.55555558, 0.55555552, 0.55555552, 0.38194442], 'f')
  412. assert_allclose(p, q, atol=1e-7, rtol=1e-7)
  413. assert_(p.dtype == q.dtype,
  414. 'dtype mismatch, %s, %s' % (p.dtype, q.dtype))
  415. def test_padded_freqs(self):
  416. x = np.zeros(12)
  417. nfft = 24
  418. f = fftpack.fftfreq(nfft, 1.0)[:nfft//2+1]
  419. f[-1] *= -1
  420. fodd, _ = welch(x, nperseg=5, nfft=nfft)
  421. feven, _ = welch(x, nperseg=6, nfft=nfft)
  422. assert_allclose(f, fodd)
  423. assert_allclose(f, feven)
  424. nfft = 25
  425. f = fftpack.fftfreq(nfft, 1.0)[:(nfft + 1)//2]
  426. fodd, _ = welch(x, nperseg=5, nfft=nfft)
  427. feven, _ = welch(x, nperseg=6, nfft=nfft)
  428. assert_allclose(f, fodd)
  429. assert_allclose(f, feven)
  430. def test_window_correction(self):
  431. A = 20
  432. fs = 1e4
  433. nperseg = int(fs//10)
  434. fsig = 300
  435. ii = int(fsig*nperseg//fs) # Freq index of fsig
  436. tt = np.arange(fs)/fs
  437. x = A*np.sin(2*np.pi*fsig*tt)
  438. for window in ['hann', 'bartlett', ('tukey', 0.1), 'flattop']:
  439. _, p_spec = welch(x, fs=fs, nperseg=nperseg, window=window,
  440. scaling='spectrum')
  441. freq, p_dens = welch(x, fs=fs, nperseg=nperseg, window=window,
  442. scaling='density')
  443. # Check peak height at signal frequency for 'spectrum'
  444. assert_allclose(p_spec[ii], A**2/2.0)
  445. # Check integrated spectrum RMS for 'density'
  446. assert_allclose(np.sqrt(np.trapz(p_dens, freq)), A*np.sqrt(2)/2,
  447. rtol=1e-3)
  448. def test_axis_rolling(self):
  449. np.random.seed(1234)
  450. x_flat = np.random.randn(1024)
  451. _, p_flat = welch(x_flat)
  452. for a in range(3):
  453. newshape = [1,]*3
  454. newshape[a] = -1
  455. x = x_flat.reshape(newshape)
  456. _, p_plus = welch(x, axis=a) # Positive axis index
  457. _, p_minus = welch(x, axis=a-x.ndim) # Negative axis index
  458. assert_equal(p_flat, p_plus.squeeze(), err_msg=a)
  459. assert_equal(p_flat, p_minus.squeeze(), err_msg=a-x.ndim)
  460. def test_average(self):
  461. x = np.zeros(16)
  462. x[0] = 1
  463. x[8] = 1
  464. f, p = welch(x, nperseg=8, average='median')
  465. assert_allclose(f, np.linspace(0, 0.5, 5))
  466. q = np.array([.1, .05, 0., 1.54074396e-33, 0.])
  467. assert_allclose(p, q, atol=1e-7, rtol=1e-7)
  468. assert_raises(ValueError, welch, x, nperseg=8,
  469. average='unrecognised-average')
  470. class TestCSD:
  471. def test_pad_shorter_x(self):
  472. x = np.zeros(8)
  473. y = np.zeros(12)
  474. f = np.linspace(0, 0.5, 7)
  475. c = np.zeros(7,dtype=np.complex128)
  476. f1, c1 = csd(x, y, nperseg=12)
  477. assert_allclose(f, f1)
  478. assert_allclose(c, c1)
  479. def test_pad_shorter_y(self):
  480. x = np.zeros(12)
  481. y = np.zeros(8)
  482. f = np.linspace(0, 0.5, 7)
  483. c = np.zeros(7,dtype=np.complex128)
  484. f1, c1 = csd(x, y, nperseg=12)
  485. assert_allclose(f, f1)
  486. assert_allclose(c, c1)
  487. def test_real_onesided_even(self):
  488. x = np.zeros(16)
  489. x[0] = 1
  490. x[8] = 1
  491. f, p = csd(x, x, nperseg=8)
  492. assert_allclose(f, np.linspace(0, 0.5, 5))
  493. q = np.array([0.08333333, 0.15277778, 0.22222222, 0.22222222,
  494. 0.11111111])
  495. assert_allclose(p, q, atol=1e-7, rtol=1e-7)
  496. def test_real_onesided_odd(self):
  497. x = np.zeros(16)
  498. x[0] = 1
  499. x[8] = 1
  500. f, p = csd(x, x, nperseg=9)
  501. assert_allclose(f, np.arange(5.0)/9.0)
  502. q = np.array([0.12477455, 0.23430933, 0.17072113, 0.17072113,
  503. 0.17072113])
  504. assert_allclose(p, q, atol=1e-7, rtol=1e-7)
  505. def test_real_twosided(self):
  506. x = np.zeros(16)
  507. x[0] = 1
  508. x[8] = 1
  509. f, p = csd(x, x, nperseg=8, return_onesided=False)
  510. assert_allclose(f, fftpack.fftfreq(8, 1.0))
  511. q = np.array([0.08333333, 0.07638889, 0.11111111, 0.11111111,
  512. 0.11111111, 0.11111111, 0.11111111, 0.07638889])
  513. assert_allclose(p, q, atol=1e-7, rtol=1e-7)
  514. def test_real_spectrum(self):
  515. x = np.zeros(16)
  516. x[0] = 1
  517. x[8] = 1
  518. f, p = csd(x, x, nperseg=8, scaling='spectrum')
  519. assert_allclose(f, np.linspace(0, 0.5, 5))
  520. q = np.array([0.015625, 0.02864583, 0.04166667, 0.04166667,
  521. 0.02083333])
  522. assert_allclose(p, q, atol=1e-7, rtol=1e-7)
  523. def test_integer_onesided_even(self):
  524. x = np.zeros(16, dtype=int)
  525. x[0] = 1
  526. x[8] = 1
  527. f, p = csd(x, x, nperseg=8)
  528. assert_allclose(f, np.linspace(0, 0.5, 5))
  529. q = np.array([0.08333333, 0.15277778, 0.22222222, 0.22222222,
  530. 0.11111111])
  531. assert_allclose(p, q, atol=1e-7, rtol=1e-7)
  532. def test_integer_onesided_odd(self):
  533. x = np.zeros(16, dtype=int)
  534. x[0] = 1
  535. x[8] = 1
  536. f, p = csd(x, x, nperseg=9)
  537. assert_allclose(f, np.arange(5.0)/9.0)
  538. q = np.array([0.12477455, 0.23430933, 0.17072113, 0.17072113,
  539. 0.17072113])
  540. assert_allclose(p, q, atol=1e-7, rtol=1e-7)
  541. def test_integer_twosided(self):
  542. x = np.zeros(16, dtype=int)
  543. x[0] = 1
  544. x[8] = 1
  545. f, p = csd(x, x, nperseg=8, return_onesided=False)
  546. assert_allclose(f, fftpack.fftfreq(8, 1.0))
  547. q = np.array([0.08333333, 0.07638889, 0.11111111, 0.11111111,
  548. 0.11111111, 0.11111111, 0.11111111, 0.07638889])
  549. assert_allclose(p, q, atol=1e-7, rtol=1e-7)
  550. def test_complex(self):
  551. x = np.zeros(16, np.complex128)
  552. x[0] = 1.0 + 2.0j
  553. x[8] = 1.0 + 2.0j
  554. f, p = csd(x, x, nperseg=8, return_onesided=False)
  555. assert_allclose(f, fftpack.fftfreq(8, 1.0))
  556. q = np.array([0.41666667, 0.38194444, 0.55555556, 0.55555556,
  557. 0.55555556, 0.55555556, 0.55555556, 0.38194444])
  558. assert_allclose(p, q, atol=1e-7, rtol=1e-7)
  559. def test_unk_scaling(self):
  560. assert_raises(ValueError, csd, np.zeros(4, np.complex128),
  561. np.ones(4, np.complex128), scaling='foo', nperseg=4)
  562. def test_detrend_linear(self):
  563. x = np.arange(10, dtype=np.float64) + 0.04
  564. f, p = csd(x, x, nperseg=10, detrend='linear')
  565. assert_allclose(p, np.zeros_like(p), atol=1e-15)
  566. def test_no_detrending(self):
  567. x = np.arange(10, dtype=np.float64) + 0.04
  568. f1, p1 = csd(x, x, nperseg=10, detrend=False)
  569. f2, p2 = csd(x, x, nperseg=10, detrend=lambda x: x)
  570. assert_allclose(f1, f2, atol=1e-15)
  571. assert_allclose(p1, p2, atol=1e-15)
  572. def test_detrend_external(self):
  573. x = np.arange(10, dtype=np.float64) + 0.04
  574. f, p = csd(x, x, nperseg=10,
  575. detrend=lambda seg: signal.detrend(seg, type='l'))
  576. assert_allclose(p, np.zeros_like(p), atol=1e-15)
  577. def test_detrend_external_nd_m1(self):
  578. x = np.arange(40, dtype=np.float64) + 0.04
  579. x = x.reshape((2,2,10))
  580. f, p = csd(x, x, nperseg=10,
  581. detrend=lambda seg: signal.detrend(seg, type='l'))
  582. assert_allclose(p, np.zeros_like(p), atol=1e-15)
  583. def test_detrend_external_nd_0(self):
  584. x = np.arange(20, dtype=np.float64) + 0.04
  585. x = x.reshape((2,1,10))
  586. x = np.rollaxis(x, 2, 0)
  587. f, p = csd(x, x, nperseg=10, axis=0,
  588. detrend=lambda seg: signal.detrend(seg, axis=0, type='l'))
  589. assert_allclose(p, np.zeros_like(p), atol=1e-15)
  590. def test_nd_axis_m1(self):
  591. x = np.arange(20, dtype=np.float64) + 0.04
  592. x = x.reshape((2,1,10))
  593. f, p = csd(x, x, nperseg=10)
  594. assert_array_equal(p.shape, (2, 1, 6))
  595. assert_allclose(p[0,0,:], p[1,0,:], atol=1e-13, rtol=1e-13)
  596. f0, p0 = csd(x[0,0,:], x[0,0,:], nperseg=10)
  597. assert_allclose(p0[np.newaxis,:], p[1,:], atol=1e-13, rtol=1e-13)
  598. def test_nd_axis_0(self):
  599. x = np.arange(20, dtype=np.float64) + 0.04
  600. x = x.reshape((10,2,1))
  601. f, p = csd(x, x, nperseg=10, axis=0)
  602. assert_array_equal(p.shape, (6,2,1))
  603. assert_allclose(p[:,0,0], p[:,1,0], atol=1e-13, rtol=1e-13)
  604. f0, p0 = csd(x[:,0,0], x[:,0,0], nperseg=10)
  605. assert_allclose(p0, p[:,1,0], atol=1e-13, rtol=1e-13)
  606. def test_window_external(self):
  607. x = np.zeros(16)
  608. x[0] = 1
  609. x[8] = 1
  610. f, p = csd(x, x, 10, 'hann', 8)
  611. win = signal.get_window('hann', 8)
  612. fe, pe = csd(x, x, 10, win, nperseg=None)
  613. assert_array_almost_equal_nulp(p, pe)
  614. assert_array_almost_equal_nulp(f, fe)
  615. assert_array_equal(fe.shape, (5,)) # because win length used as nperseg
  616. assert_array_equal(pe.shape, (5,))
  617. assert_raises(ValueError, csd, x, x,
  618. 10, win, nperseg=256) # because nperseg != win.shape[-1]
  619. win_err = signal.get_window('hann', 32)
  620. assert_raises(ValueError, csd, x, x,
  621. 10, win_err, nperseg=None) # because win longer than signal
  622. def test_empty_input(self):
  623. f, p = csd([],np.zeros(10))
  624. assert_array_equal(f.shape, (0,))
  625. assert_array_equal(p.shape, (0,))
  626. f, p = csd(np.zeros(10),[])
  627. assert_array_equal(f.shape, (0,))
  628. assert_array_equal(p.shape, (0,))
  629. for shape in [(0,), (3,0), (0,5,2)]:
  630. f, p = csd(np.empty(shape), np.empty(shape))
  631. assert_array_equal(f.shape, shape)
  632. assert_array_equal(p.shape, shape)
  633. f, p = csd(np.ones(10), np.empty((5,0)))
  634. assert_array_equal(f.shape, (5,0))
  635. assert_array_equal(p.shape, (5,0))
  636. f, p = csd(np.empty((5,0)), np.ones(10))
  637. assert_array_equal(f.shape, (5,0))
  638. assert_array_equal(p.shape, (5,0))
  639. def test_empty_input_other_axis(self):
  640. for shape in [(3,0), (0,5,2)]:
  641. f, p = csd(np.empty(shape), np.empty(shape), axis=1)
  642. assert_array_equal(f.shape, shape)
  643. assert_array_equal(p.shape, shape)
  644. f, p = csd(np.empty((10,10,3)), np.zeros((10,0,1)), axis=1)
  645. assert_array_equal(f.shape, (10,0,3))
  646. assert_array_equal(p.shape, (10,0,3))
  647. f, p = csd(np.empty((10,0,1)), np.zeros((10,10,3)), axis=1)
  648. assert_array_equal(f.shape, (10,0,3))
  649. assert_array_equal(p.shape, (10,0,3))
  650. def test_short_data(self):
  651. x = np.zeros(8)
  652. x[0] = 1
  653. #for string-like window, input signal length < nperseg value gives
  654. #UserWarning, sets nperseg to x.shape[-1]
  655. with suppress_warnings() as sup:
  656. sup.filter(UserWarning, "nperseg = 256 is greater than input length = 8, using nperseg = 8")
  657. f, p = csd(x, x, window='hann') # default nperseg
  658. f1, p1 = csd(x, x, window='hann', nperseg=256) # user-specified nperseg
  659. f2, p2 = csd(x, x, nperseg=8) # valid nperseg, doesn't give warning
  660. assert_allclose(f, f2)
  661. assert_allclose(p, p2)
  662. assert_allclose(f1, f2)
  663. assert_allclose(p1, p2)
  664. def test_window_long_or_nd(self):
  665. assert_raises(ValueError, csd, np.zeros(4), np.ones(4), 1,
  666. np.array([1,1,1,1,1]))
  667. assert_raises(ValueError, csd, np.zeros(4), np.ones(4), 1,
  668. np.arange(6).reshape((2,3)))
  669. def test_nondefault_noverlap(self):
  670. x = np.zeros(64)
  671. x[::8] = 1
  672. f, p = csd(x, x, nperseg=16, noverlap=4)
  673. q = np.array([0, 1./12., 1./3., 1./5., 1./3., 1./5., 1./3., 1./5.,
  674. 1./6.])
  675. assert_allclose(p, q, atol=1e-12)
  676. def test_bad_noverlap(self):
  677. assert_raises(ValueError, csd, np.zeros(4), np.ones(4), 1, 'hann',
  678. 2, 7)
  679. def test_nfft_too_short(self):
  680. assert_raises(ValueError, csd, np.ones(12), np.zeros(12), nfft=3,
  681. nperseg=4)
  682. def test_real_onesided_even_32(self):
  683. x = np.zeros(16, 'f')
  684. x[0] = 1
  685. x[8] = 1
  686. f, p = csd(x, x, nperseg=8)
  687. assert_allclose(f, np.linspace(0, 0.5, 5))
  688. q = np.array([0.08333333, 0.15277778, 0.22222222, 0.22222222,
  689. 0.11111111], 'f')
  690. assert_allclose(p, q, atol=1e-7, rtol=1e-7)
  691. assert_(p.dtype == q.dtype)
  692. def test_real_onesided_odd_32(self):
  693. x = np.zeros(16, 'f')
  694. x[0] = 1
  695. x[8] = 1
  696. f, p = csd(x, x, nperseg=9)
  697. assert_allclose(f, np.arange(5.0)/9.0)
  698. q = np.array([0.12477458, 0.23430935, 0.17072113, 0.17072116,
  699. 0.17072113], 'f')
  700. assert_allclose(p, q, atol=1e-7, rtol=1e-7)
  701. assert_(p.dtype == q.dtype)
  702. def test_real_twosided_32(self):
  703. x = np.zeros(16, 'f')
  704. x[0] = 1
  705. x[8] = 1
  706. f, p = csd(x, x, nperseg=8, return_onesided=False)
  707. assert_allclose(f, fftpack.fftfreq(8, 1.0))
  708. q = np.array([0.08333333, 0.07638889, 0.11111111,
  709. 0.11111111, 0.11111111, 0.11111111, 0.11111111,
  710. 0.07638889], 'f')
  711. assert_allclose(p, q, atol=1e-7, rtol=1e-7)
  712. assert_(p.dtype == q.dtype)
  713. def test_complex_32(self):
  714. x = np.zeros(16, 'F')
  715. x[0] = 1.0 + 2.0j
  716. x[8] = 1.0 + 2.0j
  717. f, p = csd(x, x, nperseg=8, return_onesided=False)
  718. assert_allclose(f, fftpack.fftfreq(8, 1.0))
  719. q = np.array([0.41666666, 0.38194442, 0.55555552, 0.55555552,
  720. 0.55555558, 0.55555552, 0.55555552, 0.38194442], 'f')
  721. assert_allclose(p, q, atol=1e-7, rtol=1e-7)
  722. assert_(p.dtype == q.dtype,
  723. 'dtype mismatch, %s, %s' % (p.dtype, q.dtype))
  724. def test_padded_freqs(self):
  725. x = np.zeros(12)
  726. y = np.ones(12)
  727. nfft = 24
  728. f = fftpack.fftfreq(nfft, 1.0)[:nfft//2+1]
  729. f[-1] *= -1
  730. fodd, _ = csd(x, y, nperseg=5, nfft=nfft)
  731. feven, _ = csd(x, y, nperseg=6, nfft=nfft)
  732. assert_allclose(f, fodd)
  733. assert_allclose(f, feven)
  734. nfft = 25
  735. f = fftpack.fftfreq(nfft, 1.0)[:(nfft + 1)//2]
  736. fodd, _ = csd(x, y, nperseg=5, nfft=nfft)
  737. feven, _ = csd(x, y, nperseg=6, nfft=nfft)
  738. assert_allclose(f, fodd)
  739. assert_allclose(f, feven)
  740. class TestCoherence(object):
  741. def test_identical_input(self):
  742. x = np.random.randn(20)
  743. y = np.copy(x) # So `y is x` -> False
  744. f = np.linspace(0, 0.5, 6)
  745. C = np.ones(6)
  746. f1, C1 = coherence(x, y, nperseg=10)
  747. assert_allclose(f, f1)
  748. assert_allclose(C, C1)
  749. def test_phase_shifted_input(self):
  750. x = np.random.randn(20)
  751. y = -x
  752. f = np.linspace(0, 0.5, 6)
  753. C = np.ones(6)
  754. f1, C1 = coherence(x, y, nperseg=10)
  755. assert_allclose(f, f1)
  756. assert_allclose(C, C1)
  757. class TestSpectrogram(object):
  758. def test_average_all_segments(self):
  759. x = np.random.randn(1024)
  760. fs = 1.0
  761. window = ('tukey', 0.25)
  762. nperseg = 16
  763. noverlap = 2
  764. f, _, P = spectrogram(x, fs, window, nperseg, noverlap)
  765. fw, Pw = welch(x, fs, window, nperseg, noverlap)
  766. assert_allclose(f, fw)
  767. assert_allclose(np.mean(P, axis=-1), Pw)
  768. def test_window_external(self):
  769. x = np.random.randn(1024)
  770. fs = 1.0
  771. window = ('tukey', 0.25)
  772. nperseg = 16
  773. noverlap = 2
  774. f, _, P = spectrogram(x, fs, window, nperseg, noverlap)
  775. win = signal.get_window(('tukey', 0.25), 16)
  776. fe, _, Pe = spectrogram(x, fs, win, nperseg=None, noverlap=2)
  777. assert_array_equal(fe.shape, (9,)) # because win length used as nperseg
  778. assert_array_equal(Pe.shape, (9,73))
  779. assert_raises(ValueError, spectrogram, x,
  780. fs, win, nperseg=8) # because nperseg != win.shape[-1]
  781. win_err = signal.get_window(('tukey', 0.25), 2048)
  782. assert_raises(ValueError, spectrogram, x,
  783. fs, win_err, nperseg=None) # win longer than signal
  784. def test_short_data(self):
  785. x = np.random.randn(1024)
  786. fs = 1.0
  787. #for string-like window, input signal length < nperseg value gives
  788. #UserWarning, sets nperseg to x.shape[-1]
  789. f, _, p = spectrogram(x, fs, window=('tukey',0.25)) # default nperseg
  790. with suppress_warnings() as sup:
  791. sup.filter(UserWarning,
  792. "nperseg = 1025 is greater than input length = 1024, using nperseg = 1024")
  793. f1, _, p1 = spectrogram(x, fs, window=('tukey',0.25),
  794. nperseg=1025) # user-specified nperseg
  795. f2, _, p2 = spectrogram(x, fs, nperseg=256) # to compare w/default
  796. f3, _, p3 = spectrogram(x, fs, nperseg=1024) # compare w/user-spec'd
  797. assert_allclose(f, f2)
  798. assert_allclose(p, p2)
  799. assert_allclose(f1, f3)
  800. assert_allclose(p1, p3)
  801. class TestLombscargle(object):
  802. def test_frequency(self):
  803. """Test if frequency location of peak corresponds to frequency of
  804. generated input signal.
  805. """
  806. # Input parameters
  807. ampl = 2.
  808. w = 1.
  809. phi = 0.5 * np.pi
  810. nin = 100
  811. nout = 1000
  812. p = 0.7 # Fraction of points to select
  813. # Randomly select a fraction of an array with timesteps
  814. np.random.seed(2353425)
  815. r = np.random.rand(nin)
  816. t = np.linspace(0.01*np.pi, 10.*np.pi, nin)[r >= p]
  817. # Plot a sine wave for the selected times
  818. x = ampl * np.sin(w*t + phi)
  819. # Define the array of frequencies for which to compute the periodogram
  820. f = np.linspace(0.01, 10., nout)
  821. # Calculate Lomb-Scargle periodogram
  822. P = lombscargle(t, x, f)
  823. # Check if difference between found frequency maximum and input
  824. # frequency is less than accuracy
  825. delta = f[1] - f[0]
  826. assert_(w - f[np.argmax(P)] < (delta/2.))
  827. def test_amplitude(self):
  828. # Test if height of peak in normalized Lomb-Scargle periodogram
  829. # corresponds to amplitude of the generated input signal.
  830. # Input parameters
  831. ampl = 2.
  832. w = 1.
  833. phi = 0.5 * np.pi
  834. nin = 100
  835. nout = 1000
  836. p = 0.7 # Fraction of points to select
  837. # Randomly select a fraction of an array with timesteps
  838. np.random.seed(2353425)
  839. r = np.random.rand(nin)
  840. t = np.linspace(0.01*np.pi, 10.*np.pi, nin)[r >= p]
  841. # Plot a sine wave for the selected times
  842. x = ampl * np.sin(w*t + phi)
  843. # Define the array of frequencies for which to compute the periodogram
  844. f = np.linspace(0.01, 10., nout)
  845. # Calculate Lomb-Scargle periodogram
  846. pgram = lombscargle(t, x, f)
  847. # Normalize
  848. pgram = np.sqrt(4 * pgram / t.shape[0])
  849. # Check if difference between found frequency maximum and input
  850. # frequency is less than accuracy
  851. assert_approx_equal(np.max(pgram), ampl, significant=2)
  852. def test_precenter(self):
  853. # Test if precenter gives the same result as manually precentering.
  854. # Input parameters
  855. ampl = 2.
  856. w = 1.
  857. phi = 0.5 * np.pi
  858. nin = 100
  859. nout = 1000
  860. p = 0.7 # Fraction of points to select
  861. offset = 0.15 # Offset to be subtracted in pre-centering
  862. # Randomly select a fraction of an array with timesteps
  863. np.random.seed(2353425)
  864. r = np.random.rand(nin)
  865. t = np.linspace(0.01*np.pi, 10.*np.pi, nin)[r >= p]
  866. # Plot a sine wave for the selected times
  867. x = ampl * np.sin(w*t + phi) + offset
  868. # Define the array of frequencies for which to compute the periodogram
  869. f = np.linspace(0.01, 10., nout)
  870. # Calculate Lomb-Scargle periodogram
  871. pgram = lombscargle(t, x, f, precenter=True)
  872. pgram2 = lombscargle(t, x - x.mean(), f, precenter=False)
  873. # check if centering worked
  874. assert_allclose(pgram, pgram2)
  875. def test_normalize(self):
  876. # Test normalize option of Lomb-Scarge.
  877. # Input parameters
  878. ampl = 2.
  879. w = 1.
  880. phi = 0.5 * np.pi
  881. nin = 100
  882. nout = 1000
  883. p = 0.7 # Fraction of points to select
  884. # Randomly select a fraction of an array with timesteps
  885. np.random.seed(2353425)
  886. r = np.random.rand(nin)
  887. t = np.linspace(0.01*np.pi, 10.*np.pi, nin)[r >= p]
  888. # Plot a sine wave for the selected times
  889. x = ampl * np.sin(w*t + phi)
  890. # Define the array of frequencies for which to compute the periodogram
  891. f = np.linspace(0.01, 10., nout)
  892. # Calculate Lomb-Scargle periodogram
  893. pgram = lombscargle(t, x, f)
  894. pgram2 = lombscargle(t, x, f, normalize=True)
  895. # check if normalization works as expected
  896. assert_allclose(pgram * 2 / np.dot(x, x), pgram2)
  897. assert_approx_equal(np.max(pgram2), 1.0, significant=2)
  898. def test_wrong_shape(self):
  899. t = np.linspace(0, 1, 1)
  900. x = np.linspace(0, 1, 2)
  901. f = np.linspace(0, 1, 3)
  902. assert_raises(ValueError, lombscargle, t, x, f)
  903. def test_zero_division(self):
  904. t = np.zeros(1)
  905. x = np.zeros(1)
  906. f = np.zeros(1)
  907. assert_raises(ZeroDivisionError, lombscargle, t, x, f)
  908. def test_lombscargle_atan_vs_atan2(self):
  909. # https://github.com/scipy/scipy/issues/3787
  910. # This raised a ZeroDivisionError.
  911. t = np.linspace(0, 10, 1000, endpoint=False)
  912. x = np.sin(4*t)
  913. f = np.linspace(0, 50, 500, endpoint=False) + 0.1
  914. q = lombscargle(t, x, f*2*np.pi)
  915. class TestSTFT(object):
  916. def test_input_validation(self):
  917. assert_raises(ValueError, check_COLA, 'hann', -10, 0)
  918. assert_raises(ValueError, check_COLA, 'hann', 10, 20)
  919. assert_raises(ValueError, check_COLA, np.ones((2,2)), 10, 0)
  920. assert_raises(ValueError, check_COLA, np.ones(20), 10, 0)
  921. assert_raises(ValueError, check_NOLA, 'hann', -10, 0)
  922. assert_raises(ValueError, check_NOLA, 'hann', 10, 20)
  923. assert_raises(ValueError, check_NOLA, np.ones((2,2)), 10, 0)
  924. assert_raises(ValueError, check_NOLA, np.ones(20), 10, 0)
  925. assert_raises(ValueError, check_NOLA, 'hann', 64, -32)
  926. x = np.empty(1024)
  927. z = stft(x)
  928. assert_raises(ValueError, stft, x, window=np.ones((2,2)))
  929. assert_raises(ValueError, stft, x, window=np.ones(10), nperseg=256)
  930. assert_raises(ValueError, stft, x, nperseg=-256)
  931. assert_raises(ValueError, stft, x, nperseg=256, noverlap=1024)
  932. assert_raises(ValueError, stft, x, nperseg=256, nfft=8)
  933. assert_raises(ValueError, istft, x) # Not 2d
  934. assert_raises(ValueError, istft, z, window=np.ones((2,2)))
  935. assert_raises(ValueError, istft, z, window=np.ones(10), nperseg=256)
  936. assert_raises(ValueError, istft, z, nperseg=-256)
  937. assert_raises(ValueError, istft, z, nperseg=256, noverlap=1024)
  938. assert_raises(ValueError, istft, z, nperseg=256, nfft=8)
  939. assert_raises(ValueError, istft, z, nperseg=256, noverlap=0,
  940. window='hann') # Doesn't meet COLA
  941. assert_raises(ValueError, istft, z, time_axis=0, freq_axis=0)
  942. assert_raises(ValueError, _spectral_helper, x, x, mode='foo')
  943. assert_raises(ValueError, _spectral_helper, x[:512], x[512:],
  944. mode='stft')
  945. assert_raises(ValueError, _spectral_helper, x, x, boundary='foo')
  946. def test_check_COLA(self):
  947. settings = [
  948. ('boxcar', 10, 0),
  949. ('boxcar', 10, 9),
  950. ('bartlett', 51, 26),
  951. ('hann', 256, 128),
  952. ('hann', 256, 192),
  953. ('blackman', 300, 200),
  954. (('tukey', 0.5), 256, 64),
  955. ('hann', 256, 255),
  956. ]
  957. for setting in settings:
  958. msg = '{0}, {1}, {2}'.format(*setting)
  959. assert_equal(True, check_COLA(*setting), err_msg=msg)
  960. def test_check_NOLA(self):
  961. settings_pass = [
  962. ('boxcar', 10, 0),
  963. ('boxcar', 10, 9),
  964. ('boxcar', 10, 7),
  965. ('bartlett', 51, 26),
  966. ('bartlett', 51, 10),
  967. ('hann', 256, 128),
  968. ('hann', 256, 192),
  969. ('hann', 256, 37),
  970. ('blackman', 300, 200),
  971. ('blackman', 300, 123),
  972. (('tukey', 0.5), 256, 64),
  973. (('tukey', 0.5), 256, 38),
  974. ('hann', 256, 255),
  975. ('hann', 256, 39),
  976. ]
  977. for setting in settings_pass:
  978. msg = '{0}, {1}, {2}'.format(*setting)
  979. assert_equal(True, check_NOLA(*setting), err_msg=msg)
  980. w_fail = np.ones(16)
  981. w_fail[::2] = 0
  982. settings_fail = [
  983. (w_fail, len(w_fail), len(w_fail) // 2),
  984. ('hann', 64, 0),
  985. ]
  986. for setting in settings_fail:
  987. msg = '{0}, {1}, {2}'.format(*setting)
  988. assert_equal(False, check_NOLA(*setting), err_msg=msg)
  989. def test_average_all_segments(self):
  990. np.random.seed(1234)
  991. x = np.random.randn(1024)
  992. fs = 1.0
  993. window = 'hann'
  994. nperseg = 16
  995. noverlap = 8
  996. # Compare twosided, because onesided welch doubles non-DC terms to
  997. # account for power at negative frequencies. stft doesn't do this,
  998. # because it breaks invertibility.
  999. f, _, Z = stft(x, fs, window, nperseg, noverlap, padded=False,
  1000. return_onesided=False, boundary=None)
  1001. fw, Pw = welch(x, fs, window, nperseg, noverlap, return_onesided=False,
  1002. scaling='spectrum', detrend=False)
  1003. assert_allclose(f, fw)
  1004. assert_allclose(np.mean(np.abs(Z)**2, axis=-1), Pw)
  1005. def test_permute_axes(self):
  1006. np.random.seed(1234)
  1007. x = np.random.randn(1024)
  1008. fs = 1.0
  1009. window = 'hann'
  1010. nperseg = 16
  1011. noverlap = 8
  1012. f1, t1, Z1 = stft(x, fs, window, nperseg, noverlap)
  1013. f2, t2, Z2 = stft(x.reshape((-1, 1, 1)), fs, window, nperseg, noverlap,
  1014. axis=0)
  1015. t3, x1 = istft(Z1, fs, window, nperseg, noverlap)
  1016. t4, x2 = istft(Z2.T, fs, window, nperseg, noverlap, time_axis=0,
  1017. freq_axis=-1)
  1018. assert_allclose(f1, f2)
  1019. assert_allclose(t1, t2)
  1020. assert_allclose(t3, t4)
  1021. assert_allclose(Z1, Z2[:, 0, 0, :])
  1022. assert_allclose(x1, x2[:, 0, 0])
  1023. def test_roundtrip_real(self):
  1024. np.random.seed(1234)
  1025. settings = [
  1026. ('boxcar', 100, 10, 0), # Test no overlap
  1027. ('boxcar', 100, 10, 9), # Test high overlap
  1028. ('bartlett', 101, 51, 26), # Test odd nperseg
  1029. ('hann', 1024, 256, 128), # Test defaults
  1030. (('tukey', 0.5), 1152, 256, 64), # Test Tukey
  1031. ('hann', 1024, 256, 255), # Test overlapped hann
  1032. ]
  1033. for window, N, nperseg, noverlap in settings:
  1034. t = np.arange(N)
  1035. x = 10*np.random.randn(t.size)
  1036. _, _, zz = stft(x, nperseg=nperseg, noverlap=noverlap,
  1037. window=window, detrend=None, padded=False)
  1038. tr, xr = istft(zz, nperseg=nperseg, noverlap=noverlap,
  1039. window=window)
  1040. msg = '{0}, {1}'.format(window, noverlap)
  1041. assert_allclose(t, tr, err_msg=msg)
  1042. assert_allclose(x, xr, err_msg=msg)
  1043. def test_roundtrip_not_nola(self):
  1044. np.random.seed(1234)
  1045. w_fail = np.ones(16)
  1046. w_fail[::2] = 0
  1047. settings = [
  1048. (w_fail, 256, len(w_fail), len(w_fail) // 2),
  1049. ('hann', 256, 64, 0),
  1050. ]
  1051. for window, N, nperseg, noverlap in settings:
  1052. msg = '{0}, {1}, {2}, {3}'.format(window, N, nperseg, noverlap)
  1053. assert not check_NOLA(window, nperseg, noverlap), msg
  1054. t = np.arange(N)
  1055. x = 10 * np.random.randn(t.size)
  1056. _, _, zz = stft(x, nperseg=nperseg, noverlap=noverlap,
  1057. window=window, detrend=None, padded=True,
  1058. boundary='zeros')
  1059. with pytest.warns(UserWarning, match='NOLA'):
  1060. tr, xr = istft(zz, nperseg=nperseg, noverlap=noverlap,
  1061. window=window, boundary=True)
  1062. assert np.allclose(t, tr[:len(t)]), msg
  1063. assert not np.allclose(x, xr[:len(x)]), msg
  1064. def test_roundtrip_nola_not_cola(self):
  1065. np.random.seed(1234)
  1066. settings = [
  1067. ('boxcar', 100, 10, 3), # NOLA True, COLA False
  1068. ('bartlett', 101, 51, 37), # NOLA True, COLA False
  1069. ('hann', 1024, 256, 127), # NOLA True, COLA False
  1070. (('tukey', 0.5), 1152, 256, 14), # NOLA True, COLA False
  1071. ('hann', 1024, 256, 5), # NOLA True, COLA False
  1072. ]
  1073. for window, N, nperseg, noverlap in settings:
  1074. msg = '{0}, {1}, {2}'.format(window, nperseg, noverlap)
  1075. assert check_NOLA(window, nperseg, noverlap), msg
  1076. assert not check_COLA(window, nperseg, noverlap), msg
  1077. t = np.arange(N)
  1078. x = 10 * np.random.randn(t.size)
  1079. _, _, zz = stft(x, nperseg=nperseg, noverlap=noverlap,
  1080. window=window, detrend=None, padded=True,
  1081. boundary='zeros')
  1082. tr, xr = istft(zz, nperseg=nperseg, noverlap=noverlap,
  1083. window=window, boundary=True)
  1084. msg = '{0}, {1}'.format(window, noverlap)
  1085. assert_allclose(t, tr[:len(t)], err_msg=msg)
  1086. assert_allclose(x, xr[:len(x)], err_msg=msg)
  1087. @pytest.mark.xfail(reason="Needs complex rfft from fftpack, see gh-2487 + gh-6058")
  1088. def test_roundtrip_float32(self):
  1089. np.random.seed(1234)
  1090. settings = [('hann', 1024, 256, 128)]
  1091. for window, N, nperseg, noverlap in settings:
  1092. t = np.arange(N)
  1093. x = 10*np.random.randn(t.size)
  1094. x = x.astype(np.float32)
  1095. _, _, zz = stft(x, nperseg=nperseg, noverlap=noverlap,
  1096. window=window, detrend=None, padded=False)
  1097. tr, xr = istft(zz, nperseg=nperseg, noverlap=noverlap,
  1098. window=window)
  1099. msg = '{0}, {1}'.format(window, noverlap)
  1100. assert_allclose(t, t, err_msg=msg)
  1101. assert_allclose(x, xr, err_msg=msg, rtol=1e-4)
  1102. assert_(x.dtype == xr.dtype)
  1103. def test_roundtrip_complex(self):
  1104. np.random.seed(1234)
  1105. settings = [
  1106. ('boxcar', 100, 10, 0), # Test no overlap
  1107. ('boxcar', 100, 10, 9), # Test high overlap
  1108. ('bartlett', 101, 51, 26), # Test odd nperseg
  1109. ('hann', 1024, 256, 128), # Test defaults
  1110. (('tukey', 0.5), 1152, 256, 64), # Test Tukey
  1111. ('hann', 1024, 256, 255), # Test overlapped hann
  1112. ]
  1113. for window, N, nperseg, noverlap in settings:
  1114. t = np.arange(N)
  1115. x = 10*np.random.randn(t.size) + 10j*np.random.randn(t.size)
  1116. _, _, zz = stft(x, nperseg=nperseg, noverlap=noverlap,
  1117. window=window, detrend=None, padded=False,
  1118. return_onesided=False)
  1119. tr, xr = istft(zz, nperseg=nperseg, noverlap=noverlap,
  1120. window=window, input_onesided=False)
  1121. msg = '{0}, {1}, {2}'.format(window, nperseg, noverlap)
  1122. assert_allclose(t, tr, err_msg=msg)
  1123. assert_allclose(x, xr, err_msg=msg)
  1124. # Check that asking for onesided switches to twosided
  1125. with suppress_warnings() as sup:
  1126. sup.filter(UserWarning,
  1127. "Input data is complex, switching to return_onesided=False")
  1128. _, _, zz = stft(x, nperseg=nperseg, noverlap=noverlap,
  1129. window=window, detrend=None, padded=False,
  1130. return_onesided=True)
  1131. tr, xr = istft(zz, nperseg=nperseg, noverlap=noverlap,
  1132. window=window, input_onesided=False)
  1133. msg = '{0}, {1}, {2}'.format(window, nperseg, noverlap)
  1134. assert_allclose(t, tr, err_msg=msg)
  1135. assert_allclose(x, xr, err_msg=msg)
  1136. def test_roundtrip_boundary_extension(self):
  1137. np.random.seed(1234)
  1138. # Test against boxcar, since window is all ones, and thus can be fully
  1139. # recovered with no boundary extension
  1140. settings = [
  1141. ('boxcar', 100, 10, 0), # Test no overlap
  1142. ('boxcar', 100, 10, 9), # Test high overlap
  1143. ]
  1144. for window, N, nperseg, noverlap in settings:
  1145. t = np.arange(N)
  1146. x = 10*np.random.randn(t.size)
  1147. _, _, zz = stft(x, nperseg=nperseg, noverlap=noverlap,
  1148. window=window, detrend=None, padded=True,
  1149. boundary=None)
  1150. _, xr = istft(zz, noverlap=noverlap, window=window, boundary=False)
  1151. for boundary in ['even', 'odd', 'constant', 'zeros']:
  1152. _, _, zz_ext = stft(x, nperseg=nperseg, noverlap=noverlap,
  1153. window=window, detrend=None, padded=True,
  1154. boundary=boundary)
  1155. _, xr_ext = istft(zz_ext, noverlap=noverlap, window=window,
  1156. boundary=True)
  1157. msg = '{0}, {1}, {2}'.format(window, noverlap, boundary)
  1158. assert_allclose(x, xr, err_msg=msg)
  1159. assert_allclose(x, xr_ext, err_msg=msg)
  1160. def test_roundtrip_padded_signal(self):
  1161. np.random.seed(1234)
  1162. settings = [
  1163. ('boxcar', 101, 10, 0),
  1164. ('hann', 1000, 256, 128),
  1165. ]
  1166. for window, N, nperseg, noverlap in settings:
  1167. t = np.arange(N)
  1168. x = 10*np.random.randn(t.size)
  1169. _, _, zz = stft(x, nperseg=nperseg, noverlap=noverlap,
  1170. window=window, detrend=None, padded=True)
  1171. tr, xr = istft(zz, noverlap=noverlap, window=window)
  1172. msg = '{0}, {1}'.format(window, noverlap)
  1173. # Account for possible zero-padding at the end
  1174. assert_allclose(t, tr[:t.size], err_msg=msg)
  1175. assert_allclose(x, xr[:x.size], err_msg=msg)
  1176. def test_roundtrip_padded_FFT(self):
  1177. np.random.seed(1234)
  1178. settings = [
  1179. ('hann', 1024, 256, 128, 512),
  1180. ('hann', 1024, 256, 128, 501),
  1181. ('boxcar', 100, 10, 0, 33),
  1182. (('tukey', 0.5), 1152, 256, 64, 1024),
  1183. ]
  1184. for window, N, nperseg, noverlap, nfft in settings:
  1185. t = np.arange(N)
  1186. x = 10*np.random.randn(t.size)
  1187. xc = x*np.exp(1j*np.pi/4)
  1188. # real signal
  1189. _, _, z = stft(x, nperseg=nperseg, noverlap=noverlap, nfft=nfft,
  1190. window=window, detrend=None, padded=True)
  1191. # complex signal
  1192. _, _, zc = stft(xc, nperseg=nperseg, noverlap=noverlap, nfft=nfft,
  1193. window=window, detrend=None, padded=True,
  1194. return_onesided=False)
  1195. tr, xr = istft(z, nperseg=nperseg, noverlap=noverlap, nfft=nfft,
  1196. window=window)
  1197. tr, xcr = istft(zc, nperseg=nperseg, noverlap=noverlap, nfft=nfft,
  1198. window=window, input_onesided=False)
  1199. msg = '{0}, {1}'.format(window, noverlap)
  1200. assert_allclose(t, tr, err_msg=msg)
  1201. assert_allclose(x, xr, err_msg=msg)
  1202. assert_allclose(xc, xcr, err_msg=msg)
  1203. def test_axis_rolling(self):
  1204. np.random.seed(1234)
  1205. x_flat = np.random.randn(1024)
  1206. _, _, z_flat = stft(x_flat)
  1207. for a in range(3):
  1208. newshape = [1,]*3
  1209. newshape[a] = -1
  1210. x = x_flat.reshape(newshape)
  1211. _, _, z_plus = stft(x, axis=a) # Positive axis index
  1212. _, _, z_minus = stft(x, axis=a-x.ndim) # Negative axis index
  1213. assert_equal(z_flat, z_plus.squeeze(), err_msg=a)
  1214. assert_equal(z_flat, z_minus.squeeze(), err_msg=a-x.ndim)
  1215. # z_flat has shape [n_freq, n_time]
  1216. # Test vs. transpose
  1217. _, x_transpose_m = istft(z_flat.T, time_axis=-2, freq_axis=-1)
  1218. _, x_transpose_p = istft(z_flat.T, time_axis=0, freq_axis=1)
  1219. assert_allclose(x_flat, x_transpose_m, err_msg='istft transpose minus')
  1220. assert_allclose(x_flat, x_transpose_p, err_msg='istft transpose plus')