scipy 1.16.2__cp311-cp311-win_arm64.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (1530) hide show
  1. scipy/__config__.py +161 -0
  2. scipy/__init__.py +150 -0
  3. scipy/_cyutility.cp311-win_arm64.lib +0 -0
  4. scipy/_cyutility.cp311-win_arm64.pyd +0 -0
  5. scipy/_distributor_init.py +18 -0
  6. scipy/_lib/__init__.py +14 -0
  7. scipy/_lib/_array_api.py +931 -0
  8. scipy/_lib/_array_api_compat_vendor.py +9 -0
  9. scipy/_lib/_array_api_no_0d.py +103 -0
  10. scipy/_lib/_bunch.py +229 -0
  11. scipy/_lib/_ccallback.py +251 -0
  12. scipy/_lib/_ccallback_c.cp311-win_arm64.lib +0 -0
  13. scipy/_lib/_ccallback_c.cp311-win_arm64.pyd +0 -0
  14. scipy/_lib/_disjoint_set.py +254 -0
  15. scipy/_lib/_docscrape.py +761 -0
  16. scipy/_lib/_elementwise_iterative_method.py +346 -0
  17. scipy/_lib/_fpumode.cp311-win_arm64.lib +0 -0
  18. scipy/_lib/_fpumode.cp311-win_arm64.pyd +0 -0
  19. scipy/_lib/_gcutils.py +105 -0
  20. scipy/_lib/_pep440.py +487 -0
  21. scipy/_lib/_sparse.py +41 -0
  22. scipy/_lib/_test_ccallback.cp311-win_arm64.lib +0 -0
  23. scipy/_lib/_test_ccallback.cp311-win_arm64.pyd +0 -0
  24. scipy/_lib/_test_deprecation_call.cp311-win_arm64.lib +0 -0
  25. scipy/_lib/_test_deprecation_call.cp311-win_arm64.pyd +0 -0
  26. scipy/_lib/_test_deprecation_def.cp311-win_arm64.lib +0 -0
  27. scipy/_lib/_test_deprecation_def.cp311-win_arm64.pyd +0 -0
  28. scipy/_lib/_testutils.py +373 -0
  29. scipy/_lib/_threadsafety.py +58 -0
  30. scipy/_lib/_tmpdirs.py +86 -0
  31. scipy/_lib/_uarray/LICENSE +29 -0
  32. scipy/_lib/_uarray/__init__.py +116 -0
  33. scipy/_lib/_uarray/_backend.py +707 -0
  34. scipy/_lib/_uarray/_uarray.cp311-win_arm64.lib +0 -0
  35. scipy/_lib/_uarray/_uarray.cp311-win_arm64.pyd +0 -0
  36. scipy/_lib/_util.py +1283 -0
  37. scipy/_lib/array_api_compat/__init__.py +22 -0
  38. scipy/_lib/array_api_compat/_internal.py +59 -0
  39. scipy/_lib/array_api_compat/common/__init__.py +1 -0
  40. scipy/_lib/array_api_compat/common/_aliases.py +727 -0
  41. scipy/_lib/array_api_compat/common/_fft.py +213 -0
  42. scipy/_lib/array_api_compat/common/_helpers.py +1058 -0
  43. scipy/_lib/array_api_compat/common/_linalg.py +232 -0
  44. scipy/_lib/array_api_compat/common/_typing.py +192 -0
  45. scipy/_lib/array_api_compat/cupy/__init__.py +13 -0
  46. scipy/_lib/array_api_compat/cupy/_aliases.py +156 -0
  47. scipy/_lib/array_api_compat/cupy/_info.py +336 -0
  48. scipy/_lib/array_api_compat/cupy/_typing.py +31 -0
  49. scipy/_lib/array_api_compat/cupy/fft.py +36 -0
  50. scipy/_lib/array_api_compat/cupy/linalg.py +49 -0
  51. scipy/_lib/array_api_compat/dask/__init__.py +0 -0
  52. scipy/_lib/array_api_compat/dask/array/__init__.py +12 -0
  53. scipy/_lib/array_api_compat/dask/array/_aliases.py +376 -0
  54. scipy/_lib/array_api_compat/dask/array/_info.py +416 -0
  55. scipy/_lib/array_api_compat/dask/array/fft.py +21 -0
  56. scipy/_lib/array_api_compat/dask/array/linalg.py +72 -0
  57. scipy/_lib/array_api_compat/numpy/__init__.py +28 -0
  58. scipy/_lib/array_api_compat/numpy/_aliases.py +190 -0
  59. scipy/_lib/array_api_compat/numpy/_info.py +366 -0
  60. scipy/_lib/array_api_compat/numpy/_typing.py +30 -0
  61. scipy/_lib/array_api_compat/numpy/fft.py +35 -0
  62. scipy/_lib/array_api_compat/numpy/linalg.py +143 -0
  63. scipy/_lib/array_api_compat/torch/__init__.py +22 -0
  64. scipy/_lib/array_api_compat/torch/_aliases.py +855 -0
  65. scipy/_lib/array_api_compat/torch/_info.py +369 -0
  66. scipy/_lib/array_api_compat/torch/_typing.py +3 -0
  67. scipy/_lib/array_api_compat/torch/fft.py +85 -0
  68. scipy/_lib/array_api_compat/torch/linalg.py +121 -0
  69. scipy/_lib/array_api_extra/__init__.py +38 -0
  70. scipy/_lib/array_api_extra/_delegation.py +171 -0
  71. scipy/_lib/array_api_extra/_lib/__init__.py +1 -0
  72. scipy/_lib/array_api_extra/_lib/_at.py +463 -0
  73. scipy/_lib/array_api_extra/_lib/_backends.py +46 -0
  74. scipy/_lib/array_api_extra/_lib/_funcs.py +937 -0
  75. scipy/_lib/array_api_extra/_lib/_lazy.py +357 -0
  76. scipy/_lib/array_api_extra/_lib/_testing.py +278 -0
  77. scipy/_lib/array_api_extra/_lib/_utils/__init__.py +1 -0
  78. scipy/_lib/array_api_extra/_lib/_utils/_compat.py +74 -0
  79. scipy/_lib/array_api_extra/_lib/_utils/_compat.pyi +45 -0
  80. scipy/_lib/array_api_extra/_lib/_utils/_helpers.py +559 -0
  81. scipy/_lib/array_api_extra/_lib/_utils/_typing.py +10 -0
  82. scipy/_lib/array_api_extra/_lib/_utils/_typing.pyi +105 -0
  83. scipy/_lib/array_api_extra/testing.py +359 -0
  84. scipy/_lib/cobyqa/__init__.py +20 -0
  85. scipy/_lib/cobyqa/framework.py +1240 -0
  86. scipy/_lib/cobyqa/main.py +1506 -0
  87. scipy/_lib/cobyqa/models.py +1529 -0
  88. scipy/_lib/cobyqa/problem.py +1296 -0
  89. scipy/_lib/cobyqa/settings.py +132 -0
  90. scipy/_lib/cobyqa/subsolvers/__init__.py +14 -0
  91. scipy/_lib/cobyqa/subsolvers/geometry.py +387 -0
  92. scipy/_lib/cobyqa/subsolvers/optim.py +1203 -0
  93. scipy/_lib/cobyqa/utils/__init__.py +18 -0
  94. scipy/_lib/cobyqa/utils/exceptions.py +22 -0
  95. scipy/_lib/cobyqa/utils/math.py +77 -0
  96. scipy/_lib/cobyqa/utils/versions.py +67 -0
  97. scipy/_lib/decorator.py +399 -0
  98. scipy/_lib/deprecation.py +274 -0
  99. scipy/_lib/doccer.py +366 -0
  100. scipy/_lib/messagestream.cp311-win_arm64.lib +0 -0
  101. scipy/_lib/messagestream.cp311-win_arm64.pyd +0 -0
  102. scipy/_lib/pyprima/__init__.py +212 -0
  103. scipy/_lib/pyprima/cobyla/__init__.py +0 -0
  104. scipy/_lib/pyprima/cobyla/cobyla.py +559 -0
  105. scipy/_lib/pyprima/cobyla/cobylb.py +714 -0
  106. scipy/_lib/pyprima/cobyla/geometry.py +226 -0
  107. scipy/_lib/pyprima/cobyla/initialize.py +215 -0
  108. scipy/_lib/pyprima/cobyla/trustregion.py +492 -0
  109. scipy/_lib/pyprima/cobyla/update.py +289 -0
  110. scipy/_lib/pyprima/common/__init__.py +0 -0
  111. scipy/_lib/pyprima/common/_bounds.py +34 -0
  112. scipy/_lib/pyprima/common/_linear_constraints.py +46 -0
  113. scipy/_lib/pyprima/common/_nonlinear_constraints.py +54 -0
  114. scipy/_lib/pyprima/common/_project.py +173 -0
  115. scipy/_lib/pyprima/common/checkbreak.py +93 -0
  116. scipy/_lib/pyprima/common/consts.py +47 -0
  117. scipy/_lib/pyprima/common/evaluate.py +99 -0
  118. scipy/_lib/pyprima/common/history.py +38 -0
  119. scipy/_lib/pyprima/common/infos.py +30 -0
  120. scipy/_lib/pyprima/common/linalg.py +435 -0
  121. scipy/_lib/pyprima/common/message.py +290 -0
  122. scipy/_lib/pyprima/common/powalg.py +131 -0
  123. scipy/_lib/pyprima/common/preproc.py +277 -0
  124. scipy/_lib/pyprima/common/present.py +5 -0
  125. scipy/_lib/pyprima/common/ratio.py +54 -0
  126. scipy/_lib/pyprima/common/redrho.py +47 -0
  127. scipy/_lib/pyprima/common/selectx.py +296 -0
  128. scipy/_lib/tests/__init__.py +0 -0
  129. scipy/_lib/tests/test__gcutils.py +110 -0
  130. scipy/_lib/tests/test__pep440.py +67 -0
  131. scipy/_lib/tests/test__testutils.py +32 -0
  132. scipy/_lib/tests/test__threadsafety.py +51 -0
  133. scipy/_lib/tests/test__util.py +641 -0
  134. scipy/_lib/tests/test_array_api.py +322 -0
  135. scipy/_lib/tests/test_bunch.py +169 -0
  136. scipy/_lib/tests/test_ccallback.py +196 -0
  137. scipy/_lib/tests/test_config.py +45 -0
  138. scipy/_lib/tests/test_deprecation.py +10 -0
  139. scipy/_lib/tests/test_doccer.py +143 -0
  140. scipy/_lib/tests/test_import_cycles.py +18 -0
  141. scipy/_lib/tests/test_public_api.py +482 -0
  142. scipy/_lib/tests/test_scipy_version.py +28 -0
  143. scipy/_lib/tests/test_tmpdirs.py +48 -0
  144. scipy/_lib/tests/test_warnings.py +137 -0
  145. scipy/_lib/uarray.py +31 -0
  146. scipy/cluster/__init__.py +31 -0
  147. scipy/cluster/_hierarchy.cp311-win_arm64.lib +0 -0
  148. scipy/cluster/_hierarchy.cp311-win_arm64.pyd +0 -0
  149. scipy/cluster/_optimal_leaf_ordering.cp311-win_arm64.lib +0 -0
  150. scipy/cluster/_optimal_leaf_ordering.cp311-win_arm64.pyd +0 -0
  151. scipy/cluster/_vq.cp311-win_arm64.lib +0 -0
  152. scipy/cluster/_vq.cp311-win_arm64.pyd +0 -0
  153. scipy/cluster/hierarchy.py +4348 -0
  154. scipy/cluster/tests/__init__.py +0 -0
  155. scipy/cluster/tests/hierarchy_test_data.py +145 -0
  156. scipy/cluster/tests/test_disjoint_set.py +202 -0
  157. scipy/cluster/tests/test_hierarchy.py +1238 -0
  158. scipy/cluster/tests/test_vq.py +434 -0
  159. scipy/cluster/vq.py +832 -0
  160. scipy/conftest.py +683 -0
  161. scipy/constants/__init__.py +358 -0
  162. scipy/constants/_codata.py +2266 -0
  163. scipy/constants/_constants.py +369 -0
  164. scipy/constants/codata.py +21 -0
  165. scipy/constants/constants.py +53 -0
  166. scipy/constants/tests/__init__.py +0 -0
  167. scipy/constants/tests/test_codata.py +78 -0
  168. scipy/constants/tests/test_constants.py +83 -0
  169. scipy/datasets/__init__.py +90 -0
  170. scipy/datasets/_download_all.py +71 -0
  171. scipy/datasets/_fetchers.py +225 -0
  172. scipy/datasets/_registry.py +26 -0
  173. scipy/datasets/_utils.py +81 -0
  174. scipy/datasets/tests/__init__.py +0 -0
  175. scipy/datasets/tests/test_data.py +128 -0
  176. scipy/differentiate/__init__.py +27 -0
  177. scipy/differentiate/_differentiate.py +1129 -0
  178. scipy/differentiate/tests/__init__.py +0 -0
  179. scipy/differentiate/tests/test_differentiate.py +694 -0
  180. scipy/fft/__init__.py +114 -0
  181. scipy/fft/_backend.py +196 -0
  182. scipy/fft/_basic.py +1650 -0
  183. scipy/fft/_basic_backend.py +197 -0
  184. scipy/fft/_debug_backends.py +22 -0
  185. scipy/fft/_fftlog.py +223 -0
  186. scipy/fft/_fftlog_backend.py +200 -0
  187. scipy/fft/_helper.py +348 -0
  188. scipy/fft/_pocketfft/LICENSE.md +25 -0
  189. scipy/fft/_pocketfft/__init__.py +9 -0
  190. scipy/fft/_pocketfft/basic.py +251 -0
  191. scipy/fft/_pocketfft/helper.py +249 -0
  192. scipy/fft/_pocketfft/pypocketfft.cp311-win_arm64.lib +0 -0
  193. scipy/fft/_pocketfft/pypocketfft.cp311-win_arm64.pyd +0 -0
  194. scipy/fft/_pocketfft/realtransforms.py +109 -0
  195. scipy/fft/_pocketfft/tests/__init__.py +0 -0
  196. scipy/fft/_pocketfft/tests/test_basic.py +1011 -0
  197. scipy/fft/_pocketfft/tests/test_real_transforms.py +505 -0
  198. scipy/fft/_realtransforms.py +706 -0
  199. scipy/fft/_realtransforms_backend.py +63 -0
  200. scipy/fft/tests/__init__.py +0 -0
  201. scipy/fft/tests/mock_backend.py +96 -0
  202. scipy/fft/tests/test_backend.py +98 -0
  203. scipy/fft/tests/test_basic.py +504 -0
  204. scipy/fft/tests/test_fftlog.py +215 -0
  205. scipy/fft/tests/test_helper.py +558 -0
  206. scipy/fft/tests/test_multithreading.py +84 -0
  207. scipy/fft/tests/test_real_transforms.py +247 -0
  208. scipy/fftpack/__init__.py +103 -0
  209. scipy/fftpack/_basic.py +428 -0
  210. scipy/fftpack/_helper.py +115 -0
  211. scipy/fftpack/_pseudo_diffs.py +554 -0
  212. scipy/fftpack/_realtransforms.py +598 -0
  213. scipy/fftpack/basic.py +20 -0
  214. scipy/fftpack/convolve.cp311-win_arm64.lib +0 -0
  215. scipy/fftpack/convolve.cp311-win_arm64.pyd +0 -0
  216. scipy/fftpack/helper.py +19 -0
  217. scipy/fftpack/pseudo_diffs.py +22 -0
  218. scipy/fftpack/realtransforms.py +19 -0
  219. scipy/fftpack/tests/__init__.py +0 -0
  220. scipy/fftpack/tests/fftw_double_ref.npz +0 -0
  221. scipy/fftpack/tests/fftw_longdouble_ref.npz +0 -0
  222. scipy/fftpack/tests/fftw_single_ref.npz +0 -0
  223. scipy/fftpack/tests/test.npz +0 -0
  224. scipy/fftpack/tests/test_basic.py +877 -0
  225. scipy/fftpack/tests/test_helper.py +54 -0
  226. scipy/fftpack/tests/test_import.py +33 -0
  227. scipy/fftpack/tests/test_pseudo_diffs.py +388 -0
  228. scipy/fftpack/tests/test_real_transforms.py +836 -0
  229. scipy/integrate/__init__.py +122 -0
  230. scipy/integrate/_bvp.py +1160 -0
  231. scipy/integrate/_cubature.py +729 -0
  232. scipy/integrate/_dop.cp311-win_arm64.lib +0 -0
  233. scipy/integrate/_dop.cp311-win_arm64.pyd +0 -0
  234. scipy/integrate/_ivp/__init__.py +8 -0
  235. scipy/integrate/_ivp/base.py +290 -0
  236. scipy/integrate/_ivp/bdf.py +478 -0
  237. scipy/integrate/_ivp/common.py +451 -0
  238. scipy/integrate/_ivp/dop853_coefficients.py +193 -0
  239. scipy/integrate/_ivp/ivp.py +755 -0
  240. scipy/integrate/_ivp/lsoda.py +224 -0
  241. scipy/integrate/_ivp/radau.py +572 -0
  242. scipy/integrate/_ivp/rk.py +601 -0
  243. scipy/integrate/_ivp/tests/__init__.py +0 -0
  244. scipy/integrate/_ivp/tests/test_ivp.py +1287 -0
  245. scipy/integrate/_ivp/tests/test_rk.py +37 -0
  246. scipy/integrate/_lebedev.py +5450 -0
  247. scipy/integrate/_lsoda.cp311-win_arm64.lib +0 -0
  248. scipy/integrate/_lsoda.cp311-win_arm64.pyd +0 -0
  249. scipy/integrate/_ode.py +1395 -0
  250. scipy/integrate/_odepack.cp311-win_arm64.lib +0 -0
  251. scipy/integrate/_odepack.cp311-win_arm64.pyd +0 -0
  252. scipy/integrate/_odepack_py.py +273 -0
  253. scipy/integrate/_quad_vec.py +674 -0
  254. scipy/integrate/_quadpack.cp311-win_arm64.lib +0 -0
  255. scipy/integrate/_quadpack.cp311-win_arm64.pyd +0 -0
  256. scipy/integrate/_quadpack_py.py +1283 -0
  257. scipy/integrate/_quadrature.py +1336 -0
  258. scipy/integrate/_rules/__init__.py +12 -0
  259. scipy/integrate/_rules/_base.py +518 -0
  260. scipy/integrate/_rules/_gauss_kronrod.py +202 -0
  261. scipy/integrate/_rules/_gauss_legendre.py +62 -0
  262. scipy/integrate/_rules/_genz_malik.py +210 -0
  263. scipy/integrate/_tanhsinh.py +1385 -0
  264. scipy/integrate/_test_multivariate.cp311-win_arm64.lib +0 -0
  265. scipy/integrate/_test_multivariate.cp311-win_arm64.pyd +0 -0
  266. scipy/integrate/_test_odeint_banded.cp311-win_arm64.lib +0 -0
  267. scipy/integrate/_test_odeint_banded.cp311-win_arm64.pyd +0 -0
  268. scipy/integrate/_vode.cp311-win_arm64.lib +0 -0
  269. scipy/integrate/_vode.cp311-win_arm64.pyd +0 -0
  270. scipy/integrate/dop.py +15 -0
  271. scipy/integrate/lsoda.py +15 -0
  272. scipy/integrate/odepack.py +17 -0
  273. scipy/integrate/quadpack.py +23 -0
  274. scipy/integrate/tests/__init__.py +0 -0
  275. scipy/integrate/tests/test__quad_vec.py +211 -0
  276. scipy/integrate/tests/test_banded_ode_solvers.py +305 -0
  277. scipy/integrate/tests/test_bvp.py +714 -0
  278. scipy/integrate/tests/test_cubature.py +1375 -0
  279. scipy/integrate/tests/test_integrate.py +840 -0
  280. scipy/integrate/tests/test_odeint_jac.py +74 -0
  281. scipy/integrate/tests/test_quadpack.py +680 -0
  282. scipy/integrate/tests/test_quadrature.py +730 -0
  283. scipy/integrate/tests/test_tanhsinh.py +1171 -0
  284. scipy/integrate/vode.py +15 -0
  285. scipy/interpolate/__init__.py +228 -0
  286. scipy/interpolate/_bary_rational.py +715 -0
  287. scipy/interpolate/_bsplines.py +2469 -0
  288. scipy/interpolate/_cubic.py +973 -0
  289. scipy/interpolate/_dfitpack.cp311-win_arm64.lib +0 -0
  290. scipy/interpolate/_dfitpack.cp311-win_arm64.pyd +0 -0
  291. scipy/interpolate/_dierckx.cp311-win_arm64.lib +0 -0
  292. scipy/interpolate/_dierckx.cp311-win_arm64.pyd +0 -0
  293. scipy/interpolate/_fitpack.cp311-win_arm64.lib +0 -0
  294. scipy/interpolate/_fitpack.cp311-win_arm64.pyd +0 -0
  295. scipy/interpolate/_fitpack2.py +2397 -0
  296. scipy/interpolate/_fitpack_impl.py +811 -0
  297. scipy/interpolate/_fitpack_py.py +898 -0
  298. scipy/interpolate/_fitpack_repro.py +996 -0
  299. scipy/interpolate/_interpnd.cp311-win_arm64.lib +0 -0
  300. scipy/interpolate/_interpnd.cp311-win_arm64.pyd +0 -0
  301. scipy/interpolate/_interpolate.py +2266 -0
  302. scipy/interpolate/_ndbspline.py +415 -0
  303. scipy/interpolate/_ndgriddata.py +329 -0
  304. scipy/interpolate/_pade.py +67 -0
  305. scipy/interpolate/_polyint.py +1025 -0
  306. scipy/interpolate/_ppoly.cp311-win_arm64.lib +0 -0
  307. scipy/interpolate/_ppoly.cp311-win_arm64.pyd +0 -0
  308. scipy/interpolate/_rbf.py +290 -0
  309. scipy/interpolate/_rbfinterp.py +550 -0
  310. scipy/interpolate/_rbfinterp_pythran.cp311-win_arm64.lib +0 -0
  311. scipy/interpolate/_rbfinterp_pythran.cp311-win_arm64.pyd +0 -0
  312. scipy/interpolate/_rgi.py +764 -0
  313. scipy/interpolate/_rgi_cython.cp311-win_arm64.lib +0 -0
  314. scipy/interpolate/_rgi_cython.cp311-win_arm64.pyd +0 -0
  315. scipy/interpolate/dfitpack.py +24 -0
  316. scipy/interpolate/fitpack.py +31 -0
  317. scipy/interpolate/fitpack2.py +29 -0
  318. scipy/interpolate/interpnd.py +24 -0
  319. scipy/interpolate/interpolate.py +30 -0
  320. scipy/interpolate/ndgriddata.py +23 -0
  321. scipy/interpolate/polyint.py +24 -0
  322. scipy/interpolate/rbf.py +18 -0
  323. scipy/interpolate/tests/__init__.py +0 -0
  324. scipy/interpolate/tests/data/bug-1310.npz +0 -0
  325. scipy/interpolate/tests/data/estimate_gradients_hang.npy +0 -0
  326. scipy/interpolate/tests/data/gcvspl.npz +0 -0
  327. scipy/interpolate/tests/test_bary_rational.py +368 -0
  328. scipy/interpolate/tests/test_bsplines.py +3754 -0
  329. scipy/interpolate/tests/test_fitpack.py +519 -0
  330. scipy/interpolate/tests/test_fitpack2.py +1431 -0
  331. scipy/interpolate/tests/test_gil.py +64 -0
  332. scipy/interpolate/tests/test_interpnd.py +452 -0
  333. scipy/interpolate/tests/test_interpolate.py +2630 -0
  334. scipy/interpolate/tests/test_ndgriddata.py +308 -0
  335. scipy/interpolate/tests/test_pade.py +107 -0
  336. scipy/interpolate/tests/test_polyint.py +972 -0
  337. scipy/interpolate/tests/test_rbf.py +246 -0
  338. scipy/interpolate/tests/test_rbfinterp.py +534 -0
  339. scipy/interpolate/tests/test_rgi.py +1151 -0
  340. scipy/io/__init__.py +116 -0
  341. scipy/io/_fast_matrix_market/__init__.py +600 -0
  342. scipy/io/_fast_matrix_market/_fmm_core.cp311-win_arm64.lib +0 -0
  343. scipy/io/_fast_matrix_market/_fmm_core.cp311-win_arm64.pyd +0 -0
  344. scipy/io/_fortran.py +354 -0
  345. scipy/io/_harwell_boeing/__init__.py +7 -0
  346. scipy/io/_harwell_boeing/_fortran_format_parser.py +316 -0
  347. scipy/io/_harwell_boeing/hb.py +571 -0
  348. scipy/io/_harwell_boeing/tests/__init__.py +0 -0
  349. scipy/io/_harwell_boeing/tests/test_fortran_format.py +74 -0
  350. scipy/io/_harwell_boeing/tests/test_hb.py +70 -0
  351. scipy/io/_idl.py +917 -0
  352. scipy/io/_mmio.py +968 -0
  353. scipy/io/_netcdf.py +1104 -0
  354. scipy/io/_test_fortran.cp311-win_arm64.lib +0 -0
  355. scipy/io/_test_fortran.cp311-win_arm64.pyd +0 -0
  356. scipy/io/arff/__init__.py +28 -0
  357. scipy/io/arff/_arffread.py +873 -0
  358. scipy/io/arff/arffread.py +19 -0
  359. scipy/io/arff/tests/__init__.py +0 -0
  360. scipy/io/arff/tests/data/iris.arff +225 -0
  361. scipy/io/arff/tests/data/missing.arff +8 -0
  362. scipy/io/arff/tests/data/nodata.arff +11 -0
  363. scipy/io/arff/tests/data/quoted_nominal.arff +13 -0
  364. scipy/io/arff/tests/data/quoted_nominal_spaces.arff +13 -0
  365. scipy/io/arff/tests/data/test1.arff +10 -0
  366. scipy/io/arff/tests/data/test10.arff +8 -0
  367. scipy/io/arff/tests/data/test11.arff +11 -0
  368. scipy/io/arff/tests/data/test2.arff +15 -0
  369. scipy/io/arff/tests/data/test3.arff +6 -0
  370. scipy/io/arff/tests/data/test4.arff +11 -0
  371. scipy/io/arff/tests/data/test5.arff +26 -0
  372. scipy/io/arff/tests/data/test6.arff +12 -0
  373. scipy/io/arff/tests/data/test7.arff +15 -0
  374. scipy/io/arff/tests/data/test8.arff +12 -0
  375. scipy/io/arff/tests/data/test9.arff +14 -0
  376. scipy/io/arff/tests/test_arffread.py +421 -0
  377. scipy/io/harwell_boeing.py +17 -0
  378. scipy/io/idl.py +17 -0
  379. scipy/io/matlab/__init__.py +66 -0
  380. scipy/io/matlab/_byteordercodes.py +75 -0
  381. scipy/io/matlab/_mio.py +375 -0
  382. scipy/io/matlab/_mio4.py +632 -0
  383. scipy/io/matlab/_mio5.py +901 -0
  384. scipy/io/matlab/_mio5_params.py +281 -0
  385. scipy/io/matlab/_mio5_utils.cp311-win_arm64.lib +0 -0
  386. scipy/io/matlab/_mio5_utils.cp311-win_arm64.pyd +0 -0
  387. scipy/io/matlab/_mio_utils.cp311-win_arm64.lib +0 -0
  388. scipy/io/matlab/_mio_utils.cp311-win_arm64.pyd +0 -0
  389. scipy/io/matlab/_miobase.py +435 -0
  390. scipy/io/matlab/_streams.cp311-win_arm64.lib +0 -0
  391. scipy/io/matlab/_streams.cp311-win_arm64.pyd +0 -0
  392. scipy/io/matlab/byteordercodes.py +17 -0
  393. scipy/io/matlab/mio.py +16 -0
  394. scipy/io/matlab/mio4.py +17 -0
  395. scipy/io/matlab/mio5.py +19 -0
  396. scipy/io/matlab/mio5_params.py +18 -0
  397. scipy/io/matlab/mio5_utils.py +17 -0
  398. scipy/io/matlab/mio_utils.py +17 -0
  399. scipy/io/matlab/miobase.py +16 -0
  400. scipy/io/matlab/streams.py +16 -0
  401. scipy/io/matlab/tests/__init__.py +0 -0
  402. scipy/io/matlab/tests/data/bad_miuint32.mat +0 -0
  403. scipy/io/matlab/tests/data/bad_miutf8_array_name.mat +0 -0
  404. scipy/io/matlab/tests/data/big_endian.mat +0 -0
  405. scipy/io/matlab/tests/data/broken_utf8.mat +0 -0
  406. scipy/io/matlab/tests/data/corrupted_zlib_checksum.mat +0 -0
  407. scipy/io/matlab/tests/data/corrupted_zlib_data.mat +0 -0
  408. scipy/io/matlab/tests/data/debigged_m4.mat +0 -0
  409. scipy/io/matlab/tests/data/japanese_utf8.txt +5 -0
  410. scipy/io/matlab/tests/data/little_endian.mat +0 -0
  411. scipy/io/matlab/tests/data/logical_sparse.mat +0 -0
  412. scipy/io/matlab/tests/data/malformed1.mat +0 -0
  413. scipy/io/matlab/tests/data/miuint32_for_miint32.mat +0 -0
  414. scipy/io/matlab/tests/data/miutf8_array_name.mat +0 -0
  415. scipy/io/matlab/tests/data/nasty_duplicate_fieldnames.mat +0 -0
  416. scipy/io/matlab/tests/data/one_by_zero_char.mat +0 -0
  417. scipy/io/matlab/tests/data/parabola.mat +0 -0
  418. scipy/io/matlab/tests/data/single_empty_string.mat +0 -0
  419. scipy/io/matlab/tests/data/some_functions.mat +0 -0
  420. scipy/io/matlab/tests/data/sqr.mat +0 -0
  421. scipy/io/matlab/tests/data/test3dmatrix_6.1_SOL2.mat +0 -0
  422. scipy/io/matlab/tests/data/test3dmatrix_6.5.1_GLNX86.mat +0 -0
  423. scipy/io/matlab/tests/data/test3dmatrix_7.1_GLNX86.mat +0 -0
  424. scipy/io/matlab/tests/data/test3dmatrix_7.4_GLNX86.mat +0 -0
  425. scipy/io/matlab/tests/data/test_empty_struct.mat +0 -0
  426. scipy/io/matlab/tests/data/test_mat4_le_floats.mat +0 -0
  427. scipy/io/matlab/tests/data/test_skip_variable.mat +0 -0
  428. scipy/io/matlab/tests/data/testbool_8_WIN64.mat +0 -0
  429. scipy/io/matlab/tests/data/testcell_6.1_SOL2.mat +0 -0
  430. scipy/io/matlab/tests/data/testcell_6.5.1_GLNX86.mat +0 -0
  431. scipy/io/matlab/tests/data/testcell_7.1_GLNX86.mat +0 -0
  432. scipy/io/matlab/tests/data/testcell_7.4_GLNX86.mat +0 -0
  433. scipy/io/matlab/tests/data/testcellnest_6.1_SOL2.mat +0 -0
  434. scipy/io/matlab/tests/data/testcellnest_6.5.1_GLNX86.mat +0 -0
  435. scipy/io/matlab/tests/data/testcellnest_7.1_GLNX86.mat +0 -0
  436. scipy/io/matlab/tests/data/testcellnest_7.4_GLNX86.mat +0 -0
  437. scipy/io/matlab/tests/data/testcomplex_4.2c_SOL2.mat +0 -0
  438. scipy/io/matlab/tests/data/testcomplex_6.1_SOL2.mat +0 -0
  439. scipy/io/matlab/tests/data/testcomplex_6.5.1_GLNX86.mat +0 -0
  440. scipy/io/matlab/tests/data/testcomplex_7.1_GLNX86.mat +0 -0
  441. scipy/io/matlab/tests/data/testcomplex_7.4_GLNX86.mat +0 -0
  442. scipy/io/matlab/tests/data/testdouble_4.2c_SOL2.mat +0 -0
  443. scipy/io/matlab/tests/data/testdouble_6.1_SOL2.mat +0 -0
  444. scipy/io/matlab/tests/data/testdouble_6.5.1_GLNX86.mat +0 -0
  445. scipy/io/matlab/tests/data/testdouble_7.1_GLNX86.mat +0 -0
  446. scipy/io/matlab/tests/data/testdouble_7.4_GLNX86.mat +0 -0
  447. scipy/io/matlab/tests/data/testemptycell_5.3_SOL2.mat +0 -0
  448. scipy/io/matlab/tests/data/testemptycell_6.5.1_GLNX86.mat +0 -0
  449. scipy/io/matlab/tests/data/testemptycell_7.1_GLNX86.mat +0 -0
  450. scipy/io/matlab/tests/data/testemptycell_7.4_GLNX86.mat +0 -0
  451. scipy/io/matlab/tests/data/testfunc_7.4_GLNX86.mat +0 -0
  452. scipy/io/matlab/tests/data/testhdf5_7.4_GLNX86.mat +0 -0
  453. scipy/io/matlab/tests/data/testmatrix_4.2c_SOL2.mat +0 -0
  454. scipy/io/matlab/tests/data/testmatrix_6.1_SOL2.mat +0 -0
  455. scipy/io/matlab/tests/data/testmatrix_6.5.1_GLNX86.mat +0 -0
  456. scipy/io/matlab/tests/data/testmatrix_7.1_GLNX86.mat +0 -0
  457. scipy/io/matlab/tests/data/testmatrix_7.4_GLNX86.mat +0 -0
  458. scipy/io/matlab/tests/data/testminus_4.2c_SOL2.mat +0 -0
  459. scipy/io/matlab/tests/data/testminus_6.1_SOL2.mat +0 -0
  460. scipy/io/matlab/tests/data/testminus_6.5.1_GLNX86.mat +0 -0
  461. scipy/io/matlab/tests/data/testminus_7.1_GLNX86.mat +0 -0
  462. scipy/io/matlab/tests/data/testminus_7.4_GLNX86.mat +0 -0
  463. scipy/io/matlab/tests/data/testmulti_4.2c_SOL2.mat +0 -0
  464. scipy/io/matlab/tests/data/testmulti_7.1_GLNX86.mat +0 -0
  465. scipy/io/matlab/tests/data/testmulti_7.4_GLNX86.mat +0 -0
  466. scipy/io/matlab/tests/data/testobject_6.1_SOL2.mat +0 -0
  467. scipy/io/matlab/tests/data/testobject_6.5.1_GLNX86.mat +0 -0
  468. scipy/io/matlab/tests/data/testobject_7.1_GLNX86.mat +0 -0
  469. scipy/io/matlab/tests/data/testobject_7.4_GLNX86.mat +0 -0
  470. scipy/io/matlab/tests/data/testonechar_4.2c_SOL2.mat +0 -0
  471. scipy/io/matlab/tests/data/testonechar_6.1_SOL2.mat +0 -0
  472. scipy/io/matlab/tests/data/testonechar_6.5.1_GLNX86.mat +0 -0
  473. scipy/io/matlab/tests/data/testonechar_7.1_GLNX86.mat +0 -0
  474. scipy/io/matlab/tests/data/testonechar_7.4_GLNX86.mat +0 -0
  475. scipy/io/matlab/tests/data/testscalarcell_7.4_GLNX86.mat +0 -0
  476. scipy/io/matlab/tests/data/testsimplecell.mat +0 -0
  477. scipy/io/matlab/tests/data/testsparse_4.2c_SOL2.mat +0 -0
  478. scipy/io/matlab/tests/data/testsparse_6.1_SOL2.mat +0 -0
  479. scipy/io/matlab/tests/data/testsparse_6.5.1_GLNX86.mat +0 -0
  480. scipy/io/matlab/tests/data/testsparse_7.1_GLNX86.mat +0 -0
  481. scipy/io/matlab/tests/data/testsparse_7.4_GLNX86.mat +0 -0
  482. scipy/io/matlab/tests/data/testsparsecomplex_4.2c_SOL2.mat +0 -0
  483. scipy/io/matlab/tests/data/testsparsecomplex_6.1_SOL2.mat +0 -0
  484. scipy/io/matlab/tests/data/testsparsecomplex_6.5.1_GLNX86.mat +0 -0
  485. scipy/io/matlab/tests/data/testsparsecomplex_7.1_GLNX86.mat +0 -0
  486. scipy/io/matlab/tests/data/testsparsecomplex_7.4_GLNX86.mat +0 -0
  487. scipy/io/matlab/tests/data/testsparsefloat_7.4_GLNX86.mat +0 -0
  488. scipy/io/matlab/tests/data/teststring_4.2c_SOL2.mat +0 -0
  489. scipy/io/matlab/tests/data/teststring_6.1_SOL2.mat +0 -0
  490. scipy/io/matlab/tests/data/teststring_6.5.1_GLNX86.mat +0 -0
  491. scipy/io/matlab/tests/data/teststring_7.1_GLNX86.mat +0 -0
  492. scipy/io/matlab/tests/data/teststring_7.4_GLNX86.mat +0 -0
  493. scipy/io/matlab/tests/data/teststringarray_4.2c_SOL2.mat +0 -0
  494. scipy/io/matlab/tests/data/teststringarray_6.1_SOL2.mat +0 -0
  495. scipy/io/matlab/tests/data/teststringarray_6.5.1_GLNX86.mat +0 -0
  496. scipy/io/matlab/tests/data/teststringarray_7.1_GLNX86.mat +0 -0
  497. scipy/io/matlab/tests/data/teststringarray_7.4_GLNX86.mat +0 -0
  498. scipy/io/matlab/tests/data/teststruct_6.1_SOL2.mat +0 -0
  499. scipy/io/matlab/tests/data/teststruct_6.5.1_GLNX86.mat +0 -0
  500. scipy/io/matlab/tests/data/teststruct_7.1_GLNX86.mat +0 -0
  501. scipy/io/matlab/tests/data/teststruct_7.4_GLNX86.mat +0 -0
  502. scipy/io/matlab/tests/data/teststructarr_6.1_SOL2.mat +0 -0
  503. scipy/io/matlab/tests/data/teststructarr_6.5.1_GLNX86.mat +0 -0
  504. scipy/io/matlab/tests/data/teststructarr_7.1_GLNX86.mat +0 -0
  505. scipy/io/matlab/tests/data/teststructarr_7.4_GLNX86.mat +0 -0
  506. scipy/io/matlab/tests/data/teststructnest_6.1_SOL2.mat +0 -0
  507. scipy/io/matlab/tests/data/teststructnest_6.5.1_GLNX86.mat +0 -0
  508. scipy/io/matlab/tests/data/teststructnest_7.1_GLNX86.mat +0 -0
  509. scipy/io/matlab/tests/data/teststructnest_7.4_GLNX86.mat +0 -0
  510. scipy/io/matlab/tests/data/testunicode_7.1_GLNX86.mat +0 -0
  511. scipy/io/matlab/tests/data/testunicode_7.4_GLNX86.mat +0 -0
  512. scipy/io/matlab/tests/data/testvec_4_GLNX86.mat +0 -0
  513. scipy/io/matlab/tests/test_byteordercodes.py +29 -0
  514. scipy/io/matlab/tests/test_mio.py +1399 -0
  515. scipy/io/matlab/tests/test_mio5_utils.py +179 -0
  516. scipy/io/matlab/tests/test_mio_funcs.py +51 -0
  517. scipy/io/matlab/tests/test_mio_utils.py +45 -0
  518. scipy/io/matlab/tests/test_miobase.py +32 -0
  519. scipy/io/matlab/tests/test_pathological.py +33 -0
  520. scipy/io/matlab/tests/test_streams.py +241 -0
  521. scipy/io/mmio.py +17 -0
  522. scipy/io/netcdf.py +17 -0
  523. scipy/io/tests/__init__.py +0 -0
  524. scipy/io/tests/data/Transparent Busy.ani +0 -0
  525. scipy/io/tests/data/array_float32_1d.sav +0 -0
  526. scipy/io/tests/data/array_float32_2d.sav +0 -0
  527. scipy/io/tests/data/array_float32_3d.sav +0 -0
  528. scipy/io/tests/data/array_float32_4d.sav +0 -0
  529. scipy/io/tests/data/array_float32_5d.sav +0 -0
  530. scipy/io/tests/data/array_float32_6d.sav +0 -0
  531. scipy/io/tests/data/array_float32_7d.sav +0 -0
  532. scipy/io/tests/data/array_float32_8d.sav +0 -0
  533. scipy/io/tests/data/array_float32_pointer_1d.sav +0 -0
  534. scipy/io/tests/data/array_float32_pointer_2d.sav +0 -0
  535. scipy/io/tests/data/array_float32_pointer_3d.sav +0 -0
  536. scipy/io/tests/data/array_float32_pointer_4d.sav +0 -0
  537. scipy/io/tests/data/array_float32_pointer_5d.sav +0 -0
  538. scipy/io/tests/data/array_float32_pointer_6d.sav +0 -0
  539. scipy/io/tests/data/array_float32_pointer_7d.sav +0 -0
  540. scipy/io/tests/data/array_float32_pointer_8d.sav +0 -0
  541. scipy/io/tests/data/example_1.nc +0 -0
  542. scipy/io/tests/data/example_2.nc +0 -0
  543. scipy/io/tests/data/example_3_maskedvals.nc +0 -0
  544. scipy/io/tests/data/fortran-3x3d-2i.dat +0 -0
  545. scipy/io/tests/data/fortran-mixed.dat +0 -0
  546. scipy/io/tests/data/fortran-sf8-11x1x10.dat +0 -0
  547. scipy/io/tests/data/fortran-sf8-15x10x22.dat +0 -0
  548. scipy/io/tests/data/fortran-sf8-1x1x1.dat +0 -0
  549. scipy/io/tests/data/fortran-sf8-1x1x5.dat +0 -0
  550. scipy/io/tests/data/fortran-sf8-1x1x7.dat +0 -0
  551. scipy/io/tests/data/fortran-sf8-1x3x5.dat +0 -0
  552. scipy/io/tests/data/fortran-si4-11x1x10.dat +0 -0
  553. scipy/io/tests/data/fortran-si4-15x10x22.dat +0 -0
  554. scipy/io/tests/data/fortran-si4-1x1x1.dat +0 -0
  555. scipy/io/tests/data/fortran-si4-1x1x5.dat +0 -0
  556. scipy/io/tests/data/fortran-si4-1x1x7.dat +0 -0
  557. scipy/io/tests/data/fortran-si4-1x3x5.dat +0 -0
  558. scipy/io/tests/data/invalid_pointer.sav +0 -0
  559. scipy/io/tests/data/null_pointer.sav +0 -0
  560. scipy/io/tests/data/scalar_byte.sav +0 -0
  561. scipy/io/tests/data/scalar_byte_descr.sav +0 -0
  562. scipy/io/tests/data/scalar_complex32.sav +0 -0
  563. scipy/io/tests/data/scalar_complex64.sav +0 -0
  564. scipy/io/tests/data/scalar_float32.sav +0 -0
  565. scipy/io/tests/data/scalar_float64.sav +0 -0
  566. scipy/io/tests/data/scalar_heap_pointer.sav +0 -0
  567. scipy/io/tests/data/scalar_int16.sav +0 -0
  568. scipy/io/tests/data/scalar_int32.sav +0 -0
  569. scipy/io/tests/data/scalar_int64.sav +0 -0
  570. scipy/io/tests/data/scalar_string.sav +0 -0
  571. scipy/io/tests/data/scalar_uint16.sav +0 -0
  572. scipy/io/tests/data/scalar_uint32.sav +0 -0
  573. scipy/io/tests/data/scalar_uint64.sav +0 -0
  574. scipy/io/tests/data/struct_arrays.sav +0 -0
  575. scipy/io/tests/data/struct_arrays_byte_idl80.sav +0 -0
  576. scipy/io/tests/data/struct_arrays_replicated.sav +0 -0
  577. scipy/io/tests/data/struct_arrays_replicated_3d.sav +0 -0
  578. scipy/io/tests/data/struct_inherit.sav +0 -0
  579. scipy/io/tests/data/struct_pointer_arrays.sav +0 -0
  580. scipy/io/tests/data/struct_pointer_arrays_replicated.sav +0 -0
  581. scipy/io/tests/data/struct_pointer_arrays_replicated_3d.sav +0 -0
  582. scipy/io/tests/data/struct_pointers.sav +0 -0
  583. scipy/io/tests/data/struct_pointers_replicated.sav +0 -0
  584. scipy/io/tests/data/struct_pointers_replicated_3d.sav +0 -0
  585. scipy/io/tests/data/struct_scalars.sav +0 -0
  586. scipy/io/tests/data/struct_scalars_replicated.sav +0 -0
  587. scipy/io/tests/data/struct_scalars_replicated_3d.sav +0 -0
  588. scipy/io/tests/data/test-1234Hz-le-1ch-10S-20bit-extra.wav +0 -0
  589. scipy/io/tests/data/test-44100Hz-2ch-32bit-float-be.wav +0 -0
  590. scipy/io/tests/data/test-44100Hz-2ch-32bit-float-le.wav +0 -0
  591. scipy/io/tests/data/test-44100Hz-be-1ch-4bytes.wav +0 -0
  592. scipy/io/tests/data/test-44100Hz-le-1ch-4bytes-early-eof-no-data.wav +0 -0
  593. scipy/io/tests/data/test-44100Hz-le-1ch-4bytes-early-eof.wav +0 -0
  594. scipy/io/tests/data/test-44100Hz-le-1ch-4bytes-incomplete-chunk.wav +0 -0
  595. scipy/io/tests/data/test-44100Hz-le-1ch-4bytes-rf64.wav +0 -0
  596. scipy/io/tests/data/test-44100Hz-le-1ch-4bytes.wav +0 -0
  597. scipy/io/tests/data/test-48000Hz-2ch-64bit-float-le-wavex.wav +0 -0
  598. scipy/io/tests/data/test-8000Hz-be-3ch-5S-24bit.wav +0 -0
  599. scipy/io/tests/data/test-8000Hz-le-1ch-1byte-ulaw.wav +0 -0
  600. scipy/io/tests/data/test-8000Hz-le-2ch-1byteu.wav +0 -0
  601. scipy/io/tests/data/test-8000Hz-le-3ch-5S-24bit-inconsistent.wav +0 -0
  602. scipy/io/tests/data/test-8000Hz-le-3ch-5S-24bit-rf64.wav +0 -0
  603. scipy/io/tests/data/test-8000Hz-le-3ch-5S-24bit.wav +0 -0
  604. scipy/io/tests/data/test-8000Hz-le-3ch-5S-36bit.wav +0 -0
  605. scipy/io/tests/data/test-8000Hz-le-3ch-5S-45bit.wav +0 -0
  606. scipy/io/tests/data/test-8000Hz-le-3ch-5S-53bit.wav +0 -0
  607. scipy/io/tests/data/test-8000Hz-le-3ch-5S-64bit.wav +0 -0
  608. scipy/io/tests/data/test-8000Hz-le-4ch-9S-12bit.wav +0 -0
  609. scipy/io/tests/data/test-8000Hz-le-5ch-9S-5bit.wav +0 -0
  610. scipy/io/tests/data/various_compressed.sav +0 -0
  611. scipy/io/tests/test_fortran.py +264 -0
  612. scipy/io/tests/test_idl.py +483 -0
  613. scipy/io/tests/test_mmio.py +831 -0
  614. scipy/io/tests/test_netcdf.py +550 -0
  615. scipy/io/tests/test_paths.py +93 -0
  616. scipy/io/tests/test_wavfile.py +501 -0
  617. scipy/io/wavfile.py +938 -0
  618. scipy/linalg/__init__.pxd +1 -0
  619. scipy/linalg/__init__.py +236 -0
  620. scipy/linalg/_basic.py +2146 -0
  621. scipy/linalg/_blas_subroutines.h +164 -0
  622. scipy/linalg/_cythonized_array_utils.cp311-win_arm64.lib +0 -0
  623. scipy/linalg/_cythonized_array_utils.cp311-win_arm64.pyd +0 -0
  624. scipy/linalg/_cythonized_array_utils.pxd +40 -0
  625. scipy/linalg/_cythonized_array_utils.pyi +16 -0
  626. scipy/linalg/_decomp.py +1645 -0
  627. scipy/linalg/_decomp_cholesky.py +413 -0
  628. scipy/linalg/_decomp_cossin.py +236 -0
  629. scipy/linalg/_decomp_interpolative.cp311-win_arm64.lib +0 -0
  630. scipy/linalg/_decomp_interpolative.cp311-win_arm64.pyd +0 -0
  631. scipy/linalg/_decomp_ldl.py +356 -0
  632. scipy/linalg/_decomp_lu.py +401 -0
  633. scipy/linalg/_decomp_lu_cython.cp311-win_arm64.lib +0 -0
  634. scipy/linalg/_decomp_lu_cython.cp311-win_arm64.pyd +0 -0
  635. scipy/linalg/_decomp_lu_cython.pyi +6 -0
  636. scipy/linalg/_decomp_polar.py +113 -0
  637. scipy/linalg/_decomp_qr.py +494 -0
  638. scipy/linalg/_decomp_qz.py +452 -0
  639. scipy/linalg/_decomp_schur.py +336 -0
  640. scipy/linalg/_decomp_svd.py +545 -0
  641. scipy/linalg/_decomp_update.cp311-win_arm64.lib +0 -0
  642. scipy/linalg/_decomp_update.cp311-win_arm64.pyd +0 -0
  643. scipy/linalg/_expm_frechet.py +417 -0
  644. scipy/linalg/_fblas.cp311-win_arm64.lib +0 -0
  645. scipy/linalg/_fblas.cp311-win_arm64.pyd +0 -0
  646. scipy/linalg/_flapack.cp311-win_arm64.lib +0 -0
  647. scipy/linalg/_flapack.cp311-win_arm64.pyd +0 -0
  648. scipy/linalg/_lapack_subroutines.h +1521 -0
  649. scipy/linalg/_linalg_pythran.cp311-win_arm64.lib +0 -0
  650. scipy/linalg/_linalg_pythran.cp311-win_arm64.pyd +0 -0
  651. scipy/linalg/_matfuncs.py +1050 -0
  652. scipy/linalg/_matfuncs_expm.cp311-win_arm64.lib +0 -0
  653. scipy/linalg/_matfuncs_expm.cp311-win_arm64.pyd +0 -0
  654. scipy/linalg/_matfuncs_expm.pyi +6 -0
  655. scipy/linalg/_matfuncs_inv_ssq.py +886 -0
  656. scipy/linalg/_matfuncs_schur_sqrtm.cp311-win_arm64.lib +0 -0
  657. scipy/linalg/_matfuncs_schur_sqrtm.cp311-win_arm64.pyd +0 -0
  658. scipy/linalg/_matfuncs_sqrtm.py +107 -0
  659. scipy/linalg/_matfuncs_sqrtm_triu.cp311-win_arm64.lib +0 -0
  660. scipy/linalg/_matfuncs_sqrtm_triu.cp311-win_arm64.pyd +0 -0
  661. scipy/linalg/_misc.py +191 -0
  662. scipy/linalg/_procrustes.py +113 -0
  663. scipy/linalg/_sketches.py +189 -0
  664. scipy/linalg/_solve_toeplitz.cp311-win_arm64.lib +0 -0
  665. scipy/linalg/_solve_toeplitz.cp311-win_arm64.pyd +0 -0
  666. scipy/linalg/_solvers.py +862 -0
  667. scipy/linalg/_special_matrices.py +1322 -0
  668. scipy/linalg/_testutils.py +65 -0
  669. scipy/linalg/basic.py +23 -0
  670. scipy/linalg/blas.py +495 -0
  671. scipy/linalg/cython_blas.cp311-win_arm64.lib +0 -0
  672. scipy/linalg/cython_blas.cp311-win_arm64.pyd +0 -0
  673. scipy/linalg/cython_blas.pxd +169 -0
  674. scipy/linalg/cython_blas.pyx +1432 -0
  675. scipy/linalg/cython_lapack.cp311-win_arm64.lib +0 -0
  676. scipy/linalg/cython_lapack.cp311-win_arm64.pyd +0 -0
  677. scipy/linalg/cython_lapack.pxd +1528 -0
  678. scipy/linalg/cython_lapack.pyx +12045 -0
  679. scipy/linalg/decomp.py +23 -0
  680. scipy/linalg/decomp_cholesky.py +21 -0
  681. scipy/linalg/decomp_lu.py +21 -0
  682. scipy/linalg/decomp_qr.py +20 -0
  683. scipy/linalg/decomp_schur.py +21 -0
  684. scipy/linalg/decomp_svd.py +21 -0
  685. scipy/linalg/interpolative.py +989 -0
  686. scipy/linalg/lapack.py +1081 -0
  687. scipy/linalg/matfuncs.py +23 -0
  688. scipy/linalg/misc.py +21 -0
  689. scipy/linalg/special_matrices.py +22 -0
  690. scipy/linalg/tests/__init__.py +0 -0
  691. scipy/linalg/tests/_cython_examples/extending.pyx +23 -0
  692. scipy/linalg/tests/_cython_examples/meson.build +34 -0
  693. scipy/linalg/tests/data/carex_15_data.npz +0 -0
  694. scipy/linalg/tests/data/carex_18_data.npz +0 -0
  695. scipy/linalg/tests/data/carex_19_data.npz +0 -0
  696. scipy/linalg/tests/data/carex_20_data.npz +0 -0
  697. scipy/linalg/tests/data/carex_6_data.npz +0 -0
  698. scipy/linalg/tests/data/gendare_20170120_data.npz +0 -0
  699. scipy/linalg/tests/test_basic.py +2074 -0
  700. scipy/linalg/tests/test_batch.py +588 -0
  701. scipy/linalg/tests/test_blas.py +1127 -0
  702. scipy/linalg/tests/test_cython_blas.py +118 -0
  703. scipy/linalg/tests/test_cython_lapack.py +22 -0
  704. scipy/linalg/tests/test_cythonized_array_utils.py +130 -0
  705. scipy/linalg/tests/test_decomp.py +3189 -0
  706. scipy/linalg/tests/test_decomp_cholesky.py +268 -0
  707. scipy/linalg/tests/test_decomp_cossin.py +314 -0
  708. scipy/linalg/tests/test_decomp_ldl.py +137 -0
  709. scipy/linalg/tests/test_decomp_lu.py +308 -0
  710. scipy/linalg/tests/test_decomp_polar.py +110 -0
  711. scipy/linalg/tests/test_decomp_update.py +1701 -0
  712. scipy/linalg/tests/test_extending.py +46 -0
  713. scipy/linalg/tests/test_fblas.py +607 -0
  714. scipy/linalg/tests/test_interpolative.py +232 -0
  715. scipy/linalg/tests/test_lapack.py +3620 -0
  716. scipy/linalg/tests/test_matfuncs.py +1125 -0
  717. scipy/linalg/tests/test_matmul_toeplitz.py +136 -0
  718. scipy/linalg/tests/test_procrustes.py +214 -0
  719. scipy/linalg/tests/test_sketches.py +118 -0
  720. scipy/linalg/tests/test_solve_toeplitz.py +150 -0
  721. scipy/linalg/tests/test_solvers.py +844 -0
  722. scipy/linalg/tests/test_special_matrices.py +636 -0
  723. scipy/misc/__init__.py +6 -0
  724. scipy/misc/common.py +6 -0
  725. scipy/misc/doccer.py +6 -0
  726. scipy/ndimage/__init__.py +174 -0
  727. scipy/ndimage/_ctest.cp311-win_arm64.lib +0 -0
  728. scipy/ndimage/_ctest.cp311-win_arm64.pyd +0 -0
  729. scipy/ndimage/_cytest.cp311-win_arm64.lib +0 -0
  730. scipy/ndimage/_cytest.cp311-win_arm64.pyd +0 -0
  731. scipy/ndimage/_delegators.py +303 -0
  732. scipy/ndimage/_filters.py +2422 -0
  733. scipy/ndimage/_fourier.py +306 -0
  734. scipy/ndimage/_interpolation.py +1033 -0
  735. scipy/ndimage/_measurements.py +1689 -0
  736. scipy/ndimage/_morphology.py +2634 -0
  737. scipy/ndimage/_nd_image.cp311-win_arm64.lib +0 -0
  738. scipy/ndimage/_nd_image.cp311-win_arm64.pyd +0 -0
  739. scipy/ndimage/_ndimage_api.py +16 -0
  740. scipy/ndimage/_ni_docstrings.py +214 -0
  741. scipy/ndimage/_ni_label.cp311-win_arm64.lib +0 -0
  742. scipy/ndimage/_ni_label.cp311-win_arm64.pyd +0 -0
  743. scipy/ndimage/_ni_support.py +139 -0
  744. scipy/ndimage/_rank_filter_1d.cp311-win_arm64.lib +0 -0
  745. scipy/ndimage/_rank_filter_1d.cp311-win_arm64.pyd +0 -0
  746. scipy/ndimage/_support_alternative_backends.py +84 -0
  747. scipy/ndimage/filters.py +27 -0
  748. scipy/ndimage/fourier.py +21 -0
  749. scipy/ndimage/interpolation.py +22 -0
  750. scipy/ndimage/measurements.py +24 -0
  751. scipy/ndimage/morphology.py +27 -0
  752. scipy/ndimage/tests/__init__.py +12 -0
  753. scipy/ndimage/tests/data/label_inputs.txt +21 -0
  754. scipy/ndimage/tests/data/label_results.txt +294 -0
  755. scipy/ndimage/tests/data/label_strels.txt +42 -0
  756. scipy/ndimage/tests/dots.png +0 -0
  757. scipy/ndimage/tests/test_c_api.py +102 -0
  758. scipy/ndimage/tests/test_datatypes.py +67 -0
  759. scipy/ndimage/tests/test_filters.py +3083 -0
  760. scipy/ndimage/tests/test_fourier.py +187 -0
  761. scipy/ndimage/tests/test_interpolation.py +1491 -0
  762. scipy/ndimage/tests/test_measurements.py +1592 -0
  763. scipy/ndimage/tests/test_morphology.py +2950 -0
  764. scipy/ndimage/tests/test_ni_support.py +78 -0
  765. scipy/ndimage/tests/test_splines.py +70 -0
  766. scipy/odr/__init__.py +131 -0
  767. scipy/odr/__odrpack.cp311-win_arm64.lib +0 -0
  768. scipy/odr/__odrpack.cp311-win_arm64.pyd +0 -0
  769. scipy/odr/_add_newdocs.py +34 -0
  770. scipy/odr/_models.py +315 -0
  771. scipy/odr/_odrpack.py +1154 -0
  772. scipy/odr/models.py +20 -0
  773. scipy/odr/odrpack.py +21 -0
  774. scipy/odr/tests/__init__.py +0 -0
  775. scipy/odr/tests/test_odr.py +607 -0
  776. scipy/optimize/__init__.pxd +1 -0
  777. scipy/optimize/__init__.py +460 -0
  778. scipy/optimize/_basinhopping.py +741 -0
  779. scipy/optimize/_bglu_dense.cp311-win_arm64.lib +0 -0
  780. scipy/optimize/_bglu_dense.cp311-win_arm64.pyd +0 -0
  781. scipy/optimize/_bracket.py +706 -0
  782. scipy/optimize/_chandrupatla.py +551 -0
  783. scipy/optimize/_cobyla_py.py +297 -0
  784. scipy/optimize/_cobyqa_py.py +72 -0
  785. scipy/optimize/_constraints.py +598 -0
  786. scipy/optimize/_dcsrch.py +728 -0
  787. scipy/optimize/_differentiable_functions.py +835 -0
  788. scipy/optimize/_differentialevolution.py +1970 -0
  789. scipy/optimize/_direct.cp311-win_arm64.lib +0 -0
  790. scipy/optimize/_direct.cp311-win_arm64.pyd +0 -0
  791. scipy/optimize/_direct_py.py +280 -0
  792. scipy/optimize/_dual_annealing.py +732 -0
  793. scipy/optimize/_elementwise.py +798 -0
  794. scipy/optimize/_group_columns.cp311-win_arm64.lib +0 -0
  795. scipy/optimize/_group_columns.cp311-win_arm64.pyd +0 -0
  796. scipy/optimize/_hessian_update_strategy.py +479 -0
  797. scipy/optimize/_highspy/__init__.py +0 -0
  798. scipy/optimize/_highspy/_core.cp311-win_arm64.lib +0 -0
  799. scipy/optimize/_highspy/_core.cp311-win_arm64.pyd +0 -0
  800. scipy/optimize/_highspy/_highs_options.cp311-win_arm64.lib +0 -0
  801. scipy/optimize/_highspy/_highs_options.cp311-win_arm64.pyd +0 -0
  802. scipy/optimize/_highspy/_highs_wrapper.py +338 -0
  803. scipy/optimize/_isotonic.py +157 -0
  804. scipy/optimize/_lbfgsb.cp311-win_arm64.lib +0 -0
  805. scipy/optimize/_lbfgsb.cp311-win_arm64.pyd +0 -0
  806. scipy/optimize/_lbfgsb_py.py +634 -0
  807. scipy/optimize/_linesearch.py +896 -0
  808. scipy/optimize/_linprog.py +733 -0
  809. scipy/optimize/_linprog_doc.py +1434 -0
  810. scipy/optimize/_linprog_highs.py +422 -0
  811. scipy/optimize/_linprog_ip.py +1141 -0
  812. scipy/optimize/_linprog_rs.py +572 -0
  813. scipy/optimize/_linprog_simplex.py +663 -0
  814. scipy/optimize/_linprog_util.py +1521 -0
  815. scipy/optimize/_lsap.cp311-win_arm64.lib +0 -0
  816. scipy/optimize/_lsap.cp311-win_arm64.pyd +0 -0
  817. scipy/optimize/_lsq/__init__.py +5 -0
  818. scipy/optimize/_lsq/bvls.py +183 -0
  819. scipy/optimize/_lsq/common.py +731 -0
  820. scipy/optimize/_lsq/dogbox.py +345 -0
  821. scipy/optimize/_lsq/givens_elimination.cp311-win_arm64.lib +0 -0
  822. scipy/optimize/_lsq/givens_elimination.cp311-win_arm64.pyd +0 -0
  823. scipy/optimize/_lsq/least_squares.py +1044 -0
  824. scipy/optimize/_lsq/lsq_linear.py +361 -0
  825. scipy/optimize/_lsq/trf.py +587 -0
  826. scipy/optimize/_lsq/trf_linear.py +249 -0
  827. scipy/optimize/_milp.py +394 -0
  828. scipy/optimize/_minimize.py +1199 -0
  829. scipy/optimize/_minpack.cp311-win_arm64.lib +0 -0
  830. scipy/optimize/_minpack.cp311-win_arm64.pyd +0 -0
  831. scipy/optimize/_minpack_py.py +1178 -0
  832. scipy/optimize/_moduleTNC.cp311-win_arm64.lib +0 -0
  833. scipy/optimize/_moduleTNC.cp311-win_arm64.pyd +0 -0
  834. scipy/optimize/_nnls.py +96 -0
  835. scipy/optimize/_nonlin.py +1634 -0
  836. scipy/optimize/_numdiff.py +963 -0
  837. scipy/optimize/_optimize.py +4169 -0
  838. scipy/optimize/_pava_pybind.cp311-win_arm64.lib +0 -0
  839. scipy/optimize/_pava_pybind.cp311-win_arm64.pyd +0 -0
  840. scipy/optimize/_qap.py +760 -0
  841. scipy/optimize/_remove_redundancy.py +522 -0
  842. scipy/optimize/_root.py +732 -0
  843. scipy/optimize/_root_scalar.py +538 -0
  844. scipy/optimize/_shgo.py +1606 -0
  845. scipy/optimize/_shgo_lib/__init__.py +0 -0
  846. scipy/optimize/_shgo_lib/_complex.py +1225 -0
  847. scipy/optimize/_shgo_lib/_vertex.py +460 -0
  848. scipy/optimize/_slsqp_py.py +603 -0
  849. scipy/optimize/_slsqplib.cp311-win_arm64.lib +0 -0
  850. scipy/optimize/_slsqplib.cp311-win_arm64.pyd +0 -0
  851. scipy/optimize/_spectral.py +260 -0
  852. scipy/optimize/_tnc.py +438 -0
  853. scipy/optimize/_trlib/__init__.py +12 -0
  854. scipy/optimize/_trlib/_trlib.cp311-win_arm64.lib +0 -0
  855. scipy/optimize/_trlib/_trlib.cp311-win_arm64.pyd +0 -0
  856. scipy/optimize/_trustregion.py +318 -0
  857. scipy/optimize/_trustregion_constr/__init__.py +6 -0
  858. scipy/optimize/_trustregion_constr/canonical_constraint.py +390 -0
  859. scipy/optimize/_trustregion_constr/equality_constrained_sqp.py +231 -0
  860. scipy/optimize/_trustregion_constr/minimize_trustregion_constr.py +584 -0
  861. scipy/optimize/_trustregion_constr/projections.py +411 -0
  862. scipy/optimize/_trustregion_constr/qp_subproblem.py +637 -0
  863. scipy/optimize/_trustregion_constr/report.py +49 -0
  864. scipy/optimize/_trustregion_constr/tests/__init__.py +0 -0
  865. scipy/optimize/_trustregion_constr/tests/test_canonical_constraint.py +296 -0
  866. scipy/optimize/_trustregion_constr/tests/test_nested_minimize.py +39 -0
  867. scipy/optimize/_trustregion_constr/tests/test_projections.py +214 -0
  868. scipy/optimize/_trustregion_constr/tests/test_qp_subproblem.py +645 -0
  869. scipy/optimize/_trustregion_constr/tests/test_report.py +34 -0
  870. scipy/optimize/_trustregion_constr/tr_interior_point.py +361 -0
  871. scipy/optimize/_trustregion_dogleg.py +122 -0
  872. scipy/optimize/_trustregion_exact.py +437 -0
  873. scipy/optimize/_trustregion_krylov.py +65 -0
  874. scipy/optimize/_trustregion_ncg.py +126 -0
  875. scipy/optimize/_tstutils.py +972 -0
  876. scipy/optimize/_zeros.cp311-win_arm64.lib +0 -0
  877. scipy/optimize/_zeros.cp311-win_arm64.pyd +0 -0
  878. scipy/optimize/_zeros_py.py +1475 -0
  879. scipy/optimize/cobyla.py +19 -0
  880. scipy/optimize/cython_optimize/__init__.py +133 -0
  881. scipy/optimize/cython_optimize/_zeros.cp311-win_arm64.lib +0 -0
  882. scipy/optimize/cython_optimize/_zeros.cp311-win_arm64.pyd +0 -0
  883. scipy/optimize/cython_optimize/_zeros.pxd +33 -0
  884. scipy/optimize/cython_optimize/c_zeros.pxd +26 -0
  885. scipy/optimize/cython_optimize.pxd +11 -0
  886. scipy/optimize/elementwise.py +38 -0
  887. scipy/optimize/lbfgsb.py +23 -0
  888. scipy/optimize/linesearch.py +18 -0
  889. scipy/optimize/minpack.py +27 -0
  890. scipy/optimize/minpack2.py +17 -0
  891. scipy/optimize/moduleTNC.py +19 -0
  892. scipy/optimize/nonlin.py +29 -0
  893. scipy/optimize/optimize.py +40 -0
  894. scipy/optimize/slsqp.py +22 -0
  895. scipy/optimize/tests/__init__.py +0 -0
  896. scipy/optimize/tests/_cython_examples/extending.pyx +43 -0
  897. scipy/optimize/tests/_cython_examples/meson.build +32 -0
  898. scipy/optimize/tests/test__basinhopping.py +535 -0
  899. scipy/optimize/tests/test__differential_evolution.py +1703 -0
  900. scipy/optimize/tests/test__dual_annealing.py +416 -0
  901. scipy/optimize/tests/test__linprog_clean_inputs.py +312 -0
  902. scipy/optimize/tests/test__numdiff.py +885 -0
  903. scipy/optimize/tests/test__remove_redundancy.py +228 -0
  904. scipy/optimize/tests/test__root.py +124 -0
  905. scipy/optimize/tests/test__shgo.py +1164 -0
  906. scipy/optimize/tests/test__spectral.py +226 -0
  907. scipy/optimize/tests/test_bracket.py +896 -0
  908. scipy/optimize/tests/test_chandrupatla.py +982 -0
  909. scipy/optimize/tests/test_cobyla.py +195 -0
  910. scipy/optimize/tests/test_cobyqa.py +252 -0
  911. scipy/optimize/tests/test_constraint_conversion.py +286 -0
  912. scipy/optimize/tests/test_constraints.py +255 -0
  913. scipy/optimize/tests/test_cython_optimize.py +92 -0
  914. scipy/optimize/tests/test_differentiable_functions.py +1025 -0
  915. scipy/optimize/tests/test_direct.py +321 -0
  916. scipy/optimize/tests/test_extending.py +28 -0
  917. scipy/optimize/tests/test_hessian_update_strategy.py +300 -0
  918. scipy/optimize/tests/test_isotonic_regression.py +167 -0
  919. scipy/optimize/tests/test_lbfgsb_hessinv.py +65 -0
  920. scipy/optimize/tests/test_lbfgsb_setulb.py +122 -0
  921. scipy/optimize/tests/test_least_squares.py +986 -0
  922. scipy/optimize/tests/test_linear_assignment.py +116 -0
  923. scipy/optimize/tests/test_linesearch.py +328 -0
  924. scipy/optimize/tests/test_linprog.py +2577 -0
  925. scipy/optimize/tests/test_lsq_common.py +297 -0
  926. scipy/optimize/tests/test_lsq_linear.py +287 -0
  927. scipy/optimize/tests/test_milp.py +459 -0
  928. scipy/optimize/tests/test_minimize_constrained.py +845 -0
  929. scipy/optimize/tests/test_minpack.py +1194 -0
  930. scipy/optimize/tests/test_nnls.py +469 -0
  931. scipy/optimize/tests/test_nonlin.py +572 -0
  932. scipy/optimize/tests/test_optimize.py +3344 -0
  933. scipy/optimize/tests/test_quadratic_assignment.py +455 -0
  934. scipy/optimize/tests/test_regression.py +40 -0
  935. scipy/optimize/tests/test_slsqp.py +645 -0
  936. scipy/optimize/tests/test_tnc.py +345 -0
  937. scipy/optimize/tests/test_trustregion.py +110 -0
  938. scipy/optimize/tests/test_trustregion_exact.py +351 -0
  939. scipy/optimize/tests/test_trustregion_krylov.py +170 -0
  940. scipy/optimize/tests/test_zeros.py +998 -0
  941. scipy/optimize/tnc.py +22 -0
  942. scipy/optimize/zeros.py +26 -0
  943. scipy/signal/__init__.py +316 -0
  944. scipy/signal/_arraytools.py +264 -0
  945. scipy/signal/_czt.py +575 -0
  946. scipy/signal/_delegators.py +568 -0
  947. scipy/signal/_filter_design.py +5893 -0
  948. scipy/signal/_fir_filter_design.py +1458 -0
  949. scipy/signal/_lti_conversion.py +534 -0
  950. scipy/signal/_ltisys.py +3546 -0
  951. scipy/signal/_max_len_seq.py +139 -0
  952. scipy/signal/_max_len_seq_inner.cp311-win_arm64.lib +0 -0
  953. scipy/signal/_max_len_seq_inner.cp311-win_arm64.pyd +0 -0
  954. scipy/signal/_peak_finding.py +1310 -0
  955. scipy/signal/_peak_finding_utils.cp311-win_arm64.lib +0 -0
  956. scipy/signal/_peak_finding_utils.cp311-win_arm64.pyd +0 -0
  957. scipy/signal/_polyutils.py +172 -0
  958. scipy/signal/_savitzky_golay.py +357 -0
  959. scipy/signal/_short_time_fft.py +2228 -0
  960. scipy/signal/_signal_api.py +30 -0
  961. scipy/signal/_signaltools.py +5309 -0
  962. scipy/signal/_sigtools.cp311-win_arm64.lib +0 -0
  963. scipy/signal/_sigtools.cp311-win_arm64.pyd +0 -0
  964. scipy/signal/_sosfilt.cp311-win_arm64.lib +0 -0
  965. scipy/signal/_sosfilt.cp311-win_arm64.pyd +0 -0
  966. scipy/signal/_spectral_py.py +2471 -0
  967. scipy/signal/_spline.cp311-win_arm64.lib +0 -0
  968. scipy/signal/_spline.cp311-win_arm64.pyd +0 -0
  969. scipy/signal/_spline.pyi +34 -0
  970. scipy/signal/_spline_filters.py +848 -0
  971. scipy/signal/_support_alternative_backends.py +73 -0
  972. scipy/signal/_upfirdn.py +219 -0
  973. scipy/signal/_upfirdn_apply.cp311-win_arm64.lib +0 -0
  974. scipy/signal/_upfirdn_apply.cp311-win_arm64.pyd +0 -0
  975. scipy/signal/_waveforms.py +687 -0
  976. scipy/signal/_wavelets.py +29 -0
  977. scipy/signal/bsplines.py +21 -0
  978. scipy/signal/filter_design.py +28 -0
  979. scipy/signal/fir_filter_design.py +21 -0
  980. scipy/signal/lti_conversion.py +20 -0
  981. scipy/signal/ltisys.py +25 -0
  982. scipy/signal/signaltools.py +27 -0
  983. scipy/signal/spectral.py +21 -0
  984. scipy/signal/spline.py +18 -0
  985. scipy/signal/tests/__init__.py +0 -0
  986. scipy/signal/tests/_scipy_spectral_test_shim.py +311 -0
  987. scipy/signal/tests/mpsig.py +122 -0
  988. scipy/signal/tests/test_array_tools.py +111 -0
  989. scipy/signal/tests/test_bsplines.py +365 -0
  990. scipy/signal/tests/test_cont2discrete.py +424 -0
  991. scipy/signal/tests/test_czt.py +221 -0
  992. scipy/signal/tests/test_dltisys.py +599 -0
  993. scipy/signal/tests/test_filter_design.py +4744 -0
  994. scipy/signal/tests/test_fir_filter_design.py +851 -0
  995. scipy/signal/tests/test_ltisys.py +1225 -0
  996. scipy/signal/tests/test_max_len_seq.py +71 -0
  997. scipy/signal/tests/test_peak_finding.py +915 -0
  998. scipy/signal/tests/test_result_type.py +51 -0
  999. scipy/signal/tests/test_savitzky_golay.py +363 -0
  1000. scipy/signal/tests/test_short_time_fft.py +1107 -0
  1001. scipy/signal/tests/test_signaltools.py +4735 -0
  1002. scipy/signal/tests/test_spectral.py +2141 -0
  1003. scipy/signal/tests/test_splines.py +427 -0
  1004. scipy/signal/tests/test_upfirdn.py +322 -0
  1005. scipy/signal/tests/test_waveforms.py +400 -0
  1006. scipy/signal/tests/test_wavelets.py +59 -0
  1007. scipy/signal/tests/test_windows.py +987 -0
  1008. scipy/signal/waveforms.py +20 -0
  1009. scipy/signal/wavelets.py +17 -0
  1010. scipy/signal/windows/__init__.py +52 -0
  1011. scipy/signal/windows/_windows.py +2513 -0
  1012. scipy/signal/windows/windows.py +23 -0
  1013. scipy/sparse/__init__.py +350 -0
  1014. scipy/sparse/_base.py +1613 -0
  1015. scipy/sparse/_bsr.py +880 -0
  1016. scipy/sparse/_compressed.py +1328 -0
  1017. scipy/sparse/_construct.py +1454 -0
  1018. scipy/sparse/_coo.py +1581 -0
  1019. scipy/sparse/_csc.py +367 -0
  1020. scipy/sparse/_csparsetools.cp311-win_arm64.lib +0 -0
  1021. scipy/sparse/_csparsetools.cp311-win_arm64.pyd +0 -0
  1022. scipy/sparse/_csr.py +558 -0
  1023. scipy/sparse/_data.py +569 -0
  1024. scipy/sparse/_dia.py +677 -0
  1025. scipy/sparse/_dok.py +669 -0
  1026. scipy/sparse/_extract.py +178 -0
  1027. scipy/sparse/_index.py +444 -0
  1028. scipy/sparse/_lil.py +632 -0
  1029. scipy/sparse/_matrix.py +169 -0
  1030. scipy/sparse/_matrix_io.py +167 -0
  1031. scipy/sparse/_sparsetools.cp311-win_arm64.lib +0 -0
  1032. scipy/sparse/_sparsetools.cp311-win_arm64.pyd +0 -0
  1033. scipy/sparse/_spfuncs.py +76 -0
  1034. scipy/sparse/_sputils.py +632 -0
  1035. scipy/sparse/base.py +24 -0
  1036. scipy/sparse/bsr.py +22 -0
  1037. scipy/sparse/compressed.py +20 -0
  1038. scipy/sparse/construct.py +38 -0
  1039. scipy/sparse/coo.py +23 -0
  1040. scipy/sparse/csc.py +22 -0
  1041. scipy/sparse/csgraph/__init__.py +210 -0
  1042. scipy/sparse/csgraph/_flow.cp311-win_arm64.lib +0 -0
  1043. scipy/sparse/csgraph/_flow.cp311-win_arm64.pyd +0 -0
  1044. scipy/sparse/csgraph/_laplacian.py +563 -0
  1045. scipy/sparse/csgraph/_matching.cp311-win_arm64.lib +0 -0
  1046. scipy/sparse/csgraph/_matching.cp311-win_arm64.pyd +0 -0
  1047. scipy/sparse/csgraph/_min_spanning_tree.cp311-win_arm64.lib +0 -0
  1048. scipy/sparse/csgraph/_min_spanning_tree.cp311-win_arm64.pyd +0 -0
  1049. scipy/sparse/csgraph/_reordering.cp311-win_arm64.lib +0 -0
  1050. scipy/sparse/csgraph/_reordering.cp311-win_arm64.pyd +0 -0
  1051. scipy/sparse/csgraph/_shortest_path.cp311-win_arm64.lib +0 -0
  1052. scipy/sparse/csgraph/_shortest_path.cp311-win_arm64.pyd +0 -0
  1053. scipy/sparse/csgraph/_tools.cp311-win_arm64.lib +0 -0
  1054. scipy/sparse/csgraph/_tools.cp311-win_arm64.pyd +0 -0
  1055. scipy/sparse/csgraph/_traversal.cp311-win_arm64.lib +0 -0
  1056. scipy/sparse/csgraph/_traversal.cp311-win_arm64.pyd +0 -0
  1057. scipy/sparse/csgraph/_validation.py +66 -0
  1058. scipy/sparse/csgraph/tests/__init__.py +0 -0
  1059. scipy/sparse/csgraph/tests/test_connected_components.py +119 -0
  1060. scipy/sparse/csgraph/tests/test_conversions.py +61 -0
  1061. scipy/sparse/csgraph/tests/test_flow.py +209 -0
  1062. scipy/sparse/csgraph/tests/test_graph_laplacian.py +368 -0
  1063. scipy/sparse/csgraph/tests/test_matching.py +307 -0
  1064. scipy/sparse/csgraph/tests/test_pydata_sparse.py +197 -0
  1065. scipy/sparse/csgraph/tests/test_reordering.py +70 -0
  1066. scipy/sparse/csgraph/tests/test_shortest_path.py +540 -0
  1067. scipy/sparse/csgraph/tests/test_spanning_tree.py +66 -0
  1068. scipy/sparse/csgraph/tests/test_traversal.py +148 -0
  1069. scipy/sparse/csr.py +22 -0
  1070. scipy/sparse/data.py +18 -0
  1071. scipy/sparse/dia.py +22 -0
  1072. scipy/sparse/dok.py +22 -0
  1073. scipy/sparse/extract.py +23 -0
  1074. scipy/sparse/lil.py +22 -0
  1075. scipy/sparse/linalg/__init__.py +148 -0
  1076. scipy/sparse/linalg/_dsolve/__init__.py +71 -0
  1077. scipy/sparse/linalg/_dsolve/_add_newdocs.py +147 -0
  1078. scipy/sparse/linalg/_dsolve/_superlu.cp311-win_arm64.lib +0 -0
  1079. scipy/sparse/linalg/_dsolve/_superlu.cp311-win_arm64.pyd +0 -0
  1080. scipy/sparse/linalg/_dsolve/linsolve.py +882 -0
  1081. scipy/sparse/linalg/_dsolve/tests/__init__.py +0 -0
  1082. scipy/sparse/linalg/_dsolve/tests/test_linsolve.py +928 -0
  1083. scipy/sparse/linalg/_eigen/__init__.py +22 -0
  1084. scipy/sparse/linalg/_eigen/_svds.py +540 -0
  1085. scipy/sparse/linalg/_eigen/_svds_doc.py +382 -0
  1086. scipy/sparse/linalg/_eigen/arpack/COPYING +45 -0
  1087. scipy/sparse/linalg/_eigen/arpack/__init__.py +20 -0
  1088. scipy/sparse/linalg/_eigen/arpack/_arpack.cp311-win_arm64.lib +0 -0
  1089. scipy/sparse/linalg/_eigen/arpack/_arpack.cp311-win_arm64.pyd +0 -0
  1090. scipy/sparse/linalg/_eigen/arpack/arpack.py +1706 -0
  1091. scipy/sparse/linalg/_eigen/arpack/tests/__init__.py +0 -0
  1092. scipy/sparse/linalg/_eigen/arpack/tests/test_arpack.py +717 -0
  1093. scipy/sparse/linalg/_eigen/lobpcg/__init__.py +16 -0
  1094. scipy/sparse/linalg/_eigen/lobpcg/lobpcg.py +1110 -0
  1095. scipy/sparse/linalg/_eigen/lobpcg/tests/__init__.py +0 -0
  1096. scipy/sparse/linalg/_eigen/lobpcg/tests/test_lobpcg.py +725 -0
  1097. scipy/sparse/linalg/_eigen/tests/__init__.py +0 -0
  1098. scipy/sparse/linalg/_eigen/tests/test_svds.py +886 -0
  1099. scipy/sparse/linalg/_expm_multiply.py +816 -0
  1100. scipy/sparse/linalg/_interface.py +920 -0
  1101. scipy/sparse/linalg/_isolve/__init__.py +20 -0
  1102. scipy/sparse/linalg/_isolve/_gcrotmk.py +503 -0
  1103. scipy/sparse/linalg/_isolve/iterative.py +1051 -0
  1104. scipy/sparse/linalg/_isolve/lgmres.py +230 -0
  1105. scipy/sparse/linalg/_isolve/lsmr.py +486 -0
  1106. scipy/sparse/linalg/_isolve/lsqr.py +589 -0
  1107. scipy/sparse/linalg/_isolve/minres.py +372 -0
  1108. scipy/sparse/linalg/_isolve/tests/__init__.py +0 -0
  1109. scipy/sparse/linalg/_isolve/tests/test_gcrotmk.py +183 -0
  1110. scipy/sparse/linalg/_isolve/tests/test_iterative.py +809 -0
  1111. scipy/sparse/linalg/_isolve/tests/test_lgmres.py +225 -0
  1112. scipy/sparse/linalg/_isolve/tests/test_lsmr.py +185 -0
  1113. scipy/sparse/linalg/_isolve/tests/test_lsqr.py +120 -0
  1114. scipy/sparse/linalg/_isolve/tests/test_minres.py +97 -0
  1115. scipy/sparse/linalg/_isolve/tests/test_utils.py +9 -0
  1116. scipy/sparse/linalg/_isolve/tfqmr.py +179 -0
  1117. scipy/sparse/linalg/_isolve/utils.py +121 -0
  1118. scipy/sparse/linalg/_matfuncs.py +940 -0
  1119. scipy/sparse/linalg/_norm.py +195 -0
  1120. scipy/sparse/linalg/_onenormest.py +467 -0
  1121. scipy/sparse/linalg/_propack/_cpropack.cp311-win_arm64.lib +0 -0
  1122. scipy/sparse/linalg/_propack/_cpropack.cp311-win_arm64.pyd +0 -0
  1123. scipy/sparse/linalg/_propack/_dpropack.cp311-win_arm64.lib +0 -0
  1124. scipy/sparse/linalg/_propack/_dpropack.cp311-win_arm64.pyd +0 -0
  1125. scipy/sparse/linalg/_propack/_spropack.cp311-win_arm64.lib +0 -0
  1126. scipy/sparse/linalg/_propack/_spropack.cp311-win_arm64.pyd +0 -0
  1127. scipy/sparse/linalg/_propack/_zpropack.cp311-win_arm64.lib +0 -0
  1128. scipy/sparse/linalg/_propack/_zpropack.cp311-win_arm64.pyd +0 -0
  1129. scipy/sparse/linalg/_special_sparse_arrays.py +949 -0
  1130. scipy/sparse/linalg/_svdp.py +309 -0
  1131. scipy/sparse/linalg/dsolve.py +22 -0
  1132. scipy/sparse/linalg/eigen.py +21 -0
  1133. scipy/sparse/linalg/interface.py +20 -0
  1134. scipy/sparse/linalg/isolve.py +22 -0
  1135. scipy/sparse/linalg/matfuncs.py +18 -0
  1136. scipy/sparse/linalg/tests/__init__.py +0 -0
  1137. scipy/sparse/linalg/tests/propack_test_data.npz +0 -0
  1138. scipy/sparse/linalg/tests/test_expm_multiply.py +367 -0
  1139. scipy/sparse/linalg/tests/test_interface.py +561 -0
  1140. scipy/sparse/linalg/tests/test_matfuncs.py +592 -0
  1141. scipy/sparse/linalg/tests/test_norm.py +154 -0
  1142. scipy/sparse/linalg/tests/test_onenormest.py +252 -0
  1143. scipy/sparse/linalg/tests/test_propack.py +165 -0
  1144. scipy/sparse/linalg/tests/test_pydata_sparse.py +272 -0
  1145. scipy/sparse/linalg/tests/test_special_sparse_arrays.py +337 -0
  1146. scipy/sparse/sparsetools.py +17 -0
  1147. scipy/sparse/spfuncs.py +17 -0
  1148. scipy/sparse/sputils.py +17 -0
  1149. scipy/sparse/tests/__init__.py +0 -0
  1150. scipy/sparse/tests/data/csc_py2.npz +0 -0
  1151. scipy/sparse/tests/data/csc_py3.npz +0 -0
  1152. scipy/sparse/tests/test_arithmetic1d.py +341 -0
  1153. scipy/sparse/tests/test_array_api.py +561 -0
  1154. scipy/sparse/tests/test_base.py +5870 -0
  1155. scipy/sparse/tests/test_common1d.py +447 -0
  1156. scipy/sparse/tests/test_construct.py +872 -0
  1157. scipy/sparse/tests/test_coo.py +1119 -0
  1158. scipy/sparse/tests/test_csc.py +98 -0
  1159. scipy/sparse/tests/test_csr.py +214 -0
  1160. scipy/sparse/tests/test_dok.py +209 -0
  1161. scipy/sparse/tests/test_extract.py +51 -0
  1162. scipy/sparse/tests/test_indexing1d.py +603 -0
  1163. scipy/sparse/tests/test_matrix_io.py +109 -0
  1164. scipy/sparse/tests/test_minmax1d.py +128 -0
  1165. scipy/sparse/tests/test_sparsetools.py +344 -0
  1166. scipy/sparse/tests/test_spfuncs.py +97 -0
  1167. scipy/sparse/tests/test_sputils.py +424 -0
  1168. scipy/spatial/__init__.py +129 -0
  1169. scipy/spatial/_ckdtree.cp311-win_arm64.lib +0 -0
  1170. scipy/spatial/_ckdtree.cp311-win_arm64.pyd +0 -0
  1171. scipy/spatial/_distance_pybind.cp311-win_arm64.lib +0 -0
  1172. scipy/spatial/_distance_pybind.cp311-win_arm64.pyd +0 -0
  1173. scipy/spatial/_distance_wrap.cp311-win_arm64.lib +0 -0
  1174. scipy/spatial/_distance_wrap.cp311-win_arm64.pyd +0 -0
  1175. scipy/spatial/_geometric_slerp.py +238 -0
  1176. scipy/spatial/_hausdorff.cp311-win_arm64.lib +0 -0
  1177. scipy/spatial/_hausdorff.cp311-win_arm64.pyd +0 -0
  1178. scipy/spatial/_kdtree.py +920 -0
  1179. scipy/spatial/_plotutils.py +274 -0
  1180. scipy/spatial/_procrustes.py +132 -0
  1181. scipy/spatial/_qhull.cp311-win_arm64.lib +0 -0
  1182. scipy/spatial/_qhull.cp311-win_arm64.pyd +0 -0
  1183. scipy/spatial/_qhull.pyi +213 -0
  1184. scipy/spatial/_spherical_voronoi.py +341 -0
  1185. scipy/spatial/_voronoi.cp311-win_arm64.lib +0 -0
  1186. scipy/spatial/_voronoi.cp311-win_arm64.pyd +0 -0
  1187. scipy/spatial/_voronoi.pyi +4 -0
  1188. scipy/spatial/ckdtree.py +18 -0
  1189. scipy/spatial/distance.py +3147 -0
  1190. scipy/spatial/distance.pyi +210 -0
  1191. scipy/spatial/kdtree.py +25 -0
  1192. scipy/spatial/qhull.py +25 -0
  1193. scipy/spatial/qhull_src/COPYING_QHULL.txt +39 -0
  1194. scipy/spatial/tests/__init__.py +0 -0
  1195. scipy/spatial/tests/data/cdist-X1.txt +10 -0
  1196. scipy/spatial/tests/data/cdist-X2.txt +20 -0
  1197. scipy/spatial/tests/data/degenerate_pointset.npz +0 -0
  1198. scipy/spatial/tests/data/iris.txt +150 -0
  1199. scipy/spatial/tests/data/pdist-boolean-inp.txt +20 -0
  1200. scipy/spatial/tests/data/pdist-chebyshev-ml-iris.txt +1 -0
  1201. scipy/spatial/tests/data/pdist-chebyshev-ml.txt +1 -0
  1202. scipy/spatial/tests/data/pdist-cityblock-ml-iris.txt +1 -0
  1203. scipy/spatial/tests/data/pdist-cityblock-ml.txt +1 -0
  1204. scipy/spatial/tests/data/pdist-correlation-ml-iris.txt +1 -0
  1205. scipy/spatial/tests/data/pdist-correlation-ml.txt +1 -0
  1206. scipy/spatial/tests/data/pdist-cosine-ml-iris.txt +1 -0
  1207. scipy/spatial/tests/data/pdist-cosine-ml.txt +1 -0
  1208. scipy/spatial/tests/data/pdist-double-inp.txt +20 -0
  1209. scipy/spatial/tests/data/pdist-euclidean-ml-iris.txt +1 -0
  1210. scipy/spatial/tests/data/pdist-euclidean-ml.txt +1 -0
  1211. scipy/spatial/tests/data/pdist-hamming-ml.txt +1 -0
  1212. scipy/spatial/tests/data/pdist-jaccard-ml.txt +1 -0
  1213. scipy/spatial/tests/data/pdist-jensenshannon-ml-iris.txt +1 -0
  1214. scipy/spatial/tests/data/pdist-jensenshannon-ml.txt +1 -0
  1215. scipy/spatial/tests/data/pdist-minkowski-3.2-ml-iris.txt +1 -0
  1216. scipy/spatial/tests/data/pdist-minkowski-3.2-ml.txt +1 -0
  1217. scipy/spatial/tests/data/pdist-minkowski-5.8-ml-iris.txt +1 -0
  1218. scipy/spatial/tests/data/pdist-seuclidean-ml-iris.txt +1 -0
  1219. scipy/spatial/tests/data/pdist-seuclidean-ml.txt +1 -0
  1220. scipy/spatial/tests/data/pdist-spearman-ml.txt +1 -0
  1221. scipy/spatial/tests/data/random-bool-data.txt +100 -0
  1222. scipy/spatial/tests/data/random-double-data.txt +100 -0
  1223. scipy/spatial/tests/data/random-int-data.txt +100 -0
  1224. scipy/spatial/tests/data/random-uint-data.txt +100 -0
  1225. scipy/spatial/tests/data/selfdual-4d-polytope.txt +27 -0
  1226. scipy/spatial/tests/test__plotutils.py +91 -0
  1227. scipy/spatial/tests/test__procrustes.py +116 -0
  1228. scipy/spatial/tests/test_distance.py +2389 -0
  1229. scipy/spatial/tests/test_hausdorff.py +199 -0
  1230. scipy/spatial/tests/test_kdtree.py +1536 -0
  1231. scipy/spatial/tests/test_qhull.py +1313 -0
  1232. scipy/spatial/tests/test_slerp.py +417 -0
  1233. scipy/spatial/tests/test_spherical_voronoi.py +358 -0
  1234. scipy/spatial/transform/__init__.py +31 -0
  1235. scipy/spatial/transform/_rigid_transform.cp311-win_arm64.lib +0 -0
  1236. scipy/spatial/transform/_rigid_transform.cp311-win_arm64.pyd +0 -0
  1237. scipy/spatial/transform/_rotation.cp311-win_arm64.lib +0 -0
  1238. scipy/spatial/transform/_rotation.cp311-win_arm64.pyd +0 -0
  1239. scipy/spatial/transform/_rotation_groups.py +140 -0
  1240. scipy/spatial/transform/_rotation_spline.py +460 -0
  1241. scipy/spatial/transform/rotation.py +21 -0
  1242. scipy/spatial/transform/tests/__init__.py +0 -0
  1243. scipy/spatial/transform/tests/test_rigid_transform.py +1221 -0
  1244. scipy/spatial/transform/tests/test_rotation.py +2569 -0
  1245. scipy/spatial/transform/tests/test_rotation_groups.py +169 -0
  1246. scipy/spatial/transform/tests/test_rotation_spline.py +183 -0
  1247. scipy/special/__init__.pxd +1 -0
  1248. scipy/special/__init__.py +841 -0
  1249. scipy/special/_add_newdocs.py +9961 -0
  1250. scipy/special/_basic.py +3576 -0
  1251. scipy/special/_comb.cp311-win_arm64.lib +0 -0
  1252. scipy/special/_comb.cp311-win_arm64.pyd +0 -0
  1253. scipy/special/_ellip_harm.py +214 -0
  1254. scipy/special/_ellip_harm_2.cp311-win_arm64.lib +0 -0
  1255. scipy/special/_ellip_harm_2.cp311-win_arm64.pyd +0 -0
  1256. scipy/special/_gufuncs.cp311-win_arm64.lib +0 -0
  1257. scipy/special/_gufuncs.cp311-win_arm64.pyd +0 -0
  1258. scipy/special/_input_validation.py +17 -0
  1259. scipy/special/_lambertw.py +149 -0
  1260. scipy/special/_logsumexp.py +426 -0
  1261. scipy/special/_mptestutils.py +453 -0
  1262. scipy/special/_multiufuncs.py +610 -0
  1263. scipy/special/_orthogonal.py +2592 -0
  1264. scipy/special/_orthogonal.pyi +330 -0
  1265. scipy/special/_precompute/__init__.py +0 -0
  1266. scipy/special/_precompute/cosine_cdf.py +17 -0
  1267. scipy/special/_precompute/expn_asy.py +54 -0
  1268. scipy/special/_precompute/gammainc_asy.py +116 -0
  1269. scipy/special/_precompute/gammainc_data.py +124 -0
  1270. scipy/special/_precompute/hyp2f1_data.py +484 -0
  1271. scipy/special/_precompute/lambertw.py +68 -0
  1272. scipy/special/_precompute/loggamma.py +43 -0
  1273. scipy/special/_precompute/struve_convergence.py +131 -0
  1274. scipy/special/_precompute/utils.py +38 -0
  1275. scipy/special/_precompute/wright_bessel.py +342 -0
  1276. scipy/special/_precompute/wright_bessel_data.py +152 -0
  1277. scipy/special/_precompute/wrightomega.py +41 -0
  1278. scipy/special/_precompute/zetac.py +27 -0
  1279. scipy/special/_sf_error.py +15 -0
  1280. scipy/special/_specfun.cp311-win_arm64.lib +0 -0
  1281. scipy/special/_specfun.cp311-win_arm64.pyd +0 -0
  1282. scipy/special/_special_ufuncs.cp311-win_arm64.lib +0 -0
  1283. scipy/special/_special_ufuncs.cp311-win_arm64.pyd +0 -0
  1284. scipy/special/_spfun_stats.py +106 -0
  1285. scipy/special/_spherical_bessel.py +397 -0
  1286. scipy/special/_support_alternative_backends.py +295 -0
  1287. scipy/special/_test_internal.cp311-win_arm64.lib +0 -0
  1288. scipy/special/_test_internal.cp311-win_arm64.pyd +0 -0
  1289. scipy/special/_test_internal.pyi +9 -0
  1290. scipy/special/_testutils.py +321 -0
  1291. scipy/special/_ufuncs.cp311-win_arm64.lib +0 -0
  1292. scipy/special/_ufuncs.cp311-win_arm64.pyd +0 -0
  1293. scipy/special/_ufuncs.pyi +522 -0
  1294. scipy/special/_ufuncs.pyx +13173 -0
  1295. scipy/special/_ufuncs_cxx.cp311-win_arm64.lib +0 -0
  1296. scipy/special/_ufuncs_cxx.cp311-win_arm64.pyd +0 -0
  1297. scipy/special/_ufuncs_cxx.pxd +142 -0
  1298. scipy/special/_ufuncs_cxx.pyx +427 -0
  1299. scipy/special/_ufuncs_cxx_defs.h +147 -0
  1300. scipy/special/_ufuncs_defs.h +57 -0
  1301. scipy/special/add_newdocs.py +15 -0
  1302. scipy/special/basic.py +87 -0
  1303. scipy/special/cython_special.cp311-win_arm64.lib +0 -0
  1304. scipy/special/cython_special.cp311-win_arm64.pyd +0 -0
  1305. scipy/special/cython_special.pxd +259 -0
  1306. scipy/special/cython_special.pyi +3 -0
  1307. scipy/special/orthogonal.py +45 -0
  1308. scipy/special/sf_error.py +20 -0
  1309. scipy/special/specfun.py +24 -0
  1310. scipy/special/spfun_stats.py +17 -0
  1311. scipy/special/tests/__init__.py +0 -0
  1312. scipy/special/tests/_cython_examples/extending.pyx +12 -0
  1313. scipy/special/tests/_cython_examples/meson.build +34 -0
  1314. scipy/special/tests/data/__init__.py +0 -0
  1315. scipy/special/tests/data/boost.npz +0 -0
  1316. scipy/special/tests/data/gsl.npz +0 -0
  1317. scipy/special/tests/data/local.npz +0 -0
  1318. scipy/special/tests/test_basic.py +4815 -0
  1319. scipy/special/tests/test_bdtr.py +112 -0
  1320. scipy/special/tests/test_boost_ufuncs.py +64 -0
  1321. scipy/special/tests/test_boxcox.py +125 -0
  1322. scipy/special/tests/test_cdflib.py +712 -0
  1323. scipy/special/tests/test_cdft_asymptotic.py +49 -0
  1324. scipy/special/tests/test_cephes_intp_cast.py +29 -0
  1325. scipy/special/tests/test_cosine_distr.py +83 -0
  1326. scipy/special/tests/test_cython_special.py +363 -0
  1327. scipy/special/tests/test_data.py +719 -0
  1328. scipy/special/tests/test_dd.py +42 -0
  1329. scipy/special/tests/test_digamma.py +45 -0
  1330. scipy/special/tests/test_ellip_harm.py +278 -0
  1331. scipy/special/tests/test_erfinv.py +89 -0
  1332. scipy/special/tests/test_exponential_integrals.py +118 -0
  1333. scipy/special/tests/test_extending.py +28 -0
  1334. scipy/special/tests/test_faddeeva.py +85 -0
  1335. scipy/special/tests/test_gamma.py +12 -0
  1336. scipy/special/tests/test_gammainc.py +152 -0
  1337. scipy/special/tests/test_hyp2f1.py +2566 -0
  1338. scipy/special/tests/test_hypergeometric.py +234 -0
  1339. scipy/special/tests/test_iv_ratio.py +249 -0
  1340. scipy/special/tests/test_kolmogorov.py +491 -0
  1341. scipy/special/tests/test_lambertw.py +109 -0
  1342. scipy/special/tests/test_legendre.py +1518 -0
  1343. scipy/special/tests/test_log1mexp.py +85 -0
  1344. scipy/special/tests/test_loggamma.py +70 -0
  1345. scipy/special/tests/test_logit.py +162 -0
  1346. scipy/special/tests/test_logsumexp.py +469 -0
  1347. scipy/special/tests/test_mpmath.py +2293 -0
  1348. scipy/special/tests/test_nan_inputs.py +65 -0
  1349. scipy/special/tests/test_ndtr.py +77 -0
  1350. scipy/special/tests/test_ndtri_exp.py +94 -0
  1351. scipy/special/tests/test_orthogonal.py +821 -0
  1352. scipy/special/tests/test_orthogonal_eval.py +275 -0
  1353. scipy/special/tests/test_owens_t.py +53 -0
  1354. scipy/special/tests/test_pcf.py +24 -0
  1355. scipy/special/tests/test_pdtr.py +48 -0
  1356. scipy/special/tests/test_powm1.py +65 -0
  1357. scipy/special/tests/test_precompute_expn_asy.py +24 -0
  1358. scipy/special/tests/test_precompute_gammainc.py +108 -0
  1359. scipy/special/tests/test_precompute_utils.py +36 -0
  1360. scipy/special/tests/test_round.py +18 -0
  1361. scipy/special/tests/test_sf_error.py +146 -0
  1362. scipy/special/tests/test_sici.py +36 -0
  1363. scipy/special/tests/test_specfun.py +48 -0
  1364. scipy/special/tests/test_spence.py +32 -0
  1365. scipy/special/tests/test_spfun_stats.py +61 -0
  1366. scipy/special/tests/test_sph_harm.py +85 -0
  1367. scipy/special/tests/test_spherical_bessel.py +400 -0
  1368. scipy/special/tests/test_support_alternative_backends.py +248 -0
  1369. scipy/special/tests/test_trig.py +72 -0
  1370. scipy/special/tests/test_ufunc_signatures.py +46 -0
  1371. scipy/special/tests/test_wright_bessel.py +205 -0
  1372. scipy/special/tests/test_wrightomega.py +117 -0
  1373. scipy/special/tests/test_zeta.py +301 -0
  1374. scipy/stats/__init__.py +670 -0
  1375. scipy/stats/_ansari_swilk_statistics.cp311-win_arm64.lib +0 -0
  1376. scipy/stats/_ansari_swilk_statistics.cp311-win_arm64.pyd +0 -0
  1377. scipy/stats/_axis_nan_policy.py +692 -0
  1378. scipy/stats/_biasedurn.cp311-win_arm64.lib +0 -0
  1379. scipy/stats/_biasedurn.cp311-win_arm64.pyd +0 -0
  1380. scipy/stats/_biasedurn.pxd +27 -0
  1381. scipy/stats/_binned_statistic.py +795 -0
  1382. scipy/stats/_binomtest.py +375 -0
  1383. scipy/stats/_bws_test.py +177 -0
  1384. scipy/stats/_censored_data.py +459 -0
  1385. scipy/stats/_common.py +5 -0
  1386. scipy/stats/_constants.py +42 -0
  1387. scipy/stats/_continued_fraction.py +387 -0
  1388. scipy/stats/_continuous_distns.py +12486 -0
  1389. scipy/stats/_correlation.py +210 -0
  1390. scipy/stats/_covariance.py +636 -0
  1391. scipy/stats/_crosstab.py +204 -0
  1392. scipy/stats/_discrete_distns.py +2098 -0
  1393. scipy/stats/_distn_infrastructure.py +4201 -0
  1394. scipy/stats/_distr_params.py +299 -0
  1395. scipy/stats/_distribution_infrastructure.py +5750 -0
  1396. scipy/stats/_entropy.py +428 -0
  1397. scipy/stats/_finite_differences.py +145 -0
  1398. scipy/stats/_fit.py +1351 -0
  1399. scipy/stats/_hypotests.py +2060 -0
  1400. scipy/stats/_kde.py +732 -0
  1401. scipy/stats/_ksstats.py +600 -0
  1402. scipy/stats/_levy_stable/__init__.py +1231 -0
  1403. scipy/stats/_levy_stable/levyst.cp311-win_arm64.lib +0 -0
  1404. scipy/stats/_levy_stable/levyst.cp311-win_arm64.pyd +0 -0
  1405. scipy/stats/_mannwhitneyu.py +492 -0
  1406. scipy/stats/_mgc.py +550 -0
  1407. scipy/stats/_morestats.py +4626 -0
  1408. scipy/stats/_mstats_basic.py +3658 -0
  1409. scipy/stats/_mstats_extras.py +521 -0
  1410. scipy/stats/_multicomp.py +449 -0
  1411. scipy/stats/_multivariate.py +7281 -0
  1412. scipy/stats/_new_distributions.py +452 -0
  1413. scipy/stats/_odds_ratio.py +466 -0
  1414. scipy/stats/_page_trend_test.py +486 -0
  1415. scipy/stats/_probability_distribution.py +1964 -0
  1416. scipy/stats/_qmc.py +2956 -0
  1417. scipy/stats/_qmc_cy.cp311-win_arm64.lib +0 -0
  1418. scipy/stats/_qmc_cy.cp311-win_arm64.pyd +0 -0
  1419. scipy/stats/_qmc_cy.pyi +54 -0
  1420. scipy/stats/_qmvnt.py +454 -0
  1421. scipy/stats/_qmvnt_cy.cp311-win_arm64.lib +0 -0
  1422. scipy/stats/_qmvnt_cy.cp311-win_arm64.pyd +0 -0
  1423. scipy/stats/_quantile.py +335 -0
  1424. scipy/stats/_rcont/__init__.py +4 -0
  1425. scipy/stats/_rcont/rcont.cp311-win_arm64.lib +0 -0
  1426. scipy/stats/_rcont/rcont.cp311-win_arm64.pyd +0 -0
  1427. scipy/stats/_relative_risk.py +263 -0
  1428. scipy/stats/_resampling.py +2352 -0
  1429. scipy/stats/_result_classes.py +40 -0
  1430. scipy/stats/_sampling.py +1314 -0
  1431. scipy/stats/_sensitivity_analysis.py +713 -0
  1432. scipy/stats/_sobol.cp311-win_arm64.lib +0 -0
  1433. scipy/stats/_sobol.cp311-win_arm64.pyd +0 -0
  1434. scipy/stats/_sobol.pyi +54 -0
  1435. scipy/stats/_sobol_direction_numbers.npz +0 -0
  1436. scipy/stats/_stats.cp311-win_arm64.lib +0 -0
  1437. scipy/stats/_stats.cp311-win_arm64.pyd +0 -0
  1438. scipy/stats/_stats.pxd +10 -0
  1439. scipy/stats/_stats_mstats_common.py +322 -0
  1440. scipy/stats/_stats_py.py +11089 -0
  1441. scipy/stats/_stats_pythran.cp311-win_arm64.lib +0 -0
  1442. scipy/stats/_stats_pythran.cp311-win_arm64.pyd +0 -0
  1443. scipy/stats/_survival.py +683 -0
  1444. scipy/stats/_tukeylambda_stats.py +199 -0
  1445. scipy/stats/_unuran/__init__.py +0 -0
  1446. scipy/stats/_unuran/unuran_wrapper.cp311-win_arm64.lib +0 -0
  1447. scipy/stats/_unuran/unuran_wrapper.cp311-win_arm64.pyd +0 -0
  1448. scipy/stats/_unuran/unuran_wrapper.pyi +179 -0
  1449. scipy/stats/_variation.py +126 -0
  1450. scipy/stats/_warnings_errors.py +38 -0
  1451. scipy/stats/_wilcoxon.py +265 -0
  1452. scipy/stats/biasedurn.py +16 -0
  1453. scipy/stats/contingency.py +521 -0
  1454. scipy/stats/distributions.py +24 -0
  1455. scipy/stats/kde.py +18 -0
  1456. scipy/stats/morestats.py +27 -0
  1457. scipy/stats/mstats.py +140 -0
  1458. scipy/stats/mstats_basic.py +42 -0
  1459. scipy/stats/mstats_extras.py +25 -0
  1460. scipy/stats/mvn.py +17 -0
  1461. scipy/stats/qmc.py +236 -0
  1462. scipy/stats/sampling.py +73 -0
  1463. scipy/stats/stats.py +41 -0
  1464. scipy/stats/tests/__init__.py +0 -0
  1465. scipy/stats/tests/common_tests.py +356 -0
  1466. scipy/stats/tests/data/_mvt.py +171 -0
  1467. scipy/stats/tests/data/fisher_exact_results_from_r.py +607 -0
  1468. scipy/stats/tests/data/jf_skew_t_gamlss_pdf_data.npy +0 -0
  1469. scipy/stats/tests/data/levy_stable/stable-Z1-cdf-sample-data.npy +0 -0
  1470. scipy/stats/tests/data/levy_stable/stable-Z1-pdf-sample-data.npy +0 -0
  1471. scipy/stats/tests/data/levy_stable/stable-loc-scale-sample-data.npy +0 -0
  1472. scipy/stats/tests/data/nist_anova/AtmWtAg.dat +108 -0
  1473. scipy/stats/tests/data/nist_anova/SiRstv.dat +85 -0
  1474. scipy/stats/tests/data/nist_anova/SmLs01.dat +249 -0
  1475. scipy/stats/tests/data/nist_anova/SmLs02.dat +1869 -0
  1476. scipy/stats/tests/data/nist_anova/SmLs03.dat +18069 -0
  1477. scipy/stats/tests/data/nist_anova/SmLs04.dat +249 -0
  1478. scipy/stats/tests/data/nist_anova/SmLs05.dat +1869 -0
  1479. scipy/stats/tests/data/nist_anova/SmLs06.dat +18069 -0
  1480. scipy/stats/tests/data/nist_anova/SmLs07.dat +249 -0
  1481. scipy/stats/tests/data/nist_anova/SmLs08.dat +1869 -0
  1482. scipy/stats/tests/data/nist_anova/SmLs09.dat +18069 -0
  1483. scipy/stats/tests/data/nist_linregress/Norris.dat +97 -0
  1484. scipy/stats/tests/data/rel_breitwigner_pdf_sample_data_ROOT.npy +0 -0
  1485. scipy/stats/tests/data/studentized_range_mpmath_ref.json +1499 -0
  1486. scipy/stats/tests/test_axis_nan_policy.py +1388 -0
  1487. scipy/stats/tests/test_binned_statistic.py +568 -0
  1488. scipy/stats/tests/test_censored_data.py +152 -0
  1489. scipy/stats/tests/test_contingency.py +294 -0
  1490. scipy/stats/tests/test_continued_fraction.py +173 -0
  1491. scipy/stats/tests/test_continuous.py +2198 -0
  1492. scipy/stats/tests/test_continuous_basic.py +1053 -0
  1493. scipy/stats/tests/test_continuous_fit_censored.py +683 -0
  1494. scipy/stats/tests/test_correlation.py +80 -0
  1495. scipy/stats/tests/test_crosstab.py +115 -0
  1496. scipy/stats/tests/test_discrete_basic.py +580 -0
  1497. scipy/stats/tests/test_discrete_distns.py +700 -0
  1498. scipy/stats/tests/test_distributions.py +10413 -0
  1499. scipy/stats/tests/test_entropy.py +322 -0
  1500. scipy/stats/tests/test_fast_gen_inversion.py +435 -0
  1501. scipy/stats/tests/test_fit.py +1090 -0
  1502. scipy/stats/tests/test_hypotests.py +1991 -0
  1503. scipy/stats/tests/test_kdeoth.py +676 -0
  1504. scipy/stats/tests/test_marray.py +289 -0
  1505. scipy/stats/tests/test_mgc.py +217 -0
  1506. scipy/stats/tests/test_morestats.py +3259 -0
  1507. scipy/stats/tests/test_mstats_basic.py +2071 -0
  1508. scipy/stats/tests/test_mstats_extras.py +172 -0
  1509. scipy/stats/tests/test_multicomp.py +405 -0
  1510. scipy/stats/tests/test_multivariate.py +4381 -0
  1511. scipy/stats/tests/test_odds_ratio.py +148 -0
  1512. scipy/stats/tests/test_qmc.py +1492 -0
  1513. scipy/stats/tests/test_quantile.py +199 -0
  1514. scipy/stats/tests/test_rank.py +345 -0
  1515. scipy/stats/tests/test_relative_risk.py +95 -0
  1516. scipy/stats/tests/test_resampling.py +2000 -0
  1517. scipy/stats/tests/test_sampling.py +1450 -0
  1518. scipy/stats/tests/test_sensitivity_analysis.py +310 -0
  1519. scipy/stats/tests/test_stats.py +9707 -0
  1520. scipy/stats/tests/test_survival.py +466 -0
  1521. scipy/stats/tests/test_tukeylambda_stats.py +85 -0
  1522. scipy/stats/tests/test_variation.py +216 -0
  1523. scipy/version.py +12 -0
  1524. scipy-1.16.2.dist-info/DELVEWHEEL +2 -0
  1525. scipy-1.16.2.dist-info/LICENSE.txt +912 -0
  1526. scipy-1.16.2.dist-info/METADATA +1061 -0
  1527. scipy-1.16.2.dist-info/RECORD +1530 -0
  1528. scipy-1.16.2.dist-info/WHEEL +4 -0
  1529. scipy.libs/msvcp140-5f1c5dd31916990d94181e07bc3afb32.dll +0 -0
  1530. scipy.libs/scipy_openblas-f3ac85b1f412f7e86514c923dc4058d1.dll +0 -0
@@ -0,0 +1,4744 @@
1
+ import math
2
+ import cmath
3
+ import warnings
4
+
5
+ from itertools import product
6
+
7
+ from scipy._lib import _pep440
8
+ import numpy as np
9
+ from numpy.testing import (
10
+ assert_array_almost_equal_nulp, assert_warns, suppress_warnings
11
+ )
12
+ import pytest
13
+ from pytest import raises as assert_raises
14
+ from scipy._lib._array_api import (
15
+ xp_assert_close, xp_assert_equal,
16
+ assert_array_almost_equal, xp_size, xp_default_dtype, is_numpy
17
+ )
18
+
19
+ from numpy import array, spacing, sin, pi
20
+ from scipy.signal import (argrelextrema, BadCoefficients, bessel, besselap, bilinear,
21
+ buttap, butter, buttord, cheb1ap, cheb1ord, cheb2ap,
22
+ cheb2ord, cheby1, cheby2, ellip, ellipap, ellipord,
23
+ firwin, freqs_zpk, freqs, freqz, freqz_zpk,
24
+ gammatone, group_delay, iircomb, iirdesign, iirfilter,
25
+ iirnotch, iirpeak, lp2bp, lp2bs, lp2hp, lp2lp, normalize,
26
+ sos2tf, sos2zpk, sosfreqz, freqz_sos, tf2sos, tf2zpk, zpk2sos,
27
+ zpk2tf, bilinear_zpk, lp2lp_zpk, lp2hp_zpk, lp2bp_zpk,
28
+ lp2bs_zpk)
29
+ from scipy.signal._filter_design import (_cplxreal, _cplxpair, _norm_factor,
30
+ _bessel_poly, _bessel_zeros)
31
+ from scipy.signal._filter_design import _logspace
32
+ from scipy.signal import _polyutils as _pu
33
+ from scipy.signal._polyutils import _sort_cmplx
34
+
35
+ skip_xp_backends = pytest.mark.skip_xp_backends
36
+ xfail_xp_backends = pytest.mark.xfail_xp_backends
37
+
38
+
39
+ try:
40
+ import mpmath
41
+ except ImportError:
42
+ mpmath = None
43
+
44
+
45
+ def mpmath_check(min_ver):
46
+ return pytest.mark.skipif(
47
+ mpmath is None
48
+ or _pep440.parse(mpmath.__version__) < _pep440.Version(min_ver),
49
+ reason=f"mpmath version >= {min_ver} required",
50
+ )
51
+
52
+
53
+ class TestCplxPair:
54
+
55
+ def test_trivial_input(self):
56
+ assert _cplxpair([]).size == 0
57
+ assert _cplxpair(1) == 1
58
+
59
+ def test_output_order(self):
60
+ xp_assert_close(_cplxpair([1+1j, 1-1j]), [1-1j, 1+1j])
61
+
62
+ a = [1+1j, 1+1j, 1, 1-1j, 1-1j, 2]
63
+ b = [1-1j, 1+1j, 1-1j, 1+1j, 1, 2]
64
+ xp_assert_close(_cplxpair(a), b)
65
+
66
+ # points spaced around the unit circle
67
+ z = np.exp(2j*pi*array([4, 3, 5, 2, 6, 1, 0])/7)
68
+ z1 = np.copy(z)
69
+ np.random.shuffle(z)
70
+ xp_assert_close(_cplxpair(z), z1)
71
+ np.random.shuffle(z)
72
+ xp_assert_close(_cplxpair(z), z1)
73
+ np.random.shuffle(z)
74
+ xp_assert_close(_cplxpair(z), z1)
75
+
76
+ # Should be able to pair up all the conjugates
77
+ x = np.random.rand(10000) + 1j * np.random.rand(10000)
78
+ y = x.conj()
79
+ z = np.random.rand(10000)
80
+ x = np.concatenate((x, y, z))
81
+ np.random.shuffle(x)
82
+ c = _cplxpair(x)
83
+
84
+ # Every other element of head should be conjugates:
85
+ xp_assert_close(c[0:20000:2], np.conj(c[1:20000:2]))
86
+ # Real parts of head should be in sorted order:
87
+ xp_assert_close(c[0:20000:2].real, np.sort(c[0:20000:2].real))
88
+ # Tail should be sorted real numbers:
89
+ xp_assert_close(c[20000:], np.sort(c[20000:]))
90
+
91
+ def test_real_integer_input(self):
92
+ xp_assert_equal(_cplxpair([2, 0, 1]), [0, 1, 2])
93
+
94
+ def test_tolerances(self):
95
+ eps = spacing(1)
96
+ xp_assert_close(_cplxpair([1j, -1j, 1+1j*eps], tol=2*eps),
97
+ [-1j, 1j, 1+1j*eps])
98
+
99
+ # sorting close to 0
100
+ xp_assert_close(_cplxpair([-eps+1j, +eps-1j]), [-1j, +1j])
101
+ xp_assert_close(_cplxpair([+eps+1j, -eps-1j]), [-1j, +1j])
102
+ xp_assert_close(_cplxpair([+1j, -1j]), [-1j, +1j])
103
+
104
+ def test_unmatched_conjugates(self):
105
+ # 1+2j is unmatched
106
+ assert_raises(ValueError, _cplxpair, [1+3j, 1-3j, 1+2j])
107
+
108
+ # 1+2j and 1-3j are unmatched
109
+ assert_raises(ValueError, _cplxpair, [1+3j, 1-3j, 1+2j, 1-3j])
110
+
111
+ # 1+3j is unmatched
112
+ assert_raises(ValueError, _cplxpair, [1+3j, 1-3j, 1+3j])
113
+
114
+ # Not conjugates
115
+ assert_raises(ValueError, _cplxpair, [4+5j, 4+5j])
116
+ assert_raises(ValueError, _cplxpair, [1-7j, 1-7j])
117
+
118
+ # No pairs
119
+ assert_raises(ValueError, _cplxpair, [1+3j])
120
+ assert_raises(ValueError, _cplxpair, [1-3j])
121
+
122
+
123
+ class TestCplxReal:
124
+
125
+ def test_trivial_input(self):
126
+ assert all(x.size == 0 for x in _cplxreal([]))
127
+
128
+ x = _cplxreal(1)
129
+ assert x[0].size == 0
130
+ xp_assert_equal(x[1], np.asarray([1]))
131
+
132
+
133
+ def test_output_order(self):
134
+ zc, zr = _cplxreal(np.roots(array([1, 0, 0, 1])))
135
+ xp_assert_close(np.append(zc, zr), [1/2 + 1j*sin(pi/3), -1])
136
+
137
+ eps = spacing(1)
138
+
139
+ a = [0+1j, 0-1j, eps + 1j, eps - 1j, -eps + 1j, -eps - 1j,
140
+ 1, 4, 2, 3, 0, 0,
141
+ 2+3j, 2-3j,
142
+ 1-eps + 1j, 1+2j, 1-2j, 1+eps - 1j, # sorts out of order
143
+ 3+1j, 3+1j, 3+1j, 3-1j, 3-1j, 3-1j,
144
+ 2-3j, 2+3j]
145
+ zc, zr = _cplxreal(a)
146
+ xp_assert_close(zc, [1j, 1j, 1j, 1+1j, 1+2j, 2+3j, 2+3j, 3+1j, 3+1j,
147
+ 3+1j])
148
+ xp_assert_close(zr, [0.0, 0, 1, 2, 3, 4])
149
+
150
+ z = array([1-eps + 1j, 1+2j, 1-2j, 1+eps - 1j, 1+eps+3j, 1-2*eps-3j,
151
+ 0+1j, 0-1j, 2+4j, 2-4j, 2+3j, 2-3j, 3+7j, 3-7j, 4-eps+1j,
152
+ 4+eps-2j, 4-1j, 4-eps+2j])
153
+
154
+ zc, zr = _cplxreal(z)
155
+ xp_assert_close(zc, [1j, 1+1j, 1+2j, 1+3j, 2+3j, 2+4j, 3+7j, 4+1j,
156
+ 4+2j])
157
+ xp_assert_equal(zr, np.asarray([]))
158
+
159
+ def test_unmatched_conjugates(self):
160
+ # 1+2j is unmatched
161
+ assert_raises(ValueError, _cplxreal, [1+3j, 1-3j, 1+2j])
162
+
163
+ # 1+2j and 1-3j are unmatched
164
+ assert_raises(ValueError, _cplxreal, [1+3j, 1-3j, 1+2j, 1-3j])
165
+
166
+ # 1+3j is unmatched
167
+ assert_raises(ValueError, _cplxreal, [1+3j, 1-3j, 1+3j])
168
+
169
+ # No pairs
170
+ assert_raises(ValueError, _cplxreal, [1+3j])
171
+ assert_raises(ValueError, _cplxreal, [1-3j])
172
+
173
+ def test_real_integer_input(self):
174
+ zc, zr = _cplxreal([2, 0, 1, 4])
175
+ xp_assert_equal(zc, [])
176
+ xp_assert_equal(zr, [0, 1, 2, 4])
177
+
178
+
179
+ class TestTf2zpk:
180
+
181
+ @skip_xp_backends(
182
+ cpu_only=True, reason="XXX zpk2sos is numpy-only", exceptions=['cupy']
183
+ )
184
+ @skip_xp_backends("dask.array", reason="https://github.com/dask/dask/issues/11883")
185
+ @pytest.mark.parametrize('dt', ('float64', 'complex128'))
186
+ def test_simple(self, dt, xp):
187
+ dtyp = getattr(xp, dt)
188
+
189
+ z_r = xp.asarray([0.5, -0.5])
190
+ p_r = xp.asarray([1.j / math.sqrt(2), -1.j / math.sqrt(2)])
191
+ # Sort the zeros/poles so that we don't fail the test if the order
192
+ # changes
193
+ z_r = _sort_cmplx(z_r, xp=xp)
194
+ p_r = _sort_cmplx(p_r, xp=xp)
195
+
196
+ b = xp.astype(_pu.poly(z_r, xp=xp), dtyp)
197
+ a = xp.astype(_pu.poly(p_r, xp=xp), dtyp)
198
+
199
+ z, p, k = tf2zpk(b, a)
200
+ z = _sort_cmplx(z, xp=xp)
201
+ # The real part of `p` is ~0.0, so sort by imaginary part
202
+ p = p[xp.argsort(xp.imag(p))]
203
+
204
+ assert_array_almost_equal(z, z_r)
205
+ assert_array_almost_equal(p, p_r)
206
+ assert math.isclose(xp.real(k), 1.)
207
+ assert k.dtype == dtyp
208
+
209
+ def test_bad_filter(self):
210
+ # Regression test for #651: better handling of badly conditioned
211
+ # filter coefficients.
212
+ with suppress_warnings():
213
+ warnings.simplefilter("error", BadCoefficients)
214
+ assert_raises(BadCoefficients, tf2zpk, [1e-15], [1.0, 1.0])
215
+
216
+
217
+ class TestZpk2Tf:
218
+
219
+ def test_identity(self, xp):
220
+ """Test the identity transfer function."""
221
+ z = xp.asarray([])
222
+ p = xp.asarray([])
223
+ k = 1.
224
+ b, a = zpk2tf(z, p, k)
225
+ b_r = xp.asarray([1.]) # desired result
226
+ a_r = xp.asarray([1.]) # desired result
227
+ # The test for the *type* of the return values is a regression
228
+ # test for ticket #1095. In the case p=[], zpk2tf used to
229
+ # return the scalar 1.0 instead of array([1.0]).
230
+ xp_assert_equal(b, b_r)
231
+ xp_assert_equal(a, a_r)
232
+ if is_numpy(xp):
233
+ assert isinstance(b, np.ndarray)
234
+ assert isinstance(a, np.ndarray)
235
+
236
+ @skip_xp_backends("dask.array", reason="https://github.com/dask/dask/issues/11883")
237
+ @skip_xp_backends(cpu_only=True, reason="XXX zpk2sos is numpy-only")
238
+ def test_conj_pair(self, xp):
239
+ # conjugate pairs give real-coeff num & den
240
+ z = xp.asarray([1j, -1j, 2j, -2j])
241
+ # shouldn't need elements of pairs to be adjacent
242
+ p = xp.asarray([1+1j, 3-100j, 3+100j, 1-1j])
243
+ k = 23
244
+
245
+ # np.poly should do the right thing, but be explicit about
246
+ # taking real part
247
+ z_np, p_np = map(np.asarray, (z, p))
248
+ b_np = k * np.poly(z_np).real
249
+ a_np = np.poly(p_np).real
250
+ b, a = map(xp.asarray, (b_np, a_np))
251
+
252
+ bp, ap = zpk2tf(z, p, k)
253
+
254
+ xp_assert_close(b, bp)
255
+ xp_assert_close(a, ap)
256
+
257
+ assert xp.isdtype(bp.dtype, 'real floating')
258
+ assert xp.isdtype(ap.dtype, 'real floating')
259
+
260
+ @skip_xp_backends("dask.array", reason="https://github.com/dask/dask/issues/11883")
261
+ @skip_xp_backends(
262
+ cpu_only=True, reason="XXX zpk2sos is numpy-only", exceptions=['cupy']
263
+ )
264
+ def test_complexk(self, xp):
265
+ # regression: z, p real, k complex k gave real b, a
266
+ b, a = xp.asarray([1j, 1j]), xp.asarray([1.0, 2])
267
+ z, p, k = tf2zpk(b, a)
268
+ xp_assert_close(k, xp.asarray(1j), check_0d=False)
269
+ bp, ap = zpk2tf(z, p, k)
270
+ xp_assert_close(b, bp)
271
+ xp_assert_close(a, ap)
272
+
273
+
274
+ @skip_xp_backends("jax.numpy", reason='no eig in JAX on GPU.')
275
+ class TestSos2Zpk:
276
+
277
+ @skip_xp_backends("dask.array", reason="it https://github.com/dask/dask/issues/11883")
278
+ def test_basic(self, xp):
279
+ sos = [[1, 0, 1, 1, 0, -0.81],
280
+ [1, 0, 0, 1, 0, +0.49]]
281
+ sos = xp.asarray(sos)
282
+ z, p, k = sos2zpk(sos)
283
+ z2 = xp.asarray([1j, -1j, 0, 0])
284
+ p2 = xp.asarray([0.9, -0.9, 0.7j, -0.7j])
285
+ k2 = 1.
286
+ assert_array_almost_equal(_sort_cmplx(z, xp), _sort_cmplx(z2, xp), decimal=4)
287
+ assert_array_almost_equal(_sort_cmplx(p, xp), _sort_cmplx(p2, xp), decimal=4)
288
+ assert math.isclose(k, k2)
289
+
290
+ sos = [[1.00000, +0.61803, 1.0000, 1.00000, +0.60515, 0.95873],
291
+ [1.00000, -1.61803, 1.0000, 1.00000, -1.58430, 0.95873],
292
+ [1.00000, +1.00000, 0.0000, 1.00000, +0.97915, 0.00000]]
293
+ sos = xp.asarray(sos)
294
+ z, p, k = sos2zpk(sos)
295
+ z2 = [-0.3090 + 0.9511j, -0.3090 - 0.9511j, 0.8090 + 0.5878j,
296
+ 0.8090 - 0.5878j, -1.0000 + 0.0000j, 0]
297
+ p2 = [-0.3026 + 0.9312j, -0.3026 - 0.9312j, 0.7922 + 0.5755j,
298
+ 0.7922 - 0.5755j, -0.9791 + 0.0000j, 0]
299
+ z2 = xp.asarray(z2)
300
+ p2 = xp.asarray(p2)
301
+ k2 = 1
302
+ assert_array_almost_equal(_sort_cmplx(z, xp), _sort_cmplx(z2, xp), decimal=4)
303
+ assert_array_almost_equal(_sort_cmplx(p, xp), _sort_cmplx(p2, xp), decimal=4)
304
+
305
+ sos = array([[1, 2, 3, 1, 0.2, 0.3],
306
+ [4, 5, 6, 1, 0.4, 0.5]])
307
+ z = array([-1 - 1.41421356237310j, -1 + 1.41421356237310j,
308
+ -0.625 - 1.05326872164704j, -0.625 + 1.05326872164704j])
309
+ p = array([-0.2 - 0.678232998312527j, -0.2 + 0.678232998312527j,
310
+ -0.1 - 0.538516480713450j, -0.1 + 0.538516480713450j])
311
+ sos, z, p = map(xp.asarray, (sos, z, p))
312
+ k = 4
313
+ z2, p2, k2 = sos2zpk(sos)
314
+
315
+ xp_assert_close(_sort_cmplx(z2, xp=xp), _sort_cmplx(z, xp=xp))
316
+ xp_assert_close(_sort_cmplx(p2, xp=xp), _sort_cmplx(p, xp=xp))
317
+ assert k2 == k
318
+
319
+ @pytest.mark.thread_unsafe
320
+ def test_fewer_zeros(self, xp):
321
+ """Test not the expected number of p/z (effectively at origin)."""
322
+ sos = butter(3, 0.1, output='sos')
323
+ sos = xp.asarray(sos) # XXX convert butter
324
+ z, p, k = sos2zpk(sos)
325
+ assert z.shape[0] == 4
326
+ assert p.shape[0] == 4
327
+
328
+ sos = butter(12, [5., 30.], 'bandpass', fs=1200., analog=False,
329
+ output='sos')
330
+ xp = xp.asarray(sos)
331
+ with pytest.warns(BadCoefficients, match='Badly conditioned'):
332
+ z, p, k = sos2zpk(sos)
333
+ assert z.shape[0] == 24
334
+ assert p.shape[0] == 24
335
+
336
+
337
+ @skip_xp_backends(
338
+ cpu_only=True, reason="XXX zpk2sos is numpy-only", exceptions=['cupy']
339
+ )
340
+ class TestSos2Tf:
341
+
342
+ def test_basic(self, xp):
343
+ sos = [[1.0, 1, 1, 1, 0, -1],
344
+ [-2, 3, 1, 1, 10, 1]]
345
+ sos = xp.asarray(sos)
346
+ b, a = sos2tf(sos)
347
+ assert_array_almost_equal(b, xp.asarray([-2.0, 1, 2, 4, 1]))
348
+ assert_array_almost_equal(a, xp.asarray([1.0, 10, 0, -10, -1]))
349
+
350
+
351
+ @skip_xp_backends(cpu_only=True, reason="XXX zpk2sos is numpy-only")
352
+ class TestTf2Sos:
353
+
354
+ def test_basic(self, xp):
355
+ num = xp.asarray([2., 16, 44, 56, 32])
356
+ den = xp.asarray([3., 3, -15, 18, -12])
357
+ sos = tf2sos(num, den)
358
+ sos2 = [[0.6667, 4.0000, 5.3333, 1.0000, +2.0000, -4.0000],
359
+ [1.0000, 2.0000, 2.0000, 1.0000, -1.0000, +1.0000]]
360
+ sos2 = xp.asarray(sos2)
361
+ assert_array_almost_equal(sos, sos2, decimal=4)
362
+
363
+ b = xp.asarray([1.0, -3, 11, -27, 18])
364
+ a = xp.asarray([16.0, 12, 2, -4, -1])
365
+ sos = tf2sos(b, a)
366
+ sos2 = [[0.0625, -0.1875, 0.1250, 1.0000, -0.2500, -0.1250],
367
+ [1.0000, +0.0000, 9.0000, 1.0000, +1.0000, +0.5000]]
368
+ sos2 = xp.asarray(sos2)
369
+ #assert_array_almost_equal(sos, sos2, decimal=4)
370
+
371
+ @pytest.mark.parametrize('b, a, analog, sos',
372
+ [([1.0], [1.0], False, [[1., 0., 0., 1., 0., 0.]]),
373
+ ([1.0], [1.0], True, [[0., 0., 1., 0., 0., 1.]]),
374
+ ([1.0], [1., 0., -1.01, 0, 0.01], False,
375
+ [[1., 0., 0., 1., 0., -0.01],
376
+ [1., 0., 0., 1., 0., -1]]),
377
+ ([1.0], [1., 0., -1.01, 0, 0.01], True,
378
+ [[0., 0., 1., 1., 0., -1],
379
+ [0., 0., 1., 1., 0., -0.01]])])
380
+ def test_analog(self, b, a, analog, sos, xp):
381
+ b, a, sos = map(xp.asarray, (b, a, sos))
382
+ sos2 = tf2sos(b, a, analog=analog)
383
+ assert_array_almost_equal(sos, sos2, decimal=4)
384
+
385
+ def test_gh_23221(self):
386
+ # Tests that this tf2sos call below does not produce ComplexWarnings
387
+ # This test is specific for scipy==1.16.0: later scipy versions do not produce
388
+ # the warning.
389
+ with suppress_warnings():
390
+ warnings.simplefilter("error")
391
+ tf2sos([0.21860986786301265, -0.4372197357260253, -0.2186098678630126,
392
+ 0.8744394714520509, -0.21860986786301248, -0.4372197357260253,
393
+ 0.21860986786301265],
394
+ [1., -4.18323041786553, 6.829924151626914, -5.407777865686045,
395
+ 2.0773105450802336, -0.33482732571537893, 0.0186009178695853 ]
396
+ )
397
+
398
+
399
+ @skip_xp_backends(
400
+ cpu_only=True, reason="XXX zpk2sos is numpy-only", exceptions=['cupy']
401
+ )
402
+ class TestZpk2Sos:
403
+
404
+ # @pytest.mark.parametrize('dt', 'fdgFDG')
405
+ # XXX: quietly remove float128 and complex256
406
+ @pytest.mark.parametrize('dt', ['float32', 'float64', 'complex64', 'complex128'])
407
+ @pytest.mark.parametrize('pairing, analog',
408
+ [('nearest', False),
409
+ ('keep_odd', False),
410
+ ('minimal', False),
411
+ ('minimal', True)])
412
+ def test_dtypes(self, dt, pairing, analog, xp):
413
+ dtype = getattr(xp, dt)
414
+ # the poles have to be complex
415
+ cdtype = (xp.empty(1, dtype=dtype) + 1j*xp.empty(1, dtype=dtype)).dtype
416
+
417
+ z = xp.asarray([-1, -1], dtype=dtype)
418
+ p = xp.asarray([0.57149 + 0.29360j, 0.57149 - 0.29360j], dtype=cdtype)
419
+ k = xp.asarray(1, dtype=dtype)
420
+ sos = zpk2sos(z, p, k, pairing=pairing, analog=analog)
421
+ # octave & MATLAB
422
+ sos2 = xp.asarray([[1, 2, 1, 1, -1.14298, 0.41280]], dtype=dtype)
423
+ assert_array_almost_equal(sos, sos2, decimal=4)
424
+
425
+ def test_basic(self, xp):
426
+ for pairing in ('nearest', 'keep_odd'):
427
+ #
428
+ # Cases that match octave
429
+ #
430
+
431
+ z = xp.asarray([-1.0, -1.0])
432
+ p = xp.asarray([0.57149 + 0.29360j, 0.57149 - 0.29360j])
433
+ k = 1
434
+ sos = zpk2sos(z, p, k, pairing=pairing)
435
+ sos2 = xp.asarray([[1, 2, 1, 1, -1.14298, 0.41280]]) # octave & MATLAB
436
+ assert_array_almost_equal(sos, sos2, decimal=4)
437
+
438
+ z = xp.asarray([1j, -1j])
439
+ p = xp.asarray([0.9, -0.9, 0.7j, -0.7j])
440
+ k = 1
441
+ sos = zpk2sos(z, p, k, pairing=pairing)
442
+ sos2 = [[1, 0, 1, 1, 0, +0.49],
443
+ [1, 0, 0, 1, 0, -0.81]] # octave
444
+ sos2 = xp.asarray(sos2)
445
+ # sos2 = [[0, 0, 1, 1, -0.9, 0],
446
+ # [1, 0, 1, 1, 0.9, 0]] # MATLAB
447
+ assert_array_almost_equal(sos, sos2, decimal=4)
448
+
449
+ z = xp.asarray([])
450
+ p = xp.asarray([0.8, -0.5+0.25j, -0.5-0.25j])
451
+ k = 1.
452
+ sos = zpk2sos(z, p, k, pairing=pairing)
453
+ sos2 = [[1., 0., 0., 1., 1., 0.3125],
454
+ [1., 0., 0., 1., -0.8, 0.]] # octave, MATLAB fails
455
+ sos2 = xp.asarray(sos2)
456
+ assert_array_almost_equal(sos, sos2, decimal=4)
457
+
458
+ z = xp.asarray([1., 1., 0.9j, -0.9j])
459
+ p = xp.asarray([0.99+0.01j, 0.99-0.01j, 0.1+0.9j, 0.1-0.9j])
460
+ k = 1
461
+ sos = zpk2sos(z, p, k, pairing=pairing)
462
+ sos2 = [[1, 0, 0.81, 1, -0.2, 0.82],
463
+ [1, -2, 1, 1, -1.98, 0.9802]] # octave
464
+ sos2 = xp.asarray(sos2)
465
+ # sos2 = [[1, -2, 1, 1, -0.2, 0.82],
466
+ # [1, 0, 0.81, 1, -1.98, 0.9802]] # MATLAB
467
+ assert_array_almost_equal(sos, sos2, decimal=4)
468
+
469
+ z = xp.asarray([0.9+0.1j, 0.9-0.1j, -0.9])
470
+ p = xp.asarray([0.75+0.25j, 0.75-0.25j, 0.9])
471
+ k = 1
472
+ sos = zpk2sos(z, p, k, pairing=pairing)
473
+ if pairing == 'keep_odd':
474
+ sos2 = [[1, -1.8, 0.82, 1, -1.5, 0.625],
475
+ [1, 0.9, 0, 1, -0.9, 0]] # octave; MATLAB fails
476
+ sos2 = xp.asarray(sos2)
477
+ assert_array_almost_equal(sos, sos2, decimal=4)
478
+ else: # pairing == 'nearest'
479
+ sos2 = [[1, 0.9, 0, 1, -1.5, 0.625],
480
+ [1, -1.8, 0.82, 1, -0.9, 0]] # our algorithm
481
+ sos2 = xp.asarray(sos2)
482
+ assert_array_almost_equal(sos, sos2, decimal=4)
483
+
484
+ #
485
+ # Cases that differ from octave:
486
+ #
487
+
488
+ z = [-0.3090 + 0.9511j, -0.3090 - 0.9511j, 0.8090 + 0.5878j,
489
+ +0.8090 - 0.5878j, -1.0000 + 0.0000j]
490
+ p = [-0.3026 + 0.9312j, -0.3026 - 0.9312j, 0.7922 + 0.5755j,
491
+ +0.7922 - 0.5755j, -0.9791 + 0.0000j]
492
+ z = xp.asarray(z)
493
+ p = xp.asarray(p)
494
+ k = 1
495
+ sos = zpk2sos(z, p, k, pairing=pairing)
496
+ # sos2 = [[1, 0.618, 1, 1, 0.6052, 0.95870],
497
+ # [1, -1.618, 1, 1, -1.5844, 0.95878],
498
+ # [1, 1, 0, 1, 0.9791, 0]] # octave, MATLAB fails
499
+ sos2 = [[1, 1, 0, 1, +0.97915, 0],
500
+ [1, 0.61803, 1, 1, +0.60515, 0.95873],
501
+ [1, -1.61803, 1, 1, -1.58430, 0.95873]]
502
+ sos2 = xp.asarray(sos2)
503
+ assert_array_almost_equal(sos, sos2, decimal=4)
504
+
505
+ z = [-1 - 1.4142j, -1 + 1.4142j,
506
+ -0.625 - 1.0533j, -0.625 + 1.0533j]
507
+ p = [-0.2 - 0.6782j, -0.2 + 0.6782j,
508
+ -0.1 - 0.5385j, -0.1 + 0.5385j]
509
+ z = xp.asarray(z)
510
+ p = xp.asarray(p)
511
+ k = 4
512
+ sos = zpk2sos(z, p, k, pairing=pairing)
513
+ sos2 = [[4, 8, 12, 1, 0.2, 0.3],
514
+ [1, 1.25, 1.5, 1, 0.4, 0.5]] # MATLAB
515
+ sos2 = xp.asarray(sos2, dtype=xp.float64)
516
+ # sos2 = [[4, 8, 12, 1, 0.4, 0.5],
517
+ # [1, 1.25, 1.5, 1, 0.2, 0.3]] # octave
518
+ xp_assert_close(sos, sos2, rtol=1e-4, atol=1e-4)
519
+
520
+ z = xp.asarray([])
521
+ p = xp.asarray([0.2, -0.5+0.25j, -0.5-0.25j])
522
+ k = 1.
523
+ sos = zpk2sos(z, p, k, pairing=pairing)
524
+ sos2 = [[1., 0., 0., 1., -0.2, 0.],
525
+ [1., 0., 0., 1., 1., 0.3125]]
526
+ sos2 = xp.asarray(sos2)
527
+ # sos2 = [[1., 0., 0., 1., 1., 0.3125],
528
+ # [1., 0., 0., 1., -0.2, 0]] # octave, MATLAB fails
529
+ assert_array_almost_equal(sos, sos2, decimal=4)
530
+
531
+ # The next two examples are adapted from Leland B. Jackson,
532
+ # "Digital Filters and Signal Processing (1995) p.400:
533
+ # http://books.google.com/books?id=VZ8uabI1pNMC&lpg=PA400&ots=gRD9pi8Jua&dq=Pole%2Fzero%20pairing%20for%20minimum%20roundoff%20noise%20in%20BSF.&pg=PA400#v=onepage&q=Pole%2Fzero%20pairing%20for%20minimum%20roundoff%20noise%20in%20BSF.&f=false
534
+
535
+ deg2rad = xp.pi / 180.
536
+ k = 1.
537
+
538
+ # first example
539
+ thetas = xp.asarray([22.5, 45, 77.5])
540
+ mags = xp.asarray([0.8, 0.6, 0.9])
541
+ z = xp.exp(1j * deg2rad * thetas)
542
+ z = xp.concat((z, xp.conj(z)))
543
+ p = xp.exp(1j * deg2rad * thetas) * mags
544
+ p = xp.concat((p, xp.conj(p)))
545
+ sos = zpk2sos(z, p, k)
546
+ # sos2 = [[1, -0.43288, 1, 1, -0.38959, 0.81], # octave,
547
+ # [1, -1.41421, 1, 1, -0.84853, 0.36], # MATLAB fails
548
+ # [1, -1.84776, 1, 1, -1.47821, 0.64]]
549
+ # Note that pole-zero pairing matches, but ordering is different
550
+ sos2 = [[1, -1.41421, 1, 1, -0.84853, 0.36],
551
+ [1, -1.84776, 1, 1, -1.47821, 0.64],
552
+ [1, -0.43288, 1, 1, -0.38959, 0.81]]
553
+ sos2 = xp.asarray(sos2)
554
+ assert_array_almost_equal(sos, sos2, decimal=4)
555
+
556
+ # second example
557
+ thetas = xp.asarray([85., 10.])
558
+ z = xp.exp(1j * deg2rad * thetas)
559
+ z = xp.concat((z, xp.conj(z), xp.asarray([1.0, -1.0])))
560
+ sos = zpk2sos(z, p, k)
561
+
562
+ # sos2 = [[1, -0.17431, 1, 1, -0.38959, 0.81], # octave "wrong",
563
+ # [1, -1.96962, 1, 1, -0.84853, 0.36], # MATLAB fails
564
+ # [1, 0, -1, 1, -1.47821, 0.64000]]
565
+ # Our pole-zero pairing matches the text, Octave does not
566
+ sos2 = [[1, 0, -1, 1, -0.84853, 0.36],
567
+ [1, -1.96962, 1, 1, -1.47821, 0.64],
568
+ [1, -0.17431, 1, 1, -0.38959, 0.81]]
569
+ sos2 = xp.asarray(sos2)
570
+ assert_array_almost_equal(sos, sos2, decimal=4)
571
+
572
+ # these examples are taken from the doc string, and show the
573
+ # effect of the 'pairing' argument
574
+ @pytest.mark.parametrize('pairing, sos',
575
+ [('nearest',
576
+ np.array([[1., 1., 0.5, 1., -0.75, 0.],
577
+ [1., 1., 0., 1., -1.6, 0.65]])),
578
+ ('keep_odd',
579
+ np.array([[1., 1., 0, 1., -0.75, 0.],
580
+ [1., 1., 0.5, 1., -1.6, 0.65]])),
581
+ ('minimal',
582
+ np.array([[0., 1., 1., 0., 1., -0.75],
583
+ [1., 1., 0.5, 1., -1.6, 0.65]]))])
584
+ def test_pairing(self, pairing, sos, xp):
585
+ sos = xp.asarray(sos)
586
+ z1 = xp.asarray([-1, -0.5-0.5j, -0.5+0.5j])
587
+ p1 = xp.asarray([0.75, 0.8+0.1j, 0.8-0.1j])
588
+ sos2 = zpk2sos(z1, p1, 1, pairing=pairing)
589
+ assert_array_almost_equal(sos, sos2, decimal=4)
590
+
591
+ @pytest.mark.parametrize('p, sos_dt',
592
+ [([-1, 1, -0.1, 0.1],
593
+ [[0., 0., 1., 1., 0., -0.01],
594
+ [0., 0., 1., 1., 0., -1]]),
595
+ ([-0.7071+0.7071j, -0.7071-0.7071j, -0.1j, 0.1j],
596
+ [[0., 0., 1., 1., 0., 0.01],
597
+ [0., 0., 1., 1., 1.4142, 1.]])])
598
+ def test_analog(self, p, sos_dt, xp):
599
+ # test `analog` argument
600
+ # for discrete time, poles closest to unit circle should appear last
601
+ # for cont. time, poles closest to imaginary axis should appear last
602
+ z, p = xp.asarray([]), xp.asarray(p)
603
+ sos_dt = xp.asarray(sos_dt)
604
+ sos2_dt = zpk2sos(z, p, 1, pairing='minimal', analog=False)
605
+ sos2_ct = zpk2sos(z, p, 1, pairing='minimal', analog=True)
606
+ assert_array_almost_equal(sos_dt, sos2_dt, decimal=4)
607
+ assert_array_almost_equal(xp.flip(sos_dt, axis=0), sos2_ct, decimal=4)
608
+
609
+ def test_bad_args(self):
610
+ with pytest.raises(ValueError, match=r'pairing must be one of'):
611
+ zpk2sos([1], [2], 1, pairing='no_such_pairing')
612
+
613
+ with pytest.raises(ValueError, match=r'.*pairing must be "minimal"'):
614
+ zpk2sos([1], [2], 1, pairing='keep_odd', analog=True)
615
+
616
+ with pytest.raises(ValueError,
617
+ match=r'.*must have len\(p\)>=len\(z\)'):
618
+ zpk2sos([1, 1], [2], 1, analog=True)
619
+
620
+ with pytest.raises(ValueError, match=r'k must be real'):
621
+ zpk2sos([1], [2], k=1j)
622
+
623
+
624
+ class TestFreqs:
625
+
626
+ def test_basic(self, xp):
627
+ _, h = freqs(xp.asarray([1.0]), xp.asarray([1.0]), worN=8)
628
+ assert_array_almost_equal(h, xp.ones(8))
629
+
630
+ def test_output(self, xp):
631
+ # 1st order low-pass filter: H(s) = 1 / (s + 1)
632
+ w = xp.asarray([0.1, 1, 10, 100])
633
+ num = xp.asarray([1.])
634
+ den = xp.asarray([1, 1.])
635
+ w, H = freqs(num, den, worN=w)
636
+ s = w * 1j
637
+ expected = 1 / (s + 1)
638
+ assert_array_almost_equal(xp.real(H), xp.real(expected))
639
+ assert_array_almost_equal(xp.imag(H), xp.imag(expected))
640
+
641
+ @skip_xp_backends("jax.numpy", reason="eigvals not available on CUDA")
642
+ def test_freq_range(self, xp):
643
+ # Test that freqresp() finds a reasonable frequency range.
644
+ # 1st order low-pass filter: H(s) = 1 / (s + 1)
645
+ # Expected range is from 0.01 to 10.
646
+ num = xp.asarray([1.])
647
+ den = xp.asarray([1, 1.])
648
+ n = 10
649
+ expected_w = _logspace(-2, 1, n, xp=xp)
650
+ w, H = freqs(num, den, worN=n)
651
+ assert_array_almost_equal(w, expected_w)
652
+
653
+ def test_plot(self, xp):
654
+
655
+ def plot(w, h):
656
+ assert_array_almost_equal(h, xp.ones(8))
657
+
658
+ with assert_raises(ZeroDivisionError):
659
+ freqs([1.0], [1.0], worN=8, plot=lambda w, h: 1 / 0)
660
+
661
+ freqs(xp.asarray([1.0]), xp.asarray([1.0]), worN=8, plot=plot)
662
+
663
+ def test_backward_compat(self, xp):
664
+ # For backward compatibility, test if None act as a wrapper for default
665
+ w1, h1 = freqs(xp.asarray([1.0]), xp.asarray([1.0]))
666
+ w2, h2 = freqs(xp.asarray([1.0]), xp.asarray([1.0]), None)
667
+ assert_array_almost_equal(w1, w2)
668
+ assert_array_almost_equal(h1, h2)
669
+
670
+ def test_w_or_N_types(self):
671
+ # Measure at 8 equally-spaced points
672
+ for N in (8, np.int8(8), np.int16(8), np.int32(8), np.int64(8),
673
+ np.array(8)):
674
+ w, h = freqs([1.0], [1.0], worN=N)
675
+ assert len(w) == 8
676
+ assert_array_almost_equal(h, np.ones(8))
677
+
678
+ # Measure at frequency 8 rad/sec
679
+ for w in (8.0, 8.0+0j):
680
+ w_out, h = freqs([1.0], [1.0], worN=w)
681
+ assert_array_almost_equal(w_out, [8])
682
+ assert_array_almost_equal(h, [1])
683
+
684
+
685
+ class TestFreqs_zpk:
686
+
687
+ def test_basic(self, xp):
688
+ _, h = freqs_zpk(
689
+ xp.asarray([1.0]), xp.asarray([1.0]), xp.asarray([1.0]), worN=8
690
+ )
691
+ assert_array_almost_equal(h, xp.ones(8))
692
+
693
+ def test_output(self, xp):
694
+ # 1st order low-pass filter: H(s) = 1 / (s + 1)
695
+ w = xp.asarray([0.1, 1, 10, 100])
696
+ z = xp.asarray([])
697
+ p = xp.asarray([-1.0])
698
+ k = 1
699
+ w, H = freqs_zpk(z, p, k, worN=w)
700
+ s = w * 1j
701
+ expected = 1 / (s + 1)
702
+ assert_array_almost_equal(xp.real(H), xp.real(expected))
703
+ assert_array_almost_equal(xp.imag(H), xp.imag(expected))
704
+
705
+ def test_freq_range(self, xp):
706
+ # Test that freqresp() finds a reasonable frequency range.
707
+ # 1st order low-pass filter: H(s) = 1 / (s + 1)
708
+ # Expected range is from 0.01 to 10.
709
+ z = xp.asarray([])
710
+ p = xp.asarray([-1.])
711
+ k = 1
712
+ n = 10
713
+ expected_w = _logspace(-2, 1, n, xp=xp)
714
+ w, H = freqs_zpk(z, p, k, worN=n)
715
+ assert_array_almost_equal(w, expected_w)
716
+
717
+ @skip_xp_backends("jax.numpy", reason="eigvals not available on CUDA")
718
+ def test_vs_freqs(self, xp):
719
+ b, a = cheby1(4, 5, 100, analog=True, output='ba')
720
+ z, p, k = cheby1(4, 5, 100, analog=True, output='zpk')
721
+
722
+ b, a = map(xp.asarray, (b, a)) # XXX convert cheby1
723
+ z, p = map(xp.asarray, (z, p))
724
+
725
+ w1, h1 = freqs(b, a)
726
+ w2, h2 = freqs_zpk(z, p, k)
727
+ xp_assert_close(w1, w2)
728
+ xp_assert_close(h1, h2, rtol=1e-6)
729
+
730
+ def test_backward_compat(self, xp):
731
+ # For backward compatibility, test if None act as a wrapper for default
732
+ # Also, keep testing `k` a length-one list: it is documented as a scalar,
733
+ # but the implementation was allowing for a one-element array-likes
734
+ w1, h1 = freqs_zpk(xp.asarray([1.0]), xp.asarray([1.0]), [1.0])
735
+ w2, h2 = freqs_zpk(xp.asarray([1.0]), xp.asarray([1.0]), [1.0], None)
736
+ assert_array_almost_equal(w1, w2)
737
+ assert_array_almost_equal(h1, h2)
738
+
739
+ def test_w_or_N_types(self):
740
+ # Measure at 8 equally-spaced points
741
+ for N in (8, np.int8(8), np.int16(8), np.int32(8), np.int64(8),
742
+ np.array(8)):
743
+ w, h = freqs_zpk([], [], 1, worN=N)
744
+ assert len(w) == 8
745
+ assert_array_almost_equal(h, np.ones(8))
746
+
747
+ # Measure at frequency 8 rad/sec
748
+ for w in (8.0, 8.0+0j):
749
+ w_out, h = freqs_zpk([], [], 1, worN=w)
750
+ assert_array_almost_equal(w_out, [8])
751
+ assert_array_almost_equal(h, [1])
752
+
753
+
754
+ class TestFreqz:
755
+
756
+ def test_ticket1441(self, xp):
757
+ """Regression test for ticket 1441."""
758
+ # Because freqz previously used arange instead of linspace,
759
+ # when N was large, it would return one more point than
760
+ # requested.
761
+ N = 100000
762
+ w, h = freqz(xp.asarray([1.0]), worN=N)
763
+ assert w.shape == (N,)
764
+
765
+ def test_gh_22886(self, xp):
766
+ w, h = freqz(xp.asarray([1.]), worN=xp.asarray([0., 0.1]))
767
+ xp_assert_equal(w, xp.asarray([0. , 0.1]))
768
+ xp_assert_equal(h, xp.asarray([1.+0.j, 1.+0.j]))
769
+
770
+ def test_gh_23277(self):
771
+ # backwards compatibility: `w` array must be real, not complex
772
+ filt = [0.5 + 0.0j, 0.5 + 0.0j]
773
+ w, _ = freqz(filt, worN=8)
774
+ assert w.dtype == np.float64
775
+
776
+ def test_basic(self, xp):
777
+ w, h = freqz(xp.asarray([1.0]), worN=8)
778
+ assert_array_almost_equal(w, xp.pi * xp.arange(8, dtype=w.dtype) / 8.)
779
+ assert_array_almost_equal(h, xp.ones(8))
780
+ w, h = freqz(xp.asarray([1.0]), worN=9)
781
+ assert_array_almost_equal(w, xp.pi * xp.arange(9, dtype=w.dtype) / 9.)
782
+ assert_array_almost_equal(h, xp.ones(9))
783
+
784
+ for a in [1, xp.ones(2)]:
785
+ w, h = freqz(xp.ones(2), a, worN=0)
786
+ assert w.shape == (0,)
787
+ assert h.shape == (0,)
788
+ hdt = xp.complex128 if xp_default_dtype(xp) == xp.float64 else xp.complex64
789
+ assert h.dtype == hdt
790
+
791
+ def test_basic2(self, xp):
792
+ t = xp.linspace(0, 1, 4, endpoint=False)
793
+ for b, a, h_whole in zip(
794
+ (xp.asarray([1., 0, 0, 0]), xp.sin(2 * xp.pi * t)),
795
+ (xp.asarray([1., 0, 0, 0]), xp.asarray([0.5, 0, 0, 0])),
796
+ (xp.asarray([1., 1., 1., 1.]), xp.asarray([0, -4j, 0, 4j]))
797
+ ):
798
+
799
+ w, h = freqz(b, a, worN=4, whole=True)
800
+ expected_w = xp.linspace(0, 2 * xp.pi, 4, endpoint=False)
801
+ assert_array_almost_equal(w, expected_w)
802
+ assert_array_almost_equal(h, h_whole)
803
+
804
+ # simultaneously check int-like support
805
+ w, h = freqz(b, a, worN=np.int32(4), whole=True)
806
+ assert_array_almost_equal(w, expected_w)
807
+ assert_array_almost_equal(h, h_whole)
808
+
809
+ w, h = freqz(b, a, worN=w, whole=True)
810
+ assert_array_almost_equal(w, expected_w)
811
+ assert_array_almost_equal(h, h_whole)
812
+
813
+ def test_basic3(self):
814
+ t = np.linspace(0, 1, 4, endpoint=False)
815
+ expected_w = np.linspace(0, 2 * np.pi, 4, endpoint=False)
816
+ for b, a, h_whole in zip(
817
+ (np.asarray([1., 0, 0, 0]), np.sin(2 * np.pi * t)),
818
+ (np.asarray([1., 0, 0, 0]), np.asarray([0.5, 0, 0, 0])),
819
+ (np.asarray([1., 1., 1., 1.]), np.asarray([0, -4j, 0, 4j]))
820
+ ):
821
+
822
+ w, h = freqz(b, a, worN=np.int32(4), whole=True)
823
+ assert_array_almost_equal(w, expected_w)
824
+ assert_array_almost_equal(h, h_whole)
825
+
826
+ w, h = freqz(b, a, worN=w, whole=True)
827
+ assert_array_almost_equal(w, expected_w)
828
+ assert_array_almost_equal(h, h_whole)
829
+
830
+ def test_basic_whole(self, xp):
831
+ w, h = freqz(xp.asarray([1.0]), worN=8, whole=True)
832
+ assert_array_almost_equal(w, 2 * xp.pi * xp.arange(8.0) / 8)
833
+ assert_array_almost_equal(h, xp.ones(8))
834
+
835
+ def test_plot(self, xp):
836
+
837
+ def plot(w, h):
838
+ assert_array_almost_equal(w, xp.pi * xp.arange(8.0) / 8)
839
+ assert_array_almost_equal(h, xp.ones(8))
840
+
841
+ with assert_raises(ZeroDivisionError):
842
+ freqz(xp.asarray([1.0]), worN=8, plot=lambda w, h: 1 / 0)
843
+
844
+ freqz(xp.asarray([1.0]), worN=8, plot=plot)
845
+
846
+ def test_fft_wrapping(self, xp):
847
+ # Some simple real FIR filters
848
+ bs = list() # filters
849
+ as_ = list()
850
+ hs_whole = list()
851
+ hs_half = list()
852
+ # 3 taps
853
+ t = xp.linspace(0, 1, 3, endpoint=False)
854
+ bs.append(xp.sin(2 * xp.pi * t))
855
+ as_.append(3.)
856
+ hs_whole.append(xp.asarray([0, -0.5j, 0.5j]))
857
+ hs_half.append(xp.asarray([0, math.sqrt(1./12.), -0.5j]))
858
+ # 4 taps
859
+ t = xp.linspace(0, 1, 4, endpoint=False)
860
+ bs.append(xp.sin(2 * xp.pi * t))
861
+ as_.append(0.5)
862
+ hs_whole.append(xp.asarray([0, -4j, 0, 4j]))
863
+ hs_half.append(xp.asarray([0, math.sqrt(8), -4j, -math.sqrt(8)]))
864
+ del t
865
+ for ii, b in enumerate(bs):
866
+ # whole
867
+ a = as_[ii]
868
+ expected_w = xp.linspace(0, 2 * xp.pi, b.shape[0], endpoint=False)
869
+ w, h = freqz(b, a, worN=expected_w, whole=True) # polyval
870
+ err_msg = f'b = {b}, a={a}'
871
+ assert_array_almost_equal(w, expected_w, err_msg=err_msg)
872
+ assert_array_almost_equal(h, hs_whole[ii], err_msg=err_msg)
873
+
874
+ w, h = freqz(b, a, worN=b.shape[0], whole=True) # FFT
875
+ assert_array_almost_equal(w, expected_w, err_msg=err_msg)
876
+ assert_array_almost_equal(h, hs_whole[ii], err_msg=err_msg)
877
+
878
+ # non-whole
879
+ expected_w = xp.linspace(0, xp.pi, b.shape[0], endpoint=False)
880
+ w, h = freqz(b, a, worN=expected_w, whole=False) # polyval
881
+ assert_array_almost_equal(w, expected_w, err_msg=err_msg)
882
+ assert_array_almost_equal(h, hs_half[ii], err_msg=err_msg)
883
+
884
+ w, h = freqz(b, a, worN=b.shape[0], whole=False) # FFT
885
+ assert_array_almost_equal(w, expected_w, err_msg=err_msg)
886
+ assert_array_almost_equal(h, hs_half[ii], err_msg=err_msg)
887
+
888
+ # some random FIR filters (real + complex)
889
+ # assume polyval is accurate
890
+ rng = np.random.RandomState(0)
891
+ for ii in range(2, 10): # number of taps
892
+ b = xp.asarray(rng.randn(ii))
893
+ for kk in range(2):
894
+ a = xp.asarray(rng.randn(1) if kk == 0 else rng.randn(3))
895
+ for jj in range(2):
896
+ if jj == 1:
897
+ b = b + xp.asarray(rng.randn(ii)) * 1j
898
+
899
+ # whole
900
+ expected_w = xp.linspace(0, 2 * xp.pi, ii, endpoint=False)
901
+ w, expected_h = freqz(b, a, worN=expected_w, whole=True)
902
+ assert_array_almost_equal(w, expected_w)
903
+ w, h = freqz(b, a, worN=ii, whole=True)
904
+ assert_array_almost_equal(w, expected_w)
905
+ assert_array_almost_equal(h, expected_h, decimal=4)
906
+
907
+ # half
908
+ expected_w = xp.linspace(0, xp.pi, ii, endpoint=False)
909
+ w, expected_h = freqz(b, a, worN=expected_w, whole=False)
910
+ assert_array_almost_equal(w, expected_w)
911
+ w, h = freqz(b, a, worN=ii, whole=False)
912
+ assert_array_almost_equal(w, expected_w)
913
+ assert_array_almost_equal(h, expected_h, decimal=4)
914
+
915
+ def test_broadcasting1(self, xp):
916
+ # Test broadcasting with worN an integer or a 1-D array,
917
+ # b and a are n-dimensional arrays.
918
+ np.random.seed(123)
919
+ b = np.random.rand(3, 5, 1)
920
+ a = np.random.rand(2, 1)
921
+ b, a = map(xp.asarray, (b, a))
922
+
923
+ for whole in [False, True]:
924
+ # Test with worN being integers (one fast for FFT and one not),
925
+ # a 1-D array, and an empty array.
926
+ for worN in [16, 17, xp.linspace(0, 1, 10), xp.asarray([])]:
927
+ w, h = freqz(b, a, worN=worN, whole=whole)
928
+ for k in range(b.shape[1]):
929
+ bk = b[:, k, 0]
930
+ ak = a[:, 0]
931
+ ww, hh = freqz(bk, ak, worN=worN, whole=whole)
932
+ xp_assert_close(ww, w)
933
+ xp_assert_close(hh, h[k, ...])
934
+
935
+ def test_broadcasting2(self, xp):
936
+ # Test broadcasting with worN an integer or a 1-D array,
937
+ # b is an n-dimensional array, and a is left at the default value.
938
+ np.random.seed(123)
939
+ b = np.random.rand(3, 5, 1)
940
+ b = xp.asarray(b)
941
+ for whole in [False, True]:
942
+ for worN in [16, 17, xp.linspace(0, 1, 10)]:
943
+ w, h = freqz(b, worN=worN, whole=whole)
944
+ for k in range(b.shape[1]):
945
+ bk = b[:, k, 0]
946
+ ww, hh = freqz(bk, worN=worN, whole=whole)
947
+ xp_assert_close(ww, w)
948
+ xp_assert_close(hh, h[k, :])
949
+
950
+ def test_broadcasting3(self, xp):
951
+ # Test broadcasting where b.shape[-1] is the same length
952
+ # as worN, and a is left at the default value.
953
+ np.random.seed(123)
954
+ N = 16
955
+ b = np.random.rand(3, N)
956
+ b = xp.asarray(b)
957
+ for whole in [False, True]:
958
+ for worN in [N, xp.linspace(0, 1, N)]:
959
+ w, h = freqz(b, worN=worN, whole=whole)
960
+ assert xp_size(w) == N
961
+ for k in range(N):
962
+ bk = b[:, k]
963
+ ww, hh = freqz(bk, worN=w[k], whole=whole)
964
+ xp_assert_close(ww, xp.asarray(w[k])[None])
965
+ xp_assert_close(hh, xp.asarray(h[k])[None])
966
+
967
+ def test_broadcasting4(self, xp):
968
+ # Test broadcasting with worN a 2-D array.
969
+ np.random.seed(123)
970
+ b = np.random.rand(4, 2, 1, 1)
971
+ a = np.random.rand(5, 2, 1, 1)
972
+ b, a = map(xp.asarray, (b, a))
973
+
974
+ for whole in [False, True]:
975
+ for worN in [np.random.rand(6, 7), np.empty((6, 0))]:
976
+ worN = xp.asarray(worN)
977
+ w, h = freqz(b, a, worN=worN, whole=whole)
978
+ xp_assert_close(w, worN, rtol=1e-14)
979
+ assert h.shape == (2,) + worN.shape
980
+ for k in range(2):
981
+ ww, hh = freqz(b[:, k, 0, 0], a[:, k, 0, 0],
982
+ worN=xp.reshape(worN, (-1,)),
983
+ whole=whole)
984
+ xp_assert_close(ww, xp.reshape(worN, (-1,)), rtol=1e-14)
985
+ xp_assert_close(hh, xp.reshape(h[k, :, :], (-1,)))
986
+
987
+ def test_backward_compat(self):
988
+ # For backward compatibility, test if None act as a wrapper for default
989
+ w1, h1 = freqz([1.0], 1)
990
+ w2, h2 = freqz([1.0], 1, None)
991
+ assert_array_almost_equal(w1, w2)
992
+ assert_array_almost_equal(h1, h2)
993
+
994
+ def test_fs_param(self, xp):
995
+ fs = 900
996
+ b = xp.asarray([0.039479155677484369, 0.11843746703245311, 0.11843746703245311,
997
+ 0.039479155677484369])
998
+ a = xp.asarray([1.0, -1.3199152021838287, 0.80341991081938424,
999
+ -0.16767146321568049])
1000
+
1001
+ # N = None, whole=False
1002
+ w1, h1 = freqz(b, a, fs=fs)
1003
+ w2, h2 = freqz(b, a)
1004
+ xp_assert_close(h1, h2)
1005
+ xp_assert_close(w1, xp.linspace(0, fs/2, 512, endpoint=False))
1006
+
1007
+ # N = None, whole=True
1008
+ w1, h1 = freqz(b, a, whole=True, fs=fs)
1009
+ w2, h2 = freqz(b, a, whole=True)
1010
+ xp_assert_close(h1, h2)
1011
+ xp_assert_close(w1, xp.linspace(0, fs, 512, endpoint=False))
1012
+
1013
+ # N = 5, whole=False
1014
+ w1, h1 = freqz(b, a, 5, fs=fs)
1015
+ w2, h2 = freqz(b, a, 5)
1016
+ xp_assert_close(h1, h2)
1017
+ xp_assert_close(w1, xp.linspace(0, fs/2, 5, endpoint=False))
1018
+
1019
+ # N = 5, whole=True
1020
+ w1, h1 = freqz(b, a, 5, whole=True, fs=fs)
1021
+ w2, h2 = freqz(b, a, 5, whole=True)
1022
+ xp_assert_close(h1, h2)
1023
+ xp_assert_close(w1, xp.linspace(0, fs, 5, endpoint=False))
1024
+
1025
+ # w is an array_like
1026
+ for w in ([123], (123,), xp.asarray([123]), (50, 123, 230),
1027
+ xp.asarray([50, 123, 230])):
1028
+ w1, h1 = freqz(b, a, w, fs=fs)
1029
+ w2, h2 = freqz(b, a, 2*pi*xp.asarray(w, dtype=xp.float64)/ fs)
1030
+ xp_assert_close(h1, h2)
1031
+ xp_assert_close(w1, xp.asarray(w), check_dtype=False)
1032
+
1033
+ def test_w_or_N_types(self):
1034
+ # Measure at 7 (polyval) or 8 (fft) equally-spaced points
1035
+ for N in (7, np.int8(7), np.int16(7), np.int32(7), np.int64(7),
1036
+ np.array(7),
1037
+ 8, np.int8(8), np.int16(8), np.int32(8), np.int64(8),
1038
+ np.array(8)):
1039
+
1040
+ w, h = freqz([1.0], worN=N)
1041
+ assert_array_almost_equal(w, np.pi * np.arange(N) / N)
1042
+ assert_array_almost_equal(h, np.ones(N))
1043
+
1044
+ w, h = freqz([1.0], worN=N, fs=100)
1045
+ assert_array_almost_equal(w, np.linspace(0, 50, N, endpoint=False))
1046
+ assert_array_almost_equal(h, np.ones(N))
1047
+
1048
+ # Measure at frequency 8 Hz
1049
+ for w in (8.0, 8.0+0j):
1050
+ # Only makes sense when fs is specified
1051
+ w_out, h = freqz(np.asarray([1.0]), worN=w, fs=100)
1052
+ assert_array_almost_equal(w_out, np.asarray([8]))
1053
+ assert_array_almost_equal(h, np.asarray(1.), check_0d=False)
1054
+
1055
+ def test_nyquist(self, xp):
1056
+ w, h = freqz(xp.asarray([1.0]), worN=8, include_nyquist=True)
1057
+ assert_array_almost_equal(w, xp.pi * xp.arange(8, dtype=w.dtype) / 7.)
1058
+ assert_array_almost_equal(h, xp.ones(8))
1059
+ w, h = freqz(xp.asarray([1.0]), worN=9, include_nyquist=True)
1060
+ assert_array_almost_equal(w, xp.pi * xp.arange(9, dtype=w.dtype) / 8.)
1061
+ assert_array_almost_equal(h, xp.ones(9))
1062
+
1063
+ for a in [1, xp.ones(2)]:
1064
+ w, h = freqz(xp.ones(2), a, worN=0, include_nyquist=True)
1065
+ assert w.shape == (0,)
1066
+ assert h.shape == (0,)
1067
+ hdt = xp.complex128 if xp_default_dtype(xp) == xp.float64 else xp.complex64
1068
+ assert h.dtype == hdt
1069
+
1070
+ w1, h1 = freqz(xp.asarray([1.0]), worN=8, whole = True, include_nyquist=True)
1071
+ w2, h2 = freqz(xp.asarray([1.0]), worN=8, whole = True, include_nyquist=False)
1072
+ assert_array_almost_equal(w1, w2)
1073
+ assert_array_almost_equal(h1, h2)
1074
+
1075
+ # https://github.com/scipy/scipy/issues/17289
1076
+ # https://github.com/scipy/scipy/issues/15273
1077
+ @pytest.mark.parametrize('whole,nyquist,worN',
1078
+ [(False, False, 32),
1079
+ (False, True, 32),
1080
+ (True, False, 32),
1081
+ (True, True, 32),
1082
+ (False, False, 257),
1083
+ (False, True, 257),
1084
+ (True, False, 257),
1085
+ (True, True, 257)])
1086
+ def test_17289(self, whole, nyquist, worN, xp):
1087
+ d = xp.asarray([0.0, 1.0])
1088
+ w, Drfft = freqz(d, worN=32, whole=whole, include_nyquist=nyquist)
1089
+ _, Dpoly = freqz(d, worN=w)
1090
+ xp_assert_close(Drfft, Dpoly)
1091
+
1092
+ def test_fs_validation(self):
1093
+ with pytest.raises(ValueError, match="Sampling.*single scalar"):
1094
+ freqz([1.0], fs=np.array([10, 20]))
1095
+
1096
+ with pytest.raises(ValueError, match="Sampling.*be none."):
1097
+ freqz([1.0], fs=None)
1098
+
1099
+
1100
+ class TestFreqz_sos:
1101
+
1102
+ def test_freqz_sos_basic(self, xp):
1103
+ # Compare the results of freqz and freqz_sos for a low order
1104
+ # Butterworth filter.
1105
+
1106
+ N = 500
1107
+
1108
+ b, a = butter(4, 0.2)
1109
+ sos = butter(4, 0.2, output='sos')
1110
+ b, a, sos = map(xp.asarray, (b, a, sos)) # XXX until butter is converted
1111
+
1112
+ w, h = freqz(b, a, worN=N)
1113
+ w2, h2 = freqz_sos(sos, worN=N)
1114
+ xp_assert_equal(w2, w)
1115
+ xp_assert_close(h2, h, rtol=1e-10, atol=1e-14)
1116
+
1117
+ b, a = ellip(3, 1, 30, (0.2, 0.3), btype='bandpass')
1118
+ sos = ellip(3, 1, 30, (0.2, 0.3), btype='bandpass', output='sos')
1119
+ b, a, sos = map(xp.asarray, (b, a, sos)) # XXX until ellip is converted
1120
+
1121
+ w, h = freqz(b, a, worN=N)
1122
+ w2, h2 = freqz_sos(sos, worN=N)
1123
+ xp_assert_equal(w2, w)
1124
+ xp_assert_close(h2, h, rtol=1e-10, atol=1e-14)
1125
+
1126
+ # must have at least one section
1127
+ with assert_raises(ValueError):
1128
+ freqz_sos(sos[:0, ...])
1129
+
1130
+ def test_backward_compat(self, xp):
1131
+ # For backward compatibility, test if None act as a wrapper for default
1132
+ N = 500
1133
+
1134
+ sos = butter(4, 0.2, output='sos')
1135
+ sos = xp.asarray(sos) # XXX until butter is converted
1136
+ w1, h1 = freqz_sos(sos, worN=N)
1137
+ w2, h2 = sosfreqz(sos, worN=N)
1138
+ assert_array_almost_equal(w1, w2)
1139
+ assert_array_almost_equal(h1, h2)
1140
+
1141
+ @skip_xp_backends("dask.array", reason="float cannot be interpreted as in integer")
1142
+ def test_freqz_sos_design(self, xp):
1143
+ # Compare freqz_sos output against expected values for different
1144
+ # filter types
1145
+
1146
+ # from cheb2ord
1147
+ N, Wn = cheb2ord([0.1, 0.6], [0.2, 0.5], 3, 60)
1148
+ sos = cheby2(N, 60, Wn, 'stop', output='sos')
1149
+ sos = xp.asarray(sos) # XXX
1150
+ zero = xp.asarray(0., dtype=xp.float64)
1151
+
1152
+ w, h = freqz_sos(sos)
1153
+ h = xp.abs(h)
1154
+ w = w / xp.pi
1155
+ xp_assert_close(20 * xp.log10(h[w <= 0.1]),
1156
+ zero, atol=3.01,
1157
+ check_shape=False)
1158
+ xp_assert_close(20 * xp.log10(h[w >= 0.6]),
1159
+ zero, atol=3.01,
1160
+ check_shape=False)
1161
+ xp_assert_close(h[(w >= 0.2) & (w <= 0.5)],
1162
+ zero, atol=1e-3,
1163
+ check_shape=False) # <= -60 dB
1164
+
1165
+ N, Wn = cheb2ord([0.1, 0.6], [0.2, 0.5], 3, 150)
1166
+ sos = cheby2(N, 150, Wn, 'stop', output='sos')
1167
+ sos = xp.asarray(sos)
1168
+
1169
+ w, h = freqz_sos(sos)
1170
+ dB = 20*xp.log10(xp.abs(h))
1171
+ w = w / xp.pi
1172
+ xp_assert_close(dB[w <= 0.1], zero, atol=3.01, check_shape=False)
1173
+ xp_assert_close(dB[w >= 0.6], zero, atol=3.01, check_shape=False)
1174
+ assert xp.all(dB[(w >= 0.2) & (w <= 0.5)] < -149.9)
1175
+
1176
+ # from cheb1ord
1177
+ N, Wn = cheb1ord(0.2, 0.3, 3, 40)
1178
+ sos = cheby1(N, 3, Wn, 'low', output='sos')
1179
+ sos = xp.asarray(sos)
1180
+
1181
+ w, h = freqz_sos(sos)
1182
+ h = xp.abs(h)
1183
+ w = w / xp.pi
1184
+ xp_assert_close(20 * xp.log10(h[w <= 0.2]), zero, atol=3.01,
1185
+ check_shape=False)
1186
+ xp_assert_close(h[w >= 0.3], zero, atol=1e-2,
1187
+ check_shape=False) # <= -40 dB
1188
+
1189
+ N, Wn = cheb1ord(0.2, 0.3, 1, 150)
1190
+ sos = cheby1(N, 1, Wn, 'low', output='sos')
1191
+ sos = xp.asarray(sos)
1192
+
1193
+ w, h = freqz_sos(sos)
1194
+ dB = 20*xp.log10(xp.abs(h))
1195
+ w /= np.pi
1196
+ xp_assert_close(dB[w <= 0.2], zero, atol=1.01, check_shape=False)
1197
+ assert xp.all(dB[w >= 0.3] < -149.9)
1198
+
1199
+ # adapted from ellipord
1200
+ N, Wn = ellipord(0.3, 0.2, 3, 60)
1201
+ sos = ellip(N, 0.3, 60, Wn, 'high', output='sos')
1202
+ sos = xp.asarray(sos)
1203
+
1204
+ w, h = freqz_sos(sos)
1205
+ h = xp.abs(h)
1206
+ w = w / xp.pi
1207
+ xp_assert_close(20 * xp.log10(h[w >= 0.3]), zero, atol=3.01,
1208
+ check_shape=False)
1209
+ xp_assert_close(h[w <= 0.1], zero, atol=1.5e-3,
1210
+ check_shape=False) # <= -60 dB (approx)
1211
+
1212
+ # adapted from buttord
1213
+ N, Wn = buttord([0.2, 0.5], [0.14, 0.6], 3, 40)
1214
+ sos = butter(N, Wn, 'band', output='sos')
1215
+ sos = xp.asarray(sos)
1216
+
1217
+ w, h = freqz_sos(sos)
1218
+ h = xp.abs(h)
1219
+ w = w / xp.pi
1220
+
1221
+ h014 = h[w <= 0.14]
1222
+ xp_assert_close(h014, xp.zeros_like(h014), atol=1e-2) # <= -40 dB
1223
+ h06 = h[w >= 0.6]
1224
+ xp_assert_close(h06, xp.zeros_like(h06), atol=1e-2) # <= -40 dB
1225
+ h0205 = 20 * xp.log10(h[(w >= 0.2) & (w <= 0.5)])
1226
+ xp_assert_close(h0205, xp.zeros_like(h0205), atol=3.01)
1227
+
1228
+ N, Wn = buttord([0.2, 0.5], [0.14, 0.6], 3, 100)
1229
+ sos = butter(N, Wn, 'band', output='sos')
1230
+ sos = xp.asarray(sos)
1231
+
1232
+ w, h = freqz_sos(sos)
1233
+ dB = 20*xp.log10(xp.maximum(xp.abs(h), xp.asarray(1e-10)))
1234
+ w = w / xp.pi
1235
+
1236
+ assert xp.all(dB[(w > 0) & (w <= 0.14)] < -99.9)
1237
+ assert xp.all(dB[w >= 0.6] < -99.9)
1238
+ db0205 = dB[(w >= 0.2) & (w <= 0.5)]
1239
+ xp_assert_close(db0205, xp.zeros_like(db0205), atol=3.01)
1240
+
1241
+ def test_freqz_sos_design_ellip(self, xp):
1242
+ N, Wn = ellipord(0.3, 0.1, 3, 60)
1243
+ sos = ellip(N, 0.3, 60, Wn, 'high', output='sos')
1244
+ sos = xp.asarray(sos)
1245
+
1246
+ w, h = freqz_sos(sos)
1247
+ h = xp.abs(h)
1248
+ w = w / xp.pi
1249
+
1250
+ h03 = 20 * xp.log10(h[w >= 0.3])
1251
+ xp_assert_close(h03, xp.zeros_like(h03), atol=3.01)
1252
+ h01 = h[w <= 0.1]
1253
+ xp_assert_close(h01, xp.zeros_like(h01), atol=1.5e-3) # <= -60 dB (approx)
1254
+
1255
+ N, Wn = ellipord(0.3, 0.2, .5, 150)
1256
+ sos = ellip(N, .5, 150, Wn, 'high', output='sos')
1257
+ sos = xp.asarray(sos)
1258
+
1259
+ w, h = freqz_sos(sos)
1260
+ dB = 20*xp.log10(xp.maximum(xp.abs(h), xp.asarray(1e-10)))
1261
+ w = w / xp.pi
1262
+
1263
+ db03 = dB[w >= 0.3]
1264
+ xp_assert_close(db03, xp.zeros_like(db03), atol=.55)
1265
+ # Allow some numerical slop in the upper bound -150, so this is
1266
+ # a check that dB[w <= 0.2] is less than or almost equal to -150.
1267
+ assert xp.max(dB[w <= 0.2]) < -150*(1 - 1e-12)
1268
+
1269
+ @mpmath_check("0.10")
1270
+ def test_freqz_sos_against_mp(self, xp):
1271
+ # Compare the result of freqz_sos applied to a high order Butterworth
1272
+ # filter against the result computed using mpmath. (signal.freqz fails
1273
+ # miserably with such high order filters.)
1274
+ from . import mpsig
1275
+ N = 500
1276
+ order = 25
1277
+ Wn = 0.15
1278
+ with mpmath.workdps(80):
1279
+ z_mp, p_mp, k_mp = mpsig.butter_lp(order, Wn)
1280
+ w_mp, h_mp = mpsig.zpkfreqz(z_mp, p_mp, k_mp, N)
1281
+ w_mp = xp.asarray([float(x) for x in w_mp], dtype=xp.float64)
1282
+ h_mp = xp.asarray([complex(x) for x in h_mp], dtype=xp.complex128)
1283
+
1284
+ sos = butter(order, Wn, output='sos')
1285
+ sos = xp.asarray(sos, dtype=xp.float64)
1286
+ w, h = freqz_sos(sos, worN=N)
1287
+ xp_assert_close(w, w_mp, rtol=1e-12, atol=1e-14)
1288
+ xp_assert_close(h, h_mp, rtol=1e-12, atol=1e-14)
1289
+
1290
+ def test_fs_param(self, xp):
1291
+ fs = 900
1292
+ sos = xp.asarray(
1293
+ [[0.03934683014103762, 0.07869366028207524, 0.03934683014103762,
1294
+ 1.0, -0.37256600288916636, 0.0],
1295
+ [1.0, 1.0, 0.0, 1.0, -0.9495739996946778, 0.45125966317124144]]
1296
+ )
1297
+
1298
+ # N = None, whole=False
1299
+ w1, h1 = freqz_sos(sos, fs=fs)
1300
+ w2, h2 = freqz_sos(sos)
1301
+ xp_assert_close(h1, h2)
1302
+ xp_assert_close(w1, xp.linspace(0, fs/2, 512, endpoint=False))
1303
+
1304
+ # N = None, whole=True
1305
+ w1, h1 = freqz_sos(sos, whole=True, fs=fs)
1306
+ w2, h2 = freqz_sos(sos, whole=True)
1307
+ xp_assert_close(h1, h2, atol=1e-27)
1308
+ xp_assert_close(w1, xp.linspace(0, fs, 512, endpoint=False))
1309
+
1310
+ # N = 5, whole=False
1311
+ w1, h1 = freqz_sos(sos, 5, fs=fs)
1312
+ w2, h2 = freqz_sos(sos, 5)
1313
+ xp_assert_close(h1, h2)
1314
+ xp_assert_close(w1, xp.linspace(0, fs/2, 5, endpoint=False))
1315
+
1316
+ # N = 5, whole=True
1317
+ w1, h1 = freqz_sos(sos, 5, whole=True, fs=fs)
1318
+ w2, h2 = freqz_sos(sos, 5, whole=True)
1319
+ xp_assert_close(h1, h2)
1320
+ xp_assert_close(w1, xp.linspace(0, fs, 5, endpoint=False))
1321
+
1322
+ @skip_xp_backends(np_only=True, reason="array-likes")
1323
+ def test_fs_param2(self, xp):
1324
+ fs = 900
1325
+ sos = xp.asarray(
1326
+ [[0.03934683014103762, 0.07869366028207524, 0.03934683014103762,
1327
+ 1.0, -0.37256600288916636, 0.0],
1328
+ [1.0, 1.0, 0.0, 1.0, -0.9495739996946778, 0.45125966317124144]]
1329
+ )
1330
+
1331
+ # w is an array_like
1332
+ for w in ([123], (123,), xp.asarray([123]), (50, 123, 230),
1333
+ xp.asarray([50, 123, 230])):
1334
+ w1, h1 = freqz_sos(sos, w, fs=fs)
1335
+ w1, h1 = map(xp.asarray, (w1, h1))
1336
+
1337
+ w2, h2 = freqz_sos(sos, 2*pi*xp.asarray(w, dtype=sos.dtype)/fs)
1338
+ xp_assert_close(h1, h2)
1339
+ xp_assert_close(w, w1, check_dtype=False)
1340
+
1341
+ def test_w_or_N_types(self):
1342
+ # Measure at 7 (polyval) or 8 (fft) equally-spaced points
1343
+ for N in (7, np.int8(7), np.int16(7), np.int32(7), np.int64(7),
1344
+ np.array(7),
1345
+ 8, np.int8(8), np.int16(8), np.int32(8), np.int64(8),
1346
+ np.array(8)):
1347
+
1348
+ w, h = freqz_sos([1, 0, 0, 1, 0, 0], worN=N)
1349
+ assert_array_almost_equal(w, np.pi * np.arange(N) / N)
1350
+ assert_array_almost_equal(h, np.ones(N))
1351
+
1352
+ w, h = freqz_sos([1, 0, 0, 1, 0, 0], worN=N, fs=100)
1353
+ assert_array_almost_equal(w, np.linspace(0, 50, N, endpoint=False))
1354
+ assert_array_almost_equal(h, np.ones(N))
1355
+
1356
+ # Measure at frequency 8 Hz
1357
+ for w in (8.0, 8.0+0j):
1358
+ # Only makes sense when fs is specified
1359
+ w_out, h = freqz_sos([1, 0, 0, 1, 0, 0], worN=w, fs=100)
1360
+ assert_array_almost_equal(w_out, [8])
1361
+ assert_array_almost_equal(h, [1])
1362
+
1363
+ def test_fs_validation(self):
1364
+ sos = butter(4, 0.2, output='sos')
1365
+ with pytest.raises(ValueError, match="Sampling.*single scalar"):
1366
+ freqz_sos(sos, fs=np.array([10, 20]))
1367
+
1368
+
1369
+ class TestFreqz_zpk:
1370
+
1371
+ def test_ticket1441(self, xp):
1372
+ """Regression test for ticket 1441."""
1373
+ # Because freqz previously used arange instead of linspace,
1374
+ # when N was large, it would return one more point than
1375
+ # requested.
1376
+ N = 100000
1377
+ w, h = freqz_zpk(xp.asarray([0.5]), xp.asarray([0.5]), 1.0, worN=N)
1378
+ assert w.shape == (N,)
1379
+
1380
+ def test_basic(self, xp):
1381
+ w, h = freqz_zpk(xp.asarray([0.5]), xp.asarray([0.5]), 1.0, worN=8)
1382
+ assert_array_almost_equal(w, xp.pi * xp.arange(8.0) / 8)
1383
+ assert_array_almost_equal(h, xp.ones(8))
1384
+
1385
+ def test_basic_whole(self, xp):
1386
+ w, h = freqz_zpk(xp.asarray([0.5]), xp.asarray([0.5]), 1.0, worN=8, whole=True)
1387
+ assert_array_almost_equal(w, 2 * xp.pi * xp.arange(8.0) / 8)
1388
+ assert_array_almost_equal(h, xp.ones(8))
1389
+
1390
+ def test_vs_freqz(self, xp):
1391
+ b, a = cheby1(4, 5, 0.5, analog=False, output='ba')
1392
+ z, p, k = cheby1(4, 5, 0.5, analog=False, output='zpk')
1393
+
1394
+ b, a = map(xp.asarray, (b, a)) # XXX convert cheby1
1395
+ z, p = map(xp.asarray, (z, p))
1396
+
1397
+ w1, h1 = freqz(b, a)
1398
+ w2, h2 = freqz_zpk(z, p, k)
1399
+ xp_assert_close(w1, w2)
1400
+ xp_assert_close(h1, h2, rtol=1e-6)
1401
+
1402
+ def test_backward_compat(self, xp):
1403
+ # For backward compatibility, test if None act as a wrapper for default
1404
+ w1, h1 = freqz_zpk(xp.asarray([0.5]), xp.asarray([0.5]), 1.0)
1405
+ w2, h2 = freqz_zpk(xp.asarray([0.5]), xp.asarray([0.5]), 1.0, None)
1406
+ assert_array_almost_equal(w1, w2)
1407
+ assert_array_almost_equal(h1, h2)
1408
+
1409
+ def test_fs_param(self, xp):
1410
+ fs = 900
1411
+ z = xp.asarray([-1, -1, -1.0])
1412
+ p = xp.asarray(
1413
+ [0.4747869998473389 + 0.4752230717749344j,
1414
+ 0.37256600288916636,
1415
+ 0.4747869998473389 - 0.4752230717749344j]
1416
+ )
1417
+ k = 0.03934683014103762
1418
+
1419
+ # N = None, whole=False
1420
+ w1, h1 = freqz_zpk(z, p, k, whole=False, fs=fs)
1421
+ w2, h2 = freqz_zpk(z, p, k, whole=False)
1422
+ xp_assert_close(h1, h2)
1423
+ xp_assert_close(w1, xp.linspace(0, fs/2, 512, endpoint=False))
1424
+
1425
+ # N = None, whole=True
1426
+ w1, h1 = freqz_zpk(z, p, k, whole=True, fs=fs)
1427
+ w2, h2 = freqz_zpk(z, p, k, whole=True)
1428
+ xp_assert_close(h1, h2)
1429
+ xp_assert_close(w1, xp.linspace(0, fs, 512, endpoint=False))
1430
+
1431
+ # N = 5, whole=False
1432
+ w1, h1 = freqz_zpk(z, p, k, 5, fs=fs)
1433
+ w2, h2 = freqz_zpk(z, p, k, 5)
1434
+ xp_assert_close(h1, h2)
1435
+ xp_assert_close(w1, xp.linspace(0, fs/2, 5, endpoint=False))
1436
+
1437
+ # N = 5, whole=True
1438
+ w1, h1 = freqz_zpk(z, p, k, 5, whole=True, fs=fs)
1439
+ w2, h2 = freqz_zpk(z, p, k, 5, whole=True)
1440
+ xp_assert_close(h1, h2)
1441
+ xp_assert_close(w1, xp.linspace(0, fs, 5, endpoint=False))
1442
+
1443
+ @skip_xp_backends(np_only=True, reason="array_likes")
1444
+ def test_fs_param2(self, xp):
1445
+ fs = 900
1446
+ z = xp.asarray([-1, -1, -1.0])
1447
+ p = xp.asarray(
1448
+ [0.4747869998473389 + 0.4752230717749344j,
1449
+ 0.37256600288916636,
1450
+ 0.4747869998473389 - 0.4752230717749344j]
1451
+ )
1452
+ k = 0.03934683014103762
1453
+
1454
+ # w is an array_like
1455
+ for w in ([123], (123,), xp.asarray([123]), (50, 123, 230),
1456
+ xp.asarray([50, 123, 230])):
1457
+ w1, h1 = freqz_zpk(z, p, k, w, fs=fs)
1458
+ w2, h2 = freqz_zpk(z, p, k, 2*pi*xp.asarray(w)/fs)
1459
+ xp_assert_close(h1, h2)
1460
+ xp_assert_close(w, w1, check_dtype=False)
1461
+
1462
+ def test_w_or_N_types(self):
1463
+ # Measure at 8 equally-spaced points
1464
+ for N in (8, np.int8(8), np.int16(8), np.int32(8), np.int64(8),
1465
+ np.array(8)):
1466
+
1467
+ w, h = freqz_zpk([], [], 1, worN=N)
1468
+ assert_array_almost_equal(w, np.pi * np.arange(8) / 8.)
1469
+ assert_array_almost_equal(h, np.ones(8))
1470
+
1471
+ w, h = freqz_zpk([], [], 1, worN=N, fs=100)
1472
+ assert_array_almost_equal(w, np.linspace(0, 50, 8, endpoint=False))
1473
+ assert_array_almost_equal(h, np.ones(8))
1474
+
1475
+ # Measure at frequency 8 Hz
1476
+ for w in (8.0, 8.0+0j):
1477
+ # Only makes sense when fs is specified
1478
+ w_out, h = freqz_zpk([], [], 1, worN=w, fs=100)
1479
+ assert_array_almost_equal(w_out, [8])
1480
+ assert_array_almost_equal(h, [1])
1481
+
1482
+ def test_fs_validation(self):
1483
+ with pytest.raises(ValueError, match="Sampling.*single scalar"):
1484
+ freqz_zpk([1.0], [1.0], [1.0], fs=np.array([10., 20]))
1485
+
1486
+ with pytest.raises(ValueError, match="Sampling.*be none."):
1487
+ freqz_zpk([1.0], [1.0], [1.0], fs=None)
1488
+
1489
+
1490
+ class TestNormalize:
1491
+
1492
+ def test_allclose(self):
1493
+ """Test for false positive on allclose in normalize() in
1494
+ filter_design.py"""
1495
+ # Test to make sure the allclose call within signal.normalize does not
1496
+ # choose false positives. Then check against a known output from MATLAB
1497
+ # to make sure the fix doesn't break anything.
1498
+
1499
+ # These are the coefficients returned from
1500
+ # `[b,a] = cheby1(8, 0.5, 0.048)'
1501
+ # in MATLAB. There are at least 15 significant figures in each
1502
+ # coefficient, so it makes sense to test for errors on the order of
1503
+ # 1e-13 (this can always be relaxed if different platforms have
1504
+ # different rounding errors)
1505
+ b_matlab = np.array([2.150733144728282e-11, 1.720586515782626e-10,
1506
+ 6.022052805239190e-10, 1.204410561047838e-09,
1507
+ 1.505513201309798e-09, 1.204410561047838e-09,
1508
+ 6.022052805239190e-10, 1.720586515782626e-10,
1509
+ 2.150733144728282e-11])
1510
+ a_matlab = np.array([1.000000000000000e+00, -7.782402035027959e+00,
1511
+ 2.654354569747454e+01, -5.182182531666387e+01,
1512
+ 6.334127355102684e+01, -4.963358186631157e+01,
1513
+ 2.434862182949389e+01, -6.836925348604676e+00,
1514
+ 8.412934944449140e-01])
1515
+
1516
+ # This is the input to signal.normalize after passing through the
1517
+ # equivalent steps in signal.iirfilter as was done for MATLAB
1518
+ b_norm_in = np.array([1.5543135865293012e-06, 1.2434508692234413e-05,
1519
+ 4.3520780422820447e-05, 8.7041560845640893e-05,
1520
+ 1.0880195105705122e-04, 8.7041560845640975e-05,
1521
+ 4.3520780422820447e-05, 1.2434508692234413e-05,
1522
+ 1.5543135865293012e-06])
1523
+ a_norm_in = np.array([7.2269025909127173e+04, -5.6242661430467968e+05,
1524
+ 1.9182761917308895e+06, -3.7451128364682454e+06,
1525
+ 4.5776121393762771e+06, -3.5869706138592605e+06,
1526
+ 1.7596511818472347e+06, -4.9409793515707983e+05,
1527
+ 6.0799461347219651e+04])
1528
+
1529
+ b_output, a_output = normalize(b_norm_in, a_norm_in)
1530
+
1531
+ # The test on b works for decimal=14 but the one for a does not. For
1532
+ # the sake of consistency, both of these are decimal=13. If something
1533
+ # breaks on another platform, it is probably fine to relax this lower.
1534
+ assert_array_almost_equal(b_matlab, b_output, decimal=13)
1535
+ assert_array_almost_equal(a_matlab, a_output, decimal=13)
1536
+
1537
+ def test_errors(self):
1538
+ """Test the error cases."""
1539
+ # all zero denominator
1540
+ assert_raises(ValueError, normalize, [1, 2], 0)
1541
+
1542
+ # denominator not 1 dimensional
1543
+ assert_raises(ValueError, normalize, [1, 2], [[1]])
1544
+
1545
+ # numerator too many dimensions
1546
+ assert_raises(ValueError, normalize, [[[1, 2]]], 1)
1547
+
1548
+
1549
+ class TestLp2lp:
1550
+
1551
+ def test_basic(self, xp):
1552
+ b = xp.asarray([1])
1553
+ a = xp.asarray([1, math.sqrt(2), 1])
1554
+ b_lp, a_lp = lp2lp(b, a, 0.38574256627112119)
1555
+ assert_array_almost_equal(b_lp, xp.asarray([0.1488]), decimal=4)
1556
+ assert_array_almost_equal(a_lp, xp.asarray([1, 0.5455, 0.1488]), decimal=4)
1557
+
1558
+
1559
+ class TestLp2hp:
1560
+
1561
+ @skip_xp_backends(eager_only=True, reason="in-place item assignment")
1562
+ def test_basic(self, xp):
1563
+ b = xp.asarray([0.25059432325190018])
1564
+ a = xp.asarray(
1565
+ [1, 0.59724041654134863, 0.92834805757524175, 0.25059432325190018]
1566
+ )
1567
+ b_hp, a_hp = lp2hp(b, a, 2*math.pi*5000)
1568
+ xp_assert_close(b_hp, xp.asarray([1.0, 0, 0, 0]))
1569
+ xp_assert_close(
1570
+ a_hp, xp.asarray([1, 1.1638e5, 2.3522e9, 1.2373e14]), rtol=1e-4
1571
+ )
1572
+
1573
+
1574
+ class TestLp2bp:
1575
+
1576
+ @skip_xp_backends(eager_only=True, reason="in-place item assignment")
1577
+ def test_basic(self, xp):
1578
+ b = xp.asarray([1])
1579
+ a = xp.asarray([1, 2, 2, 1])
1580
+ b_bp, a_bp = lp2bp(b, a, 2*math.pi*4000, 2*math.pi*2000)
1581
+ xp_assert_close(b_bp, xp.asarray([1.9844e12, 0, 0, 0]), rtol=1e-6)
1582
+ xp_assert_close(
1583
+ a_bp,
1584
+ xp.asarray([1, 2.5133e4, 2.2108e9, 3.3735e13,
1585
+ 1.3965e18, 1.0028e22, 2.5202e26]), rtol=1e-4
1586
+ )
1587
+
1588
+
1589
+ class TestLp2bs:
1590
+
1591
+ @skip_xp_backends(eager_only=True, reason="in-place item assignment")
1592
+ def test_basic(self, xp):
1593
+ b = xp.asarray([1])
1594
+ a = xp.asarray([1, 1])
1595
+ b_bs, a_bs = lp2bs(b, a, 0.41722257286366754, 0.18460575326152251)
1596
+ assert_array_almost_equal(b_bs, xp.asarray([1, 0, 0.17407]), decimal=5)
1597
+ assert_array_almost_equal(a_bs, xp.asarray([1, 0.18461, 0.17407]), decimal=5)
1598
+
1599
+
1600
+ class TestBilinear:
1601
+ """Tests for function `signal.bilinear`. """
1602
+
1603
+ def test_exceptions(self):
1604
+ """Raise all exceptions in `bilinear()`. """
1605
+ with pytest.raises(ValueError, match="Parameter a is not .*"):
1606
+ bilinear(1., np.array([[1, 2, 3]]))
1607
+ with pytest.raises(ValueError, match="Parameter b is not .*"):
1608
+ bilinear(np.ones((2,3)), 1. )
1609
+
1610
+ def test_basic(self):
1611
+ # reference output values computed with sympy
1612
+ b = [0.14879732743343033]
1613
+ a = [1, 0.54552236880522209, 0.14879732743343033]
1614
+ b_zref = [0.08782128175913713, 0.17564256351827426, 0.08782128175913713]
1615
+ a_zref = [1.0, -1.0047722097030667, 0.3560573367396151]
1616
+
1617
+ b_z, a_z = bilinear(b, a, 0.5)
1618
+
1619
+ assert_array_almost_equal_nulp(b_z, b_zref)
1620
+ assert_array_almost_equal_nulp(a_z, a_zref)
1621
+
1622
+ b = [1, 0, 0.17407467530697837]
1623
+ a = [1, 0.18460575326152251, 0.17407467530697837]
1624
+ b_zref = [0.8641286432189045, -1.2157757001964216, 0.8641286432189045]
1625
+ a_zref = [1.0, -1.2157757001964216, 0.7282572864378091]
1626
+
1627
+ b_z, a_z = bilinear(b, a, 0.5)
1628
+
1629
+ assert_array_almost_equal_nulp(b_z, b_zref)
1630
+ assert_array_almost_equal_nulp(a_z, a_zref)
1631
+
1632
+
1633
+ def test_ignore_leading_zeros(self):
1634
+ # regression for gh-6606
1635
+ # results shouldn't change when leading zeros are added to
1636
+ # input numerator or denominator
1637
+ b = [0.14879732743343033]
1638
+ a = [1, 0.54552236880522209, 0.14879732743343033]
1639
+
1640
+ b_zref = [0.08782128175913713, 0.17564256351827426, 0.08782128175913713]
1641
+ a_zref = [1.0, -1.0047722097030667, 0.3560573367396151]
1642
+
1643
+ for lzn, lzd in product(range(4), range(4)):
1644
+ b_z, a_z = bilinear(np.pad(b, (lzn, 0)),
1645
+ np.pad(a, (lzd, 0)),
1646
+ 0.5)
1647
+ assert_array_almost_equal_nulp(b_z, b_zref)
1648
+ assert_array_almost_equal_nulp(a_z, a_zref)
1649
+
1650
+
1651
+ def test_complex(self):
1652
+ # reference output values computed with sympy
1653
+ # this is an elliptical filter, 5Hz width, centered at +50Hz:
1654
+ # z, p, k = signal.ellip(2, 0.5, 20, 2*np.pi*5/2, output='zpk', analog=True)
1655
+ # z = z.astype(complex) + 2j * np.pi * 50
1656
+ # p = p.astype(complex) + 2j * np.pi * 50
1657
+ # b, a = signal.zpk2tf(z, p, k)
1658
+ b = [(0.09999999999999991+0j),
1659
+ -62.831853071795805j,
1660
+ (-9505.857007071314+0j)]
1661
+ a = [(1+0j),
1662
+ (21.09511000343942-628.3185307179587j),
1663
+ (-98310.74322875646-6627.2242613473845j)]
1664
+ # sample frequency
1665
+ fs = 1000
1666
+ b_zref = [(0.09905575106715676-0.00013441423112828688j),
1667
+ (-0.18834281923181084-0.06032810039049478j),
1668
+ (0.08054306669414343+0.05766172295523972j)]
1669
+ a_zref = [(1+0j),
1670
+ (-1.8839476369292854-0.606808151331815j),
1671
+ (0.7954687330018285+0.5717459398142481j)]
1672
+
1673
+ b_z, a_z = bilinear(b, a, fs)
1674
+
1675
+ # the 3 ulp difference determined from testing
1676
+ assert_array_almost_equal_nulp(b_z, b_zref, 3)
1677
+ assert_array_almost_equal_nulp(a_z, a_zref, 3)
1678
+
1679
+
1680
+ def test_fs_validation(self):
1681
+ b = [0.14879732743343033]
1682
+ a = [1, 0.54552236880522209, 0.14879732743343033]
1683
+ with pytest.raises(ValueError, match="Sampling.*single scalar"):
1684
+ bilinear(b, a, fs=np.array([10, 20]))
1685
+
1686
+ with pytest.raises(ValueError, match="Sampling.*be none"):
1687
+ bilinear(b, a, fs=None)
1688
+
1689
+
1690
+ class TestLp2lp_zpk:
1691
+
1692
+ @xfail_xp_backends(
1693
+ 'dask.array', reason='https://github.com/dask/dask/issues/11883'
1694
+ )
1695
+ def test_basic(self, xp):
1696
+ z = xp.asarray([])
1697
+ p = xp.asarray([(-1+1j) / math.sqrt(2), (-1-1j) / math.sqrt(2)])
1698
+ k = 1
1699
+ z_lp, p_lp, k_lp = lp2lp_zpk(z, p, k, 5)
1700
+ xp_assert_equal(z_lp, xp.asarray([]))
1701
+ xp_assert_close(_sort_cmplx(p_lp, xp=xp), _sort_cmplx(p, xp=xp) * 5)
1702
+ assert k_lp == 25.
1703
+
1704
+ # Pseudo-Chebyshev with both poles and zeros
1705
+ z = xp.asarray([-2j, +2j])
1706
+ p = xp.asarray([-0.75, -0.5-0.5j, -0.5+0.5j])
1707
+ k = 3
1708
+ z_lp, p_lp, k_lp = lp2lp_zpk(z, p, k, 20)
1709
+ xp_assert_close(
1710
+ _sort_cmplx(z_lp, xp=xp), _sort_cmplx([-40j, +40j], xp=xp)
1711
+ )
1712
+ xp_assert_close(
1713
+ _sort_cmplx(p_lp, xp=xp), _sort_cmplx([-15, -10-10j, -10+10j], xp=xp)
1714
+ )
1715
+ assert k_lp == 60.
1716
+
1717
+ def test_fs_validation(self):
1718
+ z = [-2j, +2j]
1719
+ p = [-0.75, -0.5 - 0.5j, -0.5 + 0.5j]
1720
+ k = 3
1721
+
1722
+ with pytest.raises(ValueError, match="Sampling.*single scalar"):
1723
+ bilinear_zpk(z, p, k, fs=np.array([10, 20]))
1724
+
1725
+ with pytest.raises(ValueError, match="Sampling.*be none"):
1726
+ bilinear_zpk(z, p, k, fs=None)
1727
+
1728
+
1729
+ class TestLp2hp_zpk:
1730
+
1731
+ @xfail_xp_backends(
1732
+ 'dask.array', reason='https://github.com/dask/dask/issues/11883'
1733
+ )
1734
+ def test_basic(self, xp):
1735
+ z = xp.asarray([])
1736
+ p = xp.asarray([(-1+1j) / math.sqrt(2), (-1-1j) / math.sqrt(2)])
1737
+ k = 1
1738
+
1739
+ z_hp, p_hp, k_hp = lp2hp_zpk(z, p, k, 5)
1740
+ xp_assert_equal(z_hp, xp.asarray([0.0, 0.0], dtype=z_hp.dtype))
1741
+ xp_assert_close(_sort_cmplx(p_hp, xp=xp), _sort_cmplx(p, xp=xp) * 5)
1742
+ assert math.isclose(k_hp, 1.0, rel_tol=4e-7)
1743
+
1744
+ z = xp.asarray([-2j, +2j])
1745
+ p = xp.asarray([-0.75, -0.5-0.5j, -0.5+0.5j])
1746
+ k = 3
1747
+ z_hp, p_hp, k_hp = lp2hp_zpk(z, p, k, 6)
1748
+ xp_assert_close(
1749
+ _sort_cmplx(z_hp, xp=xp), _sort_cmplx([-3j, 0, +3j], xp=xp)
1750
+ )
1751
+ xp_assert_close(
1752
+ _sort_cmplx(p_hp, xp=xp), _sort_cmplx([-8, -6-6j, -6+6j], xp=xp)
1753
+ )
1754
+ assert k_hp == 32.0
1755
+
1756
+
1757
+ class TestLp2bp_zpk:
1758
+
1759
+ @xfail_xp_backends(
1760
+ 'dask.array', reason='https://github.com/dask/dask/issues/11883'
1761
+ )
1762
+ def test_basic(self, xp):
1763
+ z = xp.asarray([-2j, +2j])
1764
+ p = xp.asarray([-0.75, -0.5-0.5j, -0.5+0.5j])
1765
+ k = 3
1766
+ z_bp, p_bp, k_bp = lp2bp_zpk(z, p, k, 15, 8)
1767
+ xp_assert_close(
1768
+ _sort_cmplx(z_bp, xp=xp),
1769
+ _sort_cmplx([-25j, -9j, 0, +9j, +25j], xp=xp), check_dtype=False
1770
+ )
1771
+ xp_assert_close(
1772
+ _sort_cmplx(p_bp, xp=xp),
1773
+ _sort_cmplx(
1774
+ [-3 + 6j*math.sqrt(6), -3 - 6j*math.sqrt(6),
1775
+ +2j + cmath.sqrt(-8j - 225) - 2, -2j + cmath.sqrt(+8j - 225) - 2,
1776
+ +2j - cmath.sqrt(-8j - 225) - 2, -2j - cmath.sqrt(+8j - 225) - 2
1777
+ ], xp=xp
1778
+ ), check_dtype=False
1779
+ )
1780
+ assert math.isclose(k_bp, 24.0)
1781
+
1782
+
1783
+ class TestLp2bs_zpk:
1784
+
1785
+ @xfail_xp_backends(
1786
+ 'dask.array', reason='https://github.com/dask/dask/issues/11883'
1787
+ )
1788
+ def test_basic(self, xp):
1789
+ z = xp.asarray([-2j, +2j])
1790
+ p = xp.asarray([-0.75, -0.5-0.5j, -0.5+0.5j])
1791
+ k = 3
1792
+
1793
+ z_bs, p_bs, k_bs = lp2bs_zpk(z, p, k, 35, 12)
1794
+
1795
+ xp_assert_close(
1796
+ _sort_cmplx(z_bs, xp=xp),
1797
+ _sort_cmplx([+35j, -35j,
1798
+ +3j + math.sqrt(1234)*1j,
1799
+ -3j + math.sqrt(1234)*1j,
1800
+ +3j - math.sqrt(1234)*1j,
1801
+ -3j - math.sqrt(1234)*1j], xp=xp), check_dtype=False
1802
+ )
1803
+ xp_assert_close(
1804
+ _sort_cmplx(p_bs, xp=xp),
1805
+ _sort_cmplx([+3j*math.sqrt(129) - 8,
1806
+ -3j*math.sqrt(129) - 8,
1807
+ (-6 + 6j) - cmath.sqrt(-1225 - 72j),
1808
+ (-6 - 6j) - cmath.sqrt(-1225 + 72j),
1809
+ (-6 + 6j) + cmath.sqrt(-1225 - 72j),
1810
+ (-6 - 6j) + cmath.sqrt(-1225 + 72j), ], xp=xp),
1811
+ check_dtype=False
1812
+ )
1813
+ assert math.isclose(k_bs, 32.0)
1814
+
1815
+
1816
+ class TestBilinear_zpk:
1817
+
1818
+ @xfail_xp_backends(
1819
+ 'dask.array', reason='https://github.com/dask/dask/issues/11883'
1820
+ )
1821
+ def test_basic(self, xp):
1822
+ z = xp.asarray([-2j, +2j])
1823
+ p = xp.asarray([-0.75, -0.5-0.5j, -0.5+0.5j])
1824
+ k = 3
1825
+
1826
+ z_d, p_d, k_d = bilinear_zpk(z, p, k, 10)
1827
+
1828
+ xp_assert_close(
1829
+ _sort_cmplx(z_d, xp=xp),
1830
+ _sort_cmplx([(20-2j) / (20+2j), (20+2j) / (20-2j), -1], xp=xp)
1831
+ )
1832
+ xp_assert_close(
1833
+ _sort_cmplx(p_d, xp=xp),
1834
+ _sort_cmplx(
1835
+ [77/83, (1j/2 + 39/2) / (41/2 - 1j/2), (39/2 - 1j/2) / (1j/2 + 41/2)],
1836
+ xp=xp
1837
+ )
1838
+ )
1839
+ assert math.isclose(k_d, 9696/69803, rel_tol=4e-7)
1840
+
1841
+
1842
+ class TestPrototypeType:
1843
+
1844
+ def test_output_type(self):
1845
+ # Prototypes should consistently output arrays, not lists
1846
+ # https://github.com/scipy/scipy/pull/441
1847
+ for func in (buttap,
1848
+ besselap,
1849
+ lambda N: cheb1ap(N, 1),
1850
+ lambda N: cheb2ap(N, 20),
1851
+ lambda N: ellipap(N, 1, 20)):
1852
+ for N in range(7):
1853
+ z, p, k = func(N)
1854
+ assert isinstance(z, np.ndarray)
1855
+ assert isinstance(p, np.ndarray)
1856
+
1857
+
1858
+ def dB(x):
1859
+ # Return magnitude in decibels, avoiding divide-by-zero warnings
1860
+ # (and deal with some "not less-ordered" errors when -inf shows up)
1861
+ return 20 * np.log10(np.maximum(np.abs(x), np.finfo(np.float64).tiny))
1862
+
1863
+
1864
+ class TestButtord:
1865
+
1866
+ def test_lowpass(self):
1867
+ wp = 0.2
1868
+ ws = 0.3
1869
+ rp = 3
1870
+ rs = 60
1871
+ N, Wn = buttord(wp, ws, rp, rs, False)
1872
+ b, a = butter(N, Wn, 'lowpass', False)
1873
+ w, h = freqz(b, a)
1874
+ w /= np.pi
1875
+ assert np.all(-rp < dB(h[w <= wp]))
1876
+ assert np.all(dB(h[ws <= w]) < -rs)
1877
+
1878
+ assert N == 16
1879
+ xp_assert_close(Wn,
1880
+ 2.0002776782743284e-01, rtol=1e-15)
1881
+
1882
+ def test_highpass(self):
1883
+ wp = 0.3
1884
+ ws = 0.2
1885
+ rp = 3
1886
+ rs = 70
1887
+ N, Wn = buttord(wp, ws, rp, rs, False)
1888
+ b, a = butter(N, Wn, 'highpass', False)
1889
+ w, h = freqz(b, a)
1890
+ w /= np.pi
1891
+ assert np.all(-rp < dB(h[wp <= w]))
1892
+ assert np.all(dB(h[w <= ws]) < -rs)
1893
+
1894
+ assert N == 18
1895
+ xp_assert_close(Wn,
1896
+ 2.9996603079132672e-01, rtol=1e-15)
1897
+
1898
+ def test_bandpass(self):
1899
+ wp = [0.2, 0.5]
1900
+ ws = [0.1, 0.6]
1901
+ rp = 3
1902
+ rs = 80
1903
+ N, Wn = buttord(wp, ws, rp, rs, False)
1904
+ b, a = butter(N, Wn, 'bandpass', False)
1905
+ w, h = freqz(b, a)
1906
+ w /= np.pi
1907
+
1908
+ assert np.all((-rp - 0.1) < dB(h[np.logical_and(wp[0] <= w, w <= wp[1])]))
1909
+
1910
+ assert np.all(dB(h[np.logical_or(w <= ws[0], ws[1] <= w)]) < (-rs + 0.1))
1911
+
1912
+ assert N == 18
1913
+ xp_assert_close(Wn, [1.9998742411409134e-01, 5.0002139595676276e-01],
1914
+ rtol=1e-15)
1915
+
1916
+ def test_bandstop(self):
1917
+ wp = [0.1, 0.6]
1918
+ ws = [0.2, 0.5]
1919
+ rp = 3
1920
+ rs = 90
1921
+ N, Wn = buttord(wp, ws, rp, rs, False)
1922
+ b, a = butter(N, Wn, 'bandstop', False)
1923
+ w, h = freqz(b, a)
1924
+ w /= np.pi
1925
+
1926
+ assert np.all(-rp < dB(h[np.logical_or(w <= wp[0], wp[1] <= w)]))
1927
+ assert np.all(dB(h[np.logical_and(ws[0] <= w, w <= ws[1])]) < -rs)
1928
+
1929
+ assert N == 20
1930
+ xp_assert_close(Wn, [1.4759432329294042e-01, 5.9997365985276407e-01],
1931
+ rtol=1e-6)
1932
+
1933
+ def test_analog(self):
1934
+ wp = 200
1935
+ ws = 600
1936
+ rp = 3
1937
+ rs = 60
1938
+ N, Wn = buttord(wp, ws, rp, rs, True)
1939
+ b, a = butter(N, Wn, 'lowpass', True)
1940
+ w, h = freqs(b, a)
1941
+ assert np.all(-rp < dB(h[w <= wp]))
1942
+ assert np.all(dB(h[ws <= w]) < -rs)
1943
+
1944
+ assert N == 7
1945
+ xp_assert_close(Wn, 2.0006785355671877e+02, rtol=1e-15)
1946
+
1947
+ n, Wn = buttord(1, 550/450, 1, 26, analog=True)
1948
+ assert n == 19
1949
+ xp_assert_close(Wn, 1.0361980524629517, rtol=1e-15)
1950
+
1951
+ xp_assert_equal(buttord(1, 1.2, 1, 80, analog=True)[0], 55)
1952
+
1953
+ def test_fs_param(self):
1954
+ wp = [4410, 11025]
1955
+ ws = [2205, 13230]
1956
+ rp = 3
1957
+ rs = 80
1958
+ fs = 44100
1959
+ N, Wn = buttord(wp, ws, rp, rs, False, fs=fs)
1960
+ b, a = butter(N, Wn, 'bandpass', False, fs=fs)
1961
+ w, h = freqz(b, a, fs=fs)
1962
+ assert np.all(-rp - 0.1 < dB(h[np.logical_and(wp[0] <= w, w <= wp[1])]))
1963
+ assert np.all(dB(h[np.logical_or(w <= ws[0], ws[1] <= w)]) < -rs + 0.1)
1964
+
1965
+ assert N == 18
1966
+ xp_assert_close(Wn, [4409.722701715714, 11025.47178084662],
1967
+ rtol=1e-15)
1968
+
1969
+ def test_invalid_input(self):
1970
+ with pytest.raises(ValueError) as exc_info:
1971
+ buttord([20, 50], [14, 60], 3, 2)
1972
+ assert "gpass should be smaller than gstop" in str(exc_info.value)
1973
+
1974
+ with pytest.raises(ValueError) as exc_info:
1975
+ buttord([20, 50], [14, 60], -1, 2)
1976
+ assert "gpass should be larger than 0.0" in str(exc_info.value)
1977
+
1978
+ with pytest.raises(ValueError) as exc_info:
1979
+ buttord([20, 50], [14, 60], 1, -2)
1980
+ assert "gstop should be larger than 0.0" in str(exc_info.value)
1981
+
1982
+ @pytest.mark.thread_unsafe
1983
+ def test_runtime_warnings(self):
1984
+ msg = "Order is zero.*|divide by zero encountered"
1985
+ with pytest.warns(RuntimeWarning, match=msg):
1986
+ buttord(0.0, 1.0, 3, 60)
1987
+
1988
+ def test_ellip_butter(self):
1989
+ # The purpose of the test is to compare to some known output from past
1990
+ # scipy versions. The values to compare to are generated with scipy
1991
+ # 1.9.1 (there is nothing special about this particular version though)
1992
+ n, wn = buttord([0.1, 0.6], [0.2, 0.5], 3, 60)
1993
+ assert n == 14
1994
+
1995
+ def test_fs_validation(self):
1996
+ wp = 0.2
1997
+ ws = 0.3
1998
+ rp = 3
1999
+ rs = 60
2000
+
2001
+ with pytest.raises(ValueError, match="Sampling.*single scalar"):
2002
+ buttord(wp, ws, rp, rs, False, fs=np.array([10, 20]))
2003
+
2004
+
2005
+ class TestCheb1ord:
2006
+
2007
+ def test_lowpass(self):
2008
+ wp = 0.2
2009
+ ws = 0.3
2010
+ rp = 3
2011
+ rs = 60
2012
+ N, Wn = cheb1ord(wp, ws, rp, rs, False)
2013
+ b, a = cheby1(N, rp, Wn, 'low', False)
2014
+ w, h = freqz(b, a)
2015
+ w /= np.pi
2016
+ assert np.all(-rp - 0.1 < dB(h[w <= wp]))
2017
+ assert np.all(dB(h[ws <= w]) < -rs + 0.1)
2018
+
2019
+ assert N == 8
2020
+ xp_assert_close(Wn, 0.2, rtol=1e-15)
2021
+
2022
+ def test_highpass(self):
2023
+ wp = 0.3
2024
+ ws = 0.2
2025
+ rp = 3
2026
+ rs = 70
2027
+ N, Wn = cheb1ord(wp, ws, rp, rs, False)
2028
+ b, a = cheby1(N, rp, Wn, 'high', False)
2029
+ w, h = freqz(b, a)
2030
+ w /= np.pi
2031
+ assert np.all(-rp - 0.1 < dB(h[wp <= w]))
2032
+ assert np.all(dB(h[w <= ws]) < -rs + 0.1)
2033
+
2034
+ assert N == 9
2035
+ xp_assert_close(Wn, 0.3, rtol=1e-15)
2036
+
2037
+ def test_bandpass(self):
2038
+ wp = [0.2, 0.5]
2039
+ ws = [0.1, 0.6]
2040
+ rp = 3
2041
+ rs = 80
2042
+ N, Wn = cheb1ord(wp, ws, rp, rs, False)
2043
+ b, a = cheby1(N, rp, Wn, 'band', False)
2044
+ w, h = freqz(b, a)
2045
+ w /= np.pi
2046
+ assert np.all(-rp - 0.1 < dB(h[np.logical_and(wp[0] <= w, w <= wp[1])]))
2047
+ assert np.all(dB(h[np.logical_or(w <= ws[0], ws[1] <= w)]) < -rs + 0.1)
2048
+
2049
+ assert N == 9
2050
+ xp_assert_close(Wn, [0.2, 0.5], rtol=1e-15)
2051
+
2052
+ def test_bandstop(self):
2053
+ wp = [0.1, 0.6]
2054
+ ws = [0.2, 0.5]
2055
+ rp = 3
2056
+ rs = 90
2057
+ N, Wn = cheb1ord(wp, ws, rp, rs, False)
2058
+ b, a = cheby1(N, rp, Wn, 'stop', False)
2059
+ w, h = freqz(b, a)
2060
+ w /= np.pi
2061
+ assert np.all(-rp - 0.1 < dB(h[np.logical_or(w <= wp[0], wp[1] <= w)]))
2062
+ assert np.all(dB(h[np.logical_and(ws[0] <= w, w <= ws[1])]) < -rs + 0.1)
2063
+
2064
+ assert N == 10
2065
+ xp_assert_close(Wn, [0.14758232569947785, 0.6], rtol=1e-5)
2066
+
2067
+ def test_analog(self):
2068
+ wp = 700
2069
+ ws = 100
2070
+ rp = 3
2071
+ rs = 70
2072
+ N, Wn = cheb1ord(wp, ws, rp, rs, True)
2073
+ b, a = cheby1(N, rp, Wn, 'high', True)
2074
+ w, h = freqs(b, a)
2075
+ assert np.all(-rp - 0.1 < dB(h[wp <= w]))
2076
+ assert np.all(dB(h[w <= ws]) < -rs + 0.1)
2077
+
2078
+ assert N == 4
2079
+ xp_assert_close(Wn, 700.0, rtol=1e-15)
2080
+
2081
+ xp_assert_equal(cheb1ord(1, 1.2, 1, 80, analog=True)[0], 17)
2082
+
2083
+ def test_fs_param(self):
2084
+ wp = 4800
2085
+ ws = 7200
2086
+ rp = 3
2087
+ rs = 60
2088
+ fs = 48000
2089
+ N, Wn = cheb1ord(wp, ws, rp, rs, False, fs=fs)
2090
+ b, a = cheby1(N, rp, Wn, 'low', False, fs=fs)
2091
+ w, h = freqz(b, a, fs=fs)
2092
+ assert np.all(-rp - 0.1 < dB(h[w <= wp]))
2093
+ assert np.all(dB(h[ws <= w]) < -rs + 0.1)
2094
+
2095
+ assert N == 8
2096
+ xp_assert_close(Wn, 4800.0, rtol=1e-15)
2097
+
2098
+ def test_invalid_input(self):
2099
+ with pytest.raises(ValueError) as exc_info:
2100
+ cheb1ord(0.2, 0.3, 3, 2)
2101
+ assert "gpass should be smaller than gstop" in str(exc_info.value)
2102
+
2103
+ with pytest.raises(ValueError) as exc_info:
2104
+ cheb1ord(0.2, 0.3, -1, 2)
2105
+ assert "gpass should be larger than 0.0" in str(exc_info.value)
2106
+
2107
+ with pytest.raises(ValueError) as exc_info:
2108
+ cheb1ord(0.2, 0.3, 1, -2)
2109
+ assert "gstop should be larger than 0.0" in str(exc_info.value)
2110
+
2111
+ def test_ellip_cheb1(self):
2112
+ # The purpose of the test is to compare to some known output from past
2113
+ # scipy versions. The values to compare to are generated with scipy
2114
+ # 1.9.1 (there is nothing special about this particular version though)
2115
+ n, wn = cheb1ord([0.1, 0.6], [0.2, 0.5], 3, 60)
2116
+ assert n == 7
2117
+
2118
+ n2, w2 = cheb2ord([0.1, 0.6], [0.2, 0.5], 3, 60)
2119
+ assert not (wn == w2).all()
2120
+
2121
+ def test_fs_validation(self):
2122
+ wp = 0.2
2123
+ ws = 0.3
2124
+ rp = 3
2125
+ rs = 60
2126
+
2127
+ with pytest.raises(ValueError, match="Sampling.*single scalar"):
2128
+ cheb1ord(wp, ws, rp, rs, False, fs=np.array([10, 20]))
2129
+
2130
+
2131
+ class TestCheb2ord:
2132
+
2133
+ def test_lowpass(self):
2134
+ wp = 0.2
2135
+ ws = 0.3
2136
+ rp = 3
2137
+ rs = 60
2138
+ N, Wn = cheb2ord(wp, ws, rp, rs, False)
2139
+ b, a = cheby2(N, rs, Wn, 'lp', False)
2140
+ w, h = freqz(b, a)
2141
+ w /= np.pi
2142
+ assert np.all(-rp - 0.1 < dB(h[w <= wp]))
2143
+ assert np.all(dB(h[ws <= w]) < -rs + 0.1)
2144
+
2145
+ assert N == 8
2146
+ xp_assert_close(Wn, 0.28647639976553163, rtol=1e-15)
2147
+
2148
+ def test_highpass(self):
2149
+ wp = 0.3
2150
+ ws = 0.2
2151
+ rp = 3
2152
+ rs = 70
2153
+ N, Wn = cheb2ord(wp, ws, rp, rs, False)
2154
+ b, a = cheby2(N, rs, Wn, 'hp', False)
2155
+ w, h = freqz(b, a)
2156
+ w /= np.pi
2157
+ assert np.all(-rp - 0.1 < dB(h[wp <= w]))
2158
+ assert np.all(dB(h[w <= ws]) < -rs + 0.1)
2159
+
2160
+ assert N == 9
2161
+ xp_assert_close(Wn, 0.20697492182903282, rtol=1e-15)
2162
+
2163
+ def test_bandpass(self):
2164
+ wp = [0.2, 0.5]
2165
+ ws = [0.1, 0.6]
2166
+ rp = 3
2167
+ rs = 80
2168
+ N, Wn = cheb2ord(wp, ws, rp, rs, False)
2169
+ b, a = cheby2(N, rs, Wn, 'bp', False)
2170
+ w, h = freqz(b, a)
2171
+ w /= np.pi
2172
+ assert np.all(-rp - 0.1 < dB(h[np.logical_and(wp[0] <= w, w <= wp[1])]))
2173
+ assert np.all(dB(h[np.logical_or(w <= ws[0], ws[1] <= w)]) < -rs + 0.1)
2174
+
2175
+ assert N == 9
2176
+ xp_assert_close(Wn, [0.14876937565923479, 0.59748447842351482],
2177
+ rtol=1e-15)
2178
+
2179
+ def test_bandstop(self):
2180
+ wp = [0.1, 0.6]
2181
+ ws = [0.2, 0.5]
2182
+ rp = 3
2183
+ rs = 90
2184
+ N, Wn = cheb2ord(wp, ws, rp, rs, False)
2185
+ b, a = cheby2(N, rs, Wn, 'bs', False)
2186
+ w, h = freqz(b, a)
2187
+ w /= np.pi
2188
+ assert np.all(-rp - 0.1 < dB(h[np.logical_or(w <= wp[0], wp[1] <= w)]))
2189
+ assert np.all(dB(h[np.logical_and(ws[0] <= w, w <= ws[1])]) < -rs + 0.1)
2190
+
2191
+ assert N == 10
2192
+ xp_assert_close(Wn, [0.19926249974781743, 0.50125246585567362],
2193
+ rtol=1e-6)
2194
+
2195
+ def test_analog(self):
2196
+ wp = [20, 50]
2197
+ ws = [10, 60]
2198
+ rp = 3
2199
+ rs = 80
2200
+ N, Wn = cheb2ord(wp, ws, rp, rs, True)
2201
+ b, a = cheby2(N, rs, Wn, 'bp', True)
2202
+ w, h = freqs(b, a)
2203
+ assert np.all(-rp - 0.1 < dB(h[np.logical_and(wp[0] <= w, w <= wp[1])]))
2204
+ assert np.all(dB(h[np.logical_or(w <= ws[0], ws[1] <= w)]) < -rs + 0.1)
2205
+
2206
+ assert N == 11
2207
+ xp_assert_close(Wn, [1.673740595370124e+01, 5.974641487254268e+01],
2208
+ rtol=1e-15)
2209
+
2210
+ def test_fs_param(self):
2211
+ wp = 150
2212
+ ws = 100
2213
+ rp = 3
2214
+ rs = 70
2215
+ fs = 1000
2216
+ N, Wn = cheb2ord(wp, ws, rp, rs, False, fs=fs)
2217
+ b, a = cheby2(N, rs, Wn, 'hp', False, fs=fs)
2218
+ w, h = freqz(b, a, fs=fs)
2219
+ assert np.all(-rp - 0.1 < dB(h[wp <= w]))
2220
+ assert np.all(dB(h[w <= ws]) < -rs + 0.1)
2221
+
2222
+ assert N == 9
2223
+ xp_assert_close(Wn, 103.4874609145164, rtol=1e-15)
2224
+
2225
+ def test_invalid_input(self):
2226
+ with pytest.raises(ValueError) as exc_info:
2227
+ cheb2ord([0.1, 0.6], [0.2, 0.5], 3, 2)
2228
+ assert "gpass should be smaller than gstop" in str(exc_info.value)
2229
+
2230
+ with pytest.raises(ValueError) as exc_info:
2231
+ cheb2ord([0.1, 0.6], [0.2, 0.5], -1, 2)
2232
+ assert "gpass should be larger than 0.0" in str(exc_info.value)
2233
+
2234
+ with pytest.raises(ValueError) as exc_info:
2235
+ cheb2ord([0.1, 0.6], [0.2, 0.5], 1, -2)
2236
+ assert "gstop should be larger than 0.0" in str(exc_info.value)
2237
+
2238
+ def test_ellip_cheb2(self):
2239
+ # The purpose of the test is to compare to some known output from past
2240
+ # scipy versions. The values to compare to are generated with scipy
2241
+ # 1.9.1 (there is nothing special about this particular version though)
2242
+ n, wn = cheb2ord([0.1, 0.6], [0.2, 0.5], 3, 60)
2243
+ assert n == 7
2244
+
2245
+ n1, w1 = cheb1ord([0.1, 0.6], [0.2, 0.5], 3, 60)
2246
+ assert not (wn == w1).all()
2247
+
2248
+ def test_fs_validation(self):
2249
+ wp = 0.2
2250
+ ws = 0.3
2251
+ rp = 3
2252
+ rs = 60
2253
+
2254
+ with pytest.raises(ValueError, match="Sampling.*single scalar"):
2255
+ cheb2ord(wp, ws, rp, rs, False, fs=np.array([10, 20]))
2256
+
2257
+
2258
+ class TestEllipord:
2259
+
2260
+ def test_lowpass(self):
2261
+ wp = 0.2
2262
+ ws = 0.3
2263
+ rp = 3
2264
+ rs = 60
2265
+ N, Wn = ellipord(wp, ws, rp, rs, False)
2266
+ b, a = ellip(N, rp, rs, Wn, 'lp', False)
2267
+ w, h = freqz(b, a)
2268
+ w /= np.pi
2269
+ assert np.all(-rp - 0.1 < dB(h[w <= wp]))
2270
+ assert np.all(dB(h[ws <= w]) < -rs + 0.1)
2271
+
2272
+ assert N == 5
2273
+ xp_assert_close(Wn, 0.2, rtol=1e-15)
2274
+
2275
+ def test_lowpass_1000dB(self):
2276
+ # failed when ellipkm1 wasn't used in ellipord and ellipap
2277
+ wp = 0.2
2278
+ ws = 0.3
2279
+ rp = 3
2280
+ rs = 1000
2281
+ N, Wn = ellipord(wp, ws, rp, rs, False)
2282
+ sos = ellip(N, rp, rs, Wn, 'lp', False, output='sos')
2283
+ w, h = freqz_sos(sos)
2284
+ w /= np.pi
2285
+ assert np.all(-rp - 0.1 < dB(h[w <= wp]))
2286
+ assert np.all(dB(h[ws <= w]) < -rs + 0.1)
2287
+
2288
+ def test_highpass(self):
2289
+ wp = 0.3
2290
+ ws = 0.2
2291
+ rp = 3
2292
+ rs = 70
2293
+ N, Wn = ellipord(wp, ws, rp, rs, False)
2294
+ b, a = ellip(N, rp, rs, Wn, 'hp', False)
2295
+ w, h = freqz(b, a)
2296
+ w /= np.pi
2297
+ assert np.all(-rp - 0.1 < dB(h[wp <= w]))
2298
+ assert np.all(dB(h[w <= ws]) < -rs + 0.1)
2299
+
2300
+ assert N == 6
2301
+ xp_assert_close(Wn, 0.3, rtol=1e-15)
2302
+
2303
+ def test_bandpass(self):
2304
+ wp = [0.2, 0.5]
2305
+ ws = [0.1, 0.6]
2306
+ rp = 3
2307
+ rs = 80
2308
+ N, Wn = ellipord(wp, ws, rp, rs, False)
2309
+ b, a = ellip(N, rp, rs, Wn, 'bp', False)
2310
+ w, h = freqz(b, a)
2311
+ w /= np.pi
2312
+ assert np.all(-rp - 0.1 < dB(h[np.logical_and(wp[0] <= w, w <= wp[1])]))
2313
+ assert np.all(dB(h[np.logical_or(w <= ws[0], ws[1] <= w)]) < -rs + 0.1)
2314
+
2315
+ assert N == 6
2316
+ xp_assert_close(Wn, [0.2, 0.5], rtol=1e-15)
2317
+
2318
+ def test_bandstop(self):
2319
+ wp = [0.1, 0.6]
2320
+ ws = [0.2, 0.5]
2321
+ rp = 3
2322
+ rs = 90
2323
+ N, Wn = ellipord(wp, ws, rp, rs, False)
2324
+ b, a = ellip(N, rp, rs, Wn, 'bs', False)
2325
+ w, h = freqz(b, a)
2326
+ w /= np.pi
2327
+ assert np.all(-rp - 0.1 < dB(h[np.logical_or(w <= wp[0], wp[1] <= w)]))
2328
+ assert np.all(dB(h[np.logical_and(ws[0] <= w, w <= ws[1])]) < -rs + 0.1)
2329
+
2330
+ assert N == 7
2331
+ xp_assert_close(Wn, [0.14758232794342988, 0.6], rtol=1e-5)
2332
+
2333
+ def test_analog(self):
2334
+ wp = [1000, 6000]
2335
+ ws = [2000, 5000]
2336
+ rp = 3
2337
+ rs = 90
2338
+ N, Wn = ellipord(wp, ws, rp, rs, True)
2339
+ b, a = ellip(N, rp, rs, Wn, 'bs', True)
2340
+ w, h = freqs(b, a)
2341
+ assert np.all(-rp - 0.1 < dB(h[np.logical_or(w <= wp[0], wp[1] <= w)]))
2342
+ assert np.all(dB(h[np.logical_and(ws[0] <= w, w <= ws[1])]) < -rs + 0.1)
2343
+
2344
+ assert N == 8
2345
+ xp_assert_close(Wn, [1666.6666, 6000])
2346
+
2347
+ assert ellipord(1, 1.2, 1, 80, analog=True)[0] == 9
2348
+
2349
+ def test_fs_param(self):
2350
+ wp = [400, 2400]
2351
+ ws = [800, 2000]
2352
+ rp = 3
2353
+ rs = 90
2354
+ fs = 8000
2355
+ N, Wn = ellipord(wp, ws, rp, rs, False, fs=fs)
2356
+ b, a = ellip(N, rp, rs, Wn, 'bs', False, fs=fs)
2357
+ w, h = freqz(b, a, fs=fs)
2358
+ assert np.all(-rp - 0.1 < dB(h[np.logical_or(w <= wp[0], wp[1] <= w)]))
2359
+ assert np.all(dB(h[np.logical_and(ws[0] <= w, w <= ws[1])]) < -rs + 0.1)
2360
+
2361
+ assert N == 7
2362
+ xp_assert_close(Wn, [590.3293117737195, 2400], rtol=1e-5)
2363
+
2364
+ def test_invalid_input(self):
2365
+ with pytest.raises(ValueError) as exc_info:
2366
+ ellipord(0.2, 0.5, 3, 2)
2367
+ assert "gpass should be smaller than gstop" in str(exc_info.value)
2368
+
2369
+ with pytest.raises(ValueError) as exc_info:
2370
+ ellipord(0.2, 0.5, -1, 2)
2371
+ assert "gpass should be larger than 0.0" in str(exc_info.value)
2372
+
2373
+ with pytest.raises(ValueError) as exc_info:
2374
+ ellipord(0.2, 0.5, 1, -2)
2375
+ assert "gstop should be larger than 0.0" in str(exc_info.value)
2376
+
2377
+ def test_ellip_butter(self):
2378
+ # The purpose of the test is to compare to some known output from past
2379
+ # scipy versions. The values to compare to are generated with scipy
2380
+ # 1.9.1 (there is nothing special about this particular version though)
2381
+ n, wn = ellipord([0.1, 0.6], [0.2, 0.5], 3, 60)
2382
+ assert n == 5
2383
+
2384
+ def test_fs_validation(self):
2385
+ wp = 0.2
2386
+ ws = 0.3
2387
+ rp = 3
2388
+ rs = 60
2389
+
2390
+ with pytest.raises(ValueError, match="Sampling.*single scalar"):
2391
+ ellipord(wp, ws, rp, rs, False, fs=np.array([10, 20]))
2392
+
2393
+
2394
+ class TestBessel:
2395
+
2396
+ def test_degenerate(self):
2397
+ for norm in ('delay', 'phase', 'mag'):
2398
+ # 0-order filter is just a passthrough
2399
+ b, a = bessel(0, 1, analog=True, norm=norm)
2400
+ xp_assert_equal(b, np.asarray([1.0]))
2401
+ xp_assert_equal(a, np.asarray([1.0]))
2402
+
2403
+ # 1-order filter is same for all types
2404
+ b, a = bessel(1, 1, analog=True, norm=norm)
2405
+ xp_assert_close(b, np.asarray([1.0]), rtol=1e-15)
2406
+ xp_assert_close(a, np.asarray([1.0, 1]), rtol=1e-15)
2407
+
2408
+ z, p, k = bessel(1, 0.3, analog=True, output='zpk', norm=norm)
2409
+ xp_assert_equal(z, np.asarray([]))
2410
+ xp_assert_close(p, np.asarray([-0.3+0j]), rtol=1e-14)
2411
+ xp_assert_close(k, 0.3, rtol=1e-14)
2412
+
2413
+ def test_high_order(self):
2414
+ # high even order, 'phase'
2415
+ z, p, k = bessel(24, 100, analog=True, output='zpk')
2416
+ z2 = []
2417
+ p2 = [
2418
+ -9.055312334014323e+01 + 4.844005815403969e+00j,
2419
+ -8.983105162681878e+01 + 1.454056170018573e+01j,
2420
+ -8.837357994162065e+01 + 2.426335240122282e+01j,
2421
+ -8.615278316179575e+01 + 3.403202098404543e+01j,
2422
+ -8.312326467067703e+01 + 4.386985940217900e+01j,
2423
+ -7.921695461084202e+01 + 5.380628489700191e+01j,
2424
+ -7.433392285433246e+01 + 6.388084216250878e+01j,
2425
+ -6.832565803501586e+01 + 7.415032695116071e+01j,
2426
+ -6.096221567378025e+01 + 8.470292433074425e+01j,
2427
+ -5.185914574820616e+01 + 9.569048385258847e+01j,
2428
+ -4.027853855197555e+01 + 1.074195196518679e+02j,
2429
+ -2.433481337524861e+01 + 1.207298683731973e+02j,
2430
+ ]
2431
+ k2 = 9.999999999999989e+47
2432
+ xp_assert_equal(z, z2)
2433
+ xp_assert_close(sorted(p, key=np.imag),
2434
+ sorted(np.union1d(p2, np.conj(p2)), key=np.imag))
2435
+ xp_assert_close(k, k2, rtol=1e-14)
2436
+
2437
+ # high odd order, 'phase'
2438
+ z, p, k = bessel(23, 1000, analog=True, output='zpk')
2439
+ z2 = []
2440
+ p2 = [
2441
+ -2.497697202208956e+02 + 1.202813187870698e+03j,
2442
+ -4.126986617510172e+02 + 1.065328794475509e+03j,
2443
+ -5.304922463809596e+02 + 9.439760364018479e+02j,
2444
+ -9.027564978975828e+02 + 1.010534334242318e+02j,
2445
+ -8.909283244406079e+02 + 2.023024699647598e+02j,
2446
+ -8.709469394347836e+02 + 3.039581994804637e+02j,
2447
+ -8.423805948131370e+02 + 4.062657947488952e+02j,
2448
+ -8.045561642249877e+02 + 5.095305912401127e+02j,
2449
+ -7.564660146766259e+02 + 6.141594859516342e+02j,
2450
+ -6.965966033906477e+02 + 7.207341374730186e+02j,
2451
+ -6.225903228776276e+02 + 8.301558302815096e+02j,
2452
+ -9.066732476324988e+02]
2453
+ k2 = 9.999999999999983e+68
2454
+ xp_assert_equal(z, z2)
2455
+ xp_assert_close(sorted(p, key=np.imag),
2456
+ sorted(np.union1d(p2, np.conj(p2)), key=np.imag))
2457
+ xp_assert_close(k, k2, rtol=1e-14)
2458
+
2459
+ # high even order, 'delay' (Orchard 1965 "The Roots of the
2460
+ # Maximally Flat-Delay Polynomials" Table 1)
2461
+ z, p, k = bessel(31, 1, analog=True, output='zpk', norm='delay')
2462
+ p2 = [-20.876706,
2463
+ -20.826543 + 1.735732j,
2464
+ -20.675502 + 3.473320j,
2465
+ -20.421895 + 5.214702j,
2466
+ -20.062802 + 6.961982j,
2467
+ -19.593895 + 8.717546j,
2468
+ -19.009148 + 10.484195j,
2469
+ -18.300400 + 12.265351j,
2470
+ -17.456663 + 14.065350j,
2471
+ -16.463032 + 15.889910j,
2472
+ -15.298849 + 17.746914j,
2473
+ -13.934466 + 19.647827j,
2474
+ -12.324914 + 21.610519j,
2475
+ -10.395893 + 23.665701j,
2476
+ - 8.005600 + 25.875019j,
2477
+ - 4.792045 + 28.406037j,
2478
+ ]
2479
+ xp_assert_close(sorted(p, key=np.imag),
2480
+ sorted(np.union1d(p2, np.conj(p2)), key=np.imag))
2481
+
2482
+ # high odd order, 'delay'
2483
+ z, p, k = bessel(30, 1, analog=True, output='zpk', norm='delay')
2484
+ p2 = [-20.201029 + 0.867750j,
2485
+ -20.097257 + 2.604235j,
2486
+ -19.888485 + 4.343721j,
2487
+ -19.572188 + 6.088363j,
2488
+ -19.144380 + 7.840570j,
2489
+ -18.599342 + 9.603147j,
2490
+ -17.929195 + 11.379494j,
2491
+ -17.123228 + 13.173901j,
2492
+ -16.166808 + 14.992008j,
2493
+ -15.039580 + 16.841580j,
2494
+ -13.712245 + 18.733902j,
2495
+ -12.140295 + 20.686563j,
2496
+ -10.250119 + 22.729808j,
2497
+ - 7.901170 + 24.924391j,
2498
+ - 4.734679 + 27.435615j,
2499
+ ]
2500
+ xp_assert_close(sorted(p, key=np.imag),
2501
+ sorted(np.union1d(p2, np.conj(p2)), key=np.imag))
2502
+
2503
+ def test_refs(self):
2504
+ # Compare to http://www.crbond.com/papers/bsf2.pdf
2505
+ # "Delay Normalized Bessel Polynomial Coefficients"
2506
+ bond_b = np.asarray([10395.0])
2507
+ bond_a = np.asarray([1.0, 21, 210, 1260, 4725, 10395, 10395])
2508
+ b, a = bessel(6, 1, norm='delay', analog=True)
2509
+ xp_assert_close(b, bond_b)
2510
+ xp_assert_close(a, bond_a)
2511
+
2512
+ # "Delay Normalized Bessel Pole Locations"
2513
+ bond_poles = {
2514
+ 1: [-1.0000000000],
2515
+ 2: [-1.5000000000 + 0.8660254038j],
2516
+ 3: [-1.8389073227 + 1.7543809598j, -2.3221853546],
2517
+ 4: [-2.1037893972 + 2.6574180419j, -2.8962106028 + 0.8672341289j],
2518
+ 5: [-2.3246743032 + 3.5710229203j, -3.3519563992 + 1.7426614162j,
2519
+ -3.6467385953],
2520
+ 6: [-2.5159322478 + 4.4926729537j, -3.7357083563 + 2.6262723114j,
2521
+ -4.2483593959 + 0.8675096732j],
2522
+ 7: [-2.6856768789 + 5.4206941307j, -4.0701391636 + 3.5171740477j,
2523
+ -4.7582905282 + 1.7392860611j, -4.9717868585],
2524
+ 8: [-2.8389839489 + 6.3539112986j, -4.3682892172 + 4.4144425005j,
2525
+ -5.2048407906 + 2.6161751526j, -5.5878860433 + 0.8676144454j],
2526
+ 9: [-2.9792607982 + 7.2914636883j, -4.6384398872 + 5.3172716754j,
2527
+ -5.6044218195 + 3.4981569179j, -6.1293679043 + 1.7378483835j,
2528
+ -6.2970191817],
2529
+ 10: [-3.1089162336 + 8.2326994591j, -4.8862195669 + 6.2249854825j,
2530
+ -5.9675283286 + 4.3849471889j, -6.6152909655 + 2.6115679208j,
2531
+ -6.9220449054 + 0.8676651955j]
2532
+ }
2533
+
2534
+ for N in range(1, 11):
2535
+ p1 = np.sort(bond_poles[N])
2536
+ p2 = np.sort(np.concatenate(_cplxreal(besselap(N, 'delay')[1])))
2537
+ assert_array_almost_equal(p1, p2, decimal=10)
2538
+
2539
+ # "Frequency Normalized Bessel Pole Locations"
2540
+ bond_poles = {
2541
+ 1: [-1.0000000000],
2542
+ 2: [-1.1016013306 + 0.6360098248j],
2543
+ 3: [-1.0474091610 + 0.9992644363j, -1.3226757999],
2544
+ 4: [-0.9952087644 + 1.2571057395j, -1.3700678306 + 0.4102497175j],
2545
+ 5: [-0.9576765486 + 1.4711243207j, -1.3808773259 + 0.7179095876j,
2546
+ -1.5023162714],
2547
+ 6: [-0.9306565229 + 1.6618632689j, -1.3818580976 + 0.9714718907j,
2548
+ -1.5714904036 + 0.3208963742j],
2549
+ 7: [-0.9098677806 + 1.8364513530j, -1.3789032168 + 1.1915667778j,
2550
+ -1.6120387662 + 0.5892445069j, -1.6843681793],
2551
+ 8: [-0.8928697188 + 1.9983258436j, -1.3738412176 + 1.3883565759j,
2552
+ -1.6369394181 + 0.8227956251j, -1.7574084004 + 0.2728675751j],
2553
+ 9: [-0.8783992762 + 2.1498005243j, -1.3675883098 + 1.5677337122j,
2554
+ -1.6523964846 + 1.0313895670j, -1.8071705350 + 0.5123837306j,
2555
+ -1.8566005012],
2556
+ 10: [-0.8657569017 + 2.2926048310j, -1.3606922784 + 1.7335057427j,
2557
+ -1.6618102414 + 1.2211002186j, -1.8421962445 + 0.7272575978j,
2558
+ -1.9276196914 + 0.2416234710j]
2559
+ }
2560
+
2561
+ for N in range(1, 11):
2562
+ p1 = np.sort(bond_poles[N])
2563
+ p2 = np.sort(np.concatenate(_cplxreal(besselap(N, 'mag')[1])))
2564
+ assert_array_almost_equal(p1, p2, decimal=10)
2565
+
2566
+ # Compare to https://www.ranecommercial.com/legacy/note147.html
2567
+ # "Table 1 - Bessel Crossovers of Second, Third, and Fourth-Order"
2568
+ a = np.asarray([1, 1, 1/3])
2569
+ b2, a2 = bessel(2, 1, norm='delay', analog=True)
2570
+ xp_assert_close(a[::-1], a2/b2)
2571
+
2572
+ a = np.asarray([1, 1, 2/5, 1/15])
2573
+ b2, a2 = bessel(3, 1, norm='delay', analog=True)
2574
+ xp_assert_close(a[::-1], a2/b2)
2575
+
2576
+ a = np.asarray([1, 1, 9/21, 2/21, 1/105])
2577
+ b2, a2 = bessel(4, 1, norm='delay', analog=True)
2578
+ xp_assert_close(a[::-1], a2/b2)
2579
+
2580
+ a = np.asarray([1, np.sqrt(3), 1])
2581
+ b2, a2 = bessel(2, 1, norm='phase', analog=True)
2582
+ xp_assert_close(a[::-1], a2/b2)
2583
+
2584
+ # TODO: Why so inaccurate? Is reference flawed?
2585
+ a = np.asarray([1, 2.481, 2.463, 1.018])
2586
+ b2, a2 = bessel(3, 1, norm='phase', analog=True)
2587
+ assert_array_almost_equal(a[::-1], a2/b2, decimal=1)
2588
+
2589
+ # TODO: Why so inaccurate? Is reference flawed?
2590
+ a = np.asarray([1, 3.240, 4.5, 3.240, 1.050])
2591
+ b2, a2 = bessel(4, 1, norm='phase', analog=True)
2592
+ assert_array_almost_equal(a[::-1], a2/b2, decimal=1)
2593
+
2594
+ # Table of -3 dB factors:
2595
+ N, scale = 2, np.asarray([1.272, 1.272], dtype=np.complex128)
2596
+ scale2 = besselap(N, 'mag')[1] / besselap(N, 'phase')[1]
2597
+ assert_array_almost_equal(scale2, scale, decimal=3)
2598
+
2599
+ # TODO: Why so inaccurate? Is reference flawed?
2600
+ N, scale = 3, np.asarray([1.413, 1.413, 1.413], dtype=np.complex128)
2601
+ scale2 = besselap(N, 'mag')[1] / besselap(N, 'phase')[1]
2602
+ assert_array_almost_equal(scale2, scale, decimal=2)
2603
+
2604
+ # TODO: Why so inaccurate? Is reference flawed?
2605
+ N, scale = 4, np.asarray([1.533]*4, dtype=np.complex128)
2606
+ scale2 = besselap(N, 'mag')[1] / besselap(N, 'phase')[1]
2607
+ assert_array_almost_equal(scale, scale2, decimal=1)
2608
+
2609
+ def test_hardcoded(self):
2610
+ # Compare to values from original hardcoded implementation
2611
+ originals = {
2612
+ 0: [],
2613
+ 1: [-1],
2614
+ 2: [-.8660254037844386467637229 + .4999999999999999999999996j],
2615
+ 3: [-.9416000265332067855971980,
2616
+ -.7456403858480766441810907 + .7113666249728352680992154j],
2617
+ 4: [-.6572111716718829545787788 + .8301614350048733772399715j,
2618
+ -.9047587967882449459642624 + .2709187330038746636700926j],
2619
+ 5: [-.9264420773877602247196260,
2620
+ -.8515536193688395541722677 + .4427174639443327209850002j,
2621
+ -.5905759446119191779319432 + .9072067564574549539291747j],
2622
+ 6: [-.9093906830472271808050953 + .1856964396793046769246397j,
2623
+ -.7996541858328288520243325 + .5621717346937317988594118j,
2624
+ -.5385526816693109683073792 + .9616876881954277199245657j],
2625
+ 7: [-.9194871556490290014311619,
2626
+ -.8800029341523374639772340 + .3216652762307739398381830j,
2627
+ -.7527355434093214462291616 + .6504696305522550699212995j,
2628
+ -.4966917256672316755024763 + 1.002508508454420401230220j],
2629
+ 8: [-.9096831546652910216327629 + .1412437976671422927888150j,
2630
+ -.8473250802359334320103023 + .4259017538272934994996429j,
2631
+ -.7111381808485399250796172 + .7186517314108401705762571j,
2632
+ -.4621740412532122027072175 + 1.034388681126901058116589j],
2633
+ 9: [-.9154957797499037686769223,
2634
+ -.8911217017079759323183848 + .2526580934582164192308115j,
2635
+ -.8148021112269012975514135 + .5085815689631499483745341j,
2636
+ -.6743622686854761980403401 + .7730546212691183706919682j,
2637
+ -.4331415561553618854685942 + 1.060073670135929666774323j],
2638
+ 10: [-.9091347320900502436826431 + .1139583137335511169927714j,
2639
+ -.8688459641284764527921864 + .3430008233766309973110589j,
2640
+ -.7837694413101441082655890 + .5759147538499947070009852j,
2641
+ -.6417513866988316136190854 + .8175836167191017226233947j,
2642
+ -.4083220732868861566219785 + 1.081274842819124562037210j],
2643
+ 11: [-.9129067244518981934637318,
2644
+ -.8963656705721166099815744 + .2080480375071031919692341j,
2645
+ -.8453044014712962954184557 + .4178696917801248292797448j,
2646
+ -.7546938934722303128102142 + .6319150050721846494520941j,
2647
+ -.6126871554915194054182909 + .8547813893314764631518509j,
2648
+ -.3868149510055090879155425 + 1.099117466763120928733632j],
2649
+ 12: [-.9084478234140682638817772 + 95506365213450398415258360e-27j,
2650
+ -.8802534342016826507901575 + .2871779503524226723615457j,
2651
+ -.8217296939939077285792834 + .4810212115100676440620548j,
2652
+ -.7276681615395159454547013 + .6792961178764694160048987j,
2653
+ -.5866369321861477207528215 + .8863772751320727026622149j,
2654
+ -.3679640085526312839425808 + 1.114373575641546257595657j],
2655
+ 13: [-.9110914665984182781070663,
2656
+ -.8991314665475196220910718 + .1768342956161043620980863j,
2657
+ -.8625094198260548711573628 + .3547413731172988997754038j,
2658
+ -.7987460692470972510394686 + .5350752120696801938272504j,
2659
+ -.7026234675721275653944062 + .7199611890171304131266374j,
2660
+ -.5631559842430199266325818 + .9135900338325109684927731j,
2661
+ -.3512792323389821669401925 + 1.127591548317705678613239j],
2662
+ 14: [-.9077932138396487614720659 + 82196399419401501888968130e-27j,
2663
+ -.8869506674916445312089167 + .2470079178765333183201435j,
2664
+ -.8441199160909851197897667 + .4131653825102692595237260j,
2665
+ -.7766591387063623897344648 + .5819170677377608590492434j,
2666
+ -.6794256425119233117869491 + .7552857305042033418417492j,
2667
+ -.5418766775112297376541293 + .9373043683516919569183099j,
2668
+ -.3363868224902037330610040 + 1.139172297839859991370924j],
2669
+ 15: [-.9097482363849064167228581,
2670
+ -.9006981694176978324932918 + .1537681197278439351298882j,
2671
+ -.8731264620834984978337843 + .3082352470564267657715883j,
2672
+ -.8256631452587146506294553 + .4642348752734325631275134j,
2673
+ -.7556027168970728127850416 + .6229396358758267198938604j,
2674
+ -.6579196593110998676999362 + .7862895503722515897065645j,
2675
+ -.5224954069658330616875186 + .9581787261092526478889345j,
2676
+ -.3229963059766444287113517 + 1.149416154583629539665297j],
2677
+ 16: [-.9072099595087001356491337 + 72142113041117326028823950e-27j,
2678
+ -.8911723070323647674780132 + .2167089659900576449410059j,
2679
+ -.8584264231521330481755780 + .3621697271802065647661080j,
2680
+ -.8074790293236003885306146 + .5092933751171800179676218j,
2681
+ -.7356166304713115980927279 + .6591950877860393745845254j,
2682
+ -.6379502514039066715773828 + .8137453537108761895522580j,
2683
+ -.5047606444424766743309967 + .9767137477799090692947061j,
2684
+ -.3108782755645387813283867 + 1.158552841199330479412225j],
2685
+ 17: [-.9087141161336397432860029,
2686
+ -.9016273850787285964692844 + .1360267995173024591237303j,
2687
+ -.8801100704438627158492165 + .2725347156478803885651973j,
2688
+ -.8433414495836129204455491 + .4100759282910021624185986j,
2689
+ -.7897644147799708220288138 + .5493724405281088674296232j,
2690
+ -.7166893842372349049842743 + .6914936286393609433305754j,
2691
+ -.6193710717342144521602448 + .8382497252826992979368621j,
2692
+ -.4884629337672704194973683 + .9932971956316781632345466j,
2693
+ -.2998489459990082015466971 + 1.166761272925668786676672j],
2694
+ 18: [-.9067004324162775554189031 + 64279241063930693839360680e-27j,
2695
+ -.8939764278132455733032155 + .1930374640894758606940586j,
2696
+ -.8681095503628830078317207 + .3224204925163257604931634j,
2697
+ -.8281885016242836608829018 + .4529385697815916950149364j,
2698
+ -.7726285030739558780127746 + .5852778162086640620016316j,
2699
+ -.6987821445005273020051878 + .7204696509726630531663123j,
2700
+ -.6020482668090644386627299 + .8602708961893664447167418j,
2701
+ -.4734268069916151511140032 + 1.008234300314801077034158j,
2702
+ -.2897592029880489845789953 + 1.174183010600059128532230j],
2703
+ 19: [-.9078934217899404528985092,
2704
+ -.9021937639390660668922536 + .1219568381872026517578164j,
2705
+ -.8849290585034385274001112 + .2442590757549818229026280j,
2706
+ -.8555768765618421591093993 + .3672925896399872304734923j,
2707
+ -.8131725551578197705476160 + .4915365035562459055630005j,
2708
+ -.7561260971541629355231897 + .6176483917970178919174173j,
2709
+ -.6818424412912442033411634 + .7466272357947761283262338j,
2710
+ -.5858613321217832644813602 + .8801817131014566284786759j,
2711
+ -.4595043449730988600785456 + 1.021768776912671221830298j,
2712
+ -.2804866851439370027628724 + 1.180931628453291873626003j],
2713
+ 20: [-.9062570115576771146523497 + 57961780277849516990208850e-27j,
2714
+ -.8959150941925768608568248 + .1740317175918705058595844j,
2715
+ -.8749560316673332850673214 + .2905559296567908031706902j,
2716
+ -.8427907479956670633544106 + .4078917326291934082132821j,
2717
+ -.7984251191290606875799876 + .5264942388817132427317659j,
2718
+ -.7402780309646768991232610 + .6469975237605228320268752j,
2719
+ -.6658120544829934193890626 + .7703721701100763015154510j,
2720
+ -.5707026806915714094398061 + .8982829066468255593407161j,
2721
+ -.4465700698205149555701841 + 1.034097702560842962315411j,
2722
+ -.2719299580251652601727704 + 1.187099379810885886139638j],
2723
+ 21: [-.9072262653142957028884077,
2724
+ -.9025428073192696303995083 + .1105252572789856480992275j,
2725
+ -.8883808106664449854431605 + .2213069215084350419975358j,
2726
+ -.8643915813643204553970169 + .3326258512522187083009453j,
2727
+ -.8299435470674444100273463 + .4448177739407956609694059j,
2728
+ -.7840287980408341576100581 + .5583186348022854707564856j,
2729
+ -.7250839687106612822281339 + .6737426063024382240549898j,
2730
+ -.6506315378609463397807996 + .7920349342629491368548074j,
2731
+ -.5564766488918562465935297 + .9148198405846724121600860j,
2732
+ -.4345168906815271799687308 + 1.045382255856986531461592j,
2733
+ -.2640041595834031147954813 + 1.192762031948052470183960j],
2734
+ 22: [-.9058702269930872551848625 + 52774908289999045189007100e-27j,
2735
+ -.8972983138153530955952835 + .1584351912289865608659759j,
2736
+ -.8799661455640176154025352 + .2644363039201535049656450j,
2737
+ -.8534754036851687233084587 + .3710389319482319823405321j,
2738
+ -.8171682088462720394344996 + .4785619492202780899653575j,
2739
+ -.7700332930556816872932937 + .5874255426351153211965601j,
2740
+ -.7105305456418785989070935 + .6982266265924524000098548j,
2741
+ -.6362427683267827226840153 + .8118875040246347267248508j,
2742
+ -.5430983056306302779658129 + .9299947824439872998916657j,
2743
+ -.4232528745642628461715044 + 1.055755605227545931204656j,
2744
+ -.2566376987939318038016012 + 1.197982433555213008346532j],
2745
+ 23: [-.9066732476324988168207439,
2746
+ -.9027564979912504609412993 + .1010534335314045013252480j,
2747
+ -.8909283242471251458653994 + .2023024699381223418195228j,
2748
+ -.8709469395587416239596874 + .3039581993950041588888925j,
2749
+ -.8423805948021127057054288 + .4062657948237602726779246j,
2750
+ -.8045561642053176205623187 + .5095305912227258268309528j,
2751
+ -.7564660146829880581478138 + .6141594859476032127216463j,
2752
+ -.6965966033912705387505040 + .7207341374753046970247055j,
2753
+ -.6225903228771341778273152 + .8301558302812980678845563j,
2754
+ -.5304922463810191698502226 + .9439760364018300083750242j,
2755
+ -.4126986617510148836149955 + 1.065328794475513585531053j,
2756
+ -.2497697202208956030229911 + 1.202813187870697831365338j],
2757
+ 24: [-.9055312363372773709269407 + 48440066540478700874836350e-27j,
2758
+ -.8983105104397872954053307 + .1454056133873610120105857j,
2759
+ -.8837358034555706623131950 + .2426335234401383076544239j,
2760
+ -.8615278304016353651120610 + .3403202112618624773397257j,
2761
+ -.8312326466813240652679563 + .4386985933597305434577492j,
2762
+ -.7921695462343492518845446 + .5380628490968016700338001j,
2763
+ -.7433392285088529449175873 + .6388084216222567930378296j,
2764
+ -.6832565803536521302816011 + .7415032695091650806797753j,
2765
+ -.6096221567378335562589532 + .8470292433077202380020454j,
2766
+ -.5185914574820317343536707 + .9569048385259054576937721j,
2767
+ -.4027853855197518014786978 + 1.074195196518674765143729j,
2768
+ -.2433481337524869675825448 + 1.207298683731972524975429j],
2769
+ 25: [-.9062073871811708652496104,
2770
+ -.9028833390228020537142561 + 93077131185102967450643820e-27j,
2771
+ -.8928551459883548836774529 + .1863068969804300712287138j,
2772
+ -.8759497989677857803656239 + .2798521321771408719327250j,
2773
+ -.8518616886554019782346493 + .3738977875907595009446142j,
2774
+ -.8201226043936880253962552 + .4686668574656966589020580j,
2775
+ -.7800496278186497225905443 + .5644441210349710332887354j,
2776
+ -.7306549271849967721596735 + .6616149647357748681460822j,
2777
+ -.6704827128029559528610523 + .7607348858167839877987008j,
2778
+ -.5972898661335557242320528 + .8626676330388028512598538j,
2779
+ -.5073362861078468845461362 + .9689006305344868494672405j,
2780
+ -.3934529878191079606023847 + 1.082433927173831581956863j,
2781
+ -.2373280669322028974199184 + 1.211476658382565356579418j],
2782
+ }
2783
+ for N in originals:
2784
+ p1 = sorted(np.union1d(originals[N],
2785
+ np.conj(originals[N])), key=np.imag)
2786
+ p2 = sorted(besselap(N)[1], key=np.imag)
2787
+ xp_assert_close(p1,
2788
+ p2, rtol=1e-14, check_dtype=False)
2789
+
2790
+ def test_norm_phase(self):
2791
+ # Test some orders and frequencies and see that they have the right
2792
+ # phase at w0
2793
+ for N in (1, 2, 3, 4, 5, 51, 72):
2794
+ for w0 in (1, 100):
2795
+ b, a = bessel(N, w0, analog=True, norm='phase')
2796
+ w = np.linspace(0, w0, 100)
2797
+ w, h = freqs(b, a, w)
2798
+ phase = np.unwrap(np.angle(h))
2799
+ xp_assert_close(phase[[0, -1]], (0, -N*pi/4), rtol=1e-1)
2800
+
2801
+ def test_norm_mag(self):
2802
+ # Test some orders and frequencies and see that they have the right
2803
+ # mag at w0
2804
+ for N in (1, 2, 3, 4, 5, 51, 72):
2805
+ for w0 in (1, 100):
2806
+ b, a = bessel(N, w0, analog=True, norm='mag')
2807
+ w = (0, w0)
2808
+ w, h = freqs(b, a, w)
2809
+ mag = abs(h)
2810
+ xp_assert_close(mag, (1, 1/np.sqrt(2)))
2811
+
2812
+ def test_norm_delay(self):
2813
+ # Test some orders and frequencies and see that they have the right
2814
+ # delay at DC
2815
+ for N in (1, 2, 3, 4, 5, 51, 72):
2816
+ for w0 in (1, 100):
2817
+ b, a = bessel(N, w0, analog=True, norm='delay')
2818
+ w = np.linspace(0, 10*w0, 1000)
2819
+ w, h = freqs(b, a, w)
2820
+ delay = -np.diff(np.unwrap(np.angle(h)))/np.diff(w)
2821
+ xp_assert_close(delay[0], 1/w0, rtol=1e-4)
2822
+
2823
+ def test_norm_factor(self):
2824
+ mpmath_values = {
2825
+ 1: 1.0, 2: 1.361654128716130520, 3: 1.755672368681210649,
2826
+ 4: 2.113917674904215843, 5: 2.427410702152628137,
2827
+ 6: 2.703395061202921876, 7: 2.951722147038722771,
2828
+ 8: 3.179617237510651330, 9: 3.391693138911660101,
2829
+ 10: 3.590980594569163482, 11: 3.779607416439620092,
2830
+ 12: 3.959150821144285315, 13: 4.130825499383535980,
2831
+ 14: 4.295593409533637564, 15: 4.454233021624377494,
2832
+ 16: 4.607385465472647917, 17: 4.755586548961147727,
2833
+ 18: 4.899289677284488007, 19: 5.038882681488207605,
2834
+ 20: 5.174700441742707423, 21: 5.307034531360917274,
2835
+ 22: 5.436140703250035999, 23: 5.562244783787878196,
2836
+ 24: 5.685547371295963521, 25: 5.806227623775418541,
2837
+ 50: 8.268963160013226298, 51: 8.352374541546012058,
2838
+ }
2839
+ for N in mpmath_values:
2840
+ z, p, k = besselap(N, 'delay')
2841
+ xp_assert_close(mpmath_values[N], _norm_factor(p, k), rtol=1e-13)
2842
+
2843
+ def test_bessel_poly(self):
2844
+ xp_assert_equal(_bessel_poly(5), [945, 945, 420, 105, 15, 1])
2845
+ xp_assert_equal(_bessel_poly(4, True), [1, 10, 45, 105, 105])
2846
+
2847
+ def test_bessel_zeros(self):
2848
+ xp_assert_equal(_bessel_zeros(0), [])
2849
+
2850
+ def test_invalid(self):
2851
+ assert_raises(ValueError, besselap, 5, 'nonsense')
2852
+ assert_raises(ValueError, besselap, -5)
2853
+ assert_raises(ValueError, besselap, 3.2)
2854
+ assert_raises(ValueError, _bessel_poly, -3)
2855
+ assert_raises(ValueError, _bessel_poly, 3.3)
2856
+
2857
+ @pytest.mark.fail_slow(10)
2858
+ def test_fs_param(self):
2859
+ for norm in ('phase', 'mag', 'delay'):
2860
+ for fs in (900, 900.1, 1234.567):
2861
+ for N in (0, 1, 2, 3, 10):
2862
+ for fc in (100, 100.1, 432.12345):
2863
+ for btype in ('lp', 'hp'):
2864
+ ba1 = bessel(N, fc, btype, norm=norm, fs=fs)
2865
+ ba2 = bessel(N, fc/(fs/2), btype, norm=norm)
2866
+ for ba1_, ba2_ in zip(ba1, ba2):
2867
+ xp_assert_close(ba1_, ba2_)
2868
+ for fc in ((100, 200), (100.1, 200.2), (321.123, 432.123)):
2869
+ for btype in ('bp', 'bs'):
2870
+ ba1 = bessel(N, fc, btype, norm=norm, fs=fs)
2871
+ for seq in (list, tuple, array):
2872
+ fcnorm = seq([f/(fs/2) for f in fc])
2873
+ ba2 = bessel(N, fcnorm, btype, norm=norm)
2874
+ for ba1_, ba2_ in zip(ba1, ba2):
2875
+ xp_assert_close(ba1_, ba2_)
2876
+
2877
+
2878
+ class TestButter:
2879
+
2880
+ def test_degenerate(self):
2881
+ # 0-order filter is just a passthrough
2882
+ b, a = butter(0, 1, analog=True)
2883
+ xp_assert_equal(b, np.asarray([1.0]))
2884
+ xp_assert_equal(a, np.asarray([1.0]))
2885
+
2886
+ # 1-order filter is same for all types
2887
+ b, a = butter(1, 1, analog=True)
2888
+ assert_array_almost_equal(b, [1])
2889
+ assert_array_almost_equal(a, [1, 1])
2890
+
2891
+ z, p, k = butter(1, 0.3, output='zpk')
2892
+ xp_assert_equal(z, np.asarray([-1.0]))
2893
+ xp_assert_close(p, [3.249196962329063e-01 + 0j], rtol=1e-14)
2894
+ xp_assert_close(k, 3.375401518835469e-01, rtol=1e-14)
2895
+
2896
+ def test_basic(self):
2897
+ # analog s-plane
2898
+ for N in range(25):
2899
+ wn = 0.01
2900
+ z, p, k = butter(N, wn, 'low', analog=True, output='zpk')
2901
+ assert_array_almost_equal([], z)
2902
+ assert len(p) == N
2903
+ # All poles should be at distance wn from origin
2904
+ assert_array_almost_equal(abs(p), np.asarray(wn))
2905
+ assert all(np.real(p) <= 0) # No poles in right half of S-plane
2906
+ assert_array_almost_equal(wn**N, k)
2907
+
2908
+ # digital z-plane
2909
+ for N in range(25):
2910
+ wn = 0.01
2911
+ z, p, k = butter(N, wn, 'high', analog=False, output='zpk')
2912
+ xp_assert_equal(np.ones(N), z) # All zeros exactly at DC
2913
+ assert all(np.abs(p) <= 1) # No poles outside unit circle
2914
+
2915
+ b1, a1 = butter(2, 1, analog=True)
2916
+ assert_array_almost_equal(b1, [1])
2917
+ assert_array_almost_equal(a1, [1, np.sqrt(2), 1])
2918
+
2919
+ b2, a2 = butter(5, 1, analog=True)
2920
+ assert_array_almost_equal(b2, [1])
2921
+ assert_array_almost_equal(a2, [1, 3.2361, 5.2361,
2922
+ 5.2361, 3.2361, 1], decimal=4)
2923
+
2924
+ b3, a3 = butter(10, 1, analog=True)
2925
+ assert_array_almost_equal(b3, [1])
2926
+ assert_array_almost_equal(a3, [1, 6.3925, 20.4317, 42.8021, 64.8824,
2927
+ 74.2334, 64.8824, 42.8021, 20.4317,
2928
+ 6.3925, 1], decimal=4)
2929
+
2930
+ b2, a2 = butter(19, 1.0441379169150726, analog=True)
2931
+ assert_array_almost_equal(b2, [2.2720], decimal=4)
2932
+ assert_array_almost_equal(a2, 1.0e+004 * np.array([
2933
+ 0.0001, 0.0013, 0.0080, 0.0335, 0.1045, 0.2570,
2934
+ 0.5164, 0.8669, 1.2338, 1.5010, 1.5672, 1.4044,
2935
+ 1.0759, 0.6986, 0.3791, 0.1681, 0.0588, 0.0153,
2936
+ 0.0026, 0.0002]), decimal=0)
2937
+
2938
+ b, a = butter(5, 0.4)
2939
+ assert_array_almost_equal(b, [0.0219, 0.1097, 0.2194,
2940
+ 0.2194, 0.1097, 0.0219], decimal=4)
2941
+ assert_array_almost_equal(a, [1.0000, -0.9853, 0.9738,
2942
+ -0.3864, 0.1112, -0.0113], decimal=4)
2943
+
2944
+ def test_highpass(self):
2945
+ # highpass, high even order
2946
+ z, p, k = butter(28, 0.43, 'high', output='zpk')
2947
+ z2 = np.ones(28)
2948
+ p2 = [
2949
+ 2.068257195514592e-01 + 9.238294351481734e-01j,
2950
+ 2.068257195514592e-01 - 9.238294351481734e-01j,
2951
+ 1.874933103892023e-01 + 8.269455076775277e-01j,
2952
+ 1.874933103892023e-01 - 8.269455076775277e-01j,
2953
+ 1.717435567330153e-01 + 7.383078571194629e-01j,
2954
+ 1.717435567330153e-01 - 7.383078571194629e-01j,
2955
+ 1.588266870755982e-01 + 6.564623730651094e-01j,
2956
+ 1.588266870755982e-01 - 6.564623730651094e-01j,
2957
+ 1.481881532502603e-01 + 5.802343458081779e-01j,
2958
+ 1.481881532502603e-01 - 5.802343458081779e-01j,
2959
+ 1.394122576319697e-01 + 5.086609000582009e-01j,
2960
+ 1.394122576319697e-01 - 5.086609000582009e-01j,
2961
+ 1.321840881809715e-01 + 4.409411734716436e-01j,
2962
+ 1.321840881809715e-01 - 4.409411734716436e-01j,
2963
+ 1.262633413354405e-01 + 3.763990035551881e-01j,
2964
+ 1.262633413354405e-01 - 3.763990035551881e-01j,
2965
+ 1.214660449478046e-01 + 3.144545234797277e-01j,
2966
+ 1.214660449478046e-01 - 3.144545234797277e-01j,
2967
+ 1.104868766650320e-01 + 2.771505404367791e-02j,
2968
+ 1.104868766650320e-01 - 2.771505404367791e-02j,
2969
+ 1.111768629525075e-01 + 8.331369153155753e-02j,
2970
+ 1.111768629525075e-01 - 8.331369153155753e-02j,
2971
+ 1.125740630842972e-01 + 1.394219509611784e-01j,
2972
+ 1.125740630842972e-01 - 1.394219509611784e-01j,
2973
+ 1.147138487992747e-01 + 1.963932363793666e-01j,
2974
+ 1.147138487992747e-01 - 1.963932363793666e-01j,
2975
+ 1.176516491045901e-01 + 2.546021573417188e-01j,
2976
+ 1.176516491045901e-01 - 2.546021573417188e-01j,
2977
+ ]
2978
+ k2 = 1.446671081817286e-06
2979
+ xp_assert_equal(z, z2)
2980
+ xp_assert_close(sorted(p, key=np.imag),
2981
+ sorted(p2, key=np.imag), rtol=1e-7)
2982
+ xp_assert_close(k, k2, rtol=1e-10)
2983
+
2984
+ # highpass, high odd order
2985
+ z, p, k = butter(27, 0.56, 'high', output='zpk')
2986
+ z2 = np.ones(27)
2987
+ p2 = [
2988
+ -1.772572785680147e-01 + 9.276431102995948e-01j,
2989
+ -1.772572785680147e-01 - 9.276431102995948e-01j,
2990
+ -1.600766565322114e-01 + 8.264026279893268e-01j,
2991
+ -1.600766565322114e-01 - 8.264026279893268e-01j,
2992
+ -1.461948419016121e-01 + 7.341841939120078e-01j,
2993
+ -1.461948419016121e-01 - 7.341841939120078e-01j,
2994
+ -1.348975284762046e-01 + 6.493235066053785e-01j,
2995
+ -1.348975284762046e-01 - 6.493235066053785e-01j,
2996
+ -1.256628210712206e-01 + 5.704921366889227e-01j,
2997
+ -1.256628210712206e-01 - 5.704921366889227e-01j,
2998
+ -1.181038235962314e-01 + 4.966120551231630e-01j,
2999
+ -1.181038235962314e-01 - 4.966120551231630e-01j,
3000
+ -1.119304913239356e-01 + 4.267938916403775e-01j,
3001
+ -1.119304913239356e-01 - 4.267938916403775e-01j,
3002
+ -1.069237739782691e-01 + 3.602914879527338e-01j,
3003
+ -1.069237739782691e-01 - 3.602914879527338e-01j,
3004
+ -1.029178030691416e-01 + 2.964677964142126e-01j,
3005
+ -1.029178030691416e-01 - 2.964677964142126e-01j,
3006
+ -9.978747500816100e-02 + 2.347687643085738e-01j,
3007
+ -9.978747500816100e-02 - 2.347687643085738e-01j,
3008
+ -9.743974496324025e-02 + 1.747028739092479e-01j,
3009
+ -9.743974496324025e-02 - 1.747028739092479e-01j,
3010
+ -9.580754551625957e-02 + 1.158246860771989e-01j,
3011
+ -9.580754551625957e-02 - 1.158246860771989e-01j,
3012
+ -9.484562207782568e-02 + 5.772118357151691e-02j,
3013
+ -9.484562207782568e-02 - 5.772118357151691e-02j,
3014
+ -9.452783117928215e-02
3015
+ ]
3016
+ k2 = 9.585686688851069e-09
3017
+ xp_assert_equal(z, z2)
3018
+ xp_assert_close(sorted(p, key=np.imag),
3019
+ sorted(p2, key=np.imag), rtol=1e-8)
3020
+ xp_assert_close(k, k2)
3021
+
3022
+ def test_bandpass(self):
3023
+ z, p, k = butter(8, [0.25, 0.33], 'band', output='zpk')
3024
+ z2 = [1, 1, 1, 1, 1, 1, 1, 1,
3025
+ -1, -1, -1, -1, -1, -1, -1, -1]
3026
+ p2 = [
3027
+ 4.979909925436156e-01 + 8.367609424799387e-01j,
3028
+ 4.979909925436156e-01 - 8.367609424799387e-01j,
3029
+ 4.913338722555539e-01 + 7.866774509868817e-01j,
3030
+ 4.913338722555539e-01 - 7.866774509868817e-01j,
3031
+ 5.035229361778706e-01 + 7.401147376726750e-01j,
3032
+ 5.035229361778706e-01 - 7.401147376726750e-01j,
3033
+ 5.307617160406101e-01 + 7.029184459442954e-01j,
3034
+ 5.307617160406101e-01 - 7.029184459442954e-01j,
3035
+ 5.680556159453138e-01 + 6.788228792952775e-01j,
3036
+ 5.680556159453138e-01 - 6.788228792952775e-01j,
3037
+ 6.100962560818854e-01 + 6.693849403338664e-01j,
3038
+ 6.100962560818854e-01 - 6.693849403338664e-01j,
3039
+ 6.904694312740631e-01 + 6.930501690145245e-01j,
3040
+ 6.904694312740631e-01 - 6.930501690145245e-01j,
3041
+ 6.521767004237027e-01 + 6.744414640183752e-01j,
3042
+ 6.521767004237027e-01 - 6.744414640183752e-01j,
3043
+ ]
3044
+ k2 = 3.398854055800844e-08
3045
+ xp_assert_equal(z, z2, check_dtype=False)
3046
+ xp_assert_close(sorted(p, key=np.imag),
3047
+ sorted(p2, key=np.imag), rtol=1e-13)
3048
+ xp_assert_close(k, k2, rtol=1e-13)
3049
+
3050
+ # bandpass analog
3051
+ z, p, k = butter(4, [90.5, 110.5], 'bp', analog=True, output='zpk')
3052
+ z2 = np.zeros(4, dtype=z.dtype)
3053
+ p2 = [
3054
+ -4.179137760733086e+00 + 1.095935899082837e+02j,
3055
+ -4.179137760733086e+00 - 1.095935899082837e+02j,
3056
+ -9.593598668443835e+00 + 1.034745398029734e+02j,
3057
+ -9.593598668443835e+00 - 1.034745398029734e+02j,
3058
+ -8.883991981781929e+00 + 9.582087115567160e+01j,
3059
+ -8.883991981781929e+00 - 9.582087115567160e+01j,
3060
+ -3.474530886568715e+00 + 9.111599925805801e+01j,
3061
+ -3.474530886568715e+00 - 9.111599925805801e+01j,
3062
+ ]
3063
+ k2 = 1.600000000000001e+05
3064
+ xp_assert_equal(z, z2)
3065
+ xp_assert_close(sorted(p, key=np.imag),
3066
+ sorted(p2, key=np.imag))
3067
+ xp_assert_close(k, k2, rtol=1e-15)
3068
+
3069
+ def test_bandstop(self):
3070
+ z, p, k = butter(7, [0.45, 0.56], 'stop', output='zpk')
3071
+ z2 = [-1.594474531383421e-02 + 9.998728744679880e-01j,
3072
+ -1.594474531383421e-02 - 9.998728744679880e-01j,
3073
+ -1.594474531383421e-02 + 9.998728744679880e-01j,
3074
+ -1.594474531383421e-02 - 9.998728744679880e-01j,
3075
+ -1.594474531383421e-02 + 9.998728744679880e-01j,
3076
+ -1.594474531383421e-02 - 9.998728744679880e-01j,
3077
+ -1.594474531383421e-02 + 9.998728744679880e-01j,
3078
+ -1.594474531383421e-02 - 9.998728744679880e-01j,
3079
+ -1.594474531383421e-02 + 9.998728744679880e-01j,
3080
+ -1.594474531383421e-02 - 9.998728744679880e-01j,
3081
+ -1.594474531383421e-02 + 9.998728744679880e-01j,
3082
+ -1.594474531383421e-02 - 9.998728744679880e-01j,
3083
+ -1.594474531383421e-02 + 9.998728744679880e-01j,
3084
+ -1.594474531383421e-02 - 9.998728744679880e-01j]
3085
+ p2 = [-1.766850742887729e-01 + 9.466951258673900e-01j,
3086
+ -1.766850742887729e-01 - 9.466951258673900e-01j,
3087
+ 1.467897662432886e-01 + 9.515917126462422e-01j,
3088
+ 1.467897662432886e-01 - 9.515917126462422e-01j,
3089
+ -1.370083529426906e-01 + 8.880376681273993e-01j,
3090
+ -1.370083529426906e-01 - 8.880376681273993e-01j,
3091
+ 1.086774544701390e-01 + 8.915240810704319e-01j,
3092
+ 1.086774544701390e-01 - 8.915240810704319e-01j,
3093
+ -7.982704457700891e-02 + 8.506056315273435e-01j,
3094
+ -7.982704457700891e-02 - 8.506056315273435e-01j,
3095
+ 5.238812787110331e-02 + 8.524011102699969e-01j,
3096
+ 5.238812787110331e-02 - 8.524011102699969e-01j,
3097
+ -1.357545000491310e-02 + 8.382287744986582e-01j,
3098
+ -1.357545000491310e-02 - 8.382287744986582e-01j]
3099
+ k2 = 4.577122512960063e-01
3100
+ xp_assert_close(sorted(z, key=np.imag),
3101
+ sorted(z2, key=np.imag))
3102
+ xp_assert_close(sorted(p, key=np.imag),
3103
+ sorted(p2, key=np.imag))
3104
+ xp_assert_close(k, k2, rtol=1e-14)
3105
+
3106
+ def test_ba_output(self):
3107
+ b, a = butter(4, [100, 300], 'bandpass', analog=True)
3108
+ b2 = [1.6e+09, 0, 0, 0, 0]
3109
+ a2 = [1.000000000000000e+00, 5.226251859505511e+02,
3110
+ 2.565685424949238e+05, 6.794127417357160e+07,
3111
+ 1.519411254969542e+10, 2.038238225207147e+12,
3112
+ 2.309116882454312e+14, 1.411088002066486e+16,
3113
+ 8.099999999999991e+17]
3114
+ xp_assert_close(b, b2, rtol=1e-14)
3115
+ xp_assert_close(a, a2, rtol=1e-14)
3116
+
3117
+ def test_fs_param(self):
3118
+ for fs in (900, 900.1, 1234.567):
3119
+ for N in (0, 1, 2, 3, 10):
3120
+ for fc in (100, 100.1, 432.12345):
3121
+ for btype in ('lp', 'hp'):
3122
+ ba1 = butter(N, fc, btype, fs=fs)
3123
+ ba2 = butter(N, fc/(fs/2), btype)
3124
+ for ba1_, ba2_ in zip(ba1, ba2):
3125
+ xp_assert_close(ba1_, ba2_)
3126
+ for fc in ((100, 200), (100.1, 200.2), (321.123, 432.123)):
3127
+ for btype in ('bp', 'bs'):
3128
+ ba1 = butter(N, fc, btype, fs=fs)
3129
+ for seq in (list, tuple, array):
3130
+ fcnorm = seq([f/(fs/2) for f in fc])
3131
+ ba2 = butter(N, fcnorm, btype)
3132
+ for ba1_, ba2_ in zip(ba1, ba2):
3133
+ xp_assert_close(ba1_, ba2_)
3134
+
3135
+
3136
+ class TestCheby1:
3137
+
3138
+ def test_degenerate(self):
3139
+ # 0-order filter is just a passthrough
3140
+ # Even-order filters have DC gain of -rp dB
3141
+ b, a = cheby1(0, 10*np.log10(2), 1, analog=True)
3142
+ assert_array_almost_equal(b, [1/np.sqrt(2)])
3143
+ xp_assert_equal(a, np.asarray([1.0]))
3144
+
3145
+ # 1-order filter is same for all types
3146
+ b, a = cheby1(1, 10*np.log10(2), 1, analog=True)
3147
+ assert_array_almost_equal(b, [1])
3148
+ assert_array_almost_equal(a, [1, 1])
3149
+
3150
+ z, p, k = cheby1(1, 0.1, 0.3, output='zpk')
3151
+ xp_assert_equal(z, np.asarray([-1.0]))
3152
+ xp_assert_close(p, [-5.390126972799615e-01 + 0j], rtol=1e-14)
3153
+ xp_assert_close(k, 7.695063486399808e-01, rtol=1e-14)
3154
+
3155
+ def test_basic(self):
3156
+ for N in range(25):
3157
+ wn = 0.01
3158
+ z, p, k = cheby1(N, 1, wn, 'low', analog=True, output='zpk')
3159
+ assert_array_almost_equal([], z)
3160
+ assert len(p) == N
3161
+ assert all(np.real(p) <= 0) # No poles in right half of S-plane
3162
+
3163
+ for N in range(25):
3164
+ wn = 0.01
3165
+ z, p, k = cheby1(N, 1, wn, 'high', analog=False, output='zpk')
3166
+ xp_assert_equal(np.ones(N), z) # All zeros exactly at DC
3167
+ assert all(np.abs(p) <= 1) # No poles outside unit circle
3168
+
3169
+ # Same test as TestNormalize
3170
+ b, a = cheby1(8, 0.5, 0.048)
3171
+ assert_array_almost_equal(b, [
3172
+ 2.150733144728282e-11, 1.720586515782626e-10,
3173
+ 6.022052805239190e-10, 1.204410561047838e-09,
3174
+ 1.505513201309798e-09, 1.204410561047838e-09,
3175
+ 6.022052805239190e-10, 1.720586515782626e-10,
3176
+ 2.150733144728282e-11], decimal=14)
3177
+ assert_array_almost_equal(a, [
3178
+ 1.000000000000000e+00, -7.782402035027959e+00,
3179
+ 2.654354569747454e+01, -5.182182531666387e+01,
3180
+ 6.334127355102684e+01, -4.963358186631157e+01,
3181
+ 2.434862182949389e+01, -6.836925348604676e+00,
3182
+ 8.412934944449140e-01], decimal=14)
3183
+
3184
+ b, a = cheby1(4, 1, [0.4, 0.7], btype='band')
3185
+ assert_array_almost_equal(b, [0.0084, 0, -0.0335, 0, 0.0502, 0,
3186
+ -0.0335, 0, 0.0084], decimal=4)
3187
+ assert_array_almost_equal(a, [1.0, 1.1191, 2.862, 2.2986, 3.4137,
3188
+ 1.8653, 1.8982, 0.5676, 0.4103],
3189
+ decimal=4)
3190
+
3191
+ b2, a2 = cheby1(5, 3, 1, analog=True)
3192
+ assert_array_almost_equal(b2, [0.0626], decimal=4)
3193
+ assert_array_almost_equal(a2, [1, 0.5745, 1.4150, 0.5489, 0.4080,
3194
+ 0.0626], decimal=4)
3195
+
3196
+ b, a = cheby1(8, 0.5, 0.1)
3197
+ assert_array_almost_equal(b, 1.0e-006 * np.array([
3198
+ 0.00703924326028, 0.05631394608227, 0.19709881128793,
3199
+ 0.39419762257586, 0.49274702821983, 0.39419762257586,
3200
+ 0.19709881128793, 0.05631394608227, 0.00703924326028]),
3201
+ decimal=13)
3202
+ assert_array_almost_equal(a, [
3203
+ 1.00000000000000, -7.44912258934158, 24.46749067762108,
3204
+ -46.27560200466141, 55.11160187999928, -42.31640010161038,
3205
+ 20.45543300484147, -5.69110270561444, 0.69770374759022],
3206
+ decimal=13)
3207
+
3208
+ b, a = cheby1(8, 0.5, 0.25)
3209
+ assert_array_almost_equal(b, 1.0e-003 * np.array([
3210
+ 0.00895261138923, 0.07162089111382, 0.25067311889837,
3211
+ 0.50134623779673, 0.62668279724591, 0.50134623779673,
3212
+ 0.25067311889837, 0.07162089111382, 0.00895261138923]),
3213
+ decimal=13)
3214
+ assert_array_almost_equal(a, [1.00000000000000, -5.97529229188545,
3215
+ 16.58122329202101, -27.71423273542923,
3216
+ 30.39509758355313, -22.34729670426879,
3217
+ 10.74509800434910, -3.08924633697497,
3218
+ 0.40707685889802], decimal=13)
3219
+
3220
+ def test_highpass(self):
3221
+ # high even order
3222
+ z, p, k = cheby1(24, 0.7, 0.2, 'high', output='zpk')
3223
+ z2 = np.ones(24)
3224
+ p2 = [-6.136558509657073e-01 + 2.700091504942893e-01j,
3225
+ -6.136558509657073e-01 - 2.700091504942893e-01j,
3226
+ -3.303348340927516e-01 + 6.659400861114254e-01j,
3227
+ -3.303348340927516e-01 - 6.659400861114254e-01j,
3228
+ 8.779713780557169e-03 + 8.223108447483040e-01j,
3229
+ 8.779713780557169e-03 - 8.223108447483040e-01j,
3230
+ 2.742361123006911e-01 + 8.356666951611864e-01j,
3231
+ 2.742361123006911e-01 - 8.356666951611864e-01j,
3232
+ 4.562984557158206e-01 + 7.954276912303594e-01j,
3233
+ 4.562984557158206e-01 - 7.954276912303594e-01j,
3234
+ 5.777335494123628e-01 + 7.435821817961783e-01j,
3235
+ 5.777335494123628e-01 - 7.435821817961783e-01j,
3236
+ 6.593260977749194e-01 + 6.955390907990932e-01j,
3237
+ 6.593260977749194e-01 - 6.955390907990932e-01j,
3238
+ 7.149590948466562e-01 + 6.559437858502012e-01j,
3239
+ 7.149590948466562e-01 - 6.559437858502012e-01j,
3240
+ 7.532432388188739e-01 + 6.256158042292060e-01j,
3241
+ 7.532432388188739e-01 - 6.256158042292060e-01j,
3242
+ 7.794365244268271e-01 + 6.042099234813333e-01j,
3243
+ 7.794365244268271e-01 - 6.042099234813333e-01j,
3244
+ 7.967253874772997e-01 + 5.911966597313203e-01j,
3245
+ 7.967253874772997e-01 - 5.911966597313203e-01j,
3246
+ 8.069756417293870e-01 + 5.862214589217275e-01j,
3247
+ 8.069756417293870e-01 - 5.862214589217275e-01j]
3248
+ k2 = 6.190427617192018e-04
3249
+ xp_assert_equal(z, z2)
3250
+ xp_assert_close(sorted(p, key=np.imag),
3251
+ sorted(p2, key=np.imag), rtol=1e-10)
3252
+ xp_assert_close(k, k2, rtol=1e-10)
3253
+
3254
+ # high odd order
3255
+ z, p, k = cheby1(23, 0.8, 0.3, 'high', output='zpk')
3256
+ z2 = np.ones(23)
3257
+ p2 = [-7.676400532011010e-01,
3258
+ -6.754621070166477e-01 + 3.970502605619561e-01j,
3259
+ -6.754621070166477e-01 - 3.970502605619561e-01j,
3260
+ -4.528880018446727e-01 + 6.844061483786332e-01j,
3261
+ -4.528880018446727e-01 - 6.844061483786332e-01j,
3262
+ -1.986009130216447e-01 + 8.382285942941594e-01j,
3263
+ -1.986009130216447e-01 - 8.382285942941594e-01j,
3264
+ 2.504673931532608e-02 + 8.958137635794080e-01j,
3265
+ 2.504673931532608e-02 - 8.958137635794080e-01j,
3266
+ 2.001089429976469e-01 + 9.010678290791480e-01j,
3267
+ 2.001089429976469e-01 - 9.010678290791480e-01j,
3268
+ 3.302410157191755e-01 + 8.835444665962544e-01j,
3269
+ 3.302410157191755e-01 - 8.835444665962544e-01j,
3270
+ 4.246662537333661e-01 + 8.594054226449009e-01j,
3271
+ 4.246662537333661e-01 - 8.594054226449009e-01j,
3272
+ 4.919620928120296e-01 + 8.366772762965786e-01j,
3273
+ 4.919620928120296e-01 - 8.366772762965786e-01j,
3274
+ 5.385746917494749e-01 + 8.191616180796720e-01j,
3275
+ 5.385746917494749e-01 - 8.191616180796720e-01j,
3276
+ 5.855636993537203e-01 + 8.060680937701062e-01j,
3277
+ 5.855636993537203e-01 - 8.060680937701062e-01j,
3278
+ 5.688812849391721e-01 + 8.086497795114683e-01j,
3279
+ 5.688812849391721e-01 - 8.086497795114683e-01j]
3280
+ k2 = 1.941697029206324e-05
3281
+ xp_assert_equal(z, z2)
3282
+ xp_assert_close(sorted(p, key=np.imag),
3283
+ sorted(p2, key=np.imag), rtol=1e-10)
3284
+ xp_assert_close(k, k2, rtol=1e-10)
3285
+
3286
+ z, p, k = cheby1(10, 1, 1000, 'high', analog=True, output='zpk')
3287
+ z2 = np.zeros(10)
3288
+ p2 = [-3.144743169501551e+03 + 3.511680029092744e+03j,
3289
+ -3.144743169501551e+03 - 3.511680029092744e+03j,
3290
+ -5.633065604514602e+02 + 2.023615191183945e+03j,
3291
+ -5.633065604514602e+02 - 2.023615191183945e+03j,
3292
+ -1.946412183352025e+02 + 1.372309454274755e+03j,
3293
+ -1.946412183352025e+02 - 1.372309454274755e+03j,
3294
+ -7.987162953085479e+01 + 1.105207708045358e+03j,
3295
+ -7.987162953085479e+01 - 1.105207708045358e+03j,
3296
+ -2.250315039031946e+01 + 1.001723931471477e+03j,
3297
+ -2.250315039031946e+01 - 1.001723931471477e+03j]
3298
+ k2 = 8.912509381337453e-01
3299
+ xp_assert_equal(z, z2)
3300
+ xp_assert_close(sorted(p, key=np.imag),
3301
+ sorted(p2, key=np.imag), rtol=1e-13)
3302
+ xp_assert_close(k, k2, rtol=1e-15)
3303
+
3304
+ def test_bandpass(self):
3305
+ z, p, k = cheby1(8, 1, [0.3, 0.4], 'bp', output='zpk')
3306
+ z2 = [1, 1, 1, 1, 1, 1, 1, 1, -1, -1, -1, -1, -1, -1, -1, -1]
3307
+ p2 = [3.077784854851463e-01 + 9.453307017592942e-01j,
3308
+ 3.077784854851463e-01 - 9.453307017592942e-01j,
3309
+ 3.280567400654425e-01 + 9.272377218689016e-01j,
3310
+ 3.280567400654425e-01 - 9.272377218689016e-01j,
3311
+ 3.677912763284301e-01 + 9.038008865279966e-01j,
3312
+ 3.677912763284301e-01 - 9.038008865279966e-01j,
3313
+ 4.194425632520948e-01 + 8.769407159656157e-01j,
3314
+ 4.194425632520948e-01 - 8.769407159656157e-01j,
3315
+ 4.740921994669189e-01 + 8.496508528630974e-01j,
3316
+ 4.740921994669189e-01 - 8.496508528630974e-01j,
3317
+ 5.234866481897429e-01 + 8.259608422808477e-01j,
3318
+ 5.234866481897429e-01 - 8.259608422808477e-01j,
3319
+ 5.844717632289875e-01 + 8.052901363500210e-01j,
3320
+ 5.844717632289875e-01 - 8.052901363500210e-01j,
3321
+ 5.615189063336070e-01 + 8.100667803850766e-01j,
3322
+ 5.615189063336070e-01 - 8.100667803850766e-01j]
3323
+ k2 = 5.007028718074307e-09
3324
+ xp_assert_equal(z, z2, check_dtype=False)
3325
+ xp_assert_close(sorted(p, key=np.imag),
3326
+ sorted(p2, key=np.imag), rtol=1e-13)
3327
+ xp_assert_close(k, k2, rtol=1e-13)
3328
+
3329
+ def test_bandstop(self):
3330
+ z, p, k = cheby1(7, 1, [0.5, 0.6], 'stop', output='zpk')
3331
+ z2 = [-1.583844403245361e-01 + 9.873775210440450e-01j,
3332
+ -1.583844403245361e-01 - 9.873775210440450e-01j,
3333
+ -1.583844403245361e-01 + 9.873775210440450e-01j,
3334
+ -1.583844403245361e-01 - 9.873775210440450e-01j,
3335
+ -1.583844403245361e-01 + 9.873775210440450e-01j,
3336
+ -1.583844403245361e-01 - 9.873775210440450e-01j,
3337
+ -1.583844403245361e-01 + 9.873775210440450e-01j,
3338
+ -1.583844403245361e-01 - 9.873775210440450e-01j,
3339
+ -1.583844403245361e-01 + 9.873775210440450e-01j,
3340
+ -1.583844403245361e-01 - 9.873775210440450e-01j,
3341
+ -1.583844403245361e-01 + 9.873775210440450e-01j,
3342
+ -1.583844403245361e-01 - 9.873775210440450e-01j,
3343
+ -1.583844403245361e-01 + 9.873775210440450e-01j,
3344
+ -1.583844403245361e-01 - 9.873775210440450e-01j]
3345
+ p2 = [-8.942974551472813e-02 + 3.482480481185926e-01j,
3346
+ -8.942974551472813e-02 - 3.482480481185926e-01j,
3347
+ 1.293775154041798e-01 + 8.753499858081858e-01j,
3348
+ 1.293775154041798e-01 - 8.753499858081858e-01j,
3349
+ 3.399741945062013e-02 + 9.690316022705607e-01j,
3350
+ 3.399741945062013e-02 - 9.690316022705607e-01j,
3351
+ 4.167225522796539e-04 + 9.927338161087488e-01j,
3352
+ 4.167225522796539e-04 - 9.927338161087488e-01j,
3353
+ -3.912966549550960e-01 + 8.046122859255742e-01j,
3354
+ -3.912966549550960e-01 - 8.046122859255742e-01j,
3355
+ -3.307805547127368e-01 + 9.133455018206508e-01j,
3356
+ -3.307805547127368e-01 - 9.133455018206508e-01j,
3357
+ -3.072658345097743e-01 + 9.443589759799366e-01j,
3358
+ -3.072658345097743e-01 - 9.443589759799366e-01j]
3359
+ k2 = 3.619438310405028e-01
3360
+ xp_assert_close(sorted(z, key=np.imag),
3361
+ sorted(z2, key=np.imag), rtol=1e-13)
3362
+ xp_assert_close(sorted(p, key=np.imag),
3363
+ sorted(p2, key=np.imag), rtol=1e-13)
3364
+ xp_assert_close(k, k2, rtol=0, atol=5e-16)
3365
+
3366
+ def test_ba_output(self):
3367
+ # with transfer function conversion, without digital conversion
3368
+ b, a = cheby1(5, 0.9, [210, 310], 'stop', analog=True)
3369
+ b2 = [1.000000000000006e+00, 0,
3370
+ 3.255000000000020e+05, 0,
3371
+ 4.238010000000026e+10, 0,
3372
+ 2.758944510000017e+15, 0,
3373
+ 8.980364380050052e+19, 0,
3374
+ 1.169243442282517e+24
3375
+ ]
3376
+ a2 = [1.000000000000000e+00, 4.630555945694342e+02,
3377
+ 4.039266454794788e+05, 1.338060988610237e+08,
3378
+ 5.844333551294591e+10, 1.357346371637638e+13,
3379
+ 3.804661141892782e+15, 5.670715850340080e+17,
3380
+ 1.114411200988328e+20, 8.316815934908471e+21,
3381
+ 1.169243442282517e+24
3382
+ ]
3383
+ xp_assert_close(b, b2, rtol=1e-14)
3384
+ xp_assert_close(a, a2, rtol=1e-14)
3385
+
3386
+ def test_fs_param(self):
3387
+ for fs in (900, 900.1, 1234.567):
3388
+ for N in (0, 1, 2, 3, 10):
3389
+ for fc in (100, 100.1, 432.12345):
3390
+ for btype in ('lp', 'hp'):
3391
+ ba1 = cheby1(N, 1, fc, btype, fs=fs)
3392
+ ba2 = cheby1(N, 1, fc/(fs/2), btype)
3393
+ for ba1_, ba2_ in zip(ba1, ba2):
3394
+ xp_assert_close(ba1_, ba2_)
3395
+ for fc in ((100, 200), (100.1, 200.2), (321.123, 432.123)):
3396
+ for btype in ('bp', 'bs'):
3397
+ ba1 = cheby1(N, 1, fc, btype, fs=fs)
3398
+ for seq in (list, tuple, array):
3399
+ fcnorm = seq([f/(fs/2) for f in fc])
3400
+ ba2 = cheby1(N, 1, fcnorm, btype)
3401
+ for ba1_, ba2_ in zip(ba1, ba2):
3402
+ xp_assert_close(ba1_, ba2_)
3403
+
3404
+ class TestCheby2:
3405
+
3406
+ def test_degenerate(self):
3407
+ # 0-order filter is just a passthrough
3408
+ # Stopband ripple factor doesn't matter
3409
+ b, a = cheby2(0, 123.456, 1, analog=True)
3410
+ xp_assert_equal(b, np.asarray([1.0]))
3411
+ xp_assert_equal(a, np.asarray([1.0]))
3412
+
3413
+ # 1-order filter is same for all types
3414
+ b, a = cheby2(1, 10*np.log10(2), 1, analog=True)
3415
+ assert_array_almost_equal(b, [1])
3416
+ assert_array_almost_equal(a, [1, 1])
3417
+
3418
+ z, p, k = cheby2(1, 50, 0.3, output='zpk')
3419
+ xp_assert_equal(z, np.asarray([-1], dtype=np.complex128))
3420
+ xp_assert_close(p, [9.967826460175649e-01 + 0j], rtol=1e-14)
3421
+ xp_assert_close(k, 1.608676991217512e-03, rtol=1e-14)
3422
+
3423
+ def test_basic(self):
3424
+ for N in range(25):
3425
+ wn = 0.01
3426
+ z, p, k = cheby2(N, 40, wn, 'low', analog=True, output='zpk')
3427
+ assert len(p) == N
3428
+ assert all(np.real(p) <= 0) # No poles in right half of S-plane
3429
+
3430
+ for N in range(25):
3431
+ wn = 0.01
3432
+ z, p, k = cheby2(N, 40, wn, 'high', analog=False, output='zpk')
3433
+ assert all(np.abs(p) <= 1) # No poles outside unit circle
3434
+
3435
+ B, A = cheby2(18, 100, 0.5)
3436
+ assert_array_almost_equal(B, [
3437
+ 0.00167583914216, 0.01249479541868, 0.05282702120282,
3438
+ 0.15939804265706, 0.37690207631117, 0.73227013789108,
3439
+ 1.20191856962356, 1.69522872823393, 2.07598674519837,
3440
+ 2.21972389625291, 2.07598674519838, 1.69522872823395,
3441
+ 1.20191856962359, 0.73227013789110, 0.37690207631118,
3442
+ 0.15939804265707, 0.05282702120282, 0.01249479541868,
3443
+ 0.00167583914216], decimal=13)
3444
+ assert_array_almost_equal(A, [
3445
+ 1.00000000000000, -0.27631970006174, 3.19751214254060,
3446
+ -0.15685969461355, 4.13926117356269, 0.60689917820044,
3447
+ 2.95082770636540, 0.89016501910416, 1.32135245849798,
3448
+ 0.51502467236824, 0.38906643866660, 0.15367372690642,
3449
+ 0.07255803834919, 0.02422454070134, 0.00756108751837,
3450
+ 0.00179848550988, 0.00033713574499, 0.00004258794833,
3451
+ 0.00000281030149], decimal=13)
3452
+
3453
+ def test_highpass(self):
3454
+ # high even order
3455
+ z, p, k = cheby2(26, 60, 0.3, 'high', output='zpk')
3456
+ z2 = [9.981088955489852e-01 + 6.147058341984388e-02j,
3457
+ 9.981088955489852e-01 - 6.147058341984388e-02j,
3458
+ 9.832702870387426e-01 + 1.821525257215483e-01j,
3459
+ 9.832702870387426e-01 - 1.821525257215483e-01j,
3460
+ 9.550760158089112e-01 + 2.963609353922882e-01j,
3461
+ 9.550760158089112e-01 - 2.963609353922882e-01j,
3462
+ 9.162054748821922e-01 + 4.007087817803773e-01j,
3463
+ 9.162054748821922e-01 - 4.007087817803773e-01j,
3464
+ 8.700619897368064e-01 + 4.929423232136168e-01j,
3465
+ 8.700619897368064e-01 - 4.929423232136168e-01j,
3466
+ 5.889791753434985e-01 + 8.081482110427953e-01j,
3467
+ 5.889791753434985e-01 - 8.081482110427953e-01j,
3468
+ 5.984900456570295e-01 + 8.011302423760501e-01j,
3469
+ 5.984900456570295e-01 - 8.011302423760501e-01j,
3470
+ 6.172880888914629e-01 + 7.867371958365343e-01j,
3471
+ 6.172880888914629e-01 - 7.867371958365343e-01j,
3472
+ 6.448899971038180e-01 + 7.642754030030161e-01j,
3473
+ 6.448899971038180e-01 - 7.642754030030161e-01j,
3474
+ 6.804845629637927e-01 + 7.327624168637228e-01j,
3475
+ 6.804845629637927e-01 - 7.327624168637228e-01j,
3476
+ 8.202619107108660e-01 + 5.719881098737678e-01j,
3477
+ 8.202619107108660e-01 - 5.719881098737678e-01j,
3478
+ 7.228410452536148e-01 + 6.910143437705678e-01j,
3479
+ 7.228410452536148e-01 - 6.910143437705678e-01j,
3480
+ 7.702121399578629e-01 + 6.377877856007792e-01j,
3481
+ 7.702121399578629e-01 - 6.377877856007792e-01j]
3482
+ p2 = [7.365546198286450e-01 + 4.842085129329526e-02j,
3483
+ 7.365546198286450e-01 - 4.842085129329526e-02j,
3484
+ 7.292038510962885e-01 + 1.442201672097581e-01j,
3485
+ 7.292038510962885e-01 - 1.442201672097581e-01j,
3486
+ 7.151293788040354e-01 + 2.369925800458584e-01j,
3487
+ 7.151293788040354e-01 - 2.369925800458584e-01j,
3488
+ 6.955051820787286e-01 + 3.250341363856910e-01j,
3489
+ 6.955051820787286e-01 - 3.250341363856910e-01j,
3490
+ 6.719122956045220e-01 + 4.070475750638047e-01j,
3491
+ 6.719122956045220e-01 - 4.070475750638047e-01j,
3492
+ 6.461722130611300e-01 + 4.821965916689270e-01j,
3493
+ 6.461722130611300e-01 - 4.821965916689270e-01j,
3494
+ 5.528045062872224e-01 + 8.162920513838372e-01j,
3495
+ 5.528045062872224e-01 - 8.162920513838372e-01j,
3496
+ 5.464847782492791e-01 + 7.869899955967304e-01j,
3497
+ 5.464847782492791e-01 - 7.869899955967304e-01j,
3498
+ 5.488033111260949e-01 + 7.520442354055579e-01j,
3499
+ 5.488033111260949e-01 - 7.520442354055579e-01j,
3500
+ 6.201874719022955e-01 + 5.500894392527353e-01j,
3501
+ 6.201874719022955e-01 - 5.500894392527353e-01j,
3502
+ 5.586478152536709e-01 + 7.112676877332921e-01j,
3503
+ 5.586478152536709e-01 - 7.112676877332921e-01j,
3504
+ 5.958145844148228e-01 + 6.107074340842115e-01j,
3505
+ 5.958145844148228e-01 - 6.107074340842115e-01j,
3506
+ 5.747812938519067e-01 + 6.643001536914696e-01j,
3507
+ 5.747812938519067e-01 - 6.643001536914696e-01j]
3508
+ k2 = 9.932997786497189e-02
3509
+ xp_assert_close(sorted(z, key=np.angle),
3510
+ sorted(z2, key=np.angle), rtol=1e-13)
3511
+ xp_assert_close(sorted(p, key=np.angle),
3512
+ sorted(p2, key=np.angle), rtol=1e-12)
3513
+ xp_assert_close(k, k2, rtol=1e-11)
3514
+
3515
+ # high odd order
3516
+ z, p, k = cheby2(25, 80, 0.5, 'high', output='zpk')
3517
+ z2 = [9.690690376586687e-01 + 2.467897896011971e-01j,
3518
+ 9.690690376586687e-01 - 2.467897896011971e-01j,
3519
+ 9.999999999999492e-01,
3520
+ 8.835111277191199e-01 + 4.684101698261429e-01j,
3521
+ 8.835111277191199e-01 - 4.684101698261429e-01j,
3522
+ 7.613142857900539e-01 + 6.483830335935022e-01j,
3523
+ 7.613142857900539e-01 - 6.483830335935022e-01j,
3524
+ 6.232625173626231e-01 + 7.820126817709752e-01j,
3525
+ 6.232625173626231e-01 - 7.820126817709752e-01j,
3526
+ 4.864456563413621e-01 + 8.737108351316745e-01j,
3527
+ 4.864456563413621e-01 - 8.737108351316745e-01j,
3528
+ 3.618368136816749e-01 + 9.322414495530347e-01j,
3529
+ 3.618368136816749e-01 - 9.322414495530347e-01j,
3530
+ 2.549486883466794e-01 + 9.669545833752675e-01j,
3531
+ 2.549486883466794e-01 - 9.669545833752675e-01j,
3532
+ 1.676175432109457e-01 + 9.858520980390212e-01j,
3533
+ 1.676175432109457e-01 - 9.858520980390212e-01j,
3534
+ 1.975218468277521e-03 + 9.999980492540941e-01j,
3535
+ 1.975218468277521e-03 - 9.999980492540941e-01j,
3536
+ 1.786959496651858e-02 + 9.998403260399917e-01j,
3537
+ 1.786959496651858e-02 - 9.998403260399917e-01j,
3538
+ 9.967933660557139e-02 + 9.950196127985684e-01j,
3539
+ 9.967933660557139e-02 - 9.950196127985684e-01j,
3540
+ 5.013970951219547e-02 + 9.987422137518890e-01j,
3541
+ 5.013970951219547e-02 - 9.987422137518890e-01j]
3542
+ p2 = [4.218866331906864e-01,
3543
+ 4.120110200127552e-01 + 1.361290593621978e-01j,
3544
+ 4.120110200127552e-01 - 1.361290593621978e-01j,
3545
+ 3.835890113632530e-01 + 2.664910809911026e-01j,
3546
+ 3.835890113632530e-01 - 2.664910809911026e-01j,
3547
+ 3.399195570456499e-01 + 3.863983538639875e-01j,
3548
+ 3.399195570456499e-01 - 3.863983538639875e-01j,
3549
+ 2.855977834508353e-01 + 4.929444399540688e-01j,
3550
+ 2.855977834508353e-01 - 4.929444399540688e-01j,
3551
+ 2.255765441339322e-01 + 5.851631870205766e-01j,
3552
+ 2.255765441339322e-01 - 5.851631870205766e-01j,
3553
+ 1.644087535815792e-01 + 6.637356937277153e-01j,
3554
+ 1.644087535815792e-01 - 6.637356937277153e-01j,
3555
+ -7.293633845273095e-02 + 9.739218252516307e-01j,
3556
+ -7.293633845273095e-02 - 9.739218252516307e-01j,
3557
+ 1.058259206358626e-01 + 7.304739464862978e-01j,
3558
+ 1.058259206358626e-01 - 7.304739464862978e-01j,
3559
+ -5.703971947785402e-02 + 9.291057542169088e-01j,
3560
+ -5.703971947785402e-02 - 9.291057542169088e-01j,
3561
+ 5.263875132656864e-02 + 7.877974334424453e-01j,
3562
+ 5.263875132656864e-02 - 7.877974334424453e-01j,
3563
+ -3.007943405982616e-02 + 8.846331716180016e-01j,
3564
+ -3.007943405982616e-02 - 8.846331716180016e-01j,
3565
+ 6.857277464483946e-03 + 8.383275456264492e-01j,
3566
+ 6.857277464483946e-03 - 8.383275456264492e-01j]
3567
+ k2 = 6.507068761705037e-03
3568
+ xp_assert_close(sorted(z, key=np.angle),
3569
+ sorted(z2, key=np.angle), rtol=1e-13)
3570
+ xp_assert_close(sorted(p, key=np.angle),
3571
+ sorted(p2, key=np.angle), rtol=1e-12)
3572
+ xp_assert_close(k, k2, rtol=1e-11)
3573
+
3574
+ def test_bandpass(self):
3575
+ z, p, k = cheby2(9, 40, [0.07, 0.2], 'pass', output='zpk')
3576
+ z2 = [-9.999999999999999e-01,
3577
+ 3.676588029658514e-01 + 9.299607543341383e-01j,
3578
+ 3.676588029658514e-01 - 9.299607543341383e-01j,
3579
+ 7.009689684982283e-01 + 7.131917730894889e-01j,
3580
+ 7.009689684982283e-01 - 7.131917730894889e-01j,
3581
+ 7.815697973765858e-01 + 6.238178033919218e-01j,
3582
+ 7.815697973765858e-01 - 6.238178033919218e-01j,
3583
+ 8.063793628819866e-01 + 5.913986160941200e-01j,
3584
+ 8.063793628819866e-01 - 5.913986160941200e-01j,
3585
+ 1.000000000000001e+00,
3586
+ 9.944493019920448e-01 + 1.052168511576739e-01j,
3587
+ 9.944493019920448e-01 - 1.052168511576739e-01j,
3588
+ 9.854674703367308e-01 + 1.698642543566085e-01j,
3589
+ 9.854674703367308e-01 - 1.698642543566085e-01j,
3590
+ 9.762751735919308e-01 + 2.165335665157851e-01j,
3591
+ 9.762751735919308e-01 - 2.165335665157851e-01j,
3592
+ 9.792277171575134e-01 + 2.027636011479496e-01j,
3593
+ 9.792277171575134e-01 - 2.027636011479496e-01j]
3594
+ p2 = [8.143803410489621e-01 + 5.411056063397541e-01j,
3595
+ 8.143803410489621e-01 - 5.411056063397541e-01j,
3596
+ 7.650769827887418e-01 + 5.195412242095543e-01j,
3597
+ 7.650769827887418e-01 - 5.195412242095543e-01j,
3598
+ 6.096241204063443e-01 + 3.568440484659796e-01j,
3599
+ 6.096241204063443e-01 - 3.568440484659796e-01j,
3600
+ 6.918192770246239e-01 + 4.770463577106911e-01j,
3601
+ 6.918192770246239e-01 - 4.770463577106911e-01j,
3602
+ 6.986241085779207e-01 + 1.146512226180060e-01j,
3603
+ 6.986241085779207e-01 - 1.146512226180060e-01j,
3604
+ 8.654645923909734e-01 + 1.604208797063147e-01j,
3605
+ 8.654645923909734e-01 - 1.604208797063147e-01j,
3606
+ 9.164831670444591e-01 + 1.969181049384918e-01j,
3607
+ 9.164831670444591e-01 - 1.969181049384918e-01j,
3608
+ 9.630425777594550e-01 + 2.317513360702271e-01j,
3609
+ 9.630425777594550e-01 - 2.317513360702271e-01j,
3610
+ 9.438104703725529e-01 + 2.193509900269860e-01j,
3611
+ 9.438104703725529e-01 - 2.193509900269860e-01j]
3612
+ k2 = 9.345352824659604e-03
3613
+ xp_assert_close(sorted(z, key=np.angle),
3614
+ sorted(z2, key=np.angle), rtol=1e-13)
3615
+ xp_assert_close(sorted(p, key=np.angle),
3616
+ sorted(p2, key=np.angle), rtol=1e-13)
3617
+ xp_assert_close(k, k2, rtol=1e-11)
3618
+
3619
+ def test_bandstop(self):
3620
+ z, p, k = cheby2(6, 55, [0.1, 0.9], 'stop', output='zpk')
3621
+ z2 = [6.230544895101009e-01 + 7.821784343111114e-01j,
3622
+ 6.230544895101009e-01 - 7.821784343111114e-01j,
3623
+ 9.086608545660115e-01 + 4.175349702471991e-01j,
3624
+ 9.086608545660115e-01 - 4.175349702471991e-01j,
3625
+ 9.478129721465802e-01 + 3.188268649763867e-01j,
3626
+ 9.478129721465802e-01 - 3.188268649763867e-01j,
3627
+ -6.230544895100982e-01 + 7.821784343111109e-01j,
3628
+ -6.230544895100982e-01 - 7.821784343111109e-01j,
3629
+ -9.086608545660116e-01 + 4.175349702472088e-01j,
3630
+ -9.086608545660116e-01 - 4.175349702472088e-01j,
3631
+ -9.478129721465784e-01 + 3.188268649763897e-01j,
3632
+ -9.478129721465784e-01 - 3.188268649763897e-01j]
3633
+ p2 = [-9.464094036167638e-01 + 1.720048695084344e-01j,
3634
+ -9.464094036167638e-01 - 1.720048695084344e-01j,
3635
+ -8.715844103386737e-01 + 1.370665039509297e-01j,
3636
+ -8.715844103386737e-01 - 1.370665039509297e-01j,
3637
+ -8.078751204586425e-01 + 5.729329866682983e-02j,
3638
+ -8.078751204586425e-01 - 5.729329866682983e-02j,
3639
+ 9.464094036167665e-01 + 1.720048695084332e-01j,
3640
+ 9.464094036167665e-01 - 1.720048695084332e-01j,
3641
+ 8.078751204586447e-01 + 5.729329866683007e-02j,
3642
+ 8.078751204586447e-01 - 5.729329866683007e-02j,
3643
+ 8.715844103386721e-01 + 1.370665039509331e-01j,
3644
+ 8.715844103386721e-01 - 1.370665039509331e-01j]
3645
+ k2 = 2.917823332763358e-03
3646
+ xp_assert_close(sorted(z, key=np.angle),
3647
+ sorted(z2, key=np.angle), rtol=1e-13)
3648
+ xp_assert_close(sorted(p, key=np.angle),
3649
+ sorted(p2, key=np.angle), rtol=1e-13)
3650
+ xp_assert_close(k, k2, rtol=1e-11)
3651
+
3652
+ def test_ba_output(self):
3653
+ # with transfer function conversion, without digital conversion
3654
+ b, a = cheby2(5, 20, [2010, 2100], 'stop', True)
3655
+ b2 = [1.000000000000000e+00, 0, # Matlab: 6.683253076978249e-12,
3656
+ 2.111512500000000e+07, 0, # Matlab: 1.134325604589552e-04,
3657
+ 1.782966433781250e+14, 0, # Matlab: 7.216787944356781e+02,
3658
+ 7.525901316990656e+20, 0, # Matlab: 2.039829265789886e+09,
3659
+ 1.587960565565748e+27, 0, # Matlab: 2.161236218626134e+15,
3660
+ 1.339913493808585e+33]
3661
+ a2 = [1.000000000000000e+00, 1.849550755473371e+02,
3662
+ 2.113222918998538e+07, 3.125114149732283e+09,
3663
+ 1.785133457155609e+14, 1.979158697776348e+16,
3664
+ 7.535048322653831e+20, 5.567966191263037e+22,
3665
+ 1.589246884221346e+27, 5.871210648525566e+28,
3666
+ 1.339913493808590e+33]
3667
+ xp_assert_close(b, b2, rtol=1e-14)
3668
+ xp_assert_close(a, a2, rtol=1e-14)
3669
+
3670
+ def test_fs_param(self):
3671
+ for fs in (900, 900.1, 1234.567):
3672
+ for N in (0, 1, 2, 3, 10):
3673
+ for fc in (100, 100.1, 432.12345):
3674
+ for btype in ('lp', 'hp'):
3675
+ ba1 = cheby2(N, 20, fc, btype, fs=fs)
3676
+ ba2 = cheby2(N, 20, fc/(fs/2), btype)
3677
+ for ba1_, ba2_ in zip(ba1, ba2):
3678
+ xp_assert_close(ba1_, ba2_)
3679
+ for fc in ((100, 200), (100.1, 200.2), (321.123, 432.123)):
3680
+ for btype in ('bp', 'bs'):
3681
+ ba1 = cheby2(N, 20, fc, btype, fs=fs)
3682
+ for seq in (list, tuple, array):
3683
+ fcnorm = seq([f/(fs/2) for f in fc])
3684
+ ba2 = cheby2(N, 20, fcnorm, btype)
3685
+ for ba1_, ba2_ in zip(ba1, ba2):
3686
+ xp_assert_close(ba1_, ba2_)
3687
+
3688
+ class TestEllip:
3689
+
3690
+ def test_degenerate(self):
3691
+ # 0-order filter is just a passthrough
3692
+ # Even-order filters have DC gain of -rp dB
3693
+ # Stopband ripple factor doesn't matter
3694
+ b, a = ellip(0, 10*np.log10(2), 123.456, 1, analog=True)
3695
+ assert_array_almost_equal(b, [1/np.sqrt(2)])
3696
+ xp_assert_equal(a, np.asarray([1.0]))
3697
+
3698
+ # 1-order filter is same for all types
3699
+ b, a = ellip(1, 10*np.log10(2), 1, 1, analog=True)
3700
+ assert_array_almost_equal(b, [1])
3701
+ assert_array_almost_equal(a, [1, 1])
3702
+
3703
+ z, p, k = ellip(1, 1, 55, 0.3, output='zpk')
3704
+ xp_assert_close(z, [-9.999999999999998e-01], rtol=1e-14)
3705
+ xp_assert_close(p, [-6.660721153525525e-04], rtol=1e-10)
3706
+ xp_assert_close(k, 5.003330360576763e-01, rtol=1e-14)
3707
+
3708
+ def test_basic(self):
3709
+ for N in range(25):
3710
+ wn = 0.01
3711
+ z, p, k = ellip(N, 1, 40, wn, 'low', analog=True, output='zpk')
3712
+ assert len(p) == N
3713
+ assert all(np.real(p) <= 0) # No poles in right half of S-plane
3714
+
3715
+ for N in range(25):
3716
+ wn = 0.01
3717
+ z, p, k = ellip(N, 1, 40, wn, 'high', analog=False, output='zpk')
3718
+ assert all(np.abs(p) <= 1) # No poles outside unit circle
3719
+
3720
+ b3, a3 = ellip(5, 3, 26, 1, analog=True)
3721
+ assert_array_almost_equal(b3, [0.1420, 0, 0.3764, 0,
3722
+ 0.2409], decimal=4)
3723
+ assert_array_almost_equal(a3, [1, 0.5686, 1.8061, 0.8017, 0.8012,
3724
+ 0.2409], decimal=4)
3725
+
3726
+ b, a = ellip(3, 1, 60, [0.4, 0.7], 'stop')
3727
+ assert_array_almost_equal(b, [0.3310, 0.3469, 1.1042, 0.7044, 1.1042,
3728
+ 0.3469, 0.3310], decimal=4)
3729
+ assert_array_almost_equal(a, [1.0000, 0.6973, 1.1441, 0.5878, 0.7323,
3730
+ 0.1131, -0.0060], decimal=4)
3731
+
3732
+ def test_highpass(self):
3733
+ # high even order
3734
+ z, p, k = ellip(24, 1, 80, 0.3, 'high', output='zpk')
3735
+ z2 = [9.761875332501075e-01 + 2.169283290099910e-01j,
3736
+ 9.761875332501075e-01 - 2.169283290099910e-01j,
3737
+ 8.413503353963494e-01 + 5.404901600661900e-01j,
3738
+ 8.413503353963494e-01 - 5.404901600661900e-01j,
3739
+ 7.160082576305009e-01 + 6.980918098681732e-01j,
3740
+ 7.160082576305009e-01 - 6.980918098681732e-01j,
3741
+ 6.456533638965329e-01 + 7.636306264739803e-01j,
3742
+ 6.456533638965329e-01 - 7.636306264739803e-01j,
3743
+ 6.127321820971366e-01 + 7.902906256703928e-01j,
3744
+ 6.127321820971366e-01 - 7.902906256703928e-01j,
3745
+ 5.983607817490196e-01 + 8.012267936512676e-01j,
3746
+ 5.983607817490196e-01 - 8.012267936512676e-01j,
3747
+ 5.922577552594799e-01 + 8.057485658286990e-01j,
3748
+ 5.922577552594799e-01 - 8.057485658286990e-01j,
3749
+ 5.896952092563588e-01 + 8.076258788449631e-01j,
3750
+ 5.896952092563588e-01 - 8.076258788449631e-01j,
3751
+ 5.886248765538837e-01 + 8.084063054565607e-01j,
3752
+ 5.886248765538837e-01 - 8.084063054565607e-01j,
3753
+ 5.881802711123132e-01 + 8.087298490066037e-01j,
3754
+ 5.881802711123132e-01 - 8.087298490066037e-01j,
3755
+ 5.879995719101164e-01 + 8.088612386766461e-01j,
3756
+ 5.879995719101164e-01 - 8.088612386766461e-01j,
3757
+ 5.879354086709576e-01 + 8.089078780868164e-01j,
3758
+ 5.879354086709576e-01 - 8.089078780868164e-01j]
3759
+ p2 = [-3.184805259081650e-01 + 4.206951906775851e-01j,
3760
+ -3.184805259081650e-01 - 4.206951906775851e-01j,
3761
+ 1.417279173459985e-01 + 7.903955262836452e-01j,
3762
+ 1.417279173459985e-01 - 7.903955262836452e-01j,
3763
+ 4.042881216964651e-01 + 8.309042239116594e-01j,
3764
+ 4.042881216964651e-01 - 8.309042239116594e-01j,
3765
+ 5.128964442789670e-01 + 8.229563236799665e-01j,
3766
+ 5.128964442789670e-01 - 8.229563236799665e-01j,
3767
+ 5.569614712822724e-01 + 8.155957702908510e-01j,
3768
+ 5.569614712822724e-01 - 8.155957702908510e-01j,
3769
+ 5.750478870161392e-01 + 8.118633973883931e-01j,
3770
+ 5.750478870161392e-01 - 8.118633973883931e-01j,
3771
+ 5.825314018170804e-01 + 8.101960910679270e-01j,
3772
+ 5.825314018170804e-01 - 8.101960910679270e-01j,
3773
+ 5.856397379751872e-01 + 8.094825218722543e-01j,
3774
+ 5.856397379751872e-01 - 8.094825218722543e-01j,
3775
+ 5.869326035251949e-01 + 8.091827531557583e-01j,
3776
+ 5.869326035251949e-01 - 8.091827531557583e-01j,
3777
+ 5.874697218855733e-01 + 8.090593298213502e-01j,
3778
+ 5.874697218855733e-01 - 8.090593298213502e-01j,
3779
+ 5.876904783532237e-01 + 8.090127161018823e-01j,
3780
+ 5.876904783532237e-01 - 8.090127161018823e-01j,
3781
+ 5.877753105317594e-01 + 8.090050577978136e-01j,
3782
+ 5.877753105317594e-01 - 8.090050577978136e-01j]
3783
+ k2 = 4.918081266957108e-02
3784
+ xp_assert_close(sorted(z, key=np.angle),
3785
+ sorted(z2, key=np.angle), rtol=1e-4)
3786
+ xp_assert_close(sorted(p, key=np.angle),
3787
+ sorted(p2, key=np.angle), rtol=1e-4)
3788
+ xp_assert_close(k, k2, rtol=1e-3)
3789
+
3790
+ # high odd order
3791
+ z, p, k = ellip(23, 1, 70, 0.5, 'high', output='zpk')
3792
+ z2 = [9.999999999998661e-01,
3793
+ 6.603717261750994e-01 + 7.509388678638675e-01j,
3794
+ 6.603717261750994e-01 - 7.509388678638675e-01j,
3795
+ 2.788635267510325e-01 + 9.603307416968041e-01j,
3796
+ 2.788635267510325e-01 - 9.603307416968041e-01j,
3797
+ 1.070215532544218e-01 + 9.942567008268131e-01j,
3798
+ 1.070215532544218e-01 - 9.942567008268131e-01j,
3799
+ 4.049427369978163e-02 + 9.991797705105507e-01j,
3800
+ 4.049427369978163e-02 - 9.991797705105507e-01j,
3801
+ 1.531059368627931e-02 + 9.998827859909265e-01j,
3802
+ 1.531059368627931e-02 - 9.998827859909265e-01j,
3803
+ 5.808061438534933e-03 + 9.999831330689181e-01j,
3804
+ 5.808061438534933e-03 - 9.999831330689181e-01j,
3805
+ 2.224277847754599e-03 + 9.999975262909676e-01j,
3806
+ 2.224277847754599e-03 - 9.999975262909676e-01j,
3807
+ 8.731857107534554e-04 + 9.999996187732845e-01j,
3808
+ 8.731857107534554e-04 - 9.999996187732845e-01j,
3809
+ 3.649057346914968e-04 + 9.999999334218996e-01j,
3810
+ 3.649057346914968e-04 - 9.999999334218996e-01j,
3811
+ 1.765538109802615e-04 + 9.999999844143768e-01j,
3812
+ 1.765538109802615e-04 - 9.999999844143768e-01j,
3813
+ 1.143655290967426e-04 + 9.999999934602630e-01j,
3814
+ 1.143655290967426e-04 - 9.999999934602630e-01j]
3815
+ p2 = [-6.322017026545028e-01,
3816
+ -4.648423756662754e-01 + 5.852407464440732e-01j,
3817
+ -4.648423756662754e-01 - 5.852407464440732e-01j,
3818
+ -2.249233374627773e-01 + 8.577853017985717e-01j,
3819
+ -2.249233374627773e-01 - 8.577853017985717e-01j,
3820
+ -9.234137570557621e-02 + 9.506548198678851e-01j,
3821
+ -9.234137570557621e-02 - 9.506548198678851e-01j,
3822
+ -3.585663561241373e-02 + 9.821494736043981e-01j,
3823
+ -3.585663561241373e-02 - 9.821494736043981e-01j,
3824
+ -1.363917242312723e-02 + 9.933844128330656e-01j,
3825
+ -1.363917242312723e-02 - 9.933844128330656e-01j,
3826
+ -5.131505238923029e-03 + 9.975221173308673e-01j,
3827
+ -5.131505238923029e-03 - 9.975221173308673e-01j,
3828
+ -1.904937999259502e-03 + 9.990680819857982e-01j,
3829
+ -1.904937999259502e-03 - 9.990680819857982e-01j,
3830
+ -6.859439885466834e-04 + 9.996492201426826e-01j,
3831
+ -6.859439885466834e-04 - 9.996492201426826e-01j,
3832
+ -2.269936267937089e-04 + 9.998686250679161e-01j,
3833
+ -2.269936267937089e-04 - 9.998686250679161e-01j,
3834
+ -5.687071588789117e-05 + 9.999527573294513e-01j,
3835
+ -5.687071588789117e-05 - 9.999527573294513e-01j,
3836
+ -6.948417068525226e-07 + 9.999882737700173e-01j,
3837
+ -6.948417068525226e-07 - 9.999882737700173e-01j]
3838
+ k2 = 1.220910020289434e-02
3839
+ xp_assert_close(sorted(z, key=np.angle),
3840
+ sorted(z2, key=np.angle), rtol=1e-4)
3841
+ xp_assert_close(sorted(p, key=np.angle),
3842
+ sorted(p2, key=np.angle), rtol=1e-4)
3843
+ xp_assert_close(k, k2, rtol=1e-3)
3844
+
3845
+ def test_bandpass(self):
3846
+ z, p, k = ellip(7, 1, 40, [0.07, 0.2], 'pass', output='zpk')
3847
+ z2 = [-9.999999999999991e-01,
3848
+ 6.856610961780020e-01 + 7.279209168501619e-01j,
3849
+ 6.856610961780020e-01 - 7.279209168501619e-01j,
3850
+ 7.850346167691289e-01 + 6.194518952058737e-01j,
3851
+ 7.850346167691289e-01 - 6.194518952058737e-01j,
3852
+ 7.999038743173071e-01 + 6.001281461922627e-01j,
3853
+ 7.999038743173071e-01 - 6.001281461922627e-01j,
3854
+ 9.999999999999999e-01,
3855
+ 9.862938983554124e-01 + 1.649980183725925e-01j,
3856
+ 9.862938983554124e-01 - 1.649980183725925e-01j,
3857
+ 9.788558330548762e-01 + 2.045513580850601e-01j,
3858
+ 9.788558330548762e-01 - 2.045513580850601e-01j,
3859
+ 9.771155231720003e-01 + 2.127093189691258e-01j,
3860
+ 9.771155231720003e-01 - 2.127093189691258e-01j]
3861
+ p2 = [8.063992755498643e-01 + 5.858071374778874e-01j,
3862
+ 8.063992755498643e-01 - 5.858071374778874e-01j,
3863
+ 8.050395347071724e-01 + 5.639097428109795e-01j,
3864
+ 8.050395347071724e-01 - 5.639097428109795e-01j,
3865
+ 8.113124936559144e-01 + 4.855241143973142e-01j,
3866
+ 8.113124936559144e-01 - 4.855241143973142e-01j,
3867
+ 8.665595314082394e-01 + 3.334049560919331e-01j,
3868
+ 8.665595314082394e-01 - 3.334049560919331e-01j,
3869
+ 9.412369011968871e-01 + 2.457616651325908e-01j,
3870
+ 9.412369011968871e-01 - 2.457616651325908e-01j,
3871
+ 9.679465190411238e-01 + 2.228772501848216e-01j,
3872
+ 9.679465190411238e-01 - 2.228772501848216e-01j,
3873
+ 9.747235066273385e-01 + 2.178937926146544e-01j,
3874
+ 9.747235066273385e-01 - 2.178937926146544e-01j]
3875
+ k2 = 8.354782670263239e-03
3876
+ xp_assert_close(sorted(z, key=np.angle),
3877
+ sorted(z2, key=np.angle), rtol=1e-4)
3878
+ xp_assert_close(sorted(p, key=np.angle),
3879
+ sorted(p2, key=np.angle), rtol=1e-4)
3880
+ xp_assert_close(k, k2, rtol=1e-3)
3881
+
3882
+ z, p, k = ellip(5, 1, 75, [90.5, 110.5], 'pass', True, 'zpk')
3883
+ z2 = [-5.583607317695175e-14 + 1.433755965989225e+02j,
3884
+ -5.583607317695175e-14 - 1.433755965989225e+02j,
3885
+ 5.740106416459296e-14 + 1.261678754570291e+02j,
3886
+ 5.740106416459296e-14 - 1.261678754570291e+02j,
3887
+ -2.199676239638652e-14 + 6.974861996895196e+01j,
3888
+ -2.199676239638652e-14 - 6.974861996895196e+01j,
3889
+ -3.372595657044283e-14 + 7.926145989044531e+01j,
3890
+ -3.372595657044283e-14 - 7.926145989044531e+01j,
3891
+ 0]
3892
+ p2 = [-8.814960004852743e-01 + 1.104124501436066e+02j,
3893
+ -8.814960004852743e-01 - 1.104124501436066e+02j,
3894
+ -2.477372459140184e+00 + 1.065638954516534e+02j,
3895
+ -2.477372459140184e+00 - 1.065638954516534e+02j,
3896
+ -3.072156842945799e+00 + 9.995404870405324e+01j,
3897
+ -3.072156842945799e+00 - 9.995404870405324e+01j,
3898
+ -2.180456023925693e+00 + 9.379206865455268e+01j,
3899
+ -2.180456023925693e+00 - 9.379206865455268e+01j,
3900
+ -7.230484977485752e-01 + 9.056598800801140e+01j,
3901
+ -7.230484977485752e-01 - 9.056598800801140e+01j]
3902
+ k2 = 3.774571622827070e-02
3903
+ xp_assert_close(sorted(z, key=np.imag),
3904
+ sorted(z2, key=np.imag), rtol=1e-4)
3905
+ xp_assert_close(sorted(p, key=np.imag),
3906
+ sorted(p2, key=np.imag), rtol=1e-6)
3907
+ xp_assert_close(k, k2, rtol=1e-3)
3908
+
3909
+ def test_bandstop(self):
3910
+ z, p, k = ellip(8, 1, 65, [0.2, 0.4], 'stop', output='zpk')
3911
+ z2 = [3.528578094286510e-01 + 9.356769561794296e-01j,
3912
+ 3.528578094286510e-01 - 9.356769561794296e-01j,
3913
+ 3.769716042264783e-01 + 9.262248159096587e-01j,
3914
+ 3.769716042264783e-01 - 9.262248159096587e-01j,
3915
+ 4.406101783111199e-01 + 8.976985411420985e-01j,
3916
+ 4.406101783111199e-01 - 8.976985411420985e-01j,
3917
+ 5.539386470258847e-01 + 8.325574907062760e-01j,
3918
+ 5.539386470258847e-01 - 8.325574907062760e-01j,
3919
+ 6.748464963023645e-01 + 7.379581332490555e-01j,
3920
+ 6.748464963023645e-01 - 7.379581332490555e-01j,
3921
+ 7.489887970285254e-01 + 6.625826604475596e-01j,
3922
+ 7.489887970285254e-01 - 6.625826604475596e-01j,
3923
+ 7.913118471618432e-01 + 6.114127579150699e-01j,
3924
+ 7.913118471618432e-01 - 6.114127579150699e-01j,
3925
+ 7.806804740916381e-01 + 6.249303940216475e-01j,
3926
+ 7.806804740916381e-01 - 6.249303940216475e-01j]
3927
+
3928
+ p2 = [-1.025299146693730e-01 + 5.662682444754943e-01j,
3929
+ -1.025299146693730e-01 - 5.662682444754943e-01j,
3930
+ 1.698463595163031e-01 + 8.926678667070186e-01j,
3931
+ 1.698463595163031e-01 - 8.926678667070186e-01j,
3932
+ 2.750532687820631e-01 + 9.351020170094005e-01j,
3933
+ 2.750532687820631e-01 - 9.351020170094005e-01j,
3934
+ 3.070095178909486e-01 + 9.457373499553291e-01j,
3935
+ 3.070095178909486e-01 - 9.457373499553291e-01j,
3936
+ 7.695332312152288e-01 + 2.792567212705257e-01j,
3937
+ 7.695332312152288e-01 - 2.792567212705257e-01j,
3938
+ 8.083818999225620e-01 + 4.990723496863960e-01j,
3939
+ 8.083818999225620e-01 - 4.990723496863960e-01j,
3940
+ 8.066158014414928e-01 + 5.649811440393374e-01j,
3941
+ 8.066158014414928e-01 - 5.649811440393374e-01j,
3942
+ 8.062787978834571e-01 + 5.855780880424964e-01j,
3943
+ 8.062787978834571e-01 - 5.855780880424964e-01j]
3944
+ k2 = 2.068622545291259e-01
3945
+ xp_assert_close(sorted(z, key=np.angle),
3946
+ sorted(z2, key=np.angle), rtol=1e-6)
3947
+ xp_assert_close(sorted(p, key=np.angle),
3948
+ sorted(p2, key=np.angle), rtol=1e-5)
3949
+ xp_assert_close(k, k2, rtol=1e-5)
3950
+
3951
+ def test_ba_output(self):
3952
+ # with transfer function conversion, without digital conversion
3953
+ b, a = ellip(5, 1, 40, [201, 240], 'stop', True)
3954
+ b2 = [
3955
+ 1.000000000000000e+00, 0, # Matlab: 1.743506051190569e-13,
3956
+ 2.426561778314366e+05, 0, # Matlab: 3.459426536825722e-08,
3957
+ 2.348218683400168e+10, 0, # Matlab: 2.559179747299313e-03,
3958
+ 1.132780692872241e+15, 0, # Matlab: 8.363229375535731e+01,
3959
+ 2.724038554089566e+19, 0, # Matlab: 1.018700994113120e+06,
3960
+ 2.612380874940186e+23
3961
+ ]
3962
+ a2 = [
3963
+ 1.000000000000000e+00, 1.337266601804649e+02,
3964
+ 2.486725353510667e+05, 2.628059713728125e+07,
3965
+ 2.436169536928770e+10, 1.913554568577315e+12,
3966
+ 1.175208184614438e+15, 6.115751452473410e+16,
3967
+ 2.791577695211466e+19, 7.241811142725384e+20,
3968
+ 2.612380874940182e+23
3969
+ ]
3970
+ xp_assert_close(b, b2, rtol=1e-6)
3971
+ xp_assert_close(a, a2, rtol=1e-4)
3972
+
3973
+ def test_fs_param(self):
3974
+ for fs in (900, 900.1, 1234.567):
3975
+ for N in (0, 1, 2, 3, 10):
3976
+ for fc in (100, 100.1, 432.12345):
3977
+ for btype in ('lp', 'hp'):
3978
+ ba1 = ellip(N, 1, 20, fc, btype, fs=fs)
3979
+ ba2 = ellip(N, 1, 20, fc/(fs/2), btype)
3980
+ for ba1_, ba2_ in zip(ba1, ba2):
3981
+ xp_assert_close(ba1_, ba2_)
3982
+ for fc in ((100, 200), (100.1, 200.2), (321.123, 432.123)):
3983
+ for btype in ('bp', 'bs'):
3984
+ ba1 = ellip(N, 1, 20, fc, btype, fs=fs)
3985
+ for seq in (list, tuple, array):
3986
+ fcnorm = seq([f/(fs/2) for f in fc])
3987
+ ba2 = ellip(N, 1, 20, fcnorm, btype)
3988
+ for ba1_, ba2_ in zip(ba1, ba2):
3989
+ xp_assert_close(ba1_, ba2_)
3990
+
3991
+ def test_fs_validation(self):
3992
+ with pytest.raises(ValueError, match="Sampling.*single scalar"):
3993
+ iirnotch(0.06, 30, fs=np.array([10, 20]))
3994
+
3995
+ with pytest.raises(ValueError, match="Sampling.*be none"):
3996
+ iirnotch(0.06, 30, fs=None)
3997
+
3998
+
3999
+ def test_sos_consistency():
4000
+ # Consistency checks of output='sos' for the specialized IIR filter
4001
+ # design functions.
4002
+ design_funcs = [(bessel, (0.1,)),
4003
+ (butter, (0.1,)),
4004
+ (cheby1, (45.0, 0.1)),
4005
+ (cheby2, (0.087, 0.1)),
4006
+ (ellip, (0.087, 45, 0.1))]
4007
+ for func, args in design_funcs:
4008
+ name = func.__name__
4009
+
4010
+ b, a = func(2, *args, output='ba')
4011
+ sos = func(2, *args, output='sos')
4012
+ xp_assert_close(sos, [np.hstack((b, a))], err_msg=f"{name}(2,...)")
4013
+
4014
+ zpk = func(3, *args, output='zpk')
4015
+ sos = func(3, *args, output='sos')
4016
+ xp_assert_close(sos, zpk2sos(*zpk), err_msg=f"{name}(3,...)")
4017
+
4018
+ zpk = func(4, *args, output='zpk')
4019
+ sos = func(4, *args, output='sos')
4020
+ xp_assert_close(sos, zpk2sos(*zpk), err_msg=f"{name}(4,...)")
4021
+
4022
+
4023
+ class TestIIRNotch:
4024
+
4025
+ def test_ba_output(self):
4026
+ # Compare coefficients with Matlab ones
4027
+ # for the equivalent input:
4028
+ b, a = iirnotch(0.06, 30)
4029
+ b2 = [
4030
+ 9.9686824e-01, -1.9584219e+00,
4031
+ 9.9686824e-01
4032
+ ]
4033
+ a2 = [
4034
+ 1.0000000e+00, -1.9584219e+00,
4035
+ 9.9373647e-01
4036
+ ]
4037
+
4038
+ xp_assert_close(b, b2, rtol=1e-8)
4039
+ xp_assert_close(a, a2, rtol=1e-8)
4040
+
4041
+ def test_frequency_response(self):
4042
+ # Get filter coefficients
4043
+ b, a = iirnotch(0.3, 30)
4044
+
4045
+ # Get frequency response
4046
+ w, h = freqz(b, a, 1000)
4047
+
4048
+ # Pick 5 point
4049
+ p = [200, # w0 = 0.200
4050
+ 295, # w0 = 0.295
4051
+ 300, # w0 = 0.300
4052
+ 305, # w0 = 0.305
4053
+ 400] # w0 = 0.400
4054
+
4055
+ # Get frequency response correspondent to each of those points
4056
+ hp = h[p]
4057
+
4058
+ # Check if the frequency response fulfill the specifications:
4059
+ # hp[0] and hp[4] correspond to frequencies distant from
4060
+ # w0 = 0.3 and should be close to 1
4061
+ xp_assert_close(abs(hp[0]), np.asarray(1.), rtol=1e-2, check_0d=False)
4062
+ xp_assert_close(abs(hp[4]), np.asarray(1.), rtol=1e-2, check_0d=False)
4063
+
4064
+ # hp[1] and hp[3] correspond to frequencies approximately
4065
+ # on the edges of the passband and should be close to -3dB
4066
+ xp_assert_close(abs(hp[1]), 1/np.sqrt(2), rtol=1e-2)
4067
+ xp_assert_close(abs(hp[3]), 1/np.sqrt(2), rtol=1e-2)
4068
+
4069
+ # hp[2] correspond to the frequency that should be removed
4070
+ # the frequency response should be very close to 0
4071
+ xp_assert_close(abs(hp[2]), np.asarray(0.0), atol=1e-10, check_0d=False)
4072
+
4073
+ def test_errors(self):
4074
+ # Exception should be raised if w0 > 1 or w0 <0
4075
+ assert_raises(ValueError, iirnotch, w0=2, Q=30)
4076
+ assert_raises(ValueError, iirnotch, w0=-1, Q=30)
4077
+
4078
+ # Exception should be raised if any of the parameters
4079
+ # are not float (or cannot be converted to one)
4080
+ assert_raises(ValueError, iirnotch, w0="blabla", Q=30)
4081
+ assert_raises(TypeError, iirnotch, w0=-1, Q=[1, 2, 3])
4082
+
4083
+ def test_fs_param(self):
4084
+ # Get filter coefficients
4085
+ b, a = iirnotch(1500, 30, fs=10000)
4086
+
4087
+ # Get frequency response
4088
+ w, h = freqz(b, a, 1000, fs=10000)
4089
+
4090
+ # Pick 5 point
4091
+ p = [200, # w0 = 1000
4092
+ 295, # w0 = 1475
4093
+ 300, # w0 = 1500
4094
+ 305, # w0 = 1525
4095
+ 400] # w0 = 2000
4096
+
4097
+ # Get frequency response correspondent to each of those points
4098
+ hp = h[p]
4099
+
4100
+ # Check if the frequency response fulfill the specifications:
4101
+ # hp[0] and hp[4] correspond to frequencies distant from
4102
+ # w0 = 1500 and should be close to 1
4103
+ xp_assert_close(abs(hp[0]), np.ones_like(abs(hp[0])), rtol=1e-2,
4104
+ check_0d=False)
4105
+ xp_assert_close(abs(hp[4]), np.ones_like(abs(hp[4])), rtol=1e-2,
4106
+ check_0d=False)
4107
+
4108
+ # hp[1] and hp[3] correspond to frequencies approximately
4109
+ # on the edges of the passband and should be close to -3dB
4110
+ xp_assert_close(abs(hp[1]), 1/np.sqrt(2), rtol=1e-2)
4111
+ xp_assert_close(abs(hp[3]), 1/np.sqrt(2), rtol=1e-2)
4112
+
4113
+ # hp[2] correspond to the frequency that should be removed
4114
+ # the frequency response should be very close to 0
4115
+ xp_assert_close(abs(hp[2]), np.asarray(0.0), atol=1e-10, check_0d=False)
4116
+
4117
+
4118
+ class TestIIRPeak:
4119
+
4120
+ def test_ba_output(self):
4121
+ # Compare coefficients with Matlab ones
4122
+ # for the equivalent input:
4123
+ b, a = iirpeak(0.06, 30)
4124
+ b2 = [
4125
+ 3.131764229e-03, 0,
4126
+ -3.131764229e-03
4127
+ ]
4128
+ a2 = [
4129
+ 1.0000000e+00, -1.958421917e+00,
4130
+ 9.9373647e-01
4131
+ ]
4132
+ xp_assert_close(b, b2, rtol=1e-8)
4133
+ xp_assert_close(a, a2, rtol=1e-8)
4134
+
4135
+ def test_frequency_response(self):
4136
+ # Get filter coefficients
4137
+ b, a = iirpeak(0.3, 30)
4138
+
4139
+ # Get frequency response
4140
+ w, h = freqz(b, a, 1000)
4141
+
4142
+ # Pick 5 point
4143
+ p = [30, # w0 = 0.030
4144
+ 295, # w0 = 0.295
4145
+ 300, # w0 = 0.300
4146
+ 305, # w0 = 0.305
4147
+ 800] # w0 = 0.800
4148
+
4149
+ # Get frequency response correspondent to each of those points
4150
+ hp = h[p]
4151
+
4152
+ # Check if the frequency response fulfill the specifications:
4153
+ # hp[0] and hp[4] correspond to frequencies distant from
4154
+ # w0 = 0.3 and should be close to 0
4155
+ xp_assert_close(abs(hp[0]),
4156
+ np.zeros_like(abs(hp[0])), atol=1e-2, check_0d=False)
4157
+ xp_assert_close(abs(hp[4]),
4158
+ np.zeros_like(abs(hp[4])), atol=1e-2, check_0d=False)
4159
+
4160
+ # hp[1] and hp[3] correspond to frequencies approximately
4161
+ # on the edges of the passband and should be close to 10**(-3/20)
4162
+ xp_assert_close(abs(hp[1]), 1/np.sqrt(2), rtol=1e-2)
4163
+ xp_assert_close(abs(hp[3]), 1/np.sqrt(2), rtol=1e-2)
4164
+
4165
+ # hp[2] correspond to the frequency that should be retained and
4166
+ # the frequency response should be very close to 1
4167
+ xp_assert_close(abs(hp[2]), np.asarray(1.0), rtol=1e-10, check_0d=False)
4168
+
4169
+ def test_errors(self):
4170
+ # Exception should be raised if w0 > 1 or w0 <0
4171
+ assert_raises(ValueError, iirpeak, w0=2, Q=30)
4172
+ assert_raises(ValueError, iirpeak, w0=-1, Q=30)
4173
+
4174
+ # Exception should be raised if any of the parameters
4175
+ # are not float (or cannot be converted to one)
4176
+ assert_raises(ValueError, iirpeak, w0="blabla", Q=30)
4177
+ assert_raises(TypeError, iirpeak, w0=-1, Q=[1, 2, 3])
4178
+
4179
+ def test_fs_param(self):
4180
+ # Get filter coefficients
4181
+ b, a = iirpeak(1200, 30, fs=8000)
4182
+
4183
+ # Get frequency response
4184
+ w, h = freqz(b, a, 1000, fs=8000)
4185
+
4186
+ # Pick 5 point
4187
+ p = [30, # w0 = 120
4188
+ 295, # w0 = 1180
4189
+ 300, # w0 = 1200
4190
+ 305, # w0 = 1220
4191
+ 800] # w0 = 3200
4192
+
4193
+ # Get frequency response correspondent to each of those points
4194
+ hp = h[p]
4195
+
4196
+ # Check if the frequency response fulfill the specifications:
4197
+ # hp[0] and hp[4] correspond to frequencies distant from
4198
+ # w0 = 1200 and should be close to 0
4199
+ xp_assert_close(abs(hp[0]),
4200
+ np.zeros_like(abs(hp[0])), atol=1e-2, check_0d=False)
4201
+ xp_assert_close(abs(hp[4]),
4202
+ np.zeros_like(abs(hp[4])), atol=1e-2, check_0d=False)
4203
+
4204
+ # hp[1] and hp[3] correspond to frequencies approximately
4205
+ # on the edges of the passband and should be close to 10**(-3/20)
4206
+ xp_assert_close(abs(hp[1]), 1/np.sqrt(2), rtol=1e-2)
4207
+ xp_assert_close(abs(hp[3]), 1/np.sqrt(2), rtol=1e-2)
4208
+
4209
+ # hp[2] correspond to the frequency that should be retained and
4210
+ # the frequency response should be very close to 1
4211
+ xp_assert_close(abs(hp[2]),
4212
+ np.ones_like(abs(hp[2])), rtol=1e-10, check_0d=False)
4213
+
4214
+
4215
+ class TestIIRComb:
4216
+ # Test erroneous input cases
4217
+ def test_invalid_input(self):
4218
+ # w0 is <= 0 or >= fs / 2
4219
+ fs = 1000
4220
+ for args in [(-fs, 30), (0, 35), (fs / 2, 40), (fs, 35)]:
4221
+ with pytest.raises(ValueError, match='w0 must be between '):
4222
+ iircomb(*args, fs=fs)
4223
+
4224
+ # fs is not divisible by w0
4225
+ for args in [(120, 30), (157, 35)]:
4226
+ with pytest.raises(ValueError, match='fs must be divisible '):
4227
+ iircomb(*args, fs=fs)
4228
+
4229
+ # https://github.com/scipy/scipy/issues/14043#issuecomment-1107349140
4230
+ # Previously, fs=44100, w0=49.999 was rejected, but fs=2,
4231
+ # w0=49.999/int(44100/2) was accepted. Now it is rejected, too.
4232
+ with pytest.raises(ValueError, match='fs must be divisible '):
4233
+ iircomb(w0=49.999/int(44100/2), Q=30)
4234
+
4235
+ with pytest.raises(ValueError, match='fs must be divisible '):
4236
+ iircomb(w0=49.999, Q=30, fs=44100)
4237
+
4238
+ # Filter type is not notch or peak
4239
+ for args in [(0.2, 30, 'natch'), (0.5, 35, 'comb')]:
4240
+ with pytest.raises(ValueError, match='ftype must be '):
4241
+ iircomb(*args)
4242
+
4243
+ # Verify that the filter's frequency response contains a
4244
+ # notch at the cutoff frequency
4245
+ @pytest.mark.parametrize('ftype', ('notch', 'peak'))
4246
+ def test_frequency_response(self, ftype):
4247
+ # Create a notching or peaking comb filter at 1000 Hz
4248
+ b, a = iircomb(1000, 30, ftype=ftype, fs=10000)
4249
+
4250
+ # Compute the frequency response
4251
+ freqs, response = freqz(b, a, 1000, fs=10000)
4252
+
4253
+ # Find the notch using argrelextrema
4254
+ comb_points = argrelextrema(abs(response), np.less)[0]
4255
+
4256
+ # Verify that the first notch sits at 1000 Hz
4257
+ comb1 = comb_points[0]
4258
+ xp_assert_close(freqs[comb1], np.asarray(1000.), check_0d=False)
4259
+
4260
+ # Verify pass_zero parameter
4261
+ @pytest.mark.parametrize('ftype,pass_zero,peak,notch',
4262
+ [('peak', True, 123.45, 61.725),
4263
+ ('peak', False, 61.725, 123.45),
4264
+ ('peak', None, 61.725, 123.45),
4265
+ ('notch', None, 61.725, 123.45),
4266
+ ('notch', True, 123.45, 61.725),
4267
+ ('notch', False, 61.725, 123.45)])
4268
+ def test_pass_zero(self, ftype, pass_zero, peak, notch):
4269
+ # Create a notching or peaking comb filter
4270
+ b, a = iircomb(123.45, 30, ftype=ftype, fs=1234.5, pass_zero=pass_zero)
4271
+
4272
+ # Compute the frequency response
4273
+ freqs, response = freqz(b, a, [peak, notch], fs=1234.5)
4274
+
4275
+ # Verify that expected notches are notches and peaks are peaks
4276
+ assert abs(response[0]) > 0.99
4277
+ assert abs(response[1]) < 1e-10
4278
+
4279
+ # All built-in IIR filters are real, so should have perfectly
4280
+ # symmetrical poles and zeros. Then ba representation (using
4281
+ # numpy.poly) will be purely real instead of having negligible
4282
+ # imaginary parts.
4283
+ def test_iir_symmetry(self):
4284
+ b, a = iircomb(400, 30, fs=24000)
4285
+ z, p, k = tf2zpk(b, a)
4286
+ xp_assert_equal(sorted(z), sorted(z.conj()))
4287
+ xp_assert_equal(sorted(p), sorted(p.conj()))
4288
+ xp_assert_equal(k, np.real(k))
4289
+
4290
+ assert issubclass(b.dtype.type, np.floating)
4291
+ assert issubclass(a.dtype.type, np.floating)
4292
+
4293
+ # Verify filter coefficients with MATLAB's iircomb function
4294
+ def test_ba_output(self):
4295
+ b_notch, a_notch = iircomb(60, 35, ftype='notch', fs=600)
4296
+ b_notch2 = [0.957020174408697, 0.0, 0.0, 0.0, 0.0, 0.0,
4297
+ 0.0, 0.0, 0.0, 0.0, -0.957020174408697]
4298
+ a_notch2 = [1.0, 0.0, 0.0, 0.0, 0.0, 0.0,
4299
+ 0.0, 0.0, 0.0, 0.0, -0.914040348817395]
4300
+ xp_assert_close(b_notch, b_notch2)
4301
+ xp_assert_close(a_notch, a_notch2)
4302
+
4303
+ b_peak, a_peak = iircomb(60, 35, ftype='peak', fs=600)
4304
+ b_peak2 = [0.0429798255913026, 0.0, 0.0, 0.0, 0.0, 0.0,
4305
+ 0.0, 0.0, 0.0, 0.0, -0.0429798255913026]
4306
+ a_peak2 = [1.0, 0.0, 0.0, 0.0, 0.0, 0.0,
4307
+ 0.0, 0.0, 0.0, 0.0, 0.914040348817395]
4308
+ xp_assert_close(b_peak, b_peak2)
4309
+ xp_assert_close(a_peak, a_peak2)
4310
+
4311
+ # Verify that https://github.com/scipy/scipy/issues/14043 is fixed
4312
+ def test_nearest_divisor(self):
4313
+ # Create a notching comb filter
4314
+ b, a = iircomb(50/int(44100/2), 50.0, ftype='notch')
4315
+
4316
+ # Compute the frequency response at an upper harmonic of 50
4317
+ freqs, response = freqz(b, a, [22000], fs=44100)
4318
+
4319
+ # Before bug fix, this would produce N = 881, so that 22 kHz was ~0 dB.
4320
+ # Now N = 882 correctly and 22 kHz should be a notch <-220 dB
4321
+ assert abs(response[0]) < 1e-10
4322
+
4323
+ def test_fs_validation(self):
4324
+ with pytest.raises(ValueError, match="Sampling.*single scalar"):
4325
+ iircomb(1000, 30, fs=np.array([10, 20]))
4326
+
4327
+ with pytest.raises(ValueError, match="Sampling.*be none"):
4328
+ iircomb(1000, 30, fs=None)
4329
+
4330
+
4331
+ class TestIIRDesign:
4332
+
4333
+ def test_exceptions(self):
4334
+ with pytest.raises(ValueError, match="the same shape"):
4335
+ iirdesign(0.2, [0.1, 0.3], 1, 40)
4336
+ with pytest.raises(ValueError, match="the same shape"):
4337
+ iirdesign(np.array([[0.3, 0.6], [0.3, 0.6]]),
4338
+ np.array([[0.4, 0.5], [0.4, 0.5]]), 1, 40)
4339
+
4340
+ # discrete filter with non-positive frequency
4341
+ with pytest.raises(ValueError, match="must be greater than 0"):
4342
+ iirdesign(0, 0.5, 1, 40)
4343
+ with pytest.raises(ValueError, match="must be greater than 0"):
4344
+ iirdesign(-0.1, 0.5, 1, 40)
4345
+ with pytest.raises(ValueError, match="must be greater than 0"):
4346
+ iirdesign(0.1, 0, 1, 40)
4347
+ with pytest.raises(ValueError, match="must be greater than 0"):
4348
+ iirdesign(0.1, -0.5, 1, 40)
4349
+ with pytest.raises(ValueError, match="must be greater than 0"):
4350
+ iirdesign([0, 0.3], [0.1, 0.5], 1, 40)
4351
+ with pytest.raises(ValueError, match="must be greater than 0"):
4352
+ iirdesign([-0.1, 0.3], [0.1, 0.5], 1, 40)
4353
+ with pytest.raises(ValueError, match="must be greater than 0"):
4354
+ iirdesign([0.1, 0], [0.1, 0.5], 1, 40)
4355
+ with pytest.raises(ValueError, match="must be greater than 0"):
4356
+ iirdesign([0.1, -0.3], [0.1, 0.5], 1, 40)
4357
+ with pytest.raises(ValueError, match="must be greater than 0"):
4358
+ iirdesign([0.1, 0.3], [0, 0.5], 1, 40)
4359
+ with pytest.raises(ValueError, match="must be greater than 0"):
4360
+ iirdesign([0.1, 0.3], [-0.1, 0.5], 1, 40)
4361
+ with pytest.raises(ValueError, match="must be greater than 0"):
4362
+ iirdesign([0.1, 0.3], [0.1, 0], 1, 40)
4363
+ with pytest.raises(ValueError, match="must be greater than 0"):
4364
+ iirdesign([0.1, 0.3], [0.1, -0.5], 1, 40)
4365
+
4366
+ # analog filter with negative frequency
4367
+ with pytest.raises(ValueError, match="must be greater than 0"):
4368
+ iirdesign(-0.1, 0.5, 1, 40, analog=True)
4369
+ with pytest.raises(ValueError, match="must be greater than 0"):
4370
+ iirdesign(0.1, -0.5, 1, 40, analog=True)
4371
+ with pytest.raises(ValueError, match="must be greater than 0"):
4372
+ iirdesign([-0.1, 0.3], [0.1, 0.5], 1, 40, analog=True)
4373
+ with pytest.raises(ValueError, match="must be greater than 0"):
4374
+ iirdesign([0.1, -0.3], [0.1, 0.5], 1, 40, analog=True)
4375
+ with pytest.raises(ValueError, match="must be greater than 0"):
4376
+ iirdesign([0.1, 0.3], [-0.1, 0.5], 1, 40, analog=True)
4377
+ with pytest.raises(ValueError, match="must be greater than 0"):
4378
+ iirdesign([0.1, 0.3], [0.1, -0.5], 1, 40, analog=True)
4379
+
4380
+ # discrete filter with fs=None, freq > 1
4381
+ with pytest.raises(ValueError, match="must be less than 1"):
4382
+ iirdesign(1, 0.5, 1, 40)
4383
+ with pytest.raises(ValueError, match="must be less than 1"):
4384
+ iirdesign(1.1, 0.5, 1, 40)
4385
+ with pytest.raises(ValueError, match="must be less than 1"):
4386
+ iirdesign(0.1, 1, 1, 40)
4387
+ with pytest.raises(ValueError, match="must be less than 1"):
4388
+ iirdesign(0.1, 1.5, 1, 40)
4389
+ with pytest.raises(ValueError, match="must be less than 1"):
4390
+ iirdesign([1, 0.3], [0.1, 0.5], 1, 40)
4391
+ with pytest.raises(ValueError, match="must be less than 1"):
4392
+ iirdesign([1.1, 0.3], [0.1, 0.5], 1, 40)
4393
+ with pytest.raises(ValueError, match="must be less than 1"):
4394
+ iirdesign([0.1, 1], [0.1, 0.5], 1, 40)
4395
+ with pytest.raises(ValueError, match="must be less than 1"):
4396
+ iirdesign([0.1, 1.1], [0.1, 0.5], 1, 40)
4397
+ with pytest.raises(ValueError, match="must be less than 1"):
4398
+ iirdesign([0.1, 0.3], [1, 0.5], 1, 40)
4399
+ with pytest.raises(ValueError, match="must be less than 1"):
4400
+ iirdesign([0.1, 0.3], [1.1, 0.5], 1, 40)
4401
+ with pytest.raises(ValueError, match="must be less than 1"):
4402
+ iirdesign([0.1, 0.3], [0.1, 1], 1, 40)
4403
+ with pytest.raises(ValueError, match="must be less than 1"):
4404
+ iirdesign([0.1, 0.3], [0.1, 1.5], 1, 40)
4405
+
4406
+ # discrete filter with fs>2, wp, ws < fs/2 must pass
4407
+ iirdesign(100, 500, 1, 40, fs=2000)
4408
+ iirdesign(500, 100, 1, 40, fs=2000)
4409
+ iirdesign([200, 400], [100, 500], 1, 40, fs=2000)
4410
+ iirdesign([100, 500], [200, 400], 1, 40, fs=2000)
4411
+
4412
+ # discrete filter with fs>2, freq > fs/2: this must raise
4413
+ with pytest.raises(ValueError, match="must be less than fs/2"):
4414
+ iirdesign(1000, 400, 1, 40, fs=2000)
4415
+ with pytest.raises(ValueError, match="must be less than fs/2"):
4416
+ iirdesign(1100, 500, 1, 40, fs=2000)
4417
+ with pytest.raises(ValueError, match="must be less than fs/2"):
4418
+ iirdesign(100, 1000, 1, 40, fs=2000)
4419
+ with pytest.raises(ValueError, match="must be less than fs/2"):
4420
+ iirdesign(100, 1100, 1, 40, fs=2000)
4421
+ with pytest.raises(ValueError, match="must be less than fs/2"):
4422
+ iirdesign([1000, 400], [100, 500], 1, 40, fs=2000)
4423
+ with pytest.raises(ValueError, match="must be less than fs/2"):
4424
+ iirdesign([1100, 400], [100, 500], 1, 40, fs=2000)
4425
+ with pytest.raises(ValueError, match="must be less than fs/2"):
4426
+ iirdesign([200, 1000], [100, 500], 1, 40, fs=2000)
4427
+ with pytest.raises(ValueError, match="must be less than fs/2"):
4428
+ iirdesign([200, 1100], [100, 500], 1, 40, fs=2000)
4429
+ with pytest.raises(ValueError, match="must be less than fs/2"):
4430
+ iirdesign([200, 400], [1000, 500], 1, 40, fs=2000)
4431
+ with pytest.raises(ValueError, match="must be less than fs/2"):
4432
+ iirdesign([200, 400], [1100, 500], 1, 40, fs=2000)
4433
+ with pytest.raises(ValueError, match="must be less than fs/2"):
4434
+ iirdesign([200, 400], [100, 1000], 1, 40, fs=2000)
4435
+ with pytest.raises(ValueError, match="must be less than fs/2"):
4436
+ iirdesign([200, 400], [100, 1100], 1, 40, fs=2000)
4437
+
4438
+ with pytest.raises(ValueError, match="strictly inside stopband"):
4439
+ iirdesign([0.1, 0.4], [0.5, 0.6], 1, 40)
4440
+ with pytest.raises(ValueError, match="strictly inside stopband"):
4441
+ iirdesign([0.5, 0.6], [0.1, 0.4], 1, 40)
4442
+ with pytest.raises(ValueError, match="strictly inside stopband"):
4443
+ iirdesign([0.3, 0.6], [0.4, 0.7], 1, 40)
4444
+ with pytest.raises(ValueError, match="strictly inside stopband"):
4445
+ iirdesign([0.4, 0.7], [0.3, 0.6], 1, 40)
4446
+
4447
+ def test_fs_validation(self):
4448
+ with pytest.raises(ValueError, match="Sampling.*single scalar"):
4449
+ iirfilter(1, 1, btype="low", fs=np.array([10, 20]))
4450
+
4451
+
4452
+ class TestIIRFilter:
4453
+
4454
+ def test_symmetry(self):
4455
+ # All built-in IIR filters are real, so should have perfectly
4456
+ # symmetrical poles and zeros. Then ba representation (using
4457
+ # numpy.poly) will be purely real instead of having negligible
4458
+ # imaginary parts.
4459
+ for N in np.arange(1, 26):
4460
+ for ftype in ('butter', 'bessel', 'cheby1', 'cheby2', 'ellip'):
4461
+ z, p, k = iirfilter(N, 1.1, 1, 20, 'low', analog=True,
4462
+ ftype=ftype, output='zpk')
4463
+ xp_assert_equal(sorted(z),
4464
+ sorted(z.conj()))
4465
+ xp_assert_equal(sorted(p),
4466
+ sorted(p.conj()))
4467
+ xp_assert_equal(k, np.real(k))
4468
+
4469
+ b, a = iirfilter(N, 1.1, 1, 20, 'low', analog=True,
4470
+ ftype=ftype, output='ba')
4471
+ assert issubclass(b.dtype.type, np.floating)
4472
+ assert issubclass(a.dtype.type, np.floating)
4473
+
4474
+ def test_int_inputs(self):
4475
+ # Using integer frequency arguments and large N should not produce
4476
+ # numpy integers that wraparound to negative numbers
4477
+ k = iirfilter(24, 100, btype='low', analog=True, ftype='bessel',
4478
+ output='zpk')[2]
4479
+ k2 = 9.999999999999989e+47
4480
+ xp_assert_close(np.asarray(k), np.asarray(k2))
4481
+ # if fs is specified then the normalization of Wn to have
4482
+ # 0 <= Wn <= 1 should not cause an integer overflow
4483
+ # the following line should not raise an exception
4484
+ iirfilter(20, [1000000000, 1100000000], btype='bp',
4485
+ analog=False, fs=6250000000)
4486
+
4487
+ def test_invalid_wn_size(self):
4488
+ # low and high have 1 Wn, band and stop have 2 Wn
4489
+ assert_raises(ValueError, iirfilter, 1, [0.1, 0.9], btype='low')
4490
+ assert_raises(ValueError, iirfilter, 1, [0.2, 0.5], btype='high')
4491
+ assert_raises(ValueError, iirfilter, 1, 0.2, btype='bp')
4492
+ assert_raises(ValueError, iirfilter, 1, 400, btype='bs', analog=True)
4493
+
4494
+ def test_invalid_wn_range(self):
4495
+ # For digital filters, 0 <= Wn <= 1
4496
+ assert_raises(ValueError, iirfilter, 1, 2, btype='low')
4497
+ assert_raises(ValueError, iirfilter, 1, [0.5, 1], btype='band')
4498
+ assert_raises(ValueError, iirfilter, 1, [0., 0.5], btype='band')
4499
+ assert_raises(ValueError, iirfilter, 1, -1, btype='high')
4500
+ assert_raises(ValueError, iirfilter, 1, [1, 2], btype='band')
4501
+ assert_raises(ValueError, iirfilter, 1, [10, 20], btype='stop')
4502
+
4503
+ # analog=True with non-positive critical frequencies
4504
+ with pytest.raises(ValueError, match="must be greater than 0"):
4505
+ iirfilter(2, 0, btype='low', analog=True)
4506
+ with pytest.raises(ValueError, match="must be greater than 0"):
4507
+ iirfilter(2, -1, btype='low', analog=True)
4508
+ with pytest.raises(ValueError, match="must be greater than 0"):
4509
+ iirfilter(2, [0, 100], analog=True)
4510
+ with pytest.raises(ValueError, match="must be greater than 0"):
4511
+ iirfilter(2, [-1, 100], analog=True)
4512
+ with pytest.raises(ValueError, match="must be greater than 0"):
4513
+ iirfilter(2, [10, 0], analog=True)
4514
+ with pytest.raises(ValueError, match="must be greater than 0"):
4515
+ iirfilter(2, [10, -1], analog=True)
4516
+
4517
+ def test_analog_sos(self):
4518
+ # first order Butterworth filter with Wn = 1 has tf 1/(s+1)
4519
+ sos = [[0., 0., 1., 0., 1., 1.]]
4520
+ sos2 = iirfilter(N=1, Wn=1, btype='low', analog=True, output='sos')
4521
+ assert_array_almost_equal(sos, sos2)
4522
+
4523
+ def test_wn1_ge_wn0(self):
4524
+ # gh-15773: should raise error if Wn[0] >= Wn[1]
4525
+ with pytest.raises(ValueError,
4526
+ match=r"Wn\[0\] must be less than Wn\[1\]"):
4527
+ iirfilter(2, [0.5, 0.5])
4528
+ with pytest.raises(ValueError,
4529
+ match=r"Wn\[0\] must be less than Wn\[1\]"):
4530
+ iirfilter(2, [0.6, 0.5])
4531
+
4532
+
4533
+ class TestGroupDelay:
4534
+ def test_identity_filter(self):
4535
+ w, gd = group_delay((1, 1))
4536
+ assert_array_almost_equal(w, pi * np.arange(512) / 512)
4537
+ assert_array_almost_equal(gd, np.zeros(512))
4538
+ w, gd = group_delay((1, 1), whole=True)
4539
+ assert_array_almost_equal(w, 2 * pi * np.arange(512) / 512)
4540
+ assert_array_almost_equal(gd, np.zeros(512))
4541
+
4542
+ def test_fir(self):
4543
+ # Let's design linear phase FIR and check that the group delay
4544
+ # is constant.
4545
+ N = 100
4546
+ b = firwin(N + 1, 0.1)
4547
+ w, gd = group_delay((b, 1))
4548
+ xp_assert_close(gd, np.ones_like(gd)*(0.5 * N))
4549
+
4550
+ def test_iir(self):
4551
+ # Let's design Butterworth filter and test the group delay at
4552
+ # some points against MATLAB answer.
4553
+ b, a = butter(4, 0.1)
4554
+ w = np.linspace(0, pi, num=10, endpoint=False)
4555
+ w, gd = group_delay((b, a), w=w)
4556
+ matlab_gd = np.array([8.249313898506037, 11.958947880907104,
4557
+ 2.452325615326005, 1.048918665702008,
4558
+ 0.611382575635897, 0.418293269460578,
4559
+ 0.317932917836572, 0.261371844762525,
4560
+ 0.229038045801298, 0.212185774208521])
4561
+ assert_array_almost_equal(gd, matlab_gd)
4562
+
4563
+ @pytest.mark.thread_unsafe
4564
+ def test_singular(self):
4565
+ # Let's create a filter with zeros and poles on the unit circle and
4566
+ # check if warnings are raised at those frequencies.
4567
+ z1 = np.exp(1j * 0.1 * pi)
4568
+ z2 = np.exp(1j * 0.25 * pi)
4569
+ p1 = np.exp(1j * 0.5 * pi)
4570
+ p2 = np.exp(1j * 0.8 * pi)
4571
+ b = np.convolve([1, -z1], [1, -z2])
4572
+ a = np.convolve([1, -p1], [1, -p2])
4573
+ w = np.array([0.1 * pi, 0.25 * pi, -0.5 * pi, -0.8 * pi])
4574
+
4575
+ w, gd = assert_warns(UserWarning, group_delay, (b, a), w=w)
4576
+
4577
+ def test_backward_compat(self):
4578
+ # For backward compatibility, test if None act as a wrapper for default
4579
+ w1, gd1 = group_delay((1, 1))
4580
+ w2, gd2 = group_delay((1, 1), None)
4581
+ assert_array_almost_equal(w1, w2)
4582
+ assert_array_almost_equal(gd1, gd2)
4583
+
4584
+ def test_fs_param(self):
4585
+ # Let's design Butterworth filter and test the group delay at
4586
+ # some points against the normalized frequency answer.
4587
+ b, a = butter(4, 4800, fs=96000)
4588
+ w = np.linspace(0, 96000/2, num=10, endpoint=False)
4589
+ w, gd = group_delay((b, a), w=w, fs=96000)
4590
+ norm_gd = np.array([8.249313898506037, 11.958947880907104,
4591
+ 2.452325615326005, 1.048918665702008,
4592
+ 0.611382575635897, 0.418293269460578,
4593
+ 0.317932917836572, 0.261371844762525,
4594
+ 0.229038045801298, 0.212185774208521])
4595
+ assert_array_almost_equal(gd, norm_gd)
4596
+
4597
+ def test_w_or_N_types(self):
4598
+ # Measure at 8 equally-spaced points
4599
+ for N in (8, np.int8(8), np.int16(8), np.int32(8), np.int64(8),
4600
+ np.array(8)):
4601
+ w, gd = group_delay((1, 1), N)
4602
+ assert_array_almost_equal(w, pi * np.arange(8) / 8)
4603
+ assert_array_almost_equal(gd, np.zeros(8))
4604
+
4605
+ # Measure at frequency 8 rad/sec
4606
+ for w in (8.0, 8.0+0j):
4607
+ w_out, gd = group_delay((1, 1), w)
4608
+ assert_array_almost_equal(w_out, [8])
4609
+ assert_array_almost_equal(gd, [0])
4610
+
4611
+ def test_complex_coef(self):
4612
+ # gh-19586: handle complex coef TFs
4613
+ #
4614
+ # for g(z) = (alpha*z+1)/(1+conjugate(alpha)), group delay is
4615
+ # given by function below.
4616
+ #
4617
+ # def gd_expr(w, alpha):
4618
+ # num = 1j*(abs(alpha)**2-1)*np.exp(1j*w)
4619
+ # den = (alpha*np.exp(1j*w)+1)*(np.exp(1j*w)+np.conj(alpha))
4620
+ # return -np.imag(num/den)
4621
+
4622
+ # arbitrary non-real alpha
4623
+ alpha = -0.6143077933232609+0.3355978770229421j
4624
+ # 8 points from from -pi to pi
4625
+ wref = np.array([-3.141592653589793 ,
4626
+ -2.356194490192345 ,
4627
+ -1.5707963267948966,
4628
+ -0.7853981633974483,
4629
+ 0. ,
4630
+ 0.7853981633974483,
4631
+ 1.5707963267948966,
4632
+ 2.356194490192345 ])
4633
+ gdref = array([0.18759548150354619,
4634
+ 0.17999770352712252,
4635
+ 0.23598047471879877,
4636
+ 0.46539443069907194,
4637
+ 1.9511492420564165 ,
4638
+ 3.478129975138865 ,
4639
+ 0.6228594960517333 ,
4640
+ 0.27067831839471224])
4641
+ b = [alpha,1]
4642
+ a = [1, np.conjugate(alpha)]
4643
+ gdtest = group_delay((b,a), wref)[1]
4644
+ # need nulp=14 for macOS arm64 wheel builds; added 2 for some
4645
+ # robustness on other platforms.
4646
+ assert_array_almost_equal_nulp(gdtest, gdref, nulp=16)
4647
+
4648
+ def test_fs_validation(self):
4649
+ with pytest.raises(ValueError, match="Sampling.*single scalar"):
4650
+ group_delay((1, 1), fs=np.array([10, 20]))
4651
+
4652
+ with pytest.raises(ValueError, match="Sampling.*be none"):
4653
+ group_delay((1, 1), fs=None)
4654
+
4655
+
4656
+ class TestGammatone:
4657
+ # Test erroneous input cases.
4658
+ def test_invalid_input(self):
4659
+ # Cutoff frequency is <= 0 or >= fs / 2.
4660
+ fs = 16000
4661
+ for args in [(-fs, 'iir'), (0, 'fir'), (fs / 2, 'iir'), (fs, 'fir')]:
4662
+ with pytest.raises(ValueError, match='The frequency must be '
4663
+ 'between '):
4664
+ gammatone(*args, fs=fs)
4665
+
4666
+ # Filter type is not fir or iir
4667
+ for args in [(440, 'fie'), (220, 'it')]:
4668
+ with pytest.raises(ValueError, match='ftype must be '):
4669
+ gammatone(*args, fs=fs)
4670
+
4671
+ # Order is <= 0 or > 24 for FIR filter.
4672
+ for args in [(440, 'fir', -50), (220, 'fir', 0), (110, 'fir', 25),
4673
+ (55, 'fir', 50)]:
4674
+ with pytest.raises(ValueError, match='Invalid order: '):
4675
+ gammatone(*args, numtaps=None, fs=fs)
4676
+
4677
+ # Verify that the filter's frequency response is approximately
4678
+ # 1 at the cutoff frequency.
4679
+ def test_frequency_response(self):
4680
+ fs = 16000
4681
+ ftypes = ['fir', 'iir']
4682
+ for ftype in ftypes:
4683
+ # Create a gammatone filter centered at 1000 Hz.
4684
+ b, a = gammatone(1000, ftype, fs=fs)
4685
+
4686
+ # Calculate the frequency response.
4687
+ freqs, response = freqz(b, a)
4688
+
4689
+ # Determine peak magnitude of the response
4690
+ # and corresponding frequency.
4691
+ response_max = np.max(np.abs(response))
4692
+ freq_hz = freqs[np.argmax(np.abs(response))] / ((2 * np.pi) / fs)
4693
+
4694
+ # Check that the peak magnitude is 1 and the frequency is 1000 Hz.
4695
+ xp_assert_close(response_max,
4696
+ np.ones_like(response_max), rtol=1e-2, check_0d=False)
4697
+ xp_assert_close(freq_hz,
4698
+ 1000*np.ones_like(freq_hz), rtol=1e-2, check_0d=False)
4699
+
4700
+ # All built-in IIR filters are real, so should have perfectly
4701
+ # symmetrical poles and zeros. Then ba representation (using
4702
+ # numpy.poly) will be purely real instead of having negligible
4703
+ # imaginary parts.
4704
+ def test_iir_symmetry(self):
4705
+ b, a = gammatone(440, 'iir', fs=24000)
4706
+ z, p, k = tf2zpk(b, a)
4707
+ xp_assert_equal(sorted(z), sorted(z.conj()))
4708
+ xp_assert_equal(sorted(p), sorted(p.conj()))
4709
+ xp_assert_equal(k, np.real(k))
4710
+
4711
+ assert issubclass(b.dtype.type, np.floating)
4712
+ assert issubclass(a.dtype.type, np.floating)
4713
+
4714
+ # Verify FIR filter coefficients with the paper's
4715
+ # Mathematica implementation
4716
+ def test_fir_ba_output(self):
4717
+ b, _ = gammatone(15, 'fir', fs=1000)
4718
+ b2 = [0.0, 2.2608075649884e-04,
4719
+ 1.5077903981357e-03, 4.2033687753998e-03,
4720
+ 8.1508962726503e-03, 1.2890059089154e-02,
4721
+ 1.7833890391666e-02, 2.2392613558564e-02,
4722
+ 2.6055195863104e-02, 2.8435872863284e-02,
4723
+ 2.9293319149544e-02, 2.852976858014e-02,
4724
+ 2.6176557156294e-02, 2.2371510270395e-02,
4725
+ 1.7332485267759e-02]
4726
+ xp_assert_close(b, b2)
4727
+
4728
+ # Verify IIR filter coefficients with the paper's MATLAB implementation
4729
+ def test_iir_ba_output(self):
4730
+ b, a = gammatone(440, 'iir', fs=16000)
4731
+ b2 = [1.31494461367464e-06, -5.03391196645395e-06,
4732
+ 7.00649426000897e-06, -4.18951968419854e-06,
4733
+ 9.02614910412011e-07]
4734
+ a2 = [1.0, -7.65646235454218,
4735
+ 25.7584699322366, -49.7319214483238,
4736
+ 60.2667361289181, -46.9399590980486,
4737
+ 22.9474798808461, -6.43799381299034,
4738
+ 0.793651554625368]
4739
+ xp_assert_close(b, b2)
4740
+ xp_assert_close(a, a2)
4741
+
4742
+ def test_fs_validation(self):
4743
+ with pytest.raises(ValueError, match="Sampling.*single scalar"):
4744
+ gammatone(440, 'iir', fs=np.array([10, 20]))