scipy 1.15.3__cp313-cp313-win_amd64.whl → 1.16.0rc2__cp313-cp313-win_amd64.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.
- scipy/__config__.py +8 -8
- scipy/__init__.py +3 -6
- scipy/_cyutility.cp313-win_amd64.dll.a +0 -0
- scipy/_cyutility.cp313-win_amd64.pyd +0 -0
- scipy/_lib/_array_api.py +486 -161
- scipy/_lib/_array_api_compat_vendor.py +9 -0
- scipy/_lib/_bunch.py +4 -0
- scipy/_lib/_ccallback_c.cp313-win_amd64.dll.a +0 -0
- scipy/_lib/_ccallback_c.cp313-win_amd64.pyd +0 -0
- scipy/_lib/_docscrape.py +1 -1
- scipy/_lib/_elementwise_iterative_method.py +15 -26
- scipy/_lib/_fpumode.cp313-win_amd64.dll.a +0 -0
- scipy/_lib/_fpumode.cp313-win_amd64.pyd +0 -0
- scipy/_lib/_sparse.py +41 -0
- scipy/_lib/_test_ccallback.cp313-win_amd64.dll.a +0 -0
- scipy/_lib/_test_ccallback.cp313-win_amd64.pyd +0 -0
- scipy/_lib/_test_deprecation_call.cp313-win_amd64.dll.a +0 -0
- scipy/_lib/_test_deprecation_call.cp313-win_amd64.pyd +0 -0
- scipy/_lib/_test_deprecation_def.cp313-win_amd64.dll.a +0 -0
- scipy/_lib/_test_deprecation_def.cp313-win_amd64.pyd +0 -0
- scipy/_lib/_testutils.py +6 -2
- scipy/_lib/_uarray/_uarray.cp313-win_amd64.dll.a +0 -0
- scipy/_lib/_uarray/_uarray.cp313-win_amd64.pyd +0 -0
- scipy/_lib/_util.py +222 -125
- scipy/_lib/array_api_compat/__init__.py +4 -4
- scipy/_lib/array_api_compat/_internal.py +19 -6
- scipy/_lib/array_api_compat/common/__init__.py +1 -1
- scipy/_lib/array_api_compat/common/_aliases.py +365 -193
- scipy/_lib/array_api_compat/common/_fft.py +94 -64
- scipy/_lib/array_api_compat/common/_helpers.py +413 -180
- scipy/_lib/array_api_compat/common/_linalg.py +116 -40
- scipy/_lib/array_api_compat/common/_typing.py +179 -10
- scipy/_lib/array_api_compat/cupy/__init__.py +1 -4
- scipy/_lib/array_api_compat/cupy/_aliases.py +61 -41
- scipy/_lib/array_api_compat/cupy/_info.py +16 -6
- scipy/_lib/array_api_compat/cupy/_typing.py +24 -39
- scipy/_lib/array_api_compat/dask/array/__init__.py +6 -3
- scipy/_lib/array_api_compat/dask/array/_aliases.py +267 -108
- scipy/_lib/array_api_compat/dask/array/_info.py +105 -34
- scipy/_lib/array_api_compat/dask/array/fft.py +5 -8
- scipy/_lib/array_api_compat/dask/array/linalg.py +21 -22
- scipy/_lib/array_api_compat/numpy/__init__.py +13 -15
- scipy/_lib/array_api_compat/numpy/_aliases.py +98 -49
- scipy/_lib/array_api_compat/numpy/_info.py +36 -16
- scipy/_lib/array_api_compat/numpy/_typing.py +27 -43
- scipy/_lib/array_api_compat/numpy/fft.py +11 -5
- scipy/_lib/array_api_compat/numpy/linalg.py +75 -22
- scipy/_lib/array_api_compat/torch/__init__.py +3 -5
- scipy/_lib/array_api_compat/torch/_aliases.py +262 -159
- scipy/_lib/array_api_compat/torch/_info.py +27 -16
- scipy/_lib/array_api_compat/torch/_typing.py +3 -0
- scipy/_lib/array_api_compat/torch/fft.py +17 -18
- scipy/_lib/array_api_compat/torch/linalg.py +16 -16
- scipy/_lib/array_api_extra/__init__.py +26 -3
- scipy/_lib/array_api_extra/_delegation.py +171 -0
- scipy/_lib/array_api_extra/_lib/__init__.py +1 -0
- scipy/_lib/array_api_extra/_lib/_at.py +463 -0
- scipy/_lib/array_api_extra/_lib/_backends.py +46 -0
- scipy/_lib/array_api_extra/_lib/_funcs.py +937 -0
- scipy/_lib/array_api_extra/_lib/_lazy.py +357 -0
- scipy/_lib/array_api_extra/_lib/_testing.py +278 -0
- scipy/_lib/array_api_extra/_lib/_utils/__init__.py +1 -0
- scipy/_lib/array_api_extra/_lib/_utils/_compat.py +74 -0
- scipy/_lib/array_api_extra/_lib/_utils/_compat.pyi +45 -0
- scipy/_lib/array_api_extra/_lib/_utils/_helpers.py +559 -0
- scipy/_lib/array_api_extra/_lib/_utils/_typing.py +10 -0
- scipy/_lib/array_api_extra/_lib/_utils/_typing.pyi +105 -0
- scipy/_lib/array_api_extra/testing.py +359 -0
- scipy/_lib/decorator.py +2 -2
- scipy/_lib/doccer.py +1 -7
- scipy/_lib/messagestream.cp313-win_amd64.dll.a +0 -0
- scipy/_lib/messagestream.cp313-win_amd64.pyd +0 -0
- scipy/_lib/pyprima/__init__.py +212 -0
- scipy/_lib/pyprima/cobyla/__init__.py +0 -0
- scipy/_lib/pyprima/cobyla/cobyla.py +559 -0
- scipy/_lib/pyprima/cobyla/cobylb.py +714 -0
- scipy/_lib/pyprima/cobyla/geometry.py +226 -0
- scipy/_lib/pyprima/cobyla/initialize.py +215 -0
- scipy/_lib/pyprima/cobyla/trustregion.py +492 -0
- scipy/_lib/pyprima/cobyla/update.py +289 -0
- scipy/_lib/pyprima/common/__init__.py +0 -0
- scipy/_lib/pyprima/common/_bounds.py +34 -0
- scipy/_lib/pyprima/common/_linear_constraints.py +46 -0
- scipy/_lib/pyprima/common/_nonlinear_constraints.py +54 -0
- scipy/_lib/pyprima/common/_project.py +173 -0
- scipy/_lib/pyprima/common/checkbreak.py +93 -0
- scipy/_lib/pyprima/common/consts.py +47 -0
- scipy/_lib/pyprima/common/evaluate.py +99 -0
- scipy/_lib/pyprima/common/history.py +38 -0
- scipy/_lib/pyprima/common/infos.py +30 -0
- scipy/_lib/pyprima/common/linalg.py +435 -0
- scipy/_lib/pyprima/common/message.py +290 -0
- scipy/_lib/pyprima/common/powalg.py +131 -0
- scipy/_lib/pyprima/common/preproc.py +277 -0
- scipy/_lib/pyprima/common/present.py +5 -0
- scipy/_lib/pyprima/common/ratio.py +54 -0
- scipy/_lib/pyprima/common/redrho.py +47 -0
- scipy/_lib/pyprima/common/selectx.py +296 -0
- scipy/_lib/tests/test__util.py +105 -121
- scipy/_lib/tests/test_array_api.py +166 -35
- scipy/_lib/tests/test_bunch.py +7 -0
- scipy/_lib/tests/test_ccallback.py +2 -10
- scipy/_lib/tests/test_public_api.py +13 -0
- scipy/cluster/_hierarchy.cp313-win_amd64.dll.a +0 -0
- scipy/cluster/_hierarchy.cp313-win_amd64.pyd +0 -0
- scipy/cluster/_optimal_leaf_ordering.cp313-win_amd64.dll.a +0 -0
- scipy/cluster/_optimal_leaf_ordering.cp313-win_amd64.pyd +0 -0
- scipy/cluster/_vq.cp313-win_amd64.dll.a +0 -0
- scipy/cluster/_vq.cp313-win_amd64.pyd +0 -0
- scipy/cluster/hierarchy.py +393 -223
- scipy/cluster/tests/test_hierarchy.py +273 -335
- scipy/cluster/tests/test_vq.py +45 -61
- scipy/cluster/vq.py +39 -35
- scipy/conftest.py +263 -157
- scipy/constants/_constants.py +4 -1
- scipy/constants/tests/test_codata.py +2 -2
- scipy/constants/tests/test_constants.py +11 -18
- scipy/datasets/_download_all.py +15 -1
- scipy/datasets/_fetchers.py +7 -1
- scipy/datasets/_utils.py +1 -1
- scipy/differentiate/_differentiate.py +25 -25
- scipy/differentiate/tests/test_differentiate.py +24 -25
- scipy/fft/_basic.py +20 -0
- scipy/fft/_helper.py +3 -34
- scipy/fft/_pocketfft/helper.py +29 -1
- scipy/fft/_pocketfft/pypocketfft.cp313-win_amd64.dll.a +0 -0
- scipy/fft/_pocketfft/pypocketfft.cp313-win_amd64.pyd +0 -0
- scipy/fft/_pocketfft/tests/test_basic.py +2 -4
- scipy/fft/_pocketfft/tests/test_real_transforms.py +4 -4
- scipy/fft/_realtransforms.py +13 -0
- scipy/fft/tests/test_basic.py +27 -25
- scipy/fft/tests/test_fftlog.py +16 -7
- scipy/fft/tests/test_helper.py +18 -34
- scipy/fft/tests/test_real_transforms.py +8 -10
- scipy/fftpack/convolve.cp313-win_amd64.dll.a +0 -0
- scipy/fftpack/convolve.cp313-win_amd64.pyd +0 -0
- scipy/fftpack/tests/test_basic.py +2 -4
- scipy/fftpack/tests/test_real_transforms.py +8 -9
- scipy/integrate/_bvp.py +9 -3
- scipy/integrate/_cubature.py +3 -2
- scipy/integrate/_dop.cp313-win_amd64.dll.a +0 -0
- scipy/integrate/_dop.cp313-win_amd64.pyd +0 -0
- scipy/integrate/_lsoda.cp313-win_amd64.dll.a +0 -0
- scipy/integrate/_lsoda.cp313-win_amd64.pyd +0 -0
- scipy/integrate/_ode.py +9 -2
- scipy/integrate/_odepack.cp313-win_amd64.dll.a +0 -0
- scipy/integrate/_odepack.cp313-win_amd64.pyd +0 -0
- scipy/integrate/_quad_vec.py +21 -29
- scipy/integrate/_quadpack.cp313-win_amd64.dll.a +0 -0
- scipy/integrate/_quadpack.cp313-win_amd64.pyd +0 -0
- scipy/integrate/_quadpack_py.py +11 -7
- scipy/integrate/_quadrature.py +3 -3
- scipy/integrate/_rules/_base.py +2 -2
- scipy/integrate/_tanhsinh.py +48 -47
- scipy/integrate/_test_multivariate.cp313-win_amd64.dll.a +0 -0
- scipy/integrate/_test_multivariate.cp313-win_amd64.pyd +0 -0
- scipy/integrate/_test_odeint_banded.cp313-win_amd64.dll.a +0 -0
- scipy/integrate/_test_odeint_banded.cp313-win_amd64.pyd +0 -0
- scipy/integrate/_vode.cp313-win_amd64.dll.a +0 -0
- scipy/integrate/_vode.cp313-win_amd64.pyd +0 -0
- scipy/integrate/tests/test__quad_vec.py +0 -6
- scipy/integrate/tests/test_banded_ode_solvers.py +85 -0
- scipy/integrate/tests/test_cubature.py +21 -35
- scipy/integrate/tests/test_quadrature.py +6 -8
- scipy/integrate/tests/test_tanhsinh.py +56 -48
- scipy/interpolate/__init__.py +70 -58
- scipy/interpolate/_bary_rational.py +22 -22
- scipy/interpolate/_bsplines.py +119 -66
- scipy/interpolate/_cubic.py +65 -50
- scipy/interpolate/_dfitpack.cp313-win_amd64.dll.a +0 -0
- scipy/interpolate/_dfitpack.cp313-win_amd64.pyd +0 -0
- scipy/interpolate/_dierckx.cp313-win_amd64.dll.a +0 -0
- scipy/interpolate/_dierckx.cp313-win_amd64.pyd +0 -0
- scipy/interpolate/_fitpack.cp313-win_amd64.dll.a +0 -0
- scipy/interpolate/_fitpack.cp313-win_amd64.pyd +0 -0
- scipy/interpolate/_fitpack2.py +9 -6
- scipy/interpolate/_fitpack_impl.py +32 -26
- scipy/interpolate/_fitpack_repro.py +23 -19
- scipy/interpolate/_interpnd.cp313-win_amd64.dll.a +0 -0
- scipy/interpolate/_interpnd.cp313-win_amd64.pyd +0 -0
- scipy/interpolate/_interpolate.py +30 -12
- scipy/interpolate/_ndbspline.py +13 -18
- scipy/interpolate/_ndgriddata.py +5 -8
- scipy/interpolate/_polyint.py +95 -31
- scipy/interpolate/_ppoly.cp313-win_amd64.dll.a +0 -0
- scipy/interpolate/_ppoly.cp313-win_amd64.pyd +0 -0
- scipy/interpolate/_rbf.py +2 -2
- scipy/interpolate/_rbfinterp.py +1 -1
- scipy/interpolate/_rbfinterp_pythran.cp313-win_amd64.dll.a +0 -0
- scipy/interpolate/_rbfinterp_pythran.cp313-win_amd64.pyd +0 -0
- scipy/interpolate/_rgi.py +31 -26
- scipy/interpolate/_rgi_cython.cp313-win_amd64.dll.a +0 -0
- scipy/interpolate/_rgi_cython.cp313-win_amd64.pyd +0 -0
- scipy/interpolate/dfitpack.py +0 -20
- scipy/interpolate/interpnd.py +1 -2
- scipy/interpolate/tests/test_bary_rational.py +2 -2
- scipy/interpolate/tests/test_bsplines.py +97 -1
- scipy/interpolate/tests/test_fitpack2.py +39 -1
- scipy/interpolate/tests/test_interpnd.py +32 -20
- scipy/interpolate/tests/test_interpolate.py +48 -4
- scipy/interpolate/tests/test_rgi.py +2 -1
- scipy/io/_fast_matrix_market/__init__.py +2 -0
- scipy/io/_fast_matrix_market/_fmm_core.cp313-win_amd64.dll.a +0 -0
- scipy/io/_fast_matrix_market/_fmm_core.cp313-win_amd64.pyd +0 -0
- scipy/io/_harwell_boeing/_fortran_format_parser.py +19 -16
- scipy/io/_harwell_boeing/hb.py +7 -11
- scipy/io/_idl.py +5 -7
- scipy/io/_netcdf.py +15 -5
- scipy/io/_test_fortran.cp313-win_amd64.dll.a +0 -0
- scipy/io/_test_fortran.cp313-win_amd64.pyd +0 -0
- scipy/io/arff/tests/test_arffread.py +3 -3
- scipy/io/matlab/__init__.py +5 -3
- scipy/io/matlab/_mio.py +4 -1
- scipy/io/matlab/_mio5.py +19 -13
- scipy/io/matlab/_mio5_utils.cp313-win_amd64.dll.a +0 -0
- scipy/io/matlab/_mio5_utils.cp313-win_amd64.pyd +0 -0
- scipy/io/matlab/_mio_utils.cp313-win_amd64.dll.a +0 -0
- scipy/io/matlab/_mio_utils.cp313-win_amd64.pyd +0 -0
- scipy/io/matlab/_miobase.py +4 -1
- scipy/io/matlab/_streams.cp313-win_amd64.dll.a +0 -0
- scipy/io/matlab/_streams.cp313-win_amd64.pyd +0 -0
- scipy/io/matlab/tests/test_mio.py +46 -18
- scipy/io/matlab/tests/test_mio_funcs.py +1 -1
- scipy/io/tests/test_mmio.py +7 -1
- scipy/io/tests/test_wavfile.py +41 -0
- scipy/io/wavfile.py +57 -10
- scipy/linalg/_basic.py +113 -86
- scipy/linalg/_cythonized_array_utils.cp313-win_amd64.dll.a +0 -0
- scipy/linalg/_cythonized_array_utils.cp313-win_amd64.pyd +0 -0
- scipy/linalg/_decomp.py +22 -9
- scipy/linalg/_decomp_cholesky.py +28 -13
- scipy/linalg/_decomp_cossin.py +45 -30
- scipy/linalg/_decomp_interpolative.cp313-win_amd64.dll.a +0 -0
- scipy/linalg/_decomp_interpolative.cp313-win_amd64.pyd +0 -0
- scipy/linalg/_decomp_ldl.py +4 -1
- scipy/linalg/_decomp_lu.py +18 -6
- scipy/linalg/_decomp_lu_cython.cp313-win_amd64.dll.a +0 -0
- scipy/linalg/_decomp_lu_cython.cp313-win_amd64.pyd +0 -0
- scipy/linalg/_decomp_polar.py +2 -0
- scipy/linalg/_decomp_qr.py +6 -2
- scipy/linalg/_decomp_qz.py +3 -0
- scipy/linalg/_decomp_schur.py +3 -1
- scipy/linalg/_decomp_svd.py +13 -2
- scipy/linalg/_decomp_update.cp313-win_amd64.dll.a +0 -0
- scipy/linalg/_decomp_update.cp313-win_amd64.pyd +0 -0
- scipy/linalg/_expm_frechet.py +4 -0
- scipy/linalg/_fblas.cp313-win_amd64.dll.a +0 -0
- scipy/linalg/_fblas.cp313-win_amd64.pyd +0 -0
- scipy/linalg/_flapack.cp313-win_amd64.dll.a +0 -0
- scipy/linalg/_flapack.cp313-win_amd64.pyd +0 -0
- scipy/linalg/_linalg_pythran.cp313-win_amd64.dll.a +0 -0
- scipy/linalg/_linalg_pythran.cp313-win_amd64.pyd +0 -0
- scipy/linalg/_matfuncs.py +187 -4
- scipy/linalg/_matfuncs_expm.cp313-win_amd64.dll.a +0 -0
- scipy/linalg/_matfuncs_expm.cp313-win_amd64.pyd +0 -0
- scipy/linalg/_matfuncs_schur_sqrtm.cp313-win_amd64.dll.a +0 -0
- scipy/linalg/_matfuncs_schur_sqrtm.cp313-win_amd64.pyd +0 -0
- scipy/linalg/_matfuncs_sqrtm.py +1 -99
- scipy/linalg/_matfuncs_sqrtm_triu.cp313-win_amd64.dll.a +0 -0
- scipy/linalg/_matfuncs_sqrtm_triu.cp313-win_amd64.pyd +0 -0
- scipy/linalg/_procrustes.py +2 -0
- scipy/linalg/_sketches.py +17 -6
- scipy/linalg/_solve_toeplitz.cp313-win_amd64.dll.a +0 -0
- scipy/linalg/_solve_toeplitz.cp313-win_amd64.pyd +0 -0
- scipy/linalg/_solvers.py +7 -2
- scipy/linalg/_special_matrices.py +26 -36
- scipy/linalg/cython_blas.cp313-win_amd64.dll.a +0 -0
- scipy/linalg/cython_blas.cp313-win_amd64.pyd +0 -0
- scipy/linalg/cython_lapack.cp313-win_amd64.dll.a +0 -0
- scipy/linalg/cython_lapack.cp313-win_amd64.pyd +0 -0
- scipy/linalg/lapack.py +22 -2
- scipy/linalg/tests/_cython_examples/meson.build +7 -0
- scipy/linalg/tests/test_basic.py +31 -16
- scipy/linalg/tests/test_batch.py +588 -0
- scipy/linalg/tests/test_cythonized_array_utils.py +0 -2
- scipy/linalg/tests/test_decomp.py +40 -3
- scipy/linalg/tests/test_decomp_cossin.py +14 -0
- scipy/linalg/tests/test_decomp_ldl.py +1 -1
- scipy/linalg/tests/test_lapack.py +115 -7
- scipy/linalg/tests/test_matfuncs.py +157 -102
- scipy/linalg/tests/test_procrustes.py +0 -7
- scipy/linalg/tests/test_solve_toeplitz.py +1 -1
- scipy/linalg/tests/test_special_matrices.py +1 -5
- scipy/ndimage/__init__.py +1 -0
- scipy/ndimage/_ctest.cp313-win_amd64.dll.a +0 -0
- scipy/ndimage/_ctest.cp313-win_amd64.pyd +0 -0
- scipy/ndimage/_cytest.cp313-win_amd64.dll.a +0 -0
- scipy/ndimage/_cytest.cp313-win_amd64.pyd +0 -0
- scipy/ndimage/_delegators.py +8 -2
- scipy/ndimage/_filters.py +453 -5
- scipy/ndimage/_interpolation.py +36 -6
- scipy/ndimage/_measurements.py +4 -2
- scipy/ndimage/_morphology.py +5 -0
- scipy/ndimage/_nd_image.cp313-win_amd64.dll.a +0 -0
- scipy/ndimage/_nd_image.cp313-win_amd64.pyd +0 -0
- scipy/ndimage/_ni_docstrings.py +5 -1
- scipy/ndimage/_ni_label.cp313-win_amd64.dll.a +0 -0
- scipy/ndimage/_ni_label.cp313-win_amd64.pyd +0 -0
- scipy/ndimage/_ni_support.py +1 -5
- scipy/ndimage/_rank_filter_1d.cp313-win_amd64.dll.a +0 -0
- scipy/ndimage/_rank_filter_1d.cp313-win_amd64.pyd +0 -0
- scipy/ndimage/_support_alternative_backends.py +18 -6
- scipy/ndimage/tests/test_filters.py +370 -259
- scipy/ndimage/tests/test_fourier.py +7 -9
- scipy/ndimage/tests/test_interpolation.py +68 -61
- scipy/ndimage/tests/test_measurements.py +18 -35
- scipy/ndimage/tests/test_morphology.py +143 -131
- scipy/ndimage/tests/test_splines.py +1 -3
- scipy/odr/__odrpack.cp313-win_amd64.dll.a +0 -0
- scipy/odr/__odrpack.cp313-win_amd64.pyd +0 -0
- scipy/optimize/_basinhopping.py +13 -7
- scipy/optimize/_bglu_dense.cp313-win_amd64.dll.a +0 -0
- scipy/optimize/_bglu_dense.cp313-win_amd64.pyd +0 -0
- scipy/optimize/_bracket.py +17 -24
- scipy/optimize/_chandrupatla.py +9 -10
- scipy/optimize/_cobyla_py.py +104 -123
- scipy/optimize/_constraints.py +14 -10
- scipy/optimize/_differentiable_functions.py +371 -230
- scipy/optimize/_differentialevolution.py +4 -3
- scipy/optimize/_direct.cp313-win_amd64.dll.a +0 -0
- scipy/optimize/_direct.cp313-win_amd64.pyd +0 -0
- scipy/optimize/_dual_annealing.py +1 -1
- scipy/optimize/_elementwise.py +1 -4
- scipy/optimize/_group_columns.cp313-win_amd64.dll.a +0 -0
- scipy/optimize/_group_columns.cp313-win_amd64.pyd +0 -0
- scipy/optimize/_highspy/_core.cp313-win_amd64.dll.a +0 -0
- scipy/optimize/_highspy/_core.cp313-win_amd64.pyd +0 -0
- scipy/optimize/_highspy/_highs_options.cp313-win_amd64.dll.a +0 -0
- scipy/optimize/_highspy/_highs_options.cp313-win_amd64.pyd +0 -0
- scipy/optimize/_lbfgsb.cp313-win_amd64.dll.a +0 -0
- scipy/optimize/_lbfgsb.cp313-win_amd64.pyd +0 -0
- scipy/optimize/_lbfgsb_py.py +57 -16
- scipy/optimize/_linprog_doc.py +2 -2
- scipy/optimize/_linprog_highs.py +2 -2
- scipy/optimize/_linprog_ip.py +25 -10
- scipy/optimize/_linprog_util.py +14 -16
- scipy/optimize/_lsap.cp313-win_amd64.dll.a +0 -0
- scipy/optimize/_lsap.cp313-win_amd64.pyd +0 -0
- scipy/optimize/_lsq/common.py +3 -3
- scipy/optimize/_lsq/dogbox.py +16 -2
- scipy/optimize/_lsq/givens_elimination.cp313-win_amd64.dll.a +0 -0
- scipy/optimize/_lsq/givens_elimination.cp313-win_amd64.pyd +0 -0
- scipy/optimize/_lsq/least_squares.py +198 -126
- scipy/optimize/_lsq/lsq_linear.py +6 -6
- scipy/optimize/_lsq/trf.py +35 -8
- scipy/optimize/_milp.py +3 -1
- scipy/optimize/_minimize.py +105 -36
- scipy/optimize/_minpack.cp313-win_amd64.dll.a +0 -0
- scipy/optimize/_minpack.cp313-win_amd64.pyd +0 -0
- scipy/optimize/_minpack_py.py +21 -14
- scipy/optimize/_moduleTNC.cp313-win_amd64.dll.a +0 -0
- scipy/optimize/_moduleTNC.cp313-win_amd64.pyd +0 -0
- scipy/optimize/_nnls.py +20 -21
- scipy/optimize/_nonlin.py +34 -3
- scipy/optimize/_numdiff.py +288 -110
- scipy/optimize/_optimize.py +86 -48
- scipy/optimize/_pava_pybind.cp313-win_amd64.dll.a +0 -0
- scipy/optimize/_pava_pybind.cp313-win_amd64.pyd +0 -0
- scipy/optimize/_remove_redundancy.py +5 -5
- scipy/optimize/_root_scalar.py +1 -1
- scipy/optimize/_shgo.py +6 -0
- scipy/optimize/_shgo_lib/_complex.py +1 -1
- scipy/optimize/_slsqp_py.py +216 -124
- scipy/optimize/_slsqplib.cp313-win_amd64.dll.a +0 -0
- scipy/optimize/_slsqplib.cp313-win_amd64.pyd +0 -0
- scipy/optimize/_spectral.py +1 -1
- scipy/optimize/_tnc.py +8 -1
- scipy/optimize/_trlib/_trlib.cp313-win_amd64.dll.a +0 -0
- scipy/optimize/_trlib/_trlib.cp313-win_amd64.pyd +0 -0
- scipy/optimize/_trustregion.py +20 -6
- scipy/optimize/_trustregion_constr/canonical_constraint.py +7 -7
- scipy/optimize/_trustregion_constr/equality_constrained_sqp.py +1 -1
- scipy/optimize/_trustregion_constr/minimize_trustregion_constr.py +11 -3
- scipy/optimize/_trustregion_constr/projections.py +12 -8
- scipy/optimize/_trustregion_constr/qp_subproblem.py +9 -9
- scipy/optimize/_trustregion_constr/tests/test_projections.py +7 -7
- scipy/optimize/_trustregion_constr/tests/test_qp_subproblem.py +77 -77
- scipy/optimize/_trustregion_constr/tr_interior_point.py +5 -5
- scipy/optimize/_trustregion_exact.py +0 -1
- scipy/optimize/_zeros.cp313-win_amd64.dll.a +0 -0
- scipy/optimize/_zeros.cp313-win_amd64.pyd +0 -0
- scipy/optimize/_zeros_py.py +97 -17
- scipy/optimize/cython_optimize/_zeros.cp313-win_amd64.dll.a +0 -0
- scipy/optimize/cython_optimize/_zeros.cp313-win_amd64.pyd +0 -0
- scipy/optimize/slsqp.py +0 -1
- scipy/optimize/tests/test__basinhopping.py +1 -1
- scipy/optimize/tests/test__differential_evolution.py +4 -4
- scipy/optimize/tests/test__linprog_clean_inputs.py +5 -3
- scipy/optimize/tests/test__numdiff.py +66 -22
- scipy/optimize/tests/test__remove_redundancy.py +2 -2
- scipy/optimize/tests/test__shgo.py +9 -1
- scipy/optimize/tests/test_bracket.py +36 -46
- scipy/optimize/tests/test_chandrupatla.py +133 -135
- scipy/optimize/tests/test_cobyla.py +74 -45
- scipy/optimize/tests/test_constraints.py +1 -1
- scipy/optimize/tests/test_differentiable_functions.py +226 -6
- scipy/optimize/tests/test_lbfgsb_hessinv.py +22 -0
- scipy/optimize/tests/test_least_squares.py +125 -13
- scipy/optimize/tests/test_linear_assignment.py +3 -3
- scipy/optimize/tests/test_linprog.py +3 -3
- scipy/optimize/tests/test_lsq_linear.py +6 -6
- scipy/optimize/tests/test_minimize_constrained.py +2 -2
- scipy/optimize/tests/test_minpack.py +4 -4
- scipy/optimize/tests/test_nnls.py +43 -3
- scipy/optimize/tests/test_nonlin.py +36 -0
- scipy/optimize/tests/test_optimize.py +95 -17
- scipy/optimize/tests/test_slsqp.py +36 -4
- scipy/optimize/tests/test_zeros.py +34 -1
- scipy/signal/__init__.py +12 -23
- scipy/signal/_delegators.py +568 -0
- scipy/signal/_filter_design.py +459 -241
- scipy/signal/_fir_filter_design.py +262 -90
- scipy/signal/_lti_conversion.py +3 -2
- scipy/signal/_ltisys.py +118 -91
- scipy/signal/_max_len_seq_inner.cp313-win_amd64.dll.a +0 -0
- scipy/signal/_max_len_seq_inner.cp313-win_amd64.pyd +0 -0
- scipy/signal/_peak_finding_utils.cp313-win_amd64.dll.a +0 -0
- scipy/signal/_peak_finding_utils.cp313-win_amd64.pyd +0 -0
- scipy/signal/_polyutils.py +172 -0
- scipy/signal/_short_time_fft.py +519 -70
- scipy/signal/_signal_api.py +30 -0
- scipy/signal/_signaltools.py +719 -399
- scipy/signal/_sigtools.cp313-win_amd64.dll.a +0 -0
- scipy/signal/_sigtools.cp313-win_amd64.pyd +0 -0
- scipy/signal/_sosfilt.cp313-win_amd64.dll.a +0 -0
- scipy/signal/_sosfilt.cp313-win_amd64.pyd +0 -0
- scipy/signal/_spectral_py.py +230 -50
- scipy/signal/_spline.cp313-win_amd64.dll.a +0 -0
- scipy/signal/_spline.cp313-win_amd64.pyd +0 -0
- scipy/signal/_spline_filters.py +108 -68
- scipy/signal/_support_alternative_backends.py +73 -0
- scipy/signal/_upfirdn.py +4 -1
- scipy/signal/_upfirdn_apply.cp313-win_amd64.dll.a +0 -0
- scipy/signal/_upfirdn_apply.cp313-win_amd64.pyd +0 -0
- scipy/signal/_waveforms.py +2 -11
- scipy/signal/_wavelets.py +1 -1
- scipy/signal/fir_filter_design.py +1 -0
- scipy/signal/spline.py +4 -11
- scipy/signal/tests/_scipy_spectral_test_shim.py +2 -171
- scipy/signal/tests/test_bsplines.py +114 -79
- scipy/signal/tests/test_cont2discrete.py +9 -2
- scipy/signal/tests/test_filter_design.py +721 -481
- scipy/signal/tests/test_fir_filter_design.py +332 -140
- scipy/signal/tests/test_savitzky_golay.py +4 -3
- scipy/signal/tests/test_short_time_fft.py +221 -3
- scipy/signal/tests/test_signaltools.py +2144 -1348
- scipy/signal/tests/test_spectral.py +50 -6
- scipy/signal/tests/test_splines.py +161 -96
- scipy/signal/tests/test_upfirdn.py +84 -50
- scipy/signal/tests/test_waveforms.py +20 -0
- scipy/signal/tests/test_windows.py +607 -466
- scipy/signal/windows/_windows.py +287 -148
- scipy/sparse/__init__.py +23 -4
- scipy/sparse/_base.py +270 -108
- scipy/sparse/_bsr.py +7 -4
- scipy/sparse/_compressed.py +59 -231
- scipy/sparse/_construct.py +90 -38
- scipy/sparse/_coo.py +115 -181
- scipy/sparse/_csc.py +4 -4
- scipy/sparse/_csparsetools.cp313-win_amd64.dll.a +0 -0
- scipy/sparse/_csparsetools.cp313-win_amd64.pyd +0 -0
- scipy/sparse/_csr.py +2 -2
- scipy/sparse/_data.py +48 -48
- scipy/sparse/_dia.py +105 -18
- scipy/sparse/_dok.py +0 -23
- scipy/sparse/_index.py +4 -4
- scipy/sparse/_matrix.py +23 -0
- scipy/sparse/_sparsetools.cp313-win_amd64.dll.a +0 -0
- scipy/sparse/_sparsetools.cp313-win_amd64.pyd +0 -0
- scipy/sparse/_sputils.py +37 -22
- scipy/sparse/base.py +0 -9
- scipy/sparse/bsr.py +0 -14
- scipy/sparse/compressed.py +0 -23
- scipy/sparse/construct.py +0 -6
- scipy/sparse/coo.py +0 -14
- scipy/sparse/csc.py +0 -3
- scipy/sparse/csgraph/_flow.cp313-win_amd64.dll.a +0 -0
- scipy/sparse/csgraph/_flow.cp313-win_amd64.pyd +0 -0
- scipy/sparse/csgraph/_matching.cp313-win_amd64.dll.a +0 -0
- scipy/sparse/csgraph/_matching.cp313-win_amd64.pyd +0 -0
- scipy/sparse/csgraph/_min_spanning_tree.cp313-win_amd64.dll.a +0 -0
- scipy/sparse/csgraph/_min_spanning_tree.cp313-win_amd64.pyd +0 -0
- scipy/sparse/csgraph/_reordering.cp313-win_amd64.dll.a +0 -0
- scipy/sparse/csgraph/_reordering.cp313-win_amd64.pyd +0 -0
- scipy/sparse/csgraph/_shortest_path.cp313-win_amd64.dll.a +0 -0
- scipy/sparse/csgraph/_shortest_path.cp313-win_amd64.pyd +0 -0
- scipy/sparse/csgraph/_tools.cp313-win_amd64.dll.a +0 -0
- scipy/sparse/csgraph/_tools.cp313-win_amd64.pyd +0 -0
- scipy/sparse/csgraph/_traversal.cp313-win_amd64.dll.a +0 -0
- scipy/sparse/csgraph/_traversal.cp313-win_amd64.pyd +0 -0
- scipy/sparse/csgraph/tests/test_matching.py +14 -2
- scipy/sparse/csgraph/tests/test_pydata_sparse.py +4 -1
- scipy/sparse/csgraph/tests/test_shortest_path.py +83 -27
- scipy/sparse/csr.py +0 -5
- scipy/sparse/data.py +1 -6
- scipy/sparse/dia.py +0 -7
- scipy/sparse/dok.py +0 -10
- scipy/sparse/linalg/_dsolve/_superlu.cp313-win_amd64.dll.a +0 -0
- scipy/sparse/linalg/_dsolve/_superlu.cp313-win_amd64.pyd +0 -0
- scipy/sparse/linalg/_dsolve/linsolve.py +9 -0
- scipy/sparse/linalg/_dsolve/tests/test_linsolve.py +35 -28
- scipy/sparse/linalg/_eigen/arpack/_arpack.cp313-win_amd64.dll.a +0 -0
- scipy/sparse/linalg/_eigen/arpack/_arpack.cp313-win_amd64.pyd +0 -0
- scipy/sparse/linalg/_eigen/arpack/arpack.py +23 -17
- scipy/sparse/linalg/_eigen/lobpcg/lobpcg.py +6 -6
- scipy/sparse/linalg/_interface.py +17 -18
- scipy/sparse/linalg/_isolve/_gcrotmk.py +4 -4
- scipy/sparse/linalg/_isolve/iterative.py +51 -45
- scipy/sparse/linalg/_isolve/lgmres.py +6 -6
- scipy/sparse/linalg/_isolve/minres.py +5 -5
- scipy/sparse/linalg/_isolve/tfqmr.py +7 -7
- scipy/sparse/linalg/_isolve/utils.py +2 -8
- scipy/sparse/linalg/_matfuncs.py +1 -1
- scipy/sparse/linalg/_norm.py +1 -1
- scipy/sparse/linalg/_propack/_cpropack.cp313-win_amd64.dll.a +0 -0
- scipy/sparse/linalg/_propack/_cpropack.cp313-win_amd64.pyd +0 -0
- scipy/sparse/linalg/_propack/_dpropack.cp313-win_amd64.dll.a +0 -0
- scipy/sparse/linalg/_propack/_dpropack.cp313-win_amd64.pyd +0 -0
- scipy/sparse/linalg/_propack/_spropack.cp313-win_amd64.dll.a +0 -0
- scipy/sparse/linalg/_propack/_spropack.cp313-win_amd64.pyd +0 -0
- scipy/sparse/linalg/_propack/_zpropack.cp313-win_amd64.dll.a +0 -0
- scipy/sparse/linalg/_propack/_zpropack.cp313-win_amd64.pyd +0 -0
- scipy/sparse/linalg/_special_sparse_arrays.py +39 -38
- scipy/sparse/linalg/tests/test_pydata_sparse.py +14 -0
- scipy/sparse/tests/test_arithmetic1d.py +5 -2
- scipy/sparse/tests/test_base.py +214 -42
- scipy/sparse/tests/test_common1d.py +7 -7
- scipy/sparse/tests/test_construct.py +1 -1
- scipy/sparse/tests/test_coo.py +272 -4
- scipy/sparse/tests/test_sparsetools.py +5 -0
- scipy/sparse/tests/test_sputils.py +36 -7
- scipy/spatial/_ckdtree.cp313-win_amd64.dll.a +0 -0
- scipy/spatial/_ckdtree.cp313-win_amd64.pyd +0 -0
- scipy/spatial/_distance_pybind.cp313-win_amd64.dll.a +0 -0
- scipy/spatial/_distance_pybind.cp313-win_amd64.pyd +0 -0
- scipy/spatial/_distance_wrap.cp313-win_amd64.dll.a +0 -0
- scipy/spatial/_distance_wrap.cp313-win_amd64.pyd +0 -0
- scipy/spatial/_hausdorff.cp313-win_amd64.dll.a +0 -0
- scipy/spatial/_hausdorff.cp313-win_amd64.pyd +0 -0
- scipy/spatial/_qhull.cp313-win_amd64.dll.a +0 -0
- scipy/spatial/_qhull.cp313-win_amd64.pyd +0 -0
- scipy/spatial/_voronoi.cp313-win_amd64.dll.a +0 -0
- scipy/spatial/_voronoi.cp313-win_amd64.pyd +0 -0
- scipy/spatial/distance.py +49 -42
- scipy/spatial/tests/test_distance.py +15 -1
- scipy/spatial/tests/test_kdtree.py +1 -0
- scipy/spatial/tests/test_qhull.py +7 -2
- scipy/spatial/transform/__init__.py +5 -3
- scipy/spatial/transform/_rigid_transform.cp313-win_amd64.dll.a +0 -0
- scipy/spatial/transform/_rigid_transform.cp313-win_amd64.pyd +0 -0
- scipy/spatial/transform/_rotation.cp313-win_amd64.dll.a +0 -0
- scipy/spatial/transform/_rotation.cp313-win_amd64.pyd +0 -0
- scipy/spatial/transform/tests/test_rigid_transform.py +1221 -0
- scipy/spatial/transform/tests/test_rotation.py +1213 -832
- scipy/spatial/transform/tests/test_rotation_groups.py +3 -3
- scipy/spatial/transform/tests/test_rotation_spline.py +29 -8
- scipy/special/__init__.py +1 -47
- scipy/special/_add_newdocs.py +34 -772
- scipy/special/_basic.py +22 -25
- scipy/special/_comb.cp313-win_amd64.dll.a +0 -0
- scipy/special/_comb.cp313-win_amd64.pyd +0 -0
- scipy/special/_ellip_harm_2.cp313-win_amd64.dll.a +0 -0
- scipy/special/_ellip_harm_2.cp313-win_amd64.pyd +0 -0
- scipy/special/_gufuncs.cp313-win_amd64.dll.a +0 -0
- scipy/special/_gufuncs.cp313-win_amd64.pyd +0 -0
- scipy/special/_logsumexp.py +67 -58
- scipy/special/_orthogonal.pyi +1 -1
- scipy/special/_specfun.cp313-win_amd64.dll.a +0 -0
- scipy/special/_specfun.cp313-win_amd64.pyd +0 -0
- scipy/special/_special_ufuncs.cp313-win_amd64.dll.a +0 -0
- scipy/special/_special_ufuncs.cp313-win_amd64.pyd +0 -0
- scipy/special/_spherical_bessel.py +4 -4
- scipy/special/_support_alternative_backends.py +212 -119
- scipy/special/_test_internal.cp313-win_amd64.dll.a +0 -0
- scipy/special/_test_internal.cp313-win_amd64.pyd +0 -0
- scipy/special/_testutils.py +4 -4
- scipy/special/_ufuncs.cp313-win_amd64.dll.a +0 -0
- scipy/special/_ufuncs.cp313-win_amd64.pyd +0 -0
- scipy/special/_ufuncs.pyi +1 -0
- scipy/special/_ufuncs.pyx +215 -1400
- scipy/special/_ufuncs_cxx.cp313-win_amd64.dll.a +0 -0
- scipy/special/_ufuncs_cxx.cp313-win_amd64.pyd +0 -0
- scipy/special/_ufuncs_cxx.pxd +2 -15
- scipy/special/_ufuncs_cxx.pyx +5 -44
- scipy/special/_ufuncs_cxx_defs.h +2 -16
- scipy/special/_ufuncs_defs.h +0 -8
- scipy/special/cython_special.cp313-win_amd64.dll.a +0 -0
- scipy/special/cython_special.cp313-win_amd64.pyd +0 -0
- scipy/special/cython_special.pxd +1 -1
- scipy/special/tests/_cython_examples/meson.build +10 -1
- scipy/special/tests/test_basic.py +153 -20
- scipy/special/tests/test_boost_ufuncs.py +3 -0
- scipy/special/tests/test_cdflib.py +35 -11
- scipy/special/tests/test_gammainc.py +16 -0
- scipy/special/tests/test_hyp2f1.py +2 -2
- scipy/special/tests/test_log1mexp.py +85 -0
- scipy/special/tests/test_logsumexp.py +206 -64
- scipy/special/tests/test_mpmath.py +1 -0
- scipy/special/tests/test_nan_inputs.py +1 -1
- scipy/special/tests/test_orthogonal.py +17 -18
- scipy/special/tests/test_sf_error.py +3 -2
- scipy/special/tests/test_sph_harm.py +6 -7
- scipy/special/tests/test_support_alternative_backends.py +211 -76
- scipy/stats/__init__.py +4 -1
- scipy/stats/_ansari_swilk_statistics.cp313-win_amd64.dll.a +0 -0
- scipy/stats/_ansari_swilk_statistics.cp313-win_amd64.pyd +0 -0
- scipy/stats/_axis_nan_policy.py +5 -12
- scipy/stats/_biasedurn.cp313-win_amd64.dll.a +0 -0
- scipy/stats/_biasedurn.cp313-win_amd64.pyd +0 -0
- scipy/stats/_continued_fraction.py +387 -0
- scipy/stats/_continuous_distns.py +277 -310
- scipy/stats/_correlation.py +1 -1
- scipy/stats/_covariance.py +6 -3
- scipy/stats/_discrete_distns.py +39 -32
- scipy/stats/_distn_infrastructure.py +39 -12
- scipy/stats/_distribution_infrastructure.py +900 -238
- scipy/stats/_entropy.py +9 -10
- scipy/{_lib → stats}/_finite_differences.py +1 -1
- scipy/stats/_hypotests.py +83 -50
- scipy/stats/_kde.py +53 -49
- scipy/stats/_ksstats.py +1 -1
- scipy/stats/_levy_stable/__init__.py +7 -15
- scipy/stats/_levy_stable/levyst.cp313-win_amd64.dll.a +0 -0
- scipy/stats/_levy_stable/levyst.cp313-win_amd64.pyd +0 -0
- scipy/stats/_morestats.py +118 -73
- scipy/stats/_mstats_basic.py +13 -17
- scipy/stats/_mstats_extras.py +8 -8
- scipy/stats/_multivariate.py +89 -113
- scipy/stats/_new_distributions.py +97 -20
- scipy/stats/_page_trend_test.py +12 -5
- scipy/stats/_probability_distribution.py +265 -43
- scipy/stats/_qmc.py +14 -9
- scipy/stats/_qmc_cy.cp313-win_amd64.dll.a +0 -0
- scipy/stats/_qmc_cy.cp313-win_amd64.pyd +0 -0
- scipy/stats/_qmvnt.py +16 -95
- scipy/stats/_qmvnt_cy.cp313-win_amd64.dll.a +0 -0
- scipy/stats/_qmvnt_cy.cp313-win_amd64.pyd +0 -0
- scipy/stats/_quantile.py +335 -0
- scipy/stats/_rcont/rcont.cp313-win_amd64.dll.a +0 -0
- scipy/stats/_rcont/rcont.cp313-win_amd64.pyd +0 -0
- scipy/stats/_resampling.py +4 -29
- scipy/stats/_sampling.py +1 -1
- scipy/stats/_sobol.cp313-win_amd64.dll.a +0 -0
- scipy/stats/_sobol.cp313-win_amd64.pyd +0 -0
- scipy/stats/_stats.cp313-win_amd64.dll.a +0 -0
- scipy/stats/_stats.cp313-win_amd64.pyd +0 -0
- scipy/stats/_stats_mstats_common.py +21 -2
- scipy/stats/_stats_py.py +550 -476
- scipy/stats/_stats_pythran.cp313-win_amd64.dll.a +0 -0
- scipy/stats/_stats_pythran.cp313-win_amd64.pyd +0 -0
- scipy/stats/_unuran/unuran_wrapper.cp313-win_amd64.dll.a +0 -0
- scipy/stats/_unuran/unuran_wrapper.cp313-win_amd64.pyd +0 -0
- scipy/stats/_unuran/unuran_wrapper.pyi +2 -1
- scipy/stats/_variation.py +6 -8
- scipy/stats/_wilcoxon.py +13 -7
- scipy/stats/tests/common_tests.py +6 -4
- scipy/stats/tests/test_axis_nan_policy.py +62 -24
- scipy/stats/tests/test_continued_fraction.py +173 -0
- scipy/stats/tests/test_continuous.py +379 -60
- scipy/stats/tests/test_continuous_basic.py +18 -12
- scipy/stats/tests/test_discrete_basic.py +14 -8
- scipy/stats/tests/test_discrete_distns.py +16 -16
- scipy/stats/tests/test_distributions.py +95 -75
- scipy/stats/tests/test_entropy.py +40 -48
- scipy/stats/tests/test_fit.py +4 -3
- scipy/stats/tests/test_hypotests.py +153 -24
- scipy/stats/tests/test_kdeoth.py +109 -41
- scipy/stats/tests/test_marray.py +289 -0
- scipy/stats/tests/test_morestats.py +79 -47
- scipy/stats/tests/test_mstats_basic.py +3 -3
- scipy/stats/tests/test_multivariate.py +434 -83
- scipy/stats/tests/test_qmc.py +13 -10
- scipy/stats/tests/test_quantile.py +199 -0
- scipy/stats/tests/test_rank.py +119 -112
- scipy/stats/tests/test_resampling.py +47 -56
- scipy/stats/tests/test_sampling.py +9 -4
- scipy/stats/tests/test_stats.py +799 -939
- scipy/stats/tests/test_variation.py +8 -6
- scipy/version.py +2 -2
- scipy-1.16.0rc2.dist-info/DELVEWHEEL +2 -0
- {scipy-1.15.3.dist-info → scipy-1.16.0rc2.dist-info}/LICENSE.txt +4 -4
- {scipy-1.15.3.dist-info → scipy-1.16.0rc2.dist-info}/METADATA +11 -11
- {scipy-1.15.3.dist-info → scipy-1.16.0rc2.dist-info}/RECORD +685 -693
- scipy/_lib/array_api_extra/_funcs.py +0 -484
- scipy/_lib/array_api_extra/_typing.py +0 -8
- scipy/interpolate/_bspl.cp313-win_amd64.dll.a +0 -0
- scipy/interpolate/_bspl.cp313-win_amd64.pyd +0 -0
- scipy/optimize/_cobyla.cp313-win_amd64.dll.a +0 -0
- scipy/optimize/_cobyla.cp313-win_amd64.pyd +0 -0
- scipy/optimize/_cython_nnls.cp313-win_amd64.dll.a +0 -0
- scipy/optimize/_cython_nnls.cp313-win_amd64.pyd +0 -0
- scipy/optimize/_slsqp.cp313-win_amd64.dll.a +0 -0
- scipy/optimize/_slsqp.cp313-win_amd64.pyd +0 -0
- scipy/spatial/qhull_src/COPYING.txt +0 -38
- scipy/special/libsf_error_state.dll +0 -0
- scipy/special/libsf_error_state.dll.a +0 -0
- scipy/special/tests/test_log_softmax.py +0 -109
- scipy/special/tests/test_xsf_cuda.py +0 -114
- scipy/special/xsf/binom.h +0 -89
- scipy/special/xsf/cdflib.h +0 -100
- scipy/special/xsf/cephes/airy.h +0 -307
- scipy/special/xsf/cephes/besselpoly.h +0 -51
- scipy/special/xsf/cephes/beta.h +0 -257
- scipy/special/xsf/cephes/cbrt.h +0 -131
- scipy/special/xsf/cephes/chbevl.h +0 -85
- scipy/special/xsf/cephes/chdtr.h +0 -193
- scipy/special/xsf/cephes/const.h +0 -87
- scipy/special/xsf/cephes/ellie.h +0 -293
- scipy/special/xsf/cephes/ellik.h +0 -251
- scipy/special/xsf/cephes/ellpe.h +0 -107
- scipy/special/xsf/cephes/ellpk.h +0 -117
- scipy/special/xsf/cephes/expn.h +0 -260
- scipy/special/xsf/cephes/gamma.h +0 -398
- scipy/special/xsf/cephes/hyp2f1.h +0 -596
- scipy/special/xsf/cephes/hyperg.h +0 -361
- scipy/special/xsf/cephes/i0.h +0 -149
- scipy/special/xsf/cephes/i1.h +0 -158
- scipy/special/xsf/cephes/igam.h +0 -421
- scipy/special/xsf/cephes/igam_asymp_coeff.h +0 -195
- scipy/special/xsf/cephes/igami.h +0 -313
- scipy/special/xsf/cephes/j0.h +0 -225
- scipy/special/xsf/cephes/j1.h +0 -198
- scipy/special/xsf/cephes/jv.h +0 -715
- scipy/special/xsf/cephes/k0.h +0 -164
- scipy/special/xsf/cephes/k1.h +0 -163
- scipy/special/xsf/cephes/kn.h +0 -243
- scipy/special/xsf/cephes/lanczos.h +0 -112
- scipy/special/xsf/cephes/ndtr.h +0 -275
- scipy/special/xsf/cephes/poch.h +0 -85
- scipy/special/xsf/cephes/polevl.h +0 -167
- scipy/special/xsf/cephes/psi.h +0 -194
- scipy/special/xsf/cephes/rgamma.h +0 -111
- scipy/special/xsf/cephes/scipy_iv.h +0 -811
- scipy/special/xsf/cephes/shichi.h +0 -248
- scipy/special/xsf/cephes/sici.h +0 -224
- scipy/special/xsf/cephes/sindg.h +0 -221
- scipy/special/xsf/cephes/tandg.h +0 -139
- scipy/special/xsf/cephes/trig.h +0 -58
- scipy/special/xsf/cephes/unity.h +0 -186
- scipy/special/xsf/cephes/zeta.h +0 -172
- scipy/special/xsf/config.h +0 -304
- scipy/special/xsf/digamma.h +0 -205
- scipy/special/xsf/error.h +0 -57
- scipy/special/xsf/evalpoly.h +0 -47
- scipy/special/xsf/expint.h +0 -266
- scipy/special/xsf/hyp2f1.h +0 -694
- scipy/special/xsf/iv_ratio.h +0 -173
- scipy/special/xsf/lambertw.h +0 -150
- scipy/special/xsf/loggamma.h +0 -163
- scipy/special/xsf/sici.h +0 -200
- scipy/special/xsf/tools.h +0 -427
- scipy/special/xsf/trig.h +0 -164
- scipy/special/xsf/wright_bessel.h +0 -843
- scipy/special/xsf/zlog1.h +0 -35
- scipy/stats/_mvn.cp313-win_amd64.dll.a +0 -0
- scipy/stats/_mvn.cp313-win_amd64.pyd +0 -0
- scipy-1.15.3.dist-info/DELVEWHEEL +0 -2
- /scipy-1.15.3-cp313-cp313-win_amd64.whl → /scipy-1.16.0rc2-cp313-cp313-win_amd64.whl +0 -0
- {scipy-1.15.3.dist-info → scipy-1.16.0rc2.dist-info}/WHEEL +0 -0
@@ -1,5 +1,9 @@
|
|
1
|
+
import math
|
2
|
+
import cmath
|
1
3
|
import warnings
|
2
4
|
|
5
|
+
from itertools import product
|
6
|
+
|
3
7
|
from scipy._lib import _pep440
|
4
8
|
import numpy as np
|
5
9
|
from numpy.testing import (
|
@@ -9,22 +13,28 @@ import pytest
|
|
9
13
|
from pytest import raises as assert_raises
|
10
14
|
from scipy._lib._array_api import (
|
11
15
|
xp_assert_close, xp_assert_equal,
|
12
|
-
assert_array_almost_equal,
|
16
|
+
assert_array_almost_equal, xp_size, xp_default_dtype, is_numpy
|
13
17
|
)
|
14
18
|
|
15
|
-
from numpy import array, spacing, sin, pi
|
19
|
+
from numpy import array, spacing, sin, pi
|
16
20
|
from scipy.signal import (argrelextrema, BadCoefficients, bessel, besselap, bilinear,
|
17
21
|
buttap, butter, buttord, cheb1ap, cheb1ord, cheb2ap,
|
18
22
|
cheb2ord, cheby1, cheby2, ellip, ellipap, ellipord,
|
19
23
|
firwin, freqs_zpk, freqs, freqz, freqz_zpk,
|
20
24
|
gammatone, group_delay, iircomb, iirdesign, iirfilter,
|
21
25
|
iirnotch, iirpeak, lp2bp, lp2bs, lp2hp, lp2lp, normalize,
|
22
|
-
medfilt, order_filter,
|
23
26
|
sos2tf, sos2zpk, sosfreqz, freqz_sos, tf2sos, tf2zpk, zpk2sos,
|
24
27
|
zpk2tf, bilinear_zpk, lp2lp_zpk, lp2hp_zpk, lp2bp_zpk,
|
25
28
|
lp2bs_zpk)
|
26
29
|
from scipy.signal._filter_design import (_cplxreal, _cplxpair, _norm_factor,
|
27
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
|
+
|
28
38
|
|
29
39
|
try:
|
30
40
|
import mpmath
|
@@ -168,26 +178,33 @@ class TestCplxReal:
|
|
168
178
|
|
169
179
|
class TestTf2zpk:
|
170
180
|
|
171
|
-
@
|
172
|
-
|
173
|
-
|
174
|
-
|
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)])
|
175
191
|
# Sort the zeros/poles so that we don't fail the test if the order
|
176
192
|
# changes
|
177
|
-
z_r
|
178
|
-
p_r
|
179
|
-
|
180
|
-
|
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)
|
181
198
|
|
182
199
|
z, p, k = tf2zpk(b, a)
|
183
|
-
z
|
200
|
+
z = _sort_cmplx(z, xp=xp)
|
184
201
|
# The real part of `p` is ~0.0, so sort by imaginary part
|
185
|
-
p = p[
|
202
|
+
p = p[xp.argsort(xp.imag(p))]
|
186
203
|
|
187
204
|
assert_array_almost_equal(z, z_r)
|
188
205
|
assert_array_almost_equal(p, p_r)
|
189
|
-
|
190
|
-
assert k.dtype ==
|
206
|
+
assert math.isclose(xp.real(k), 1.)
|
207
|
+
assert k.dtype == dtyp
|
191
208
|
|
192
209
|
def test_bad_filter(self):
|
193
210
|
# Regression test for #651: better handling of badly conditioned
|
@@ -199,47 +216,91 @@ class TestTf2zpk:
|
|
199
216
|
|
200
217
|
class TestZpk2Tf:
|
201
218
|
|
202
|
-
def test_identity(self):
|
219
|
+
def test_identity(self, xp):
|
203
220
|
"""Test the identity transfer function."""
|
204
|
-
z = []
|
205
|
-
p = []
|
221
|
+
z = xp.asarray([])
|
222
|
+
p = xp.asarray([])
|
206
223
|
k = 1.
|
207
224
|
b, a = zpk2tf(z, p, k)
|
208
|
-
b_r =
|
209
|
-
a_r =
|
225
|
+
b_r = xp.asarray([1.]) # desired result
|
226
|
+
a_r = xp.asarray([1.]) # desired result
|
210
227
|
# The test for the *type* of the return values is a regression
|
211
228
|
# test for ticket #1095. In the case p=[], zpk2tf used to
|
212
229
|
# return the scalar 1.0 instead of array([1.0]).
|
213
230
|
xp_assert_equal(b, b_r)
|
214
|
-
assert isinstance(b, np.ndarray)
|
215
231
|
xp_assert_equal(a, a_r)
|
216
|
-
|
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)
|
217
272
|
|
218
273
|
|
274
|
+
@skip_xp_backends("jax.numpy", reason='no eig in JAX on GPU.')
|
219
275
|
class TestSos2Zpk:
|
220
276
|
|
221
|
-
|
277
|
+
@skip_xp_backends("dask.array", reason="it https://github.com/dask/dask/issues/11883")
|
278
|
+
def test_basic(self, xp):
|
222
279
|
sos = [[1, 0, 1, 1, 0, -0.81],
|
223
280
|
[1, 0, 0, 1, 0, +0.49]]
|
281
|
+
sos = xp.asarray(sos)
|
224
282
|
z, p, k = sos2zpk(sos)
|
225
|
-
z2 = [1j, -1j, 0, 0]
|
226
|
-
p2 = [0.9, -0.9, 0.7j, -0.7j]
|
227
|
-
k2 = 1
|
228
|
-
assert_array_almost_equal(
|
229
|
-
assert_array_almost_equal(
|
230
|
-
|
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)
|
231
289
|
|
232
290
|
sos = [[1.00000, +0.61803, 1.0000, 1.00000, +0.60515, 0.95873],
|
233
291
|
[1.00000, -1.61803, 1.0000, 1.00000, -1.58430, 0.95873],
|
234
292
|
[1.00000, +1.00000, 0.0000, 1.00000, +0.97915, 0.00000]]
|
293
|
+
sos = xp.asarray(sos)
|
235
294
|
z, p, k = sos2zpk(sos)
|
236
295
|
z2 = [-0.3090 + 0.9511j, -0.3090 - 0.9511j, 0.8090 + 0.5878j,
|
237
296
|
0.8090 - 0.5878j, -1.0000 + 0.0000j, 0]
|
238
297
|
p2 = [-0.3026 + 0.9312j, -0.3026 - 0.9312j, 0.7922 + 0.5755j,
|
239
298
|
0.7922 - 0.5755j, -0.9791 + 0.0000j, 0]
|
299
|
+
z2 = xp.asarray(z2)
|
300
|
+
p2 = xp.asarray(p2)
|
240
301
|
k2 = 1
|
241
|
-
assert_array_almost_equal(
|
242
|
-
assert_array_almost_equal(
|
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)
|
243
304
|
|
244
305
|
sos = array([[1, 2, 3, 1, 0.2, 0.3],
|
245
306
|
[4, 5, 6, 1, 0.4, 0.5]])
|
@@ -247,138 +308,164 @@ class TestSos2Zpk:
|
|
247
308
|
-0.625 - 1.05326872164704j, -0.625 + 1.05326872164704j])
|
248
309
|
p = array([-0.2 - 0.678232998312527j, -0.2 + 0.678232998312527j,
|
249
310
|
-0.1 - 0.538516480713450j, -0.1 + 0.538516480713450j])
|
311
|
+
sos, z, p = map(xp.asarray, (sos, z, p))
|
250
312
|
k = 4
|
251
313
|
z2, p2, k2 = sos2zpk(sos)
|
252
|
-
|
253
|
-
xp_assert_close(
|
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))
|
254
317
|
assert k2 == k
|
255
318
|
|
256
319
|
@pytest.mark.thread_unsafe
|
257
|
-
def test_fewer_zeros(self):
|
320
|
+
def test_fewer_zeros(self, xp):
|
258
321
|
"""Test not the expected number of p/z (effectively at origin)."""
|
259
322
|
sos = butter(3, 0.1, output='sos')
|
323
|
+
sos = xp.asarray(sos) # XXX convert butter
|
260
324
|
z, p, k = sos2zpk(sos)
|
261
|
-
assert
|
262
|
-
assert
|
325
|
+
assert z.shape[0] == 4
|
326
|
+
assert p.shape[0] == 4
|
263
327
|
|
264
328
|
sos = butter(12, [5., 30.], 'bandpass', fs=1200., analog=False,
|
265
329
|
output='sos')
|
330
|
+
xp = xp.asarray(sos)
|
266
331
|
with pytest.warns(BadCoefficients, match='Badly conditioned'):
|
267
332
|
z, p, k = sos2zpk(sos)
|
268
|
-
assert
|
269
|
-
assert
|
333
|
+
assert z.shape[0] == 24
|
334
|
+
assert p.shape[0] == 24
|
270
335
|
|
271
336
|
|
337
|
+
@skip_xp_backends(
|
338
|
+
cpu_only=True, reason="XXX zpk2sos is numpy-only", exceptions=['cupy']
|
339
|
+
)
|
272
340
|
class TestSos2Tf:
|
273
341
|
|
274
|
-
def test_basic(self):
|
275
|
-
sos = [[1, 1, 1, 1, 0, -1],
|
342
|
+
def test_basic(self, xp):
|
343
|
+
sos = [[1.0, 1, 1, 1, 0, -1],
|
276
344
|
[-2, 3, 1, 1, 10, 1]]
|
345
|
+
sos = xp.asarray(sos)
|
277
346
|
b, a = sos2tf(sos)
|
278
|
-
assert_array_almost_equal(b, [-2, 1, 2, 4, 1])
|
279
|
-
assert_array_almost_equal(a, [1, 10, 0, -10, -1])
|
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]))
|
280
349
|
|
281
350
|
|
351
|
+
@skip_xp_backends(cpu_only=True, reason="XXX zpk2sos is numpy-only")
|
282
352
|
class TestTf2Sos:
|
283
353
|
|
284
|
-
def test_basic(self):
|
285
|
-
num = [2
|
286
|
-
den = [3
|
354
|
+
def test_basic(self, xp):
|
355
|
+
num = xp.asarray([2., 16, 44, 56, 32])
|
356
|
+
den = xp.asarray([3., 3, -15, 18, -12])
|
287
357
|
sos = tf2sos(num, den)
|
288
358
|
sos2 = [[0.6667, 4.0000, 5.3333, 1.0000, +2.0000, -4.0000],
|
289
359
|
[1.0000, 2.0000, 2.0000, 1.0000, -1.0000, +1.0000]]
|
360
|
+
sos2 = xp.asarray(sos2)
|
290
361
|
assert_array_almost_equal(sos, sos2, decimal=4)
|
291
362
|
|
292
|
-
b = [1, -3, 11, -27, 18]
|
293
|
-
a = [16, 12, 2, -4, -1]
|
363
|
+
b = xp.asarray([1.0, -3, 11, -27, 18])
|
364
|
+
a = xp.asarray([16.0, 12, 2, -4, -1])
|
294
365
|
sos = tf2sos(b, a)
|
295
366
|
sos2 = [[0.0625, -0.1875, 0.1250, 1.0000, -0.2500, -0.1250],
|
296
367
|
[1.0000, +0.0000, 9.0000, 1.0000, +1.0000, +0.5000]]
|
297
|
-
|
368
|
+
sos2 = xp.asarray(sos2)
|
369
|
+
#assert_array_almost_equal(sos, sos2, decimal=4)
|
298
370
|
|
299
371
|
@pytest.mark.parametrize('b, a, analog, sos',
|
300
|
-
[([1], [1], False, [[1., 0., 0., 1., 0., 0.]]),
|
301
|
-
([1], [1], True, [[0., 0., 1., 0., 0., 1.]]),
|
302
|
-
([1], [1., 0., -1.01, 0, 0.01], False,
|
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,
|
303
375
|
[[1., 0., 0., 1., 0., -0.01],
|
304
376
|
[1., 0., 0., 1., 0., -1]]),
|
305
|
-
([1], [1., 0., -1.01, 0, 0.01], True,
|
377
|
+
([1.0], [1., 0., -1.01, 0, 0.01], True,
|
306
378
|
[[0., 0., 1., 1., 0., -1],
|
307
379
|
[0., 0., 1., 1., 0., -0.01]])])
|
308
|
-
def test_analog(self, b, a, analog, sos):
|
380
|
+
def test_analog(self, b, a, analog, sos, xp):
|
381
|
+
b, a, sos = map(xp.asarray, (b, a, sos))
|
309
382
|
sos2 = tf2sos(b, a, analog=analog)
|
310
383
|
assert_array_almost_equal(sos, sos2, decimal=4)
|
311
384
|
|
312
385
|
|
386
|
+
@skip_xp_backends(
|
387
|
+
cpu_only=True, reason="XXX zpk2sos is numpy-only", exceptions=['cupy']
|
388
|
+
)
|
313
389
|
class TestZpk2Sos:
|
314
390
|
|
315
|
-
@pytest.mark.parametrize('dt', 'fdgFDG')
|
391
|
+
# @pytest.mark.parametrize('dt', 'fdgFDG')
|
392
|
+
# XXX: quietly remove float128 and complex256
|
393
|
+
@pytest.mark.parametrize('dt', ['float32', 'float64', 'complex64', 'complex128'])
|
316
394
|
@pytest.mark.parametrize('pairing, analog',
|
317
395
|
[('nearest', False),
|
318
396
|
('keep_odd', False),
|
319
397
|
('minimal', False),
|
320
398
|
('minimal', True)])
|
321
|
-
def test_dtypes(self, dt, pairing, analog):
|
322
|
-
|
323
|
-
|
324
|
-
|
325
|
-
|
399
|
+
def test_dtypes(self, dt, pairing, analog, xp):
|
400
|
+
dtype = getattr(xp, dt)
|
401
|
+
# the poles have to be complex
|
402
|
+
cdtype = (xp.empty(1, dtype=dtype) + 1j*xp.empty(1, dtype=dtype)).dtype
|
403
|
+
|
404
|
+
z = xp.asarray([-1, -1], dtype=dtype)
|
405
|
+
p = xp.asarray([0.57149 + 0.29360j, 0.57149 - 0.29360j], dtype=cdtype)
|
406
|
+
k = xp.asarray(1, dtype=dtype)
|
326
407
|
sos = zpk2sos(z, p, k, pairing=pairing, analog=analog)
|
327
|
-
|
408
|
+
# octave & MATLAB
|
409
|
+
sos2 = xp.asarray([[1, 2, 1, 1, -1.14298, 0.41280]], dtype=dtype)
|
328
410
|
assert_array_almost_equal(sos, sos2, decimal=4)
|
329
411
|
|
330
|
-
def test_basic(self):
|
412
|
+
def test_basic(self, xp):
|
331
413
|
for pairing in ('nearest', 'keep_odd'):
|
332
414
|
#
|
333
415
|
# Cases that match octave
|
334
416
|
#
|
335
417
|
|
336
|
-
z = [-1, -1]
|
337
|
-
p = [0.57149 + 0.29360j, 0.57149 - 0.29360j]
|
418
|
+
z = xp.asarray([-1.0, -1.0])
|
419
|
+
p = xp.asarray([0.57149 + 0.29360j, 0.57149 - 0.29360j])
|
338
420
|
k = 1
|
339
421
|
sos = zpk2sos(z, p, k, pairing=pairing)
|
340
|
-
sos2 = [[1, 2, 1, 1, -1.14298, 0.41280]] # octave & MATLAB
|
422
|
+
sos2 = xp.asarray([[1, 2, 1, 1, -1.14298, 0.41280]]) # octave & MATLAB
|
341
423
|
assert_array_almost_equal(sos, sos2, decimal=4)
|
342
424
|
|
343
|
-
z = [1j, -1j]
|
344
|
-
p = [0.9, -0.9, 0.7j, -0.7j]
|
425
|
+
z = xp.asarray([1j, -1j])
|
426
|
+
p = xp.asarray([0.9, -0.9, 0.7j, -0.7j])
|
345
427
|
k = 1
|
346
428
|
sos = zpk2sos(z, p, k, pairing=pairing)
|
347
429
|
sos2 = [[1, 0, 1, 1, 0, +0.49],
|
348
430
|
[1, 0, 0, 1, 0, -0.81]] # octave
|
431
|
+
sos2 = xp.asarray(sos2)
|
349
432
|
# sos2 = [[0, 0, 1, 1, -0.9, 0],
|
350
433
|
# [1, 0, 1, 1, 0.9, 0]] # MATLAB
|
351
434
|
assert_array_almost_equal(sos, sos2, decimal=4)
|
352
435
|
|
353
|
-
z = []
|
354
|
-
p = [0.8, -0.5+0.25j, -0.5-0.25j]
|
436
|
+
z = xp.asarray([])
|
437
|
+
p = xp.asarray([0.8, -0.5+0.25j, -0.5-0.25j])
|
355
438
|
k = 1.
|
356
439
|
sos = zpk2sos(z, p, k, pairing=pairing)
|
357
440
|
sos2 = [[1., 0., 0., 1., 1., 0.3125],
|
358
441
|
[1., 0., 0., 1., -0.8, 0.]] # octave, MATLAB fails
|
442
|
+
sos2 = xp.asarray(sos2)
|
359
443
|
assert_array_almost_equal(sos, sos2, decimal=4)
|
360
444
|
|
361
|
-
z = [1., 1., 0.9j, -0.9j]
|
362
|
-
p = [0.99+0.01j, 0.99-0.01j, 0.1+0.9j, 0.1-0.9j]
|
445
|
+
z = xp.asarray([1., 1., 0.9j, -0.9j])
|
446
|
+
p = xp.asarray([0.99+0.01j, 0.99-0.01j, 0.1+0.9j, 0.1-0.9j])
|
363
447
|
k = 1
|
364
448
|
sos = zpk2sos(z, p, k, pairing=pairing)
|
365
449
|
sos2 = [[1, 0, 0.81, 1, -0.2, 0.82],
|
366
450
|
[1, -2, 1, 1, -1.98, 0.9802]] # octave
|
451
|
+
sos2 = xp.asarray(sos2)
|
367
452
|
# sos2 = [[1, -2, 1, 1, -0.2, 0.82],
|
368
453
|
# [1, 0, 0.81, 1, -1.98, 0.9802]] # MATLAB
|
369
454
|
assert_array_almost_equal(sos, sos2, decimal=4)
|
370
455
|
|
371
|
-
z = [0.9+0.1j, 0.9-0.1j, -0.9]
|
372
|
-
p = [0.75+0.25j, 0.75-0.25j, 0.9]
|
456
|
+
z = xp.asarray([0.9+0.1j, 0.9-0.1j, -0.9])
|
457
|
+
p = xp.asarray([0.75+0.25j, 0.75-0.25j, 0.9])
|
373
458
|
k = 1
|
374
459
|
sos = zpk2sos(z, p, k, pairing=pairing)
|
375
460
|
if pairing == 'keep_odd':
|
376
461
|
sos2 = [[1, -1.8, 0.82, 1, -1.5, 0.625],
|
377
462
|
[1, 0.9, 0, 1, -0.9, 0]] # octave; MATLAB fails
|
463
|
+
sos2 = xp.asarray(sos2)
|
378
464
|
assert_array_almost_equal(sos, sos2, decimal=4)
|
379
465
|
else: # pairing == 'nearest'
|
380
466
|
sos2 = [[1, 0.9, 0, 1, -1.5, 0.625],
|
381
467
|
[1, -1.8, 0.82, 1, -0.9, 0]] # our algorithm
|
468
|
+
sos2 = xp.asarray(sos2)
|
382
469
|
assert_array_almost_equal(sos, sos2, decimal=4)
|
383
470
|
|
384
471
|
#
|
@@ -389,6 +476,8 @@ class TestZpk2Sos:
|
|
389
476
|
+0.8090 - 0.5878j, -1.0000 + 0.0000j]
|
390
477
|
p = [-0.3026 + 0.9312j, -0.3026 - 0.9312j, 0.7922 + 0.5755j,
|
391
478
|
+0.7922 - 0.5755j, -0.9791 + 0.0000j]
|
479
|
+
z = xp.asarray(z)
|
480
|
+
p = xp.asarray(p)
|
392
481
|
k = 1
|
393
482
|
sos = zpk2sos(z, p, k, pairing=pairing)
|
394
483
|
# sos2 = [[1, 0.618, 1, 1, 0.6052, 0.95870],
|
@@ -397,26 +486,31 @@ class TestZpk2Sos:
|
|
397
486
|
sos2 = [[1, 1, 0, 1, +0.97915, 0],
|
398
487
|
[1, 0.61803, 1, 1, +0.60515, 0.95873],
|
399
488
|
[1, -1.61803, 1, 1, -1.58430, 0.95873]]
|
489
|
+
sos2 = xp.asarray(sos2)
|
400
490
|
assert_array_almost_equal(sos, sos2, decimal=4)
|
401
491
|
|
402
492
|
z = [-1 - 1.4142j, -1 + 1.4142j,
|
403
493
|
-0.625 - 1.0533j, -0.625 + 1.0533j]
|
404
494
|
p = [-0.2 - 0.6782j, -0.2 + 0.6782j,
|
405
495
|
-0.1 - 0.5385j, -0.1 + 0.5385j]
|
496
|
+
z = xp.asarray(z)
|
497
|
+
p = xp.asarray(p)
|
406
498
|
k = 4
|
407
499
|
sos = zpk2sos(z, p, k, pairing=pairing)
|
408
500
|
sos2 = [[4, 8, 12, 1, 0.2, 0.3],
|
409
501
|
[1, 1.25, 1.5, 1, 0.4, 0.5]] # MATLAB
|
502
|
+
sos2 = xp.asarray(sos2, dtype=xp.float64)
|
410
503
|
# sos2 = [[4, 8, 12, 1, 0.4, 0.5],
|
411
504
|
# [1, 1.25, 1.5, 1, 0.2, 0.3]] # octave
|
412
505
|
xp_assert_close(sos, sos2, rtol=1e-4, atol=1e-4)
|
413
506
|
|
414
|
-
z = []
|
415
|
-
p = [0.2, -0.5+0.25j, -0.5-0.25j]
|
507
|
+
z = xp.asarray([])
|
508
|
+
p = xp.asarray([0.2, -0.5+0.25j, -0.5-0.25j])
|
416
509
|
k = 1.
|
417
510
|
sos = zpk2sos(z, p, k, pairing=pairing)
|
418
511
|
sos2 = [[1., 0., 0., 1., -0.2, 0.],
|
419
512
|
[1., 0., 0., 1., 1., 0.3125]]
|
513
|
+
sos2 = xp.asarray(sos2)
|
420
514
|
# sos2 = [[1., 0., 0., 1., 1., 0.3125],
|
421
515
|
# [1., 0., 0., 1., -0.2, 0]] # octave, MATLAB fails
|
422
516
|
assert_array_almost_equal(sos, sos2, decimal=4)
|
@@ -425,17 +519,16 @@ class TestZpk2Sos:
|
|
425
519
|
# "Digital Filters and Signal Processing (1995) p.400:
|
426
520
|
# 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
|
427
521
|
|
428
|
-
deg2rad =
|
522
|
+
deg2rad = xp.pi / 180.
|
429
523
|
k = 1.
|
430
524
|
|
431
525
|
# first example
|
432
|
-
thetas = [22.5, 45, 77.5]
|
433
|
-
mags = [0.8, 0.6, 0.9]
|
434
|
-
z =
|
435
|
-
z =
|
436
|
-
p =
|
437
|
-
|
438
|
-
p = np.concatenate((p, np.conj(p)))
|
526
|
+
thetas = xp.asarray([22.5, 45, 77.5])
|
527
|
+
mags = xp.asarray([0.8, 0.6, 0.9])
|
528
|
+
z = xp.exp(1j * deg2rad * thetas)
|
529
|
+
z = xp.concat((z, xp.conj(z)))
|
530
|
+
p = xp.exp(1j * deg2rad * thetas) * mags
|
531
|
+
p = xp.concat((p, xp.conj(p)))
|
439
532
|
sos = zpk2sos(z, p, k)
|
440
533
|
# sos2 = [[1, -0.43288, 1, 1, -0.38959, 0.81], # octave,
|
441
534
|
# [1, -1.41421, 1, 1, -0.84853, 0.36], # MATLAB fails
|
@@ -444,12 +537,13 @@ class TestZpk2Sos:
|
|
444
537
|
sos2 = [[1, -1.41421, 1, 1, -0.84853, 0.36],
|
445
538
|
[1, -1.84776, 1, 1, -1.47821, 0.64],
|
446
539
|
[1, -0.43288, 1, 1, -0.38959, 0.81]]
|
540
|
+
sos2 = xp.asarray(sos2)
|
447
541
|
assert_array_almost_equal(sos, sos2, decimal=4)
|
448
542
|
|
449
543
|
# second example
|
450
|
-
|
451
|
-
|
452
|
-
z =
|
544
|
+
thetas = xp.asarray([85., 10.])
|
545
|
+
z = xp.exp(1j * deg2rad * thetas)
|
546
|
+
z = xp.concat((z, xp.conj(z), xp.asarray([1.0, -1.0])))
|
453
547
|
sos = zpk2sos(z, p, k)
|
454
548
|
|
455
549
|
# sos2 = [[1, -0.17431, 1, 1, -0.38959, 0.81], # octave "wrong",
|
@@ -459,6 +553,7 @@ class TestZpk2Sos:
|
|
459
553
|
sos2 = [[1, 0, -1, 1, -0.84853, 0.36],
|
460
554
|
[1, -1.96962, 1, 1, -1.47821, 0.64],
|
461
555
|
[1, -0.17431, 1, 1, -0.38959, 0.81]]
|
556
|
+
sos2 = xp.asarray(sos2)
|
462
557
|
assert_array_almost_equal(sos, sos2, decimal=4)
|
463
558
|
|
464
559
|
# these examples are taken from the doc string, and show the
|
@@ -473,9 +568,10 @@ class TestZpk2Sos:
|
|
473
568
|
('minimal',
|
474
569
|
np.array([[0., 1., 1., 0., 1., -0.75],
|
475
570
|
[1., 1., 0.5, 1., -1.6, 0.65]]))])
|
476
|
-
def test_pairing(self, pairing, sos):
|
477
|
-
|
478
|
-
|
571
|
+
def test_pairing(self, pairing, sos, xp):
|
572
|
+
sos = xp.asarray(sos)
|
573
|
+
z1 = xp.asarray([-1, -0.5-0.5j, -0.5+0.5j])
|
574
|
+
p1 = xp.asarray([0.75, 0.8+0.1j, 0.8-0.1j])
|
479
575
|
sos2 = zpk2sos(z1, p1, 1, pairing=pairing)
|
480
576
|
assert_array_almost_equal(sos, sos2, decimal=4)
|
481
577
|
|
@@ -486,14 +582,16 @@ class TestZpk2Sos:
|
|
486
582
|
([-0.7071+0.7071j, -0.7071-0.7071j, -0.1j, 0.1j],
|
487
583
|
[[0., 0., 1., 1., 0., 0.01],
|
488
584
|
[0., 0., 1., 1., 1.4142, 1.]])])
|
489
|
-
def test_analog(self, p, sos_dt):
|
585
|
+
def test_analog(self, p, sos_dt, xp):
|
490
586
|
# test `analog` argument
|
491
587
|
# for discrete time, poles closest to unit circle should appear last
|
492
588
|
# for cont. time, poles closest to imaginary axis should appear last
|
493
|
-
|
494
|
-
|
589
|
+
z, p = xp.asarray([]), xp.asarray(p)
|
590
|
+
sos_dt = xp.asarray(sos_dt)
|
591
|
+
sos2_dt = zpk2sos(z, p, 1, pairing='minimal', analog=False)
|
592
|
+
sos2_ct = zpk2sos(z, p, 1, pairing='minimal', analog=True)
|
495
593
|
assert_array_almost_equal(sos_dt, sos2_dt, decimal=4)
|
496
|
-
assert_array_almost_equal(sos_dt
|
594
|
+
assert_array_almost_equal(xp.flip(sos_dt, axis=0), sos2_ct, decimal=4)
|
497
595
|
|
498
596
|
def test_bad_args(self):
|
499
597
|
with pytest.raises(ValueError, match=r'pairing must be one of'):
|
@@ -512,45 +610,47 @@ class TestZpk2Sos:
|
|
512
610
|
|
513
611
|
class TestFreqs:
|
514
612
|
|
515
|
-
def test_basic(self):
|
516
|
-
_, h = freqs([1.0], [1.0], worN=8)
|
517
|
-
assert_array_almost_equal(h,
|
613
|
+
def test_basic(self, xp):
|
614
|
+
_, h = freqs(xp.asarray([1.0]), xp.asarray([1.0]), worN=8)
|
615
|
+
assert_array_almost_equal(h, xp.ones(8))
|
518
616
|
|
519
|
-
def test_output(self):
|
617
|
+
def test_output(self, xp):
|
520
618
|
# 1st order low-pass filter: H(s) = 1 / (s + 1)
|
521
|
-
w = [0.1, 1, 10, 100]
|
522
|
-
num = [1]
|
523
|
-
den = [1, 1]
|
619
|
+
w = xp.asarray([0.1, 1, 10, 100])
|
620
|
+
num = xp.asarray([1.])
|
621
|
+
den = xp.asarray([1, 1.])
|
524
622
|
w, H = freqs(num, den, worN=w)
|
525
623
|
s = w * 1j
|
526
624
|
expected = 1 / (s + 1)
|
527
|
-
assert_array_almost_equal(
|
528
|
-
assert_array_almost_equal(
|
625
|
+
assert_array_almost_equal(xp.real(H), xp.real(expected))
|
626
|
+
assert_array_almost_equal(xp.imag(H), xp.imag(expected))
|
529
627
|
|
530
|
-
|
628
|
+
@skip_xp_backends("jax.numpy", reason="eigvals not available on CUDA")
|
629
|
+
def test_freq_range(self, xp):
|
531
630
|
# Test that freqresp() finds a reasonable frequency range.
|
532
631
|
# 1st order low-pass filter: H(s) = 1 / (s + 1)
|
533
632
|
# Expected range is from 0.01 to 10.
|
534
|
-
num = [1]
|
535
|
-
den = [1, 1]
|
633
|
+
num = xp.asarray([1.])
|
634
|
+
den = xp.asarray([1, 1.])
|
536
635
|
n = 10
|
537
|
-
expected_w =
|
636
|
+
expected_w = _logspace(-2, 1, n, xp=xp)
|
538
637
|
w, H = freqs(num, den, worN=n)
|
539
638
|
assert_array_almost_equal(w, expected_w)
|
540
639
|
|
541
|
-
def test_plot(self):
|
640
|
+
def test_plot(self, xp):
|
542
641
|
|
543
642
|
def plot(w, h):
|
544
|
-
assert_array_almost_equal(h,
|
643
|
+
assert_array_almost_equal(h, xp.ones(8))
|
545
644
|
|
546
|
-
assert_raises(ZeroDivisionError
|
547
|
-
|
548
|
-
freqs([1.0], [1.0], worN=8, plot=plot)
|
645
|
+
with assert_raises(ZeroDivisionError):
|
646
|
+
freqs([1.0], [1.0], worN=8, plot=lambda w, h: 1 / 0)
|
549
647
|
|
550
|
-
|
648
|
+
freqs(xp.asarray([1.0]), xp.asarray([1.0]), worN=8, plot=plot)
|
649
|
+
|
650
|
+
def test_backward_compat(self, xp):
|
551
651
|
# For backward compatibility, test if None act as a wrapper for default
|
552
|
-
w1, h1 = freqs([1.0], [1.0])
|
553
|
-
w2, h2 = freqs([1.0], [1.0], None)
|
652
|
+
w1, h1 = freqs(xp.asarray([1.0]), xp.asarray([1.0]))
|
653
|
+
w2, h2 = freqs(xp.asarray([1.0]), xp.asarray([1.0]), None)
|
554
654
|
assert_array_almost_equal(w1, w2)
|
555
655
|
assert_array_almost_equal(h1, h2)
|
556
656
|
|
@@ -571,47 +671,55 @@ class TestFreqs:
|
|
571
671
|
|
572
672
|
class TestFreqs_zpk:
|
573
673
|
|
574
|
-
def test_basic(self):
|
575
|
-
_, h = freqs_zpk(
|
576
|
-
|
674
|
+
def test_basic(self, xp):
|
675
|
+
_, h = freqs_zpk(
|
676
|
+
xp.asarray([1.0]), xp.asarray([1.0]), xp.asarray([1.0]), worN=8
|
677
|
+
)
|
678
|
+
assert_array_almost_equal(h, xp.ones(8))
|
577
679
|
|
578
|
-
def test_output(self):
|
680
|
+
def test_output(self, xp):
|
579
681
|
# 1st order low-pass filter: H(s) = 1 / (s + 1)
|
580
|
-
w = [0.1, 1, 10, 100]
|
581
|
-
z = []
|
582
|
-
p = [-1]
|
682
|
+
w = xp.asarray([0.1, 1, 10, 100])
|
683
|
+
z = xp.asarray([])
|
684
|
+
p = xp.asarray([-1.0])
|
583
685
|
k = 1
|
584
686
|
w, H = freqs_zpk(z, p, k, worN=w)
|
585
687
|
s = w * 1j
|
586
688
|
expected = 1 / (s + 1)
|
587
|
-
assert_array_almost_equal(
|
588
|
-
assert_array_almost_equal(
|
689
|
+
assert_array_almost_equal(xp.real(H), xp.real(expected))
|
690
|
+
assert_array_almost_equal(xp.imag(H), xp.imag(expected))
|
589
691
|
|
590
|
-
def test_freq_range(self):
|
692
|
+
def test_freq_range(self, xp):
|
591
693
|
# Test that freqresp() finds a reasonable frequency range.
|
592
694
|
# 1st order low-pass filter: H(s) = 1 / (s + 1)
|
593
695
|
# Expected range is from 0.01 to 10.
|
594
|
-
z = []
|
595
|
-
p = [-1]
|
696
|
+
z = xp.asarray([])
|
697
|
+
p = xp.asarray([-1.])
|
596
698
|
k = 1
|
597
699
|
n = 10
|
598
|
-
expected_w =
|
700
|
+
expected_w = _logspace(-2, 1, n, xp=xp)
|
599
701
|
w, H = freqs_zpk(z, p, k, worN=n)
|
600
702
|
assert_array_almost_equal(w, expected_w)
|
601
703
|
|
602
|
-
|
704
|
+
@skip_xp_backends("jax.numpy", reason="eigvals not available on CUDA")
|
705
|
+
def test_vs_freqs(self, xp):
|
603
706
|
b, a = cheby1(4, 5, 100, analog=True, output='ba')
|
604
707
|
z, p, k = cheby1(4, 5, 100, analog=True, output='zpk')
|
605
708
|
|
709
|
+
b, a = map(xp.asarray, (b, a)) # XXX convert cheby1
|
710
|
+
z, p = map(xp.asarray, (z, p))
|
711
|
+
|
606
712
|
w1, h1 = freqs(b, a)
|
607
713
|
w2, h2 = freqs_zpk(z, p, k)
|
608
714
|
xp_assert_close(w1, w2)
|
609
715
|
xp_assert_close(h1, h2, rtol=1e-6)
|
610
716
|
|
611
|
-
def test_backward_compat(self):
|
717
|
+
def test_backward_compat(self, xp):
|
612
718
|
# For backward compatibility, test if None act as a wrapper for default
|
613
|
-
|
614
|
-
|
719
|
+
# Also, keep testing `k` a length-one list: it is documented as a scalar,
|
720
|
+
# but the implementation was allowing for a one-element array-likes
|
721
|
+
w1, h1 = freqs_zpk(xp.asarray([1.0]), xp.asarray([1.0]), [1.0])
|
722
|
+
w2, h2 = freqs_zpk(xp.asarray([1.0]), xp.asarray([1.0]), [1.0], None)
|
615
723
|
assert_array_almost_equal(w1, w2)
|
616
724
|
assert_array_almost_equal(h1, h2)
|
617
725
|
|
@@ -632,97 +740,129 @@ class TestFreqs_zpk:
|
|
632
740
|
|
633
741
|
class TestFreqz:
|
634
742
|
|
635
|
-
def test_ticket1441(self):
|
743
|
+
def test_ticket1441(self, xp):
|
636
744
|
"""Regression test for ticket 1441."""
|
637
745
|
# Because freqz previously used arange instead of linspace,
|
638
746
|
# when N was large, it would return one more point than
|
639
747
|
# requested.
|
640
748
|
N = 100000
|
641
|
-
w, h = freqz([1.0], worN=N)
|
749
|
+
w, h = freqz(xp.asarray([1.0]), worN=N)
|
642
750
|
assert w.shape == (N,)
|
643
751
|
|
644
|
-
def
|
645
|
-
w, h = freqz([1.
|
646
|
-
|
647
|
-
|
648
|
-
|
649
|
-
|
650
|
-
|
651
|
-
|
652
|
-
|
653
|
-
|
752
|
+
def test_gh_22886(self, xp):
|
753
|
+
w, h = freqz(xp.asarray([1.]), worN=xp.asarray([0., 0.1]))
|
754
|
+
xp_assert_equal(w, xp.asarray([0. , 0.1]))
|
755
|
+
xp_assert_equal(h, xp.asarray([1.+0.j, 1.+0.j]))
|
756
|
+
|
757
|
+
def test_basic(self, xp):
|
758
|
+
w, h = freqz(xp.asarray([1.0]), worN=8)
|
759
|
+
assert_array_almost_equal(w, xp.pi * xp.arange(8, dtype=w.dtype) / 8.)
|
760
|
+
assert_array_almost_equal(h, xp.ones(8))
|
761
|
+
w, h = freqz(xp.asarray([1.0]), worN=9)
|
762
|
+
assert_array_almost_equal(w, xp.pi * xp.arange(9, dtype=w.dtype) / 9.)
|
763
|
+
assert_array_almost_equal(h, xp.ones(9))
|
764
|
+
|
765
|
+
for a in [1, xp.ones(2)]:
|
766
|
+
w, h = freqz(xp.ones(2), a, worN=0)
|
654
767
|
assert w.shape == (0,)
|
655
768
|
assert h.shape == (0,)
|
656
|
-
|
769
|
+
hdt = xp.complex128 if xp_default_dtype(xp) == xp.float64 else xp.complex64
|
770
|
+
assert h.dtype == hdt
|
657
771
|
|
658
|
-
|
772
|
+
def test_basic2(self, xp):
|
773
|
+
t = xp.linspace(0, 1, 4, endpoint=False)
|
659
774
|
for b, a, h_whole in zip(
|
660
|
-
([1., 0, 0, 0],
|
661
|
-
([1., 0, 0, 0], [0.5, 0, 0, 0]),
|
662
|
-
([1., 1., 1., 1.], [0, -4j, 0, 4j]))
|
775
|
+
(xp.asarray([1., 0, 0, 0]), xp.sin(2 * xp.pi * t)),
|
776
|
+
(xp.asarray([1., 0, 0, 0]), xp.asarray([0.5, 0, 0, 0])),
|
777
|
+
(xp.asarray([1., 1., 1., 1.]), xp.asarray([0, -4j, 0, 4j]))
|
778
|
+
):
|
779
|
+
|
663
780
|
w, h = freqz(b, a, worN=4, whole=True)
|
664
|
-
expected_w =
|
781
|
+
expected_w = xp.linspace(0, 2 * xp.pi, 4, endpoint=False)
|
665
782
|
assert_array_almost_equal(w, expected_w)
|
666
783
|
assert_array_almost_equal(h, h_whole)
|
784
|
+
|
667
785
|
# simultaneously check int-like support
|
668
786
|
w, h = freqz(b, a, worN=np.int32(4), whole=True)
|
669
787
|
assert_array_almost_equal(w, expected_w)
|
670
788
|
assert_array_almost_equal(h, h_whole)
|
789
|
+
|
671
790
|
w, h = freqz(b, a, worN=w, whole=True)
|
672
791
|
assert_array_almost_equal(w, expected_w)
|
673
792
|
assert_array_almost_equal(h, h_whole)
|
674
793
|
|
675
|
-
def
|
676
|
-
|
677
|
-
|
678
|
-
|
794
|
+
def test_basic3(self):
|
795
|
+
t = np.linspace(0, 1, 4, endpoint=False)
|
796
|
+
expected_w = np.linspace(0, 2 * np.pi, 4, endpoint=False)
|
797
|
+
for b, a, h_whole in zip(
|
798
|
+
(np.asarray([1., 0, 0, 0]), np.sin(2 * np.pi * t)),
|
799
|
+
(np.asarray([1., 0, 0, 0]), np.asarray([0.5, 0, 0, 0])),
|
800
|
+
(np.asarray([1., 1., 1., 1.]), np.asarray([0, -4j, 0, 4j]))
|
801
|
+
):
|
679
802
|
|
680
|
-
|
803
|
+
w, h = freqz(b, a, worN=np.int32(4), whole=True)
|
804
|
+
assert_array_almost_equal(w, expected_w)
|
805
|
+
assert_array_almost_equal(h, h_whole)
|
806
|
+
|
807
|
+
w, h = freqz(b, a, worN=w, whole=True)
|
808
|
+
assert_array_almost_equal(w, expected_w)
|
809
|
+
assert_array_almost_equal(h, h_whole)
|
810
|
+
|
811
|
+
def test_basic_whole(self, xp):
|
812
|
+
w, h = freqz(xp.asarray([1.0]), worN=8, whole=True)
|
813
|
+
assert_array_almost_equal(w, 2 * xp.pi * xp.arange(8.0) / 8)
|
814
|
+
assert_array_almost_equal(h, xp.ones(8))
|
815
|
+
|
816
|
+
def test_plot(self, xp):
|
681
817
|
|
682
818
|
def plot(w, h):
|
683
|
-
assert_array_almost_equal(w,
|
684
|
-
assert_array_almost_equal(h,
|
819
|
+
assert_array_almost_equal(w, xp.pi * xp.arange(8.0) / 8)
|
820
|
+
assert_array_almost_equal(h, xp.ones(8))
|
685
821
|
|
686
|
-
assert_raises(ZeroDivisionError
|
687
|
-
|
688
|
-
freqz([1.0], worN=8, plot=plot)
|
822
|
+
with assert_raises(ZeroDivisionError):
|
823
|
+
freqz(xp.asarray([1.0]), worN=8, plot=lambda w, h: 1 / 0)
|
689
824
|
|
690
|
-
|
825
|
+
freqz(xp.asarray([1.0]), worN=8, plot=plot)
|
826
|
+
|
827
|
+
def test_fft_wrapping(self, xp):
|
691
828
|
# Some simple real FIR filters
|
692
829
|
bs = list() # filters
|
693
830
|
as_ = list()
|
694
831
|
hs_whole = list()
|
695
832
|
hs_half = list()
|
696
833
|
# 3 taps
|
697
|
-
t =
|
698
|
-
bs.append(
|
834
|
+
t = xp.linspace(0, 1, 3, endpoint=False)
|
835
|
+
bs.append(xp.sin(2 * xp.pi * t))
|
699
836
|
as_.append(3.)
|
700
|
-
hs_whole.append([0, -0.5j, 0.5j])
|
701
|
-
hs_half.append([0,
|
837
|
+
hs_whole.append(xp.asarray([0, -0.5j, 0.5j]))
|
838
|
+
hs_half.append(xp.asarray([0, math.sqrt(1./12.), -0.5j]))
|
702
839
|
# 4 taps
|
703
|
-
t =
|
704
|
-
bs.append(
|
840
|
+
t = xp.linspace(0, 1, 4, endpoint=False)
|
841
|
+
bs.append(xp.sin(2 * xp.pi * t))
|
705
842
|
as_.append(0.5)
|
706
|
-
hs_whole.append([0, -4j, 0, 4j])
|
707
|
-
hs_half.append([0,
|
843
|
+
hs_whole.append(xp.asarray([0, -4j, 0, 4j]))
|
844
|
+
hs_half.append(xp.asarray([0, math.sqrt(8), -4j, -math.sqrt(8)]))
|
708
845
|
del t
|
709
846
|
for ii, b in enumerate(bs):
|
710
847
|
# whole
|
711
848
|
a = as_[ii]
|
712
|
-
expected_w =
|
849
|
+
expected_w = xp.linspace(0, 2 * xp.pi, b.shape[0], endpoint=False)
|
713
850
|
w, h = freqz(b, a, worN=expected_w, whole=True) # polyval
|
714
851
|
err_msg = f'b = {b}, a={a}'
|
715
852
|
assert_array_almost_equal(w, expected_w, err_msg=err_msg)
|
716
853
|
assert_array_almost_equal(h, hs_whole[ii], err_msg=err_msg)
|
717
|
-
|
854
|
+
|
855
|
+
w, h = freqz(b, a, worN=b.shape[0], whole=True) # FFT
|
718
856
|
assert_array_almost_equal(w, expected_w, err_msg=err_msg)
|
719
857
|
assert_array_almost_equal(h, hs_whole[ii], err_msg=err_msg)
|
858
|
+
|
720
859
|
# non-whole
|
721
|
-
expected_w =
|
860
|
+
expected_w = xp.linspace(0, xp.pi, b.shape[0], endpoint=False)
|
722
861
|
w, h = freqz(b, a, worN=expected_w, whole=False) # polyval
|
723
862
|
assert_array_almost_equal(w, expected_w, err_msg=err_msg)
|
724
863
|
assert_array_almost_equal(h, hs_half[ii], err_msg=err_msg)
|
725
|
-
|
864
|
+
|
865
|
+
w, h = freqz(b, a, worN=b.shape[0], whole=False) # FFT
|
726
866
|
assert_array_almost_equal(w, expected_w, err_msg=err_msg)
|
727
867
|
assert_array_almost_equal(h, hs_half[ii], err_msg=err_msg)
|
728
868
|
|
@@ -730,91 +870,100 @@ class TestFreqz:
|
|
730
870
|
# assume polyval is accurate
|
731
871
|
rng = np.random.RandomState(0)
|
732
872
|
for ii in range(2, 10): # number of taps
|
733
|
-
b = rng.randn(ii)
|
873
|
+
b = xp.asarray(rng.randn(ii))
|
734
874
|
for kk in range(2):
|
735
|
-
a = rng.randn(1) if kk == 0 else rng.randn(3)
|
875
|
+
a = xp.asarray(rng.randn(1) if kk == 0 else rng.randn(3))
|
736
876
|
for jj in range(2):
|
737
877
|
if jj == 1:
|
738
|
-
b = b + rng.randn(ii) * 1j
|
878
|
+
b = b + xp.asarray(rng.randn(ii)) * 1j
|
879
|
+
|
739
880
|
# whole
|
740
|
-
expected_w =
|
881
|
+
expected_w = xp.linspace(0, 2 * xp.pi, ii, endpoint=False)
|
741
882
|
w, expected_h = freqz(b, a, worN=expected_w, whole=True)
|
742
883
|
assert_array_almost_equal(w, expected_w)
|
743
884
|
w, h = freqz(b, a, worN=ii, whole=True)
|
744
885
|
assert_array_almost_equal(w, expected_w)
|
745
|
-
assert_array_almost_equal(h, expected_h)
|
886
|
+
assert_array_almost_equal(h, expected_h, decimal=4)
|
887
|
+
|
746
888
|
# half
|
747
|
-
expected_w =
|
889
|
+
expected_w = xp.linspace(0, xp.pi, ii, endpoint=False)
|
748
890
|
w, expected_h = freqz(b, a, worN=expected_w, whole=False)
|
749
891
|
assert_array_almost_equal(w, expected_w)
|
750
892
|
w, h = freqz(b, a, worN=ii, whole=False)
|
751
893
|
assert_array_almost_equal(w, expected_w)
|
752
|
-
assert_array_almost_equal(h, expected_h)
|
894
|
+
assert_array_almost_equal(h, expected_h, decimal=4)
|
753
895
|
|
754
|
-
def test_broadcasting1(self):
|
896
|
+
def test_broadcasting1(self, xp):
|
755
897
|
# Test broadcasting with worN an integer or a 1-D array,
|
756
898
|
# b and a are n-dimensional arrays.
|
757
899
|
np.random.seed(123)
|
758
900
|
b = np.random.rand(3, 5, 1)
|
759
901
|
a = np.random.rand(2, 1)
|
902
|
+
b, a = map(xp.asarray, (b, a))
|
903
|
+
|
760
904
|
for whole in [False, True]:
|
761
905
|
# Test with worN being integers (one fast for FFT and one not),
|
762
906
|
# a 1-D array, and an empty array.
|
763
|
-
for worN in [16, 17,
|
907
|
+
for worN in [16, 17, xp.linspace(0, 1, 10), xp.asarray([])]:
|
764
908
|
w, h = freqz(b, a, worN=worN, whole=whole)
|
765
909
|
for k in range(b.shape[1]):
|
766
910
|
bk = b[:, k, 0]
|
767
911
|
ak = a[:, 0]
|
768
912
|
ww, hh = freqz(bk, ak, worN=worN, whole=whole)
|
769
913
|
xp_assert_close(ww, w)
|
770
|
-
xp_assert_close(hh, h[k])
|
914
|
+
xp_assert_close(hh, h[k, ...])
|
771
915
|
|
772
|
-
def test_broadcasting2(self):
|
916
|
+
def test_broadcasting2(self, xp):
|
773
917
|
# Test broadcasting with worN an integer or a 1-D array,
|
774
918
|
# b is an n-dimensional array, and a is left at the default value.
|
775
919
|
np.random.seed(123)
|
776
920
|
b = np.random.rand(3, 5, 1)
|
921
|
+
b = xp.asarray(b)
|
777
922
|
for whole in [False, True]:
|
778
|
-
for worN in [16, 17,
|
923
|
+
for worN in [16, 17, xp.linspace(0, 1, 10)]:
|
779
924
|
w, h = freqz(b, worN=worN, whole=whole)
|
780
925
|
for k in range(b.shape[1]):
|
781
926
|
bk = b[:, k, 0]
|
782
927
|
ww, hh = freqz(bk, worN=worN, whole=whole)
|
783
928
|
xp_assert_close(ww, w)
|
784
|
-
xp_assert_close(hh, h[k])
|
929
|
+
xp_assert_close(hh, h[k, :])
|
785
930
|
|
786
|
-
def test_broadcasting3(self):
|
931
|
+
def test_broadcasting3(self, xp):
|
787
932
|
# Test broadcasting where b.shape[-1] is the same length
|
788
933
|
# as worN, and a is left at the default value.
|
789
934
|
np.random.seed(123)
|
790
935
|
N = 16
|
791
936
|
b = np.random.rand(3, N)
|
937
|
+
b = xp.asarray(b)
|
792
938
|
for whole in [False, True]:
|
793
|
-
for worN in [N,
|
939
|
+
for worN in [N, xp.linspace(0, 1, N)]:
|
794
940
|
w, h = freqz(b, worN=worN, whole=whole)
|
795
|
-
assert w
|
941
|
+
assert xp_size(w) == N
|
796
942
|
for k in range(N):
|
797
943
|
bk = b[:, k]
|
798
944
|
ww, hh = freqz(bk, worN=w[k], whole=whole)
|
799
|
-
xp_assert_close(ww,
|
800
|
-
xp_assert_close(hh,
|
945
|
+
xp_assert_close(ww, xp.asarray(w[k])[None])
|
946
|
+
xp_assert_close(hh, xp.asarray(h[k])[None])
|
801
947
|
|
802
|
-
def test_broadcasting4(self):
|
948
|
+
def test_broadcasting4(self, xp):
|
803
949
|
# Test broadcasting with worN a 2-D array.
|
804
950
|
np.random.seed(123)
|
805
951
|
b = np.random.rand(4, 2, 1, 1)
|
806
952
|
a = np.random.rand(5, 2, 1, 1)
|
953
|
+
b, a = map(xp.asarray, (b, a))
|
954
|
+
|
807
955
|
for whole in [False, True]:
|
808
956
|
for worN in [np.random.rand(6, 7), np.empty((6, 0))]:
|
957
|
+
worN = xp.asarray(worN)
|
809
958
|
w, h = freqz(b, a, worN=worN, whole=whole)
|
810
959
|
xp_assert_close(w, worN, rtol=1e-14)
|
811
960
|
assert h.shape == (2,) + worN.shape
|
812
961
|
for k in range(2):
|
813
962
|
ww, hh = freqz(b[:, k, 0, 0], a[:, k, 0, 0],
|
814
|
-
worN=
|
963
|
+
worN=xp.reshape(worN, (-1,)),
|
815
964
|
whole=whole)
|
816
|
-
xp_assert_close(ww,
|
817
|
-
xp_assert_close(hh, h[k, :, :]
|
965
|
+
xp_assert_close(ww, xp.reshape(worN, (-1,)), rtol=1e-14)
|
966
|
+
xp_assert_close(hh, xp.reshape(h[k, :, :], (-1,)))
|
818
967
|
|
819
968
|
def test_backward_compat(self):
|
820
969
|
# For backward compatibility, test if None act as a wrapper for default
|
@@ -823,44 +972,44 @@ class TestFreqz:
|
|
823
972
|
assert_array_almost_equal(w1, w2)
|
824
973
|
assert_array_almost_equal(h1, h2)
|
825
974
|
|
826
|
-
def test_fs_param(self):
|
975
|
+
def test_fs_param(self, xp):
|
827
976
|
fs = 900
|
828
|
-
b = [0.039479155677484369, 0.11843746703245311, 0.11843746703245311,
|
829
|
-
|
830
|
-
a = [1.0, -1.3199152021838287, 0.80341991081938424,
|
831
|
-
|
977
|
+
b = xp.asarray([0.039479155677484369, 0.11843746703245311, 0.11843746703245311,
|
978
|
+
0.039479155677484369])
|
979
|
+
a = xp.asarray([1.0, -1.3199152021838287, 0.80341991081938424,
|
980
|
+
-0.16767146321568049])
|
832
981
|
|
833
982
|
# N = None, whole=False
|
834
983
|
w1, h1 = freqz(b, a, fs=fs)
|
835
984
|
w2, h2 = freqz(b, a)
|
836
985
|
xp_assert_close(h1, h2)
|
837
|
-
xp_assert_close(w1,
|
986
|
+
xp_assert_close(w1, xp.linspace(0, fs/2, 512, endpoint=False))
|
838
987
|
|
839
988
|
# N = None, whole=True
|
840
989
|
w1, h1 = freqz(b, a, whole=True, fs=fs)
|
841
990
|
w2, h2 = freqz(b, a, whole=True)
|
842
991
|
xp_assert_close(h1, h2)
|
843
|
-
xp_assert_close(w1,
|
992
|
+
xp_assert_close(w1, xp.linspace(0, fs, 512, endpoint=False))
|
844
993
|
|
845
994
|
# N = 5, whole=False
|
846
995
|
w1, h1 = freqz(b, a, 5, fs=fs)
|
847
996
|
w2, h2 = freqz(b, a, 5)
|
848
997
|
xp_assert_close(h1, h2)
|
849
|
-
xp_assert_close(w1,
|
998
|
+
xp_assert_close(w1, xp.linspace(0, fs/2, 5, endpoint=False))
|
850
999
|
|
851
1000
|
# N = 5, whole=True
|
852
1001
|
w1, h1 = freqz(b, a, 5, whole=True, fs=fs)
|
853
1002
|
w2, h2 = freqz(b, a, 5, whole=True)
|
854
1003
|
xp_assert_close(h1, h2)
|
855
|
-
xp_assert_close(w1,
|
1004
|
+
xp_assert_close(w1, xp.linspace(0, fs, 5, endpoint=False))
|
856
1005
|
|
857
1006
|
# w is an array_like
|
858
|
-
for w in ([123], (123,),
|
859
|
-
|
1007
|
+
for w in ([123], (123,), xp.asarray([123]), (50, 123, 230),
|
1008
|
+
xp.asarray([50, 123, 230])):
|
860
1009
|
w1, h1 = freqz(b, a, w, fs=fs)
|
861
|
-
w2, h2 = freqz(b, a, 2*pi*
|
1010
|
+
w2, h2 = freqz(b, a, 2*pi*xp.asarray(w, dtype=xp.float64)/ fs)
|
862
1011
|
xp_assert_close(h1, h2)
|
863
|
-
xp_assert_close(
|
1012
|
+
xp_assert_close(w1, xp.asarray(w), check_dtype=False)
|
864
1013
|
|
865
1014
|
def test_w_or_N_types(self):
|
866
1015
|
# Measure at 7 (polyval) or 8 (fft) equally-spaced points
|
@@ -880,26 +1029,27 @@ class TestFreqz:
|
|
880
1029
|
# Measure at frequency 8 Hz
|
881
1030
|
for w in (8.0, 8.0+0j):
|
882
1031
|
# Only makes sense when fs is specified
|
883
|
-
w_out, h = freqz([1.0], worN=w, fs=100)
|
884
|
-
assert_array_almost_equal(w_out, [8])
|
885
|
-
assert_array_almost_equal(h,
|
886
|
-
|
887
|
-
def test_nyquist(self):
|
888
|
-
w, h = freqz([1.0], worN=8, include_nyquist=True)
|
889
|
-
assert_array_almost_equal(w,
|
890
|
-
assert_array_almost_equal(h,
|
891
|
-
w, h = freqz([1.0], worN=9, include_nyquist=True)
|
892
|
-
assert_array_almost_equal(w,
|
893
|
-
assert_array_almost_equal(h,
|
894
|
-
|
895
|
-
for a in [1,
|
896
|
-
w, h = freqz(
|
1032
|
+
w_out, h = freqz(np.asarray([1.0]), worN=w, fs=100)
|
1033
|
+
assert_array_almost_equal(w_out, np.asarray([8]))
|
1034
|
+
assert_array_almost_equal(h, np.asarray(1.), check_0d=False)
|
1035
|
+
|
1036
|
+
def test_nyquist(self, xp):
|
1037
|
+
w, h = freqz(xp.asarray([1.0]), worN=8, include_nyquist=True)
|
1038
|
+
assert_array_almost_equal(w, xp.pi * xp.arange(8, dtype=w.dtype) / 7.)
|
1039
|
+
assert_array_almost_equal(h, xp.ones(8))
|
1040
|
+
w, h = freqz(xp.asarray([1.0]), worN=9, include_nyquist=True)
|
1041
|
+
assert_array_almost_equal(w, xp.pi * xp.arange(9, dtype=w.dtype) / 8.)
|
1042
|
+
assert_array_almost_equal(h, xp.ones(9))
|
1043
|
+
|
1044
|
+
for a in [1, xp.ones(2)]:
|
1045
|
+
w, h = freqz(xp.ones(2), a, worN=0, include_nyquist=True)
|
897
1046
|
assert w.shape == (0,)
|
898
1047
|
assert h.shape == (0,)
|
899
|
-
|
1048
|
+
hdt = xp.complex128 if xp_default_dtype(xp) == xp.float64 else xp.complex64
|
1049
|
+
assert h.dtype == hdt
|
900
1050
|
|
901
|
-
w1, h1 = freqz([1.0], worN=8, whole = True, include_nyquist=True)
|
902
|
-
w2, h2 = freqz([1.0], worN=8, whole = True, include_nyquist=False)
|
1051
|
+
w1, h1 = freqz(xp.asarray([1.0]), worN=8, whole = True, include_nyquist=True)
|
1052
|
+
w2, h2 = freqz(xp.asarray([1.0]), worN=8, whole = True, include_nyquist=False)
|
903
1053
|
assert_array_almost_equal(w1, w2)
|
904
1054
|
assert_array_almost_equal(h1, h2)
|
905
1055
|
|
@@ -914,8 +1064,8 @@ class TestFreqz:
|
|
914
1064
|
(False, True, 257),
|
915
1065
|
(True, False, 257),
|
916
1066
|
(True, True, 257)])
|
917
|
-
def test_17289(self, whole, nyquist, worN):
|
918
|
-
d = [0, 1]
|
1067
|
+
def test_17289(self, whole, nyquist, worN, xp):
|
1068
|
+
d = xp.asarray([0.0, 1.0])
|
919
1069
|
w, Drfft = freqz(d, worN=32, whole=whole, include_nyquist=nyquist)
|
920
1070
|
_, Dpoly = freqz(d, worN=w)
|
921
1071
|
xp_assert_close(Drfft, Dpoly)
|
@@ -928,9 +1078,9 @@ class TestFreqz:
|
|
928
1078
|
freqz([1.0], fs=None)
|
929
1079
|
|
930
1080
|
|
931
|
-
class
|
1081
|
+
class TestFreqz_sos:
|
932
1082
|
|
933
|
-
def test_freqz_sos_basic(self):
|
1083
|
+
def test_freqz_sos_basic(self, xp):
|
934
1084
|
# Compare the results of freqz and freqz_sos for a low order
|
935
1085
|
# Butterworth filter.
|
936
1086
|
|
@@ -938,6 +1088,8 @@ class Testfreqz_sos:
|
|
938
1088
|
|
939
1089
|
b, a = butter(4, 0.2)
|
940
1090
|
sos = butter(4, 0.2, output='sos')
|
1091
|
+
b, a, sos = map(xp.asarray, (b, a, sos)) # XXX until butter is converted
|
1092
|
+
|
941
1093
|
w, h = freqz(b, a, worN=N)
|
942
1094
|
w2, h2 = freqz_sos(sos, worN=N)
|
943
1095
|
xp_assert_equal(w2, w)
|
@@ -945,132 +1097,158 @@ class Testfreqz_sos:
|
|
945
1097
|
|
946
1098
|
b, a = ellip(3, 1, 30, (0.2, 0.3), btype='bandpass')
|
947
1099
|
sos = ellip(3, 1, 30, (0.2, 0.3), btype='bandpass', output='sos')
|
1100
|
+
b, a, sos = map(xp.asarray, (b, a, sos)) # XXX until ellip is converted
|
1101
|
+
|
948
1102
|
w, h = freqz(b, a, worN=N)
|
949
1103
|
w2, h2 = freqz_sos(sos, worN=N)
|
950
1104
|
xp_assert_equal(w2, w)
|
951
1105
|
xp_assert_close(h2, h, rtol=1e-10, atol=1e-14)
|
1106
|
+
|
952
1107
|
# must have at least one section
|
953
|
-
assert_raises(ValueError
|
1108
|
+
with assert_raises(ValueError):
|
1109
|
+
freqz_sos(sos[:0, ...])
|
954
1110
|
|
955
|
-
def test_backward_compat(self):
|
1111
|
+
def test_backward_compat(self, xp):
|
956
1112
|
# For backward compatibility, test if None act as a wrapper for default
|
957
1113
|
N = 500
|
958
1114
|
|
959
1115
|
sos = butter(4, 0.2, output='sos')
|
1116
|
+
sos = xp.asarray(sos) # XXX until butter is converted
|
960
1117
|
w1, h1 = freqz_sos(sos, worN=N)
|
961
1118
|
w2, h2 = sosfreqz(sos, worN=N)
|
962
1119
|
assert_array_almost_equal(w1, w2)
|
963
1120
|
assert_array_almost_equal(h1, h2)
|
964
1121
|
|
965
|
-
|
1122
|
+
@skip_xp_backends("dask.array", reason="float cannot be interpreted as in integer")
|
1123
|
+
def test_freqz_sos_design(self, xp):
|
966
1124
|
# Compare freqz_sos output against expected values for different
|
967
1125
|
# filter types
|
968
1126
|
|
969
1127
|
# from cheb2ord
|
970
1128
|
N, Wn = cheb2ord([0.1, 0.6], [0.2, 0.5], 3, 60)
|
971
1129
|
sos = cheby2(N, 60, Wn, 'stop', output='sos')
|
1130
|
+
sos = xp.asarray(sos) # XXX
|
1131
|
+
zero = xp.asarray(0., dtype=xp.float64)
|
1132
|
+
|
972
1133
|
w, h = freqz_sos(sos)
|
973
|
-
h =
|
974
|
-
w
|
975
|
-
xp_assert_close(20 *
|
1134
|
+
h = xp.abs(h)
|
1135
|
+
w = w / xp.pi
|
1136
|
+
xp_assert_close(20 * xp.log10(h[w <= 0.1]),
|
1137
|
+
zero, atol=3.01,
|
976
1138
|
check_shape=False)
|
977
|
-
xp_assert_close(20 *
|
1139
|
+
xp_assert_close(20 * xp.log10(h[w >= 0.6]),
|
1140
|
+
zero, atol=3.01,
|
978
1141
|
check_shape=False)
|
979
1142
|
xp_assert_close(h[(w >= 0.2) & (w <= 0.5)],
|
980
|
-
|
1143
|
+
zero, atol=1e-3,
|
981
1144
|
check_shape=False) # <= -60 dB
|
982
1145
|
|
983
1146
|
N, Wn = cheb2ord([0.1, 0.6], [0.2, 0.5], 3, 150)
|
984
1147
|
sos = cheby2(N, 150, Wn, 'stop', output='sos')
|
1148
|
+
sos = xp.asarray(sos)
|
1149
|
+
|
985
1150
|
w, h = freqz_sos(sos)
|
986
|
-
dB = 20*
|
987
|
-
w
|
988
|
-
xp_assert_close(dB[w <= 0.1],
|
989
|
-
xp_assert_close(dB[w >= 0.6],
|
990
|
-
assert
|
1151
|
+
dB = 20*xp.log10(xp.abs(h))
|
1152
|
+
w = w / xp.pi
|
1153
|
+
xp_assert_close(dB[w <= 0.1], zero, atol=3.01, check_shape=False)
|
1154
|
+
xp_assert_close(dB[w >= 0.6], zero, atol=3.01, check_shape=False)
|
1155
|
+
assert xp.all(dB[(w >= 0.2) & (w <= 0.5)] < -149.9)
|
991
1156
|
|
992
1157
|
# from cheb1ord
|
993
1158
|
N, Wn = cheb1ord(0.2, 0.3, 3, 40)
|
994
1159
|
sos = cheby1(N, 3, Wn, 'low', output='sos')
|
1160
|
+
sos = xp.asarray(sos)
|
1161
|
+
|
995
1162
|
w, h = freqz_sos(sos)
|
996
|
-
h =
|
997
|
-
w
|
998
|
-
xp_assert_close(20 *
|
1163
|
+
h = xp.abs(h)
|
1164
|
+
w = w / xp.pi
|
1165
|
+
xp_assert_close(20 * xp.log10(h[w <= 0.2]), zero, atol=3.01,
|
999
1166
|
check_shape=False)
|
1000
|
-
xp_assert_close(h[w >= 0.3],
|
1167
|
+
xp_assert_close(h[w >= 0.3], zero, atol=1e-2,
|
1001
1168
|
check_shape=False) # <= -40 dB
|
1002
1169
|
|
1003
1170
|
N, Wn = cheb1ord(0.2, 0.3, 1, 150)
|
1004
1171
|
sos = cheby1(N, 1, Wn, 'low', output='sos')
|
1172
|
+
sos = xp.asarray(sos)
|
1173
|
+
|
1005
1174
|
w, h = freqz_sos(sos)
|
1006
|
-
dB = 20*
|
1175
|
+
dB = 20*xp.log10(xp.abs(h))
|
1007
1176
|
w /= np.pi
|
1008
|
-
xp_assert_close(dB[w <= 0.2],
|
1009
|
-
|
1010
|
-
assert np.all(dB[w >= 0.3] < -149.9)
|
1177
|
+
xp_assert_close(dB[w <= 0.2], zero, atol=1.01, check_shape=False)
|
1178
|
+
assert xp.all(dB[w >= 0.3] < -149.9)
|
1011
1179
|
|
1012
1180
|
# adapted from ellipord
|
1013
1181
|
N, Wn = ellipord(0.3, 0.2, 3, 60)
|
1014
1182
|
sos = ellip(N, 0.3, 60, Wn, 'high', output='sos')
|
1183
|
+
sos = xp.asarray(sos)
|
1184
|
+
|
1015
1185
|
w, h = freqz_sos(sos)
|
1016
|
-
h =
|
1017
|
-
w
|
1018
|
-
xp_assert_close(20 *
|
1186
|
+
h = xp.abs(h)
|
1187
|
+
w = w / xp.pi
|
1188
|
+
xp_assert_close(20 * xp.log10(h[w >= 0.3]), zero, atol=3.01,
|
1019
1189
|
check_shape=False)
|
1020
|
-
xp_assert_close(h[w <= 0.1],
|
1190
|
+
xp_assert_close(h[w <= 0.1], zero, atol=1.5e-3,
|
1021
1191
|
check_shape=False) # <= -60 dB (approx)
|
1022
1192
|
|
1023
1193
|
# adapted from buttord
|
1024
1194
|
N, Wn = buttord([0.2, 0.5], [0.14, 0.6], 3, 40)
|
1025
1195
|
sos = butter(N, Wn, 'band', output='sos')
|
1196
|
+
sos = xp.asarray(sos)
|
1197
|
+
|
1026
1198
|
w, h = freqz_sos(sos)
|
1027
|
-
h =
|
1028
|
-
w
|
1199
|
+
h = xp.abs(h)
|
1200
|
+
w = w / xp.pi
|
1029
1201
|
|
1030
1202
|
h014 = h[w <= 0.14]
|
1031
|
-
xp_assert_close(h014,
|
1203
|
+
xp_assert_close(h014, xp.zeros_like(h014), atol=1e-2) # <= -40 dB
|
1032
1204
|
h06 = h[w >= 0.6]
|
1033
|
-
xp_assert_close(h06,
|
1034
|
-
h0205 = 20 *
|
1035
|
-
xp_assert_close(h0205,
|
1205
|
+
xp_assert_close(h06, xp.zeros_like(h06), atol=1e-2) # <= -40 dB
|
1206
|
+
h0205 = 20 * xp.log10(h[(w >= 0.2) & (w <= 0.5)])
|
1207
|
+
xp_assert_close(h0205, xp.zeros_like(h0205), atol=3.01)
|
1036
1208
|
|
1037
1209
|
N, Wn = buttord([0.2, 0.5], [0.14, 0.6], 3, 100)
|
1038
1210
|
sos = butter(N, Wn, 'band', output='sos')
|
1211
|
+
sos = xp.asarray(sos)
|
1212
|
+
|
1039
1213
|
w, h = freqz_sos(sos)
|
1040
|
-
dB = 20*
|
1041
|
-
w
|
1214
|
+
dB = 20*xp.log10(xp.maximum(xp.abs(h), xp.asarray(1e-10)))
|
1215
|
+
w = w / xp.pi
|
1042
1216
|
|
1043
|
-
assert
|
1044
|
-
assert
|
1217
|
+
assert xp.all(dB[(w > 0) & (w <= 0.14)] < -99.9)
|
1218
|
+
assert xp.all(dB[w >= 0.6] < -99.9)
|
1045
1219
|
db0205 = dB[(w >= 0.2) & (w <= 0.5)]
|
1046
|
-
xp_assert_close(db0205,
|
1220
|
+
xp_assert_close(db0205, xp.zeros_like(db0205), atol=3.01)
|
1047
1221
|
|
1048
|
-
def test_freqz_sos_design_ellip(self):
|
1222
|
+
def test_freqz_sos_design_ellip(self, xp):
|
1049
1223
|
N, Wn = ellipord(0.3, 0.1, 3, 60)
|
1050
1224
|
sos = ellip(N, 0.3, 60, Wn, 'high', output='sos')
|
1225
|
+
sos = xp.asarray(sos)
|
1226
|
+
|
1051
1227
|
w, h = freqz_sos(sos)
|
1052
|
-
h =
|
1053
|
-
w
|
1228
|
+
h = xp.abs(h)
|
1229
|
+
w = w / xp.pi
|
1054
1230
|
|
1055
|
-
h03 = 20 *
|
1056
|
-
xp_assert_close(h03,
|
1231
|
+
h03 = 20 * xp.log10(h[w >= 0.3])
|
1232
|
+
xp_assert_close(h03, xp.zeros_like(h03), atol=3.01)
|
1057
1233
|
h01 = h[w <= 0.1]
|
1058
|
-
xp_assert_close(h01,
|
1234
|
+
xp_assert_close(h01, xp.zeros_like(h01), atol=1.5e-3) # <= -60 dB (approx)
|
1059
1235
|
|
1060
1236
|
N, Wn = ellipord(0.3, 0.2, .5, 150)
|
1061
1237
|
sos = ellip(N, .5, 150, Wn, 'high', output='sos')
|
1238
|
+
sos = xp.asarray(sos)
|
1239
|
+
|
1062
1240
|
w, h = freqz_sos(sos)
|
1063
|
-
dB = 20*
|
1064
|
-
w
|
1241
|
+
dB = 20*xp.log10(xp.maximum(xp.abs(h), xp.asarray(1e-10)))
|
1242
|
+
w = w / xp.pi
|
1065
1243
|
|
1066
1244
|
db03 = dB[w >= 0.3]
|
1067
|
-
xp_assert_close(db03,
|
1245
|
+
xp_assert_close(db03, xp.zeros_like(db03), atol=.55)
|
1068
1246
|
# Allow some numerical slop in the upper bound -150, so this is
|
1069
1247
|
# a check that dB[w <= 0.2] is less than or almost equal to -150.
|
1070
|
-
assert dB[w <= 0.2]
|
1248
|
+
assert xp.max(dB[w <= 0.2]) < -150*(1 - 1e-12)
|
1071
1249
|
|
1072
1250
|
@mpmath_check("0.10")
|
1073
|
-
def test_freqz_sos_against_mp(self):
|
1251
|
+
def test_freqz_sos_against_mp(self, xp):
|
1074
1252
|
# Compare the result of freqz_sos applied to a high order Butterworth
|
1075
1253
|
# filter against the result computed using mpmath. (signal.freqz fails
|
1076
1254
|
# miserably with such high order filters.)
|
@@ -1081,49 +1259,63 @@ class Testfreqz_sos:
|
|
1081
1259
|
with mpmath.workdps(80):
|
1082
1260
|
z_mp, p_mp, k_mp = mpsig.butter_lp(order, Wn)
|
1083
1261
|
w_mp, h_mp = mpsig.zpkfreqz(z_mp, p_mp, k_mp, N)
|
1084
|
-
w_mp =
|
1085
|
-
h_mp =
|
1262
|
+
w_mp = xp.asarray([float(x) for x in w_mp], dtype=xp.float64)
|
1263
|
+
h_mp = xp.asarray([complex(x) for x in h_mp], dtype=xp.complex128)
|
1086
1264
|
|
1087
1265
|
sos = butter(order, Wn, output='sos')
|
1266
|
+
sos = xp.asarray(sos, dtype=xp.float64)
|
1088
1267
|
w, h = freqz_sos(sos, worN=N)
|
1089
1268
|
xp_assert_close(w, w_mp, rtol=1e-12, atol=1e-14)
|
1090
1269
|
xp_assert_close(h, h_mp, rtol=1e-12, atol=1e-14)
|
1091
1270
|
|
1092
|
-
def test_fs_param(self):
|
1271
|
+
def test_fs_param(self, xp):
|
1093
1272
|
fs = 900
|
1094
|
-
sos =
|
1273
|
+
sos = xp.asarray(
|
1274
|
+
[[0.03934683014103762, 0.07869366028207524, 0.03934683014103762,
|
1095
1275
|
1.0, -0.37256600288916636, 0.0],
|
1096
1276
|
[1.0, 1.0, 0.0, 1.0, -0.9495739996946778, 0.45125966317124144]]
|
1277
|
+
)
|
1097
1278
|
|
1098
1279
|
# N = None, whole=False
|
1099
1280
|
w1, h1 = freqz_sos(sos, fs=fs)
|
1100
1281
|
w2, h2 = freqz_sos(sos)
|
1101
1282
|
xp_assert_close(h1, h2)
|
1102
|
-
xp_assert_close(w1,
|
1283
|
+
xp_assert_close(w1, xp.linspace(0, fs/2, 512, endpoint=False))
|
1103
1284
|
|
1104
1285
|
# N = None, whole=True
|
1105
1286
|
w1, h1 = freqz_sos(sos, whole=True, fs=fs)
|
1106
1287
|
w2, h2 = freqz_sos(sos, whole=True)
|
1107
1288
|
xp_assert_close(h1, h2, atol=1e-27)
|
1108
|
-
xp_assert_close(w1,
|
1289
|
+
xp_assert_close(w1, xp.linspace(0, fs, 512, endpoint=False))
|
1109
1290
|
|
1110
1291
|
# N = 5, whole=False
|
1111
1292
|
w1, h1 = freqz_sos(sos, 5, fs=fs)
|
1112
1293
|
w2, h2 = freqz_sos(sos, 5)
|
1113
1294
|
xp_assert_close(h1, h2)
|
1114
|
-
xp_assert_close(w1,
|
1295
|
+
xp_assert_close(w1, xp.linspace(0, fs/2, 5, endpoint=False))
|
1115
1296
|
|
1116
1297
|
# N = 5, whole=True
|
1117
1298
|
w1, h1 = freqz_sos(sos, 5, whole=True, fs=fs)
|
1118
1299
|
w2, h2 = freqz_sos(sos, 5, whole=True)
|
1119
1300
|
xp_assert_close(h1, h2)
|
1120
|
-
xp_assert_close(w1,
|
1301
|
+
xp_assert_close(w1, xp.linspace(0, fs, 5, endpoint=False))
|
1302
|
+
|
1303
|
+
@skip_xp_backends(np_only=True, reason="array-likes")
|
1304
|
+
def test_fs_param2(self, xp):
|
1305
|
+
fs = 900
|
1306
|
+
sos = xp.asarray(
|
1307
|
+
[[0.03934683014103762, 0.07869366028207524, 0.03934683014103762,
|
1308
|
+
1.0, -0.37256600288916636, 0.0],
|
1309
|
+
[1.0, 1.0, 0.0, 1.0, -0.9495739996946778, 0.45125966317124144]]
|
1310
|
+
)
|
1121
1311
|
|
1122
1312
|
# w is an array_like
|
1123
|
-
for w in ([123], (123,),
|
1124
|
-
|
1313
|
+
for w in ([123], (123,), xp.asarray([123]), (50, 123, 230),
|
1314
|
+
xp.asarray([50, 123, 230])):
|
1125
1315
|
w1, h1 = freqz_sos(sos, w, fs=fs)
|
1126
|
-
|
1316
|
+
w1, h1 = map(xp.asarray, (w1, h1))
|
1317
|
+
|
1318
|
+
w2, h2 = freqz_sos(sos, 2*pi*xp.asarray(w, dtype=sos.dtype)/fs)
|
1127
1319
|
xp_assert_close(h1, h2)
|
1128
1320
|
xp_assert_close(w, w1, check_dtype=False)
|
1129
1321
|
|
@@ -1157,77 +1349,94 @@ class Testfreqz_sos:
|
|
1157
1349
|
|
1158
1350
|
class TestFreqz_zpk:
|
1159
1351
|
|
1160
|
-
def test_ticket1441(self):
|
1352
|
+
def test_ticket1441(self, xp):
|
1161
1353
|
"""Regression test for ticket 1441."""
|
1162
1354
|
# Because freqz previously used arange instead of linspace,
|
1163
1355
|
# when N was large, it would return one more point than
|
1164
1356
|
# requested.
|
1165
1357
|
N = 100000
|
1166
|
-
w, h = freqz_zpk([0.5], [0.5], 1.0, worN=N)
|
1358
|
+
w, h = freqz_zpk(xp.asarray([0.5]), xp.asarray([0.5]), 1.0, worN=N)
|
1167
1359
|
assert w.shape == (N,)
|
1168
1360
|
|
1169
|
-
def test_basic(self):
|
1170
|
-
w, h = freqz_zpk([0.5], [0.5], 1.0, worN=8)
|
1171
|
-
assert_array_almost_equal(w,
|
1172
|
-
assert_array_almost_equal(h,
|
1361
|
+
def test_basic(self, xp):
|
1362
|
+
w, h = freqz_zpk(xp.asarray([0.5]), xp.asarray([0.5]), 1.0, worN=8)
|
1363
|
+
assert_array_almost_equal(w, xp.pi * xp.arange(8.0) / 8)
|
1364
|
+
assert_array_almost_equal(h, xp.ones(8))
|
1173
1365
|
|
1174
|
-
def test_basic_whole(self):
|
1175
|
-
w, h = freqz_zpk([0.5], [0.5], 1.0, worN=8, whole=True)
|
1176
|
-
assert_array_almost_equal(w, 2 *
|
1177
|
-
assert_array_almost_equal(h,
|
1366
|
+
def test_basic_whole(self, xp):
|
1367
|
+
w, h = freqz_zpk(xp.asarray([0.5]), xp.asarray([0.5]), 1.0, worN=8, whole=True)
|
1368
|
+
assert_array_almost_equal(w, 2 * xp.pi * xp.arange(8.0) / 8)
|
1369
|
+
assert_array_almost_equal(h, xp.ones(8))
|
1178
1370
|
|
1179
|
-
def test_vs_freqz(self):
|
1371
|
+
def test_vs_freqz(self, xp):
|
1180
1372
|
b, a = cheby1(4, 5, 0.5, analog=False, output='ba')
|
1181
1373
|
z, p, k = cheby1(4, 5, 0.5, analog=False, output='zpk')
|
1182
1374
|
|
1375
|
+
b, a = map(xp.asarray, (b, a)) # XXX convert cheby1
|
1376
|
+
z, p = map(xp.asarray, (z, p))
|
1377
|
+
|
1183
1378
|
w1, h1 = freqz(b, a)
|
1184
1379
|
w2, h2 = freqz_zpk(z, p, k)
|
1185
1380
|
xp_assert_close(w1, w2)
|
1186
1381
|
xp_assert_close(h1, h2, rtol=1e-6)
|
1187
1382
|
|
1188
|
-
def test_backward_compat(self):
|
1383
|
+
def test_backward_compat(self, xp):
|
1189
1384
|
# For backward compatibility, test if None act as a wrapper for default
|
1190
|
-
w1, h1 = freqz_zpk([0.5], [0.5], 1.0)
|
1191
|
-
w2, h2 = freqz_zpk([0.5], [0.5], 1.0, None)
|
1385
|
+
w1, h1 = freqz_zpk(xp.asarray([0.5]), xp.asarray([0.5]), 1.0)
|
1386
|
+
w2, h2 = freqz_zpk(xp.asarray([0.5]), xp.asarray([0.5]), 1.0, None)
|
1192
1387
|
assert_array_almost_equal(w1, w2)
|
1193
1388
|
assert_array_almost_equal(h1, h2)
|
1194
1389
|
|
1195
|
-
def test_fs_param(self):
|
1390
|
+
def test_fs_param(self, xp):
|
1196
1391
|
fs = 900
|
1197
|
-
z = [-1, -1, -1]
|
1198
|
-
p =
|
1199
|
-
|
1392
|
+
z = xp.asarray([-1, -1, -1.0])
|
1393
|
+
p = xp.asarray(
|
1394
|
+
[0.4747869998473389 + 0.4752230717749344j,
|
1395
|
+
0.37256600288916636,
|
1396
|
+
0.4747869998473389 - 0.4752230717749344j]
|
1397
|
+
)
|
1200
1398
|
k = 0.03934683014103762
|
1201
1399
|
|
1202
1400
|
# N = None, whole=False
|
1203
1401
|
w1, h1 = freqz_zpk(z, p, k, whole=False, fs=fs)
|
1204
1402
|
w2, h2 = freqz_zpk(z, p, k, whole=False)
|
1205
1403
|
xp_assert_close(h1, h2)
|
1206
|
-
xp_assert_close(w1,
|
1404
|
+
xp_assert_close(w1, xp.linspace(0, fs/2, 512, endpoint=False))
|
1207
1405
|
|
1208
1406
|
# N = None, whole=True
|
1209
1407
|
w1, h1 = freqz_zpk(z, p, k, whole=True, fs=fs)
|
1210
1408
|
w2, h2 = freqz_zpk(z, p, k, whole=True)
|
1211
1409
|
xp_assert_close(h1, h2)
|
1212
|
-
xp_assert_close(w1,
|
1410
|
+
xp_assert_close(w1, xp.linspace(0, fs, 512, endpoint=False))
|
1213
1411
|
|
1214
1412
|
# N = 5, whole=False
|
1215
1413
|
w1, h1 = freqz_zpk(z, p, k, 5, fs=fs)
|
1216
1414
|
w2, h2 = freqz_zpk(z, p, k, 5)
|
1217
1415
|
xp_assert_close(h1, h2)
|
1218
|
-
xp_assert_close(w1,
|
1416
|
+
xp_assert_close(w1, xp.linspace(0, fs/2, 5, endpoint=False))
|
1219
1417
|
|
1220
1418
|
# N = 5, whole=True
|
1221
1419
|
w1, h1 = freqz_zpk(z, p, k, 5, whole=True, fs=fs)
|
1222
1420
|
w2, h2 = freqz_zpk(z, p, k, 5, whole=True)
|
1223
1421
|
xp_assert_close(h1, h2)
|
1224
|
-
xp_assert_close(w1,
|
1422
|
+
xp_assert_close(w1, xp.linspace(0, fs, 5, endpoint=False))
|
1423
|
+
|
1424
|
+
@skip_xp_backends(np_only=True, reason="array_likes")
|
1425
|
+
def test_fs_param2(self, xp):
|
1426
|
+
fs = 900
|
1427
|
+
z = xp.asarray([-1, -1, -1.0])
|
1428
|
+
p = xp.asarray(
|
1429
|
+
[0.4747869998473389 + 0.4752230717749344j,
|
1430
|
+
0.37256600288916636,
|
1431
|
+
0.4747869998473389 - 0.4752230717749344j]
|
1432
|
+
)
|
1433
|
+
k = 0.03934683014103762
|
1225
1434
|
|
1226
1435
|
# w is an array_like
|
1227
|
-
for w in ([123], (123,),
|
1228
|
-
|
1436
|
+
for w in ([123], (123,), xp.asarray([123]), (50, 123, 230),
|
1437
|
+
xp.asarray([50, 123, 230])):
|
1229
1438
|
w1, h1 = freqz_zpk(z, p, k, w, fs=fs)
|
1230
|
-
w2, h2 = freqz_zpk(z, p, k, 2*pi*
|
1439
|
+
w2, h2 = freqz_zpk(z, p, k, 2*pi*xp.asarray(w)/fs)
|
1231
1440
|
xp_assert_close(h1, h2)
|
1232
1441
|
xp_assert_close(w, w1, check_dtype=False)
|
1233
1442
|
|
@@ -1253,7 +1462,7 @@ class TestFreqz_zpk:
|
|
1253
1462
|
|
1254
1463
|
def test_fs_validation(self):
|
1255
1464
|
with pytest.raises(ValueError, match="Sampling.*single scalar"):
|
1256
|
-
freqz_zpk([1.0], [1.0], [1.0], fs=np.array([10
|
1465
|
+
freqz_zpk([1.0], [1.0], [1.0], fs=np.array([10., 20]))
|
1257
1466
|
|
1258
1467
|
with pytest.raises(ValueError, match="Sampling.*be none."):
|
1259
1468
|
freqz_zpk([1.0], [1.0], [1.0], fs=None)
|
@@ -1320,62 +1529,134 @@ class TestNormalize:
|
|
1320
1529
|
|
1321
1530
|
class TestLp2lp:
|
1322
1531
|
|
1323
|
-
def test_basic(self):
|
1324
|
-
b = [1]
|
1325
|
-
a = [1,
|
1532
|
+
def test_basic(self, xp):
|
1533
|
+
b = xp.asarray([1])
|
1534
|
+
a = xp.asarray([1, math.sqrt(2), 1])
|
1326
1535
|
b_lp, a_lp = lp2lp(b, a, 0.38574256627112119)
|
1327
|
-
assert_array_almost_equal(b_lp, [0.1488], decimal=4)
|
1328
|
-
assert_array_almost_equal(a_lp, [1, 0.5455, 0.1488], decimal=4)
|
1536
|
+
assert_array_almost_equal(b_lp, xp.asarray([0.1488]), decimal=4)
|
1537
|
+
assert_array_almost_equal(a_lp, xp.asarray([1, 0.5455, 0.1488]), decimal=4)
|
1329
1538
|
|
1330
1539
|
|
1331
1540
|
class TestLp2hp:
|
1332
1541
|
|
1333
|
-
|
1334
|
-
|
1335
|
-
|
1336
|
-
|
1337
|
-
|
1338
|
-
|
1542
|
+
@skip_xp_backends(eager_only=True, reason="in-place item assignment")
|
1543
|
+
def test_basic(self, xp):
|
1544
|
+
b = xp.asarray([0.25059432325190018])
|
1545
|
+
a = xp.asarray(
|
1546
|
+
[1, 0.59724041654134863, 0.92834805757524175, 0.25059432325190018]
|
1547
|
+
)
|
1548
|
+
b_hp, a_hp = lp2hp(b, a, 2*math.pi*5000)
|
1549
|
+
xp_assert_close(b_hp, xp.asarray([1.0, 0, 0, 0]))
|
1550
|
+
xp_assert_close(
|
1551
|
+
a_hp, xp.asarray([1, 1.1638e5, 2.3522e9, 1.2373e14]), rtol=1e-4
|
1552
|
+
)
|
1339
1553
|
|
1340
1554
|
|
1341
1555
|
class TestLp2bp:
|
1342
1556
|
|
1343
|
-
|
1344
|
-
|
1345
|
-
|
1346
|
-
|
1347
|
-
|
1348
|
-
xp_assert_close(
|
1349
|
-
|
1557
|
+
@skip_xp_backends(eager_only=True, reason="in-place item assignment")
|
1558
|
+
def test_basic(self, xp):
|
1559
|
+
b = xp.asarray([1])
|
1560
|
+
a = xp.asarray([1, 2, 2, 1])
|
1561
|
+
b_bp, a_bp = lp2bp(b, a, 2*math.pi*4000, 2*math.pi*2000)
|
1562
|
+
xp_assert_close(b_bp, xp.asarray([1.9844e12, 0, 0, 0]), rtol=1e-6)
|
1563
|
+
xp_assert_close(
|
1564
|
+
a_bp,
|
1565
|
+
xp.asarray([1, 2.5133e4, 2.2108e9, 3.3735e13,
|
1566
|
+
1.3965e18, 1.0028e22, 2.5202e26]), rtol=1e-4
|
1567
|
+
)
|
1350
1568
|
|
1351
1569
|
|
1352
1570
|
class TestLp2bs:
|
1353
1571
|
|
1354
|
-
|
1355
|
-
|
1356
|
-
|
1572
|
+
@skip_xp_backends(eager_only=True, reason="in-place item assignment")
|
1573
|
+
def test_basic(self, xp):
|
1574
|
+
b = xp.asarray([1])
|
1575
|
+
a = xp.asarray([1, 1])
|
1357
1576
|
b_bs, a_bs = lp2bs(b, a, 0.41722257286366754, 0.18460575326152251)
|
1358
|
-
assert_array_almost_equal(b_bs, [1, 0, 0.17407], decimal=5)
|
1359
|
-
assert_array_almost_equal(a_bs, [1, 0.18461, 0.17407], decimal=5)
|
1577
|
+
assert_array_almost_equal(b_bs, xp.asarray([1, 0, 0.17407]), decimal=5)
|
1578
|
+
assert_array_almost_equal(a_bs, xp.asarray([1, 0.18461, 0.17407]), decimal=5)
|
1360
1579
|
|
1361
1580
|
|
1362
1581
|
class TestBilinear:
|
1582
|
+
"""Tests for function `signal.bilinear`. """
|
1583
|
+
|
1584
|
+
def test_exceptions(self):
|
1585
|
+
"""Raise all exceptions in `bilinear()`. """
|
1586
|
+
with pytest.raises(ValueError, match="Parameter a is not .*"):
|
1587
|
+
bilinear(1., np.array([[1, 2, 3]]))
|
1588
|
+
with pytest.raises(ValueError, match="Parameter b is not .*"):
|
1589
|
+
bilinear(np.ones((2,3)), 1. )
|
1363
1590
|
|
1364
1591
|
def test_basic(self):
|
1592
|
+
# reference output values computed with sympy
|
1365
1593
|
b = [0.14879732743343033]
|
1366
1594
|
a = [1, 0.54552236880522209, 0.14879732743343033]
|
1595
|
+
b_zref = [0.08782128175913713, 0.17564256351827426, 0.08782128175913713]
|
1596
|
+
a_zref = [1.0, -1.0047722097030667, 0.3560573367396151]
|
1597
|
+
|
1367
1598
|
b_z, a_z = bilinear(b, a, 0.5)
|
1368
|
-
|
1369
|
-
|
1370
|
-
|
1599
|
+
|
1600
|
+
assert_array_almost_equal_nulp(b_z, b_zref)
|
1601
|
+
assert_array_almost_equal_nulp(a_z, a_zref)
|
1371
1602
|
|
1372
1603
|
b = [1, 0, 0.17407467530697837]
|
1373
1604
|
a = [1, 0.18460575326152251, 0.17407467530697837]
|
1605
|
+
b_zref = [0.8641286432189045, -1.2157757001964216, 0.8641286432189045]
|
1606
|
+
a_zref = [1.0, -1.2157757001964216, 0.7282572864378091]
|
1607
|
+
|
1374
1608
|
b_z, a_z = bilinear(b, a, 0.5)
|
1375
|
-
|
1376
|
-
|
1377
|
-
|
1378
|
-
|
1609
|
+
|
1610
|
+
assert_array_almost_equal_nulp(b_z, b_zref)
|
1611
|
+
assert_array_almost_equal_nulp(a_z, a_zref)
|
1612
|
+
|
1613
|
+
|
1614
|
+
def test_ignore_leading_zeros(self):
|
1615
|
+
# regression for gh-6606
|
1616
|
+
# results shouldn't change when leading zeros are added to
|
1617
|
+
# input numerator or denominator
|
1618
|
+
b = [0.14879732743343033]
|
1619
|
+
a = [1, 0.54552236880522209, 0.14879732743343033]
|
1620
|
+
|
1621
|
+
b_zref = [0.08782128175913713, 0.17564256351827426, 0.08782128175913713]
|
1622
|
+
a_zref = [1.0, -1.0047722097030667, 0.3560573367396151]
|
1623
|
+
|
1624
|
+
for lzn, lzd in product(range(4), range(4)):
|
1625
|
+
b_z, a_z = bilinear(np.pad(b, (lzn, 0)),
|
1626
|
+
np.pad(a, (lzd, 0)),
|
1627
|
+
0.5)
|
1628
|
+
assert_array_almost_equal_nulp(b_z, b_zref)
|
1629
|
+
assert_array_almost_equal_nulp(a_z, a_zref)
|
1630
|
+
|
1631
|
+
|
1632
|
+
def test_complex(self):
|
1633
|
+
# reference output values computed with sympy
|
1634
|
+
# this is an elliptical filter, 5Hz width, centered at +50Hz:
|
1635
|
+
# z, p, k = signal.ellip(2, 0.5, 20, 2*np.pi*5/2, output='zpk', analog=True)
|
1636
|
+
# z = z.astype(complex) + 2j * np.pi * 50
|
1637
|
+
# p = p.astype(complex) + 2j * np.pi * 50
|
1638
|
+
# b, a = signal.zpk2tf(z, p, k)
|
1639
|
+
b = [(0.09999999999999991+0j),
|
1640
|
+
-62.831853071795805j,
|
1641
|
+
(-9505.857007071314+0j)]
|
1642
|
+
a = [(1+0j),
|
1643
|
+
(21.09511000343942-628.3185307179587j),
|
1644
|
+
(-98310.74322875646-6627.2242613473845j)]
|
1645
|
+
# sample frequency
|
1646
|
+
fs = 1000
|
1647
|
+
b_zref = [(0.09905575106715676-0.00013441423112828688j),
|
1648
|
+
(-0.18834281923181084-0.06032810039049478j),
|
1649
|
+
(0.08054306669414343+0.05766172295523972j)]
|
1650
|
+
a_zref = [(1+0j),
|
1651
|
+
(-1.8839476369292854-0.606808151331815j),
|
1652
|
+
(0.7954687330018285+0.5717459398142481j)]
|
1653
|
+
|
1654
|
+
b_z, a_z = bilinear(b, a, fs)
|
1655
|
+
|
1656
|
+
# the 3 ulp difference determined from testing
|
1657
|
+
assert_array_almost_equal_nulp(b_z, b_zref, 3)
|
1658
|
+
assert_array_almost_equal_nulp(a_z, a_zref, 3)
|
1659
|
+
|
1379
1660
|
|
1380
1661
|
def test_fs_validation(self):
|
1381
1662
|
b = [0.14879732743343033]
|
@@ -1389,23 +1670,30 @@ class TestBilinear:
|
|
1389
1670
|
|
1390
1671
|
class TestLp2lp_zpk:
|
1391
1672
|
|
1392
|
-
|
1393
|
-
|
1394
|
-
|
1673
|
+
@xfail_xp_backends(
|
1674
|
+
'dask.array', reason='https://github.com/dask/dask/issues/11883'
|
1675
|
+
)
|
1676
|
+
def test_basic(self, xp):
|
1677
|
+
z = xp.asarray([])
|
1678
|
+
p = xp.asarray([(-1+1j) / math.sqrt(2), (-1-1j) / math.sqrt(2)])
|
1395
1679
|
k = 1
|
1396
1680
|
z_lp, p_lp, k_lp = lp2lp_zpk(z, p, k, 5)
|
1397
|
-
xp_assert_equal(z_lp, [])
|
1398
|
-
xp_assert_close(
|
1399
|
-
|
1681
|
+
xp_assert_equal(z_lp, xp.asarray([]))
|
1682
|
+
xp_assert_close(_sort_cmplx(p_lp, xp=xp), _sort_cmplx(p, xp=xp) * 5)
|
1683
|
+
assert k_lp == 25.
|
1400
1684
|
|
1401
1685
|
# Pseudo-Chebyshev with both poles and zeros
|
1402
|
-
z = [-2j, +2j]
|
1403
|
-
p = [-0.75, -0.5-0.5j, -0.5+0.5j]
|
1686
|
+
z = xp.asarray([-2j, +2j])
|
1687
|
+
p = xp.asarray([-0.75, -0.5-0.5j, -0.5+0.5j])
|
1404
1688
|
k = 3
|
1405
1689
|
z_lp, p_lp, k_lp = lp2lp_zpk(z, p, k, 20)
|
1406
|
-
xp_assert_close(
|
1407
|
-
|
1408
|
-
|
1690
|
+
xp_assert_close(
|
1691
|
+
_sort_cmplx(z_lp, xp=xp), _sort_cmplx([-40j, +40j], xp=xp)
|
1692
|
+
)
|
1693
|
+
xp_assert_close(
|
1694
|
+
_sort_cmplx(p_lp, xp=xp), _sort_cmplx([-15, -10-10j, -10+10j], xp=xp)
|
1695
|
+
)
|
1696
|
+
assert k_lp == 60.
|
1409
1697
|
|
1410
1698
|
def test_fs_validation(self):
|
1411
1699
|
z = [-2j, +2j]
|
@@ -1421,80 +1709,115 @@ class TestLp2lp_zpk:
|
|
1421
1709
|
|
1422
1710
|
class TestLp2hp_zpk:
|
1423
1711
|
|
1424
|
-
|
1425
|
-
|
1426
|
-
|
1712
|
+
@xfail_xp_backends(
|
1713
|
+
'dask.array', reason='https://github.com/dask/dask/issues/11883'
|
1714
|
+
)
|
1715
|
+
def test_basic(self, xp):
|
1716
|
+
z = xp.asarray([])
|
1717
|
+
p = xp.asarray([(-1+1j) / math.sqrt(2), (-1-1j) / math.sqrt(2)])
|
1427
1718
|
k = 1
|
1428
1719
|
|
1429
1720
|
z_hp, p_hp, k_hp = lp2hp_zpk(z, p, k, 5)
|
1430
|
-
xp_assert_equal(z_hp,
|
1431
|
-
xp_assert_close(
|
1432
|
-
|
1721
|
+
xp_assert_equal(z_hp, xp.asarray([0.0, 0.0], dtype=z_hp.dtype))
|
1722
|
+
xp_assert_close(_sort_cmplx(p_hp, xp=xp), _sort_cmplx(p, xp=xp) * 5)
|
1723
|
+
assert math.isclose(k_hp, 1.0, rel_tol=4e-7)
|
1433
1724
|
|
1434
|
-
z = [-2j, +2j]
|
1435
|
-
p = [-0.75, -0.5-0.5j, -0.5+0.5j]
|
1725
|
+
z = xp.asarray([-2j, +2j])
|
1726
|
+
p = xp.asarray([-0.75, -0.5-0.5j, -0.5+0.5j])
|
1436
1727
|
k = 3
|
1437
1728
|
z_hp, p_hp, k_hp = lp2hp_zpk(z, p, k, 6)
|
1438
|
-
xp_assert_close(
|
1439
|
-
|
1440
|
-
|
1729
|
+
xp_assert_close(
|
1730
|
+
_sort_cmplx(z_hp, xp=xp), _sort_cmplx([-3j, 0, +3j], xp=xp)
|
1731
|
+
)
|
1732
|
+
xp_assert_close(
|
1733
|
+
_sort_cmplx(p_hp, xp=xp), _sort_cmplx([-8, -6-6j, -6+6j], xp=xp)
|
1734
|
+
)
|
1735
|
+
assert k_hp == 32.0
|
1441
1736
|
|
1442
1737
|
|
1443
1738
|
class TestLp2bp_zpk:
|
1444
1739
|
|
1445
|
-
|
1446
|
-
|
1447
|
-
|
1740
|
+
@xfail_xp_backends(
|
1741
|
+
'dask.array', reason='https://github.com/dask/dask/issues/11883'
|
1742
|
+
)
|
1743
|
+
def test_basic(self, xp):
|
1744
|
+
z = xp.asarray([-2j, +2j])
|
1745
|
+
p = xp.asarray([-0.75, -0.5-0.5j, -0.5+0.5j])
|
1448
1746
|
k = 3
|
1449
1747
|
z_bp, p_bp, k_bp = lp2bp_zpk(z, p, k, 15, 8)
|
1450
|
-
xp_assert_close(
|
1451
|
-
|
1452
|
-
|
1453
|
-
|
1454
|
-
|
1455
|
-
|
1456
|
-
|
1457
|
-
|
1748
|
+
xp_assert_close(
|
1749
|
+
_sort_cmplx(z_bp, xp=xp),
|
1750
|
+
_sort_cmplx([-25j, -9j, 0, +9j, +25j], xp=xp), check_dtype=False
|
1751
|
+
)
|
1752
|
+
xp_assert_close(
|
1753
|
+
_sort_cmplx(p_bp, xp=xp),
|
1754
|
+
_sort_cmplx(
|
1755
|
+
[-3 + 6j*math.sqrt(6), -3 - 6j*math.sqrt(6),
|
1756
|
+
+2j + cmath.sqrt(-8j - 225) - 2, -2j + cmath.sqrt(+8j - 225) - 2,
|
1757
|
+
+2j - cmath.sqrt(-8j - 225) - 2, -2j - cmath.sqrt(+8j - 225) - 2
|
1758
|
+
], xp=xp
|
1759
|
+
), check_dtype=False
|
1760
|
+
)
|
1761
|
+
assert math.isclose(k_bp, 24.0)
|
1458
1762
|
|
1459
1763
|
|
1460
1764
|
class TestLp2bs_zpk:
|
1461
1765
|
|
1462
|
-
|
1463
|
-
|
1464
|
-
|
1766
|
+
@xfail_xp_backends(
|
1767
|
+
'dask.array', reason='https://github.com/dask/dask/issues/11883'
|
1768
|
+
)
|
1769
|
+
def test_basic(self, xp):
|
1770
|
+
z = xp.asarray([-2j, +2j])
|
1771
|
+
p = xp.asarray([-0.75, -0.5-0.5j, -0.5+0.5j])
|
1465
1772
|
k = 3
|
1466
1773
|
|
1467
1774
|
z_bs, p_bs, k_bs = lp2bs_zpk(z, p, k, 35, 12)
|
1468
1775
|
|
1469
|
-
xp_assert_close(
|
1470
|
-
|
1471
|
-
|
1472
|
-
|
1473
|
-
|
1474
|
-
|
1475
|
-
|
1476
|
-
|
1477
|
-
|
1478
|
-
|
1479
|
-
|
1480
|
-
|
1776
|
+
xp_assert_close(
|
1777
|
+
_sort_cmplx(z_bs, xp=xp),
|
1778
|
+
_sort_cmplx([+35j, -35j,
|
1779
|
+
+3j + math.sqrt(1234)*1j,
|
1780
|
+
-3j + math.sqrt(1234)*1j,
|
1781
|
+
+3j - math.sqrt(1234)*1j,
|
1782
|
+
-3j - math.sqrt(1234)*1j], xp=xp), check_dtype=False
|
1783
|
+
)
|
1784
|
+
xp_assert_close(
|
1785
|
+
_sort_cmplx(p_bs, xp=xp),
|
1786
|
+
_sort_cmplx([+3j*math.sqrt(129) - 8,
|
1787
|
+
-3j*math.sqrt(129) - 8,
|
1788
|
+
(-6 + 6j) - cmath.sqrt(-1225 - 72j),
|
1789
|
+
(-6 - 6j) - cmath.sqrt(-1225 + 72j),
|
1790
|
+
(-6 + 6j) + cmath.sqrt(-1225 - 72j),
|
1791
|
+
(-6 - 6j) + cmath.sqrt(-1225 + 72j), ], xp=xp),
|
1792
|
+
check_dtype=False
|
1793
|
+
)
|
1794
|
+
assert math.isclose(k_bs, 32.0)
|
1481
1795
|
|
1482
1796
|
|
1483
1797
|
class TestBilinear_zpk:
|
1484
1798
|
|
1485
|
-
|
1486
|
-
|
1487
|
-
|
1799
|
+
@xfail_xp_backends(
|
1800
|
+
'dask.array', reason='https://github.com/dask/dask/issues/11883'
|
1801
|
+
)
|
1802
|
+
def test_basic(self, xp):
|
1803
|
+
z = xp.asarray([-2j, +2j])
|
1804
|
+
p = xp.asarray([-0.75, -0.5-0.5j, -0.5+0.5j])
|
1488
1805
|
k = 3
|
1489
1806
|
|
1490
1807
|
z_d, p_d, k_d = bilinear_zpk(z, p, k, 10)
|
1491
1808
|
|
1492
|
-
xp_assert_close(
|
1493
|
-
|
1494
|
-
|
1495
|
-
|
1496
|
-
|
1497
|
-
|
1809
|
+
xp_assert_close(
|
1810
|
+
_sort_cmplx(z_d, xp=xp),
|
1811
|
+
_sort_cmplx([(20-2j) / (20+2j), (20+2j) / (20-2j), -1], xp=xp)
|
1812
|
+
)
|
1813
|
+
xp_assert_close(
|
1814
|
+
_sort_cmplx(p_d, xp=xp),
|
1815
|
+
_sort_cmplx(
|
1816
|
+
[77/83, (1j/2 + 39/2) / (41/2 - 1j/2), (39/2 - 1j/2) / (1j/2 + 41/2)],
|
1817
|
+
xp=xp
|
1818
|
+
)
|
1819
|
+
)
|
1820
|
+
assert math.isclose(k_d, 9696/69803, rel_tol=4e-7)
|
1498
1821
|
|
1499
1822
|
|
1500
1823
|
class TestPrototypeType:
|
@@ -4400,86 +4723,3 @@ class TestGammatone:
|
|
4400
4723
|
def test_fs_validation(self):
|
4401
4724
|
with pytest.raises(ValueError, match="Sampling.*single scalar"):
|
4402
4725
|
gammatone(440, 'iir', fs=np.array([10, 20]))
|
4403
|
-
|
4404
|
-
|
4405
|
-
class TestOrderFilter:
|
4406
|
-
def test_doc_example(self):
|
4407
|
-
x = np.arange(25).reshape(5, 5)
|
4408
|
-
domain = np.identity(3)
|
4409
|
-
|
4410
|
-
# minimum of elements 1,3,9 (zero-padded) on phone pad
|
4411
|
-
# 7,5,3 on numpad
|
4412
|
-
expected = np.array(
|
4413
|
-
[[0., 0., 0., 0., 0.],
|
4414
|
-
[0., 0., 1., 2., 0.],
|
4415
|
-
[0., 5., 6., 7., 0.],
|
4416
|
-
[0., 10., 11., 12., 0.],
|
4417
|
-
[0., 0., 0., 0., 0.]],
|
4418
|
-
)
|
4419
|
-
xp_assert_close(order_filter(x, domain, 0), expected, check_dtype=False)
|
4420
|
-
|
4421
|
-
# maximum of elements 1,3,9 (zero-padded) on phone pad
|
4422
|
-
# 7,5,3 on numpad
|
4423
|
-
expected = np.array(
|
4424
|
-
[[6., 7., 8., 9., 4.],
|
4425
|
-
[11., 12., 13., 14., 9.],
|
4426
|
-
[16., 17., 18., 19., 14.],
|
4427
|
-
[21., 22., 23., 24., 19.],
|
4428
|
-
[20., 21., 22., 23., 24.]],
|
4429
|
-
)
|
4430
|
-
xp_assert_close(order_filter(x, domain, 2), expected, check_dtype=False)
|
4431
|
-
|
4432
|
-
# and, just to complete the set, median of zero-padded elements
|
4433
|
-
expected = np.array(
|
4434
|
-
[[0, 1, 2, 3, 0],
|
4435
|
-
[5, 6, 7, 8, 3],
|
4436
|
-
[10, 11, 12, 13, 8],
|
4437
|
-
[15, 16, 17, 18, 13],
|
4438
|
-
[0, 15, 16, 17, 18]],
|
4439
|
-
)
|
4440
|
-
xp_assert_close(order_filter(x, domain, 1), expected)
|
4441
|
-
|
4442
|
-
def test_medfilt_order_filter(self):
|
4443
|
-
x = np.arange(25).reshape(5, 5)
|
4444
|
-
|
4445
|
-
# median of zero-padded elements 1,5,9 on phone pad
|
4446
|
-
# 7,5,3 on numpad
|
4447
|
-
expected = np.array(
|
4448
|
-
[[0, 1, 2, 3, 0],
|
4449
|
-
[1, 6, 7, 8, 4],
|
4450
|
-
[6, 11, 12, 13, 9],
|
4451
|
-
[11, 16, 17, 18, 14],
|
4452
|
-
[0, 16, 17, 18, 0]],
|
4453
|
-
)
|
4454
|
-
xp_assert_close(medfilt(x, 3), expected)
|
4455
|
-
|
4456
|
-
xp_assert_close(
|
4457
|
-
order_filter(x, np.ones((3, 3)), 4),
|
4458
|
-
expected
|
4459
|
-
)
|
4460
|
-
|
4461
|
-
def test_order_filter_asymmetric(self):
|
4462
|
-
x = np.arange(25).reshape(5, 5)
|
4463
|
-
domain = np.array(
|
4464
|
-
[[1, 1, 0],
|
4465
|
-
[0, 1, 0],
|
4466
|
-
[0, 0, 0]],
|
4467
|
-
)
|
4468
|
-
|
4469
|
-
expected = np.array(
|
4470
|
-
[[0, 0, 0, 0, 0],
|
4471
|
-
[0, 0, 1, 2, 3],
|
4472
|
-
[0, 5, 6, 7, 8],
|
4473
|
-
[0, 10, 11, 12, 13],
|
4474
|
-
[0, 15, 16, 17, 18]]
|
4475
|
-
)
|
4476
|
-
xp_assert_close(order_filter(x, domain, 0), expected)
|
4477
|
-
|
4478
|
-
expected = np.array(
|
4479
|
-
[[0, 0, 0, 0, 0],
|
4480
|
-
[0, 1, 2, 3, 4],
|
4481
|
-
[5, 6, 7, 8, 9],
|
4482
|
-
[10, 11, 12, 13, 14],
|
4483
|
-
[15, 16, 17, 18, 19]]
|
4484
|
-
)
|
4485
|
-
xp_assert_close(order_filter(x, domain, 1), expected)
|