Upload folder using huggingface_hub (part 18)
Browse filesThis view is limited to 50 files because it contains too many changes. See raw diff
- .gitattributes +78 -0
- venv/lib/python3.12/site-packages/scipy-1.18.0.dist-info/INSTALLER +1 -0
- venv/lib/python3.12/site-packages/scipy-1.18.0.dist-info/LICENSE.txt +937 -0
- venv/lib/python3.12/site-packages/scipy-1.18.0.dist-info/METADATA +1091 -0
- venv/lib/python3.12/site-packages/scipy-1.18.0.dist-info/RECORD +0 -0
- venv/lib/python3.12/site-packages/scipy-1.18.0.dist-info/WHEEL +6 -0
- venv/lib/python3.12/site-packages/scipy-1.18.0.dist-info/sboms/auditwheel.cdx.json +1 -0
- venv/lib/python3.12/site-packages/scipy.libs/libgfortran-040039e1-0352e75f.so.5.0.0 +3 -0
- venv/lib/python3.12/site-packages/scipy.libs/libgfortran-83c28eba.so.5.0.0 +3 -0
- venv/lib/python3.12/site-packages/scipy.libs/libquadmath-2284e583.so.0.0.0 +3 -0
- venv/lib/python3.12/site-packages/scipy.libs/libquadmath-96973f99-934c22de.so.0.0.0 +3 -0
- venv/lib/python3.12/site-packages/scipy.libs/libscipy_openblas-5f890258.so +3 -0
- venv/lib/python3.12/site-packages/scipy/signal/__pycache__/_filter_design.cpython-312.pyc +3 -0
- venv/lib/python3.12/site-packages/scipy/signal/__pycache__/_fir_filter_design.cpython-312.pyc +0 -0
- venv/lib/python3.12/site-packages/scipy/signal/__pycache__/_lti_conversion.cpython-312.pyc +0 -0
- venv/lib/python3.12/site-packages/scipy/signal/__pycache__/_ltisys.cpython-312.pyc +3 -0
- venv/lib/python3.12/site-packages/scipy/signal/__pycache__/_max_len_seq.cpython-312.pyc +0 -0
- venv/lib/python3.12/site-packages/scipy/signal/__pycache__/_peak_finding.cpython-312.pyc +0 -0
- venv/lib/python3.12/site-packages/scipy/signal/__pycache__/_polyutils.cpython-312.pyc +0 -0
- venv/lib/python3.12/site-packages/scipy/signal/__pycache__/_savitzky_golay.cpython-312.pyc +0 -0
- venv/lib/python3.12/site-packages/scipy/signal/__pycache__/_short_time_fft.cpython-312.pyc +3 -0
- venv/lib/python3.12/site-packages/scipy/signal/__pycache__/_signal_api.cpython-312.pyc +0 -0
- venv/lib/python3.12/site-packages/scipy/signal/__pycache__/_signaltools.cpython-312.pyc +3 -0
- venv/lib/python3.12/site-packages/scipy/signal/__pycache__/_spectral_py.cpython-312.pyc +3 -0
- venv/lib/python3.12/site-packages/scipy/signal/__pycache__/_spline_filters.cpython-312.pyc +0 -0
- venv/lib/python3.12/site-packages/scipy/signal/__pycache__/_support_alternative_backends.cpython-312.pyc +0 -0
- venv/lib/python3.12/site-packages/scipy/signal/__pycache__/_upfirdn.cpython-312.pyc +0 -0
- venv/lib/python3.12/site-packages/scipy/signal/__pycache__/_waveforms.cpython-312.pyc +0 -0
- venv/lib/python3.12/site-packages/scipy/signal/__pycache__/_wavelets.cpython-312.pyc +0 -0
- venv/lib/python3.12/site-packages/scipy/signal/__pycache__/_whittaker.cpython-312.pyc +0 -0
- venv/lib/python3.12/site-packages/scipy/signal/__pycache__/bsplines.cpython-312.pyc +0 -0
- venv/lib/python3.12/site-packages/scipy/signal/__pycache__/filter_design.cpython-312.pyc +0 -0
- venv/lib/python3.12/site-packages/scipy/signal/__pycache__/fir_filter_design.cpython-312.pyc +0 -0
- venv/lib/python3.12/site-packages/scipy/signal/__pycache__/lti_conversion.cpython-312.pyc +0 -0
- venv/lib/python3.12/site-packages/scipy/signal/__pycache__/ltisys.cpython-312.pyc +0 -0
- venv/lib/python3.12/site-packages/scipy/signal/__pycache__/signaltools.cpython-312.pyc +0 -0
- venv/lib/python3.12/site-packages/scipy/signal/__pycache__/spectral.cpython-312.pyc +0 -0
- venv/lib/python3.12/site-packages/scipy/signal/__pycache__/spline.cpython-312.pyc +0 -0
- venv/lib/python3.12/site-packages/scipy/signal/__pycache__/waveforms.cpython-312.pyc +0 -0
- venv/lib/python3.12/site-packages/scipy/signal/__pycache__/wavelets.cpython-312.pyc +0 -0
- venv/lib/python3.12/site-packages/scipy/signal/_arraytools.py +264 -0
- venv/lib/python3.12/site-packages/scipy/signal/_czt.py +580 -0
- venv/lib/python3.12/site-packages/scipy/signal/_delegators.py +573 -0
- venv/lib/python3.12/site-packages/scipy/signal/_filter_design.py +0 -0
- venv/lib/python3.12/site-packages/scipy/signal/_fir_filter_design.py +1553 -0
- venv/lib/python3.12/site-packages/scipy/signal/_lti_conversion.py +583 -0
- venv/lib/python3.12/site-packages/scipy/signal/_ltisys.py +0 -0
- venv/lib/python3.12/site-packages/scipy/signal/_max_len_seq.py +139 -0
- venv/lib/python3.12/site-packages/scipy/signal/_max_len_seq_inner.cpython-312-x86_64-linux-gnu.so +0 -0
- venv/lib/python3.12/site-packages/scipy/signal/_peak_finding.py +1307 -0
.gitattributes
CHANGED
|
@@ -302,3 +302,81 @@ venv/lib/python3.12/site-packages/scipy/optimize/_trlib/_trlib.cpython-312-x86_6
|
|
| 302 |
venv/lib/python3.12/site-packages/scipy/optimize/cython_optimize/_zeros.cpython-312-x86_64-linux-gnu.so filter=lfs diff=lfs merge=lfs -text
|
| 303 |
venv/lib/python3.12/site-packages/scipy/optimize/tests/__pycache__/test_linprog.cpython-312.pyc filter=lfs diff=lfs merge=lfs -text
|
| 304 |
venv/lib/python3.12/site-packages/scipy/optimize/tests/__pycache__/test_optimize.cpython-312.pyc filter=lfs diff=lfs merge=lfs -text
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 302 |
venv/lib/python3.12/site-packages/scipy/optimize/cython_optimize/_zeros.cpython-312-x86_64-linux-gnu.so filter=lfs diff=lfs merge=lfs -text
|
| 303 |
venv/lib/python3.12/site-packages/scipy/optimize/tests/__pycache__/test_linprog.cpython-312.pyc filter=lfs diff=lfs merge=lfs -text
|
| 304 |
venv/lib/python3.12/site-packages/scipy/optimize/tests/__pycache__/test_optimize.cpython-312.pyc filter=lfs diff=lfs merge=lfs -text
|
| 305 |
+
venv/lib/python3.12/site-packages/scipy/signal/__pycache__/_filter_design.cpython-312.pyc filter=lfs diff=lfs merge=lfs -text
|
| 306 |
+
venv/lib/python3.12/site-packages/scipy/signal/__pycache__/_ltisys.cpython-312.pyc filter=lfs diff=lfs merge=lfs -text
|
| 307 |
+
venv/lib/python3.12/site-packages/scipy/signal/__pycache__/_short_time_fft.cpython-312.pyc filter=lfs diff=lfs merge=lfs -text
|
| 308 |
+
venv/lib/python3.12/site-packages/scipy/signal/__pycache__/_signaltools.cpython-312.pyc filter=lfs diff=lfs merge=lfs -text
|
| 309 |
+
venv/lib/python3.12/site-packages/scipy/signal/__pycache__/_spectral_py.cpython-312.pyc filter=lfs diff=lfs merge=lfs -text
|
| 310 |
+
venv/lib/python3.12/site-packages/scipy/signal/_peak_finding_utils.cpython-312-x86_64-linux-gnu.so filter=lfs diff=lfs merge=lfs -text
|
| 311 |
+
venv/lib/python3.12/site-packages/scipy/signal/_sigtools.cpython-312-x86_64-linux-gnu.so filter=lfs diff=lfs merge=lfs -text
|
| 312 |
+
venv/lib/python3.12/site-packages/scipy/signal/_sosfilt.cpython-312-x86_64-linux-gnu.so filter=lfs diff=lfs merge=lfs -text
|
| 313 |
+
venv/lib/python3.12/site-packages/scipy/signal/_upfirdn_apply.cpython-312-x86_64-linux-gnu.so filter=lfs diff=lfs merge=lfs -text
|
| 314 |
+
venv/lib/python3.12/site-packages/scipy/signal/tests/__pycache__/test_filter_design.cpython-312.pyc filter=lfs diff=lfs merge=lfs -text
|
| 315 |
+
venv/lib/python3.12/site-packages/scipy/signal/tests/__pycache__/test_signaltools.cpython-312.pyc filter=lfs diff=lfs merge=lfs -text
|
| 316 |
+
venv/lib/python3.12/site-packages/scipy/signal/tests/__pycache__/test_spectral.cpython-312.pyc filter=lfs diff=lfs merge=lfs -text
|
| 317 |
+
venv/lib/python3.12/site-packages/scipy/signal/windows/__pycache__/_windows.cpython-312.pyc filter=lfs diff=lfs merge=lfs -text
|
| 318 |
+
venv/lib/python3.12/site-packages/scipy/sparse/_csparsetools.cpython-312-x86_64-linux-gnu.so filter=lfs diff=lfs merge=lfs -text
|
| 319 |
+
venv/lib/python3.12/site-packages/scipy/sparse/_sparsetools.cpython-312-x86_64-linux-gnu.so filter=lfs diff=lfs merge=lfs -text
|
| 320 |
+
venv/lib/python3.12/site-packages/scipy/sparse/csgraph/_flow.cpython-312-x86_64-linux-gnu.so filter=lfs diff=lfs merge=lfs -text
|
| 321 |
+
venv/lib/python3.12/site-packages/scipy/sparse/csgraph/_matching.cpython-312-x86_64-linux-gnu.so filter=lfs diff=lfs merge=lfs -text
|
| 322 |
+
venv/lib/python3.12/site-packages/scipy/sparse/csgraph/_reordering.cpython-312-x86_64-linux-gnu.so filter=lfs diff=lfs merge=lfs -text
|
| 323 |
+
venv/lib/python3.12/site-packages/scipy/sparse/csgraph/_shortest_path.cpython-312-x86_64-linux-gnu.so filter=lfs diff=lfs merge=lfs -text
|
| 324 |
+
venv/lib/python3.12/site-packages/scipy/sparse/csgraph/_tools.cpython-312-x86_64-linux-gnu.so filter=lfs diff=lfs merge=lfs -text
|
| 325 |
+
venv/lib/python3.12/site-packages/scipy/sparse/csgraph/_traversal.cpython-312-x86_64-linux-gnu.so filter=lfs diff=lfs merge=lfs -text
|
| 326 |
+
venv/lib/python3.12/site-packages/scipy/sparse/linalg/_dsolve/_superlu.cpython-312-x86_64-linux-gnu.so filter=lfs diff=lfs merge=lfs -text
|
| 327 |
+
venv/lib/python3.12/site-packages/scipy/sparse/linalg/_eigen/arpack/_arpacklib.cpython-312-x86_64-linux-gnu.so filter=lfs diff=lfs merge=lfs -text
|
| 328 |
+
venv/lib/python3.12/site-packages/scipy/sparse/linalg/_propack.cpython-312-x86_64-linux-gnu.so filter=lfs diff=lfs merge=lfs -text
|
| 329 |
+
venv/lib/python3.12/site-packages/scipy/sparse/tests/__pycache__/test_base.cpython-312.pyc filter=lfs diff=lfs merge=lfs -text
|
| 330 |
+
venv/lib/python3.12/site-packages/scipy/spatial/__pycache__/distance.cpython-312.pyc filter=lfs diff=lfs merge=lfs -text
|
| 331 |
+
venv/lib/python3.12/site-packages/scipy/spatial/_ckdtree.cpython-312-x86_64-linux-gnu.so filter=lfs diff=lfs merge=lfs -text
|
| 332 |
+
venv/lib/python3.12/site-packages/scipy/spatial/_distance_pybind.cpython-312-x86_64-linux-gnu.so filter=lfs diff=lfs merge=lfs -text
|
| 333 |
+
venv/lib/python3.12/site-packages/scipy/spatial/_distance_wrap.cpython-312-x86_64-linux-gnu.so filter=lfs diff=lfs merge=lfs -text
|
| 334 |
+
venv/lib/python3.12/site-packages/scipy/spatial/_qhull.cpython-312-x86_64-linux-gnu.so filter=lfs diff=lfs merge=lfs -text
|
| 335 |
+
venv/lib/python3.12/site-packages/scipy/spatial/tests/__pycache__/test_distance.cpython-312.pyc filter=lfs diff=lfs merge=lfs -text
|
| 336 |
+
venv/lib/python3.12/site-packages/scipy/spatial/tests/__pycache__/test_kdtree.cpython-312.pyc filter=lfs diff=lfs merge=lfs -text
|
| 337 |
+
venv/lib/python3.12/site-packages/scipy/spatial/transform/__pycache__/_rotation.cpython-312.pyc filter=lfs diff=lfs merge=lfs -text
|
| 338 |
+
venv/lib/python3.12/site-packages/scipy/spatial/transform/_rigid_transform_cy.cpython-312-x86_64-linux-gnu.so filter=lfs diff=lfs merge=lfs -text
|
| 339 |
+
venv/lib/python3.12/site-packages/scipy/spatial/transform/_rotation_cy.cpython-312-x86_64-linux-gnu.so filter=lfs diff=lfs merge=lfs -text
|
| 340 |
+
venv/lib/python3.12/site-packages/scipy/spatial/transform/tests/__pycache__/test_rotation.cpython-312.pyc filter=lfs diff=lfs merge=lfs -text
|
| 341 |
+
venv/lib/python3.12/site-packages/scipy/special/__pycache__/_add_newdocs.cpython-312.pyc filter=lfs diff=lfs merge=lfs -text
|
| 342 |
+
venv/lib/python3.12/site-packages/scipy/special/__pycache__/_basic.cpython-312.pyc filter=lfs diff=lfs merge=lfs -text
|
| 343 |
+
venv/lib/python3.12/site-packages/scipy/special/_ellip_harm_2.cpython-312-x86_64-linux-gnu.so filter=lfs diff=lfs merge=lfs -text
|
| 344 |
+
venv/lib/python3.12/site-packages/scipy/special/_gufuncs.cpython-312-x86_64-linux-gnu.so filter=lfs diff=lfs merge=lfs -text
|
| 345 |
+
venv/lib/python3.12/site-packages/scipy/special/_specfun.cpython-312-x86_64-linux-gnu.so filter=lfs diff=lfs merge=lfs -text
|
| 346 |
+
venv/lib/python3.12/site-packages/scipy/special/_special_ufuncs.cpython-312-x86_64-linux-gnu.so filter=lfs diff=lfs merge=lfs -text
|
| 347 |
+
venv/lib/python3.12/site-packages/scipy/special/_ufuncs.cpython-312-x86_64-linux-gnu.so filter=lfs diff=lfs merge=lfs -text
|
| 348 |
+
venv/lib/python3.12/site-packages/scipy/special/_ufuncs_cxx.cpython-312-x86_64-linux-gnu.so filter=lfs diff=lfs merge=lfs -text
|
| 349 |
+
venv/lib/python3.12/site-packages/scipy/special/cython_special.cpython-312-x86_64-linux-gnu.so filter=lfs diff=lfs merge=lfs -text
|
| 350 |
+
venv/lib/python3.12/site-packages/scipy/special/tests/__pycache__/test_basic.cpython-312.pyc filter=lfs diff=lfs merge=lfs -text
|
| 351 |
+
venv/lib/python3.12/site-packages/scipy/special/tests/__pycache__/test_mpmath.cpython-312.pyc filter=lfs diff=lfs merge=lfs -text
|
| 352 |
+
venv/lib/python3.12/site-packages/scipy/stats/__pycache__/_continuous_distns.cpython-312.pyc filter=lfs diff=lfs merge=lfs -text
|
| 353 |
+
venv/lib/python3.12/site-packages/scipy/stats/__pycache__/_distn_infrastructure.cpython-312.pyc filter=lfs diff=lfs merge=lfs -text
|
| 354 |
+
venv/lib/python3.12/site-packages/scipy/stats/__pycache__/_distribution_infrastructure.cpython-312.pyc filter=lfs diff=lfs merge=lfs -text
|
| 355 |
+
venv/lib/python3.12/site-packages/scipy/stats/__pycache__/_morestats.cpython-312.pyc filter=lfs diff=lfs merge=lfs -text
|
| 356 |
+
venv/lib/python3.12/site-packages/scipy/stats/__pycache__/_mstats_basic.cpython-312.pyc filter=lfs diff=lfs merge=lfs -text
|
| 357 |
+
venv/lib/python3.12/site-packages/scipy/stats/__pycache__/_multivariate.cpython-312.pyc filter=lfs diff=lfs merge=lfs -text
|
| 358 |
+
venv/lib/python3.12/site-packages/scipy/stats/__pycache__/_qmc.cpython-312.pyc filter=lfs diff=lfs merge=lfs -text
|
| 359 |
+
venv/lib/python3.12/site-packages/scipy/stats/__pycache__/_resampling.cpython-312.pyc filter=lfs diff=lfs merge=lfs -text
|
| 360 |
+
venv/lib/python3.12/site-packages/scipy/stats/__pycache__/_stats_py.cpython-312.pyc filter=lfs diff=lfs merge=lfs -text
|
| 361 |
+
venv/lib/python3.12/site-packages/scipy/stats/_ansari_swilk_statistics.cpython-312-x86_64-linux-gnu.so filter=lfs diff=lfs merge=lfs -text
|
| 362 |
+
venv/lib/python3.12/site-packages/scipy/stats/_biasedurn.cpython-312-x86_64-linux-gnu.so filter=lfs diff=lfs merge=lfs -text
|
| 363 |
+
venv/lib/python3.12/site-packages/scipy/stats/_qmc_cy.cpython-312-x86_64-linux-gnu.so filter=lfs diff=lfs merge=lfs -text
|
| 364 |
+
venv/lib/python3.12/site-packages/scipy/stats/_qmvnt_cy.cpython-312-x86_64-linux-gnu.so filter=lfs diff=lfs merge=lfs -text
|
| 365 |
+
venv/lib/python3.12/site-packages/scipy/stats/_rcont/rcont.cpython-312-x86_64-linux-gnu.so filter=lfs diff=lfs merge=lfs -text
|
| 366 |
+
venv/lib/python3.12/site-packages/scipy/stats/_sobol.cpython-312-x86_64-linux-gnu.so filter=lfs diff=lfs merge=lfs -text
|
| 367 |
+
venv/lib/python3.12/site-packages/scipy/stats/_stats.cpython-312-x86_64-linux-gnu.so filter=lfs diff=lfs merge=lfs -text
|
| 368 |
+
venv/lib/python3.12/site-packages/scipy/stats/_stats_pythran.cpython-312-x86_64-linux-gnu.so filter=lfs diff=lfs merge=lfs -text
|
| 369 |
+
venv/lib/python3.12/site-packages/scipy/stats/_unuran/unuran_wrapper.cpython-312-x86_64-linux-gnu.so filter=lfs diff=lfs merge=lfs -text
|
| 370 |
+
venv/lib/python3.12/site-packages/scipy/stats/tests/__pycache__/test_continuous.cpython-312.pyc filter=lfs diff=lfs merge=lfs -text
|
| 371 |
+
venv/lib/python3.12/site-packages/scipy/stats/tests/__pycache__/test_distributions.cpython-312.pyc filter=lfs diff=lfs merge=lfs -text
|
| 372 |
+
venv/lib/python3.12/site-packages/scipy/stats/tests/__pycache__/test_hypotests.cpython-312.pyc filter=lfs diff=lfs merge=lfs -text
|
| 373 |
+
venv/lib/python3.12/site-packages/scipy/stats/tests/__pycache__/test_morestats.cpython-312.pyc filter=lfs diff=lfs merge=lfs -text
|
| 374 |
+
venv/lib/python3.12/site-packages/scipy/stats/tests/__pycache__/test_mstats_basic.cpython-312.pyc filter=lfs diff=lfs merge=lfs -text
|
| 375 |
+
venv/lib/python3.12/site-packages/scipy/stats/tests/__pycache__/test_multivariate.cpython-312.pyc filter=lfs diff=lfs merge=lfs -text
|
| 376 |
+
venv/lib/python3.12/site-packages/scipy/stats/tests/__pycache__/test_resampling.cpython-312.pyc filter=lfs diff=lfs merge=lfs -text
|
| 377 |
+
venv/lib/python3.12/site-packages/scipy/stats/tests/__pycache__/test_stats.cpython-312.pyc filter=lfs diff=lfs merge=lfs -text
|
| 378 |
+
venv/lib/python3.12/site-packages/scipy.libs/libgfortran-040039e1-0352e75f.so.5.0.0 filter=lfs diff=lfs merge=lfs -text
|
| 379 |
+
venv/lib/python3.12/site-packages/scipy.libs/libgfortran-83c28eba.so.5.0.0 filter=lfs diff=lfs merge=lfs -text
|
| 380 |
+
venv/lib/python3.12/site-packages/scipy.libs/libquadmath-2284e583.so.0.0.0 filter=lfs diff=lfs merge=lfs -text
|
| 381 |
+
venv/lib/python3.12/site-packages/scipy.libs/libquadmath-96973f99-934c22de.so.0.0.0 filter=lfs diff=lfs merge=lfs -text
|
| 382 |
+
venv/lib/python3.12/site-packages/scipy.libs/libscipy_openblas-5f890258.so filter=lfs diff=lfs merge=lfs -text
|
venv/lib/python3.12/site-packages/scipy-1.18.0.dist-info/INSTALLER
ADDED
|
@@ -0,0 +1 @@
|
|
|
|
|
|
|
| 1 |
+
pip
|
venv/lib/python3.12/site-packages/scipy-1.18.0.dist-info/LICENSE.txt
ADDED
|
@@ -0,0 +1,937 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
Copyright (c) 2001-2002 Enthought, Inc. 2003, SciPy Developers.
|
| 2 |
+
All rights reserved.
|
| 3 |
+
|
| 4 |
+
Redistribution and use in source and binary forms, with or without
|
| 5 |
+
modification, are permitted provided that the following conditions
|
| 6 |
+
are met:
|
| 7 |
+
|
| 8 |
+
1. Redistributions of source code must retain the above copyright
|
| 9 |
+
notice, this list of conditions and the following disclaimer.
|
| 10 |
+
|
| 11 |
+
2. Redistributions in binary form must reproduce the above
|
| 12 |
+
copyright notice, this list of conditions and the following
|
| 13 |
+
disclaimer in the documentation and/or other materials provided
|
| 14 |
+
with the distribution.
|
| 15 |
+
|
| 16 |
+
3. Neither the name of the copyright holder nor the names of its
|
| 17 |
+
contributors may be used to endorse or promote products derived
|
| 18 |
+
from this software without specific prior written permission.
|
| 19 |
+
|
| 20 |
+
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
| 21 |
+
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
| 22 |
+
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
| 23 |
+
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
| 24 |
+
OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
| 25 |
+
SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
| 26 |
+
LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
| 27 |
+
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
| 28 |
+
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
| 29 |
+
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
| 30 |
+
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
| 31 |
+
|
| 32 |
+
----
|
| 33 |
+
|
| 34 |
+
|
| 35 |
+
----
|
| 36 |
+
|
| 37 |
+
This binary distribution of SciPy can also bundle the following software
|
| 38 |
+
(depending on the build):
|
| 39 |
+
|
| 40 |
+
|
| 41 |
+
Name: OpenBLAS
|
| 42 |
+
Files: scipy.libs/libscipy_openblas*.so
|
| 43 |
+
Description: bundled as a dynamically linked library
|
| 44 |
+
Availability: https://github.com/OpenMathLib/OpenBLAS/
|
| 45 |
+
License: BSD-3-Clause
|
| 46 |
+
Copyright (c) 2011-2014, The OpenBLAS Project
|
| 47 |
+
All rights reserved.
|
| 48 |
+
|
| 49 |
+
Redistribution and use in source and binary forms, with or without
|
| 50 |
+
modification, are permitted provided that the following conditions are
|
| 51 |
+
met:
|
| 52 |
+
|
| 53 |
+
1. Redistributions of source code must retain the above copyright
|
| 54 |
+
notice, this list of conditions and the following disclaimer.
|
| 55 |
+
|
| 56 |
+
2. Redistributions in binary form must reproduce the above copyright
|
| 57 |
+
notice, this list of conditions and the following disclaimer in
|
| 58 |
+
the documentation and/or other materials provided with the
|
| 59 |
+
distribution.
|
| 60 |
+
3. Neither the name of the OpenBLAS project nor the names of
|
| 61 |
+
its contributors may be used to endorse or promote products
|
| 62 |
+
derived from this software without specific prior written
|
| 63 |
+
permission.
|
| 64 |
+
|
| 65 |
+
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
| 66 |
+
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
| 67 |
+
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
| 68 |
+
ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
|
| 69 |
+
LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
| 70 |
+
DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
| 71 |
+
SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
|
| 72 |
+
CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
|
| 73 |
+
OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE
|
| 74 |
+
USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
| 75 |
+
|
| 76 |
+
|
| 77 |
+
Name: LAPACK
|
| 78 |
+
Files: scipy.libs/libscipy_openblas*.so
|
| 79 |
+
Description: bundled in OpenBLAS
|
| 80 |
+
Availability: https://github.com/OpenMathLib/OpenBLAS/
|
| 81 |
+
License: BSD-3-Clause-Open-MPI
|
| 82 |
+
Copyright (c) 1992-2013 The University of Tennessee and The University
|
| 83 |
+
of Tennessee Research Foundation. All rights
|
| 84 |
+
reserved.
|
| 85 |
+
Copyright (c) 2000-2013 The University of California Berkeley. All
|
| 86 |
+
rights reserved.
|
| 87 |
+
Copyright (c) 2006-2013 The University of Colorado Denver. All rights
|
| 88 |
+
reserved.
|
| 89 |
+
|
| 90 |
+
$COPYRIGHT$
|
| 91 |
+
|
| 92 |
+
Additional copyrights may follow
|
| 93 |
+
|
| 94 |
+
$HEADER$
|
| 95 |
+
|
| 96 |
+
Redistribution and use in source and binary forms, with or without
|
| 97 |
+
modification, are permitted provided that the following conditions are
|
| 98 |
+
met:
|
| 99 |
+
|
| 100 |
+
- Redistributions of source code must retain the above copyright
|
| 101 |
+
notice, this list of conditions and the following disclaimer.
|
| 102 |
+
|
| 103 |
+
- Redistributions in binary form must reproduce the above copyright
|
| 104 |
+
notice, this list of conditions and the following disclaimer listed
|
| 105 |
+
in this license in the documentation and/or other materials
|
| 106 |
+
provided with the distribution.
|
| 107 |
+
|
| 108 |
+
- Neither the name of the copyright holders nor the names of its
|
| 109 |
+
contributors may be used to endorse or promote products derived from
|
| 110 |
+
this software without specific prior written permission.
|
| 111 |
+
|
| 112 |
+
The copyright holders provide no reassurances that the source code
|
| 113 |
+
provided does not infringe any patent, copyright, or any other
|
| 114 |
+
intellectual property rights of third parties. The copyright holders
|
| 115 |
+
disclaim any liability to any recipient for claims brought against
|
| 116 |
+
recipient by any third party for infringement of that parties
|
| 117 |
+
intellectual property rights.
|
| 118 |
+
|
| 119 |
+
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
| 120 |
+
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
| 121 |
+
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
| 122 |
+
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
| 123 |
+
OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
| 124 |
+
SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
| 125 |
+
LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
| 126 |
+
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
| 127 |
+
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
| 128 |
+
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
| 129 |
+
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
| 130 |
+
|
| 131 |
+
|
| 132 |
+
Name: GCC runtime library
|
| 133 |
+
Files: scipy.libs/libgfortran*.so
|
| 134 |
+
Description: dynamically linked to files compiled with gcc
|
| 135 |
+
Availability: https://gcc.gnu.org/git/?p=gcc.git;a=tree;f=libgfortran
|
| 136 |
+
License: GPL-3.0-or-later WITH GCC-exception-3.1
|
| 137 |
+
Copyright (C) 2002-2017 Free Software Foundation, Inc.
|
| 138 |
+
|
| 139 |
+
Libgfortran is free software; you can redistribute it and/or modify
|
| 140 |
+
it under the terms of the GNU General Public License as published by
|
| 141 |
+
the Free Software Foundation; either version 3, or (at your option)
|
| 142 |
+
any later version.
|
| 143 |
+
|
| 144 |
+
Libgfortran is distributed in the hope that it will be useful,
|
| 145 |
+
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
| 146 |
+
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
| 147 |
+
GNU General Public License for more details.
|
| 148 |
+
|
| 149 |
+
Under Section 7 of GPL version 3, you are granted additional
|
| 150 |
+
permissions described in the GCC Runtime Library Exception, version
|
| 151 |
+
3.1, as published by the Free Software Foundation.
|
| 152 |
+
|
| 153 |
+
You should have received a copy of the GNU General Public License and
|
| 154 |
+
a copy of the GCC Runtime Library Exception along with this program;
|
| 155 |
+
see the files COPYING3 and COPYING.RUNTIME respectively. If not, see
|
| 156 |
+
<http://www.gnu.org/licenses/>.
|
| 157 |
+
|
| 158 |
+
----
|
| 159 |
+
|
| 160 |
+
Full text of license texts referred to above follows (that they are
|
| 161 |
+
listed below does not necessarily imply the conditions apply to the
|
| 162 |
+
present binary release):
|
| 163 |
+
|
| 164 |
+
----
|
| 165 |
+
|
| 166 |
+
GCC RUNTIME LIBRARY EXCEPTION
|
| 167 |
+
|
| 168 |
+
Version 3.1, 31 March 2009
|
| 169 |
+
|
| 170 |
+
Copyright (C) 2009 Free Software Foundation, Inc. <http://fsf.org/>
|
| 171 |
+
|
| 172 |
+
Everyone is permitted to copy and distribute verbatim copies of this
|
| 173 |
+
license document, but changing it is not allowed.
|
| 174 |
+
|
| 175 |
+
This GCC Runtime Library Exception ("Exception") is an additional
|
| 176 |
+
permission under section 7 of the GNU General Public License, version
|
| 177 |
+
3 ("GPLv3"). It applies to a given file (the "Runtime Library") that
|
| 178 |
+
bears a notice placed by the copyright holder of the file stating that
|
| 179 |
+
the file is governed by GPLv3 along with this Exception.
|
| 180 |
+
|
| 181 |
+
When you use GCC to compile a program, GCC may combine portions of
|
| 182 |
+
certain GCC header files and runtime libraries with the compiled
|
| 183 |
+
program. The purpose of this Exception is to allow compilation of
|
| 184 |
+
non-GPL (including proprietary) programs to use, in this way, the
|
| 185 |
+
header files and runtime libraries covered by this Exception.
|
| 186 |
+
|
| 187 |
+
0. Definitions.
|
| 188 |
+
|
| 189 |
+
A file is an "Independent Module" if it either requires the Runtime
|
| 190 |
+
Library for execution after a Compilation Process, or makes use of an
|
| 191 |
+
interface provided by the Runtime Library, but is not otherwise based
|
| 192 |
+
on the Runtime Library.
|
| 193 |
+
|
| 194 |
+
"GCC" means a version of the GNU Compiler Collection, with or without
|
| 195 |
+
modifications, governed by version 3 (or a specified later version) of
|
| 196 |
+
the GNU General Public License (GPL) with the option of using any
|
| 197 |
+
subsequent versions published by the FSF.
|
| 198 |
+
|
| 199 |
+
"GPL-compatible Software" is software whose conditions of propagation,
|
| 200 |
+
modification and use would permit combination with GCC in accord with
|
| 201 |
+
the license of GCC.
|
| 202 |
+
|
| 203 |
+
"Target Code" refers to output from any compiler for a real or virtual
|
| 204 |
+
target processor architecture, in executable form or suitable for
|
| 205 |
+
input to an assembler, loader, linker and/or execution
|
| 206 |
+
phase. Notwithstanding that, Target Code does not include data in any
|
| 207 |
+
format that is used as a compiler intermediate representation, or used
|
| 208 |
+
for producing a compiler intermediate representation.
|
| 209 |
+
|
| 210 |
+
The "Compilation Process" transforms code entirely represented in
|
| 211 |
+
non-intermediate languages designed for human-written code, and/or in
|
| 212 |
+
Java Virtual Machine byte code, into Target Code. Thus, for example,
|
| 213 |
+
use of source code generators and preprocessors need not be considered
|
| 214 |
+
part of the Compilation Process, since the Compilation Process can be
|
| 215 |
+
understood as starting with the output of the generators or
|
| 216 |
+
preprocessors.
|
| 217 |
+
|
| 218 |
+
A Compilation Process is "Eligible" if it is done using GCC, alone or
|
| 219 |
+
with other GPL-compatible software, or if it is done without using any
|
| 220 |
+
work based on GCC. For example, using non-GPL-compatible Software to
|
| 221 |
+
optimize any GCC intermediate representations would not qualify as an
|
| 222 |
+
Eligible Compilation Process.
|
| 223 |
+
|
| 224 |
+
1. Grant of Additional Permission.
|
| 225 |
+
|
| 226 |
+
You have permission to propagate a work of Target Code formed by
|
| 227 |
+
combining the Runtime Library with Independent Modules, even if such
|
| 228 |
+
propagation would otherwise violate the terms of GPLv3, provided that
|
| 229 |
+
all Target Code was generated by Eligible Compilation Processes. You
|
| 230 |
+
may then convey such a combination under terms of your choice,
|
| 231 |
+
consistent with the licensing of the Independent Modules.
|
| 232 |
+
|
| 233 |
+
2. No Weakening of GCC Copyleft.
|
| 234 |
+
|
| 235 |
+
The availability of this Exception does not imply any general
|
| 236 |
+
presumption that third-party software is unaffected by the copyleft
|
| 237 |
+
requirements of the license of GCC.
|
| 238 |
+
|
| 239 |
+
----
|
| 240 |
+
|
| 241 |
+
GNU GENERAL PUBLIC LICENSE
|
| 242 |
+
Version 3, 29 June 2007
|
| 243 |
+
|
| 244 |
+
Copyright (C) 2007 Free Software Foundation, Inc. <http://fsf.org/>
|
| 245 |
+
Everyone is permitted to copy and distribute verbatim copies
|
| 246 |
+
of this license document, but changing it is not allowed.
|
| 247 |
+
|
| 248 |
+
Preamble
|
| 249 |
+
|
| 250 |
+
The GNU General Public License is a free, copyleft license for
|
| 251 |
+
software and other kinds of works.
|
| 252 |
+
|
| 253 |
+
The licenses for most software and other practical works are designed
|
| 254 |
+
to take away your freedom to share and change the works. By contrast,
|
| 255 |
+
the GNU General Public License is intended to guarantee your freedom to
|
| 256 |
+
share and change all versions of a program--to make sure it remains free
|
| 257 |
+
software for all its users. We, the Free Software Foundation, use the
|
| 258 |
+
GNU General Public License for most of our software; it applies also to
|
| 259 |
+
any other work released this way by its authors. You can apply it to
|
| 260 |
+
your programs, too.
|
| 261 |
+
|
| 262 |
+
When we speak of free software, we are referring to freedom, not
|
| 263 |
+
price. Our General Public Licenses are designed to make sure that you
|
| 264 |
+
have the freedom to distribute copies of free software (and charge for
|
| 265 |
+
them if you wish), that you receive source code or can get it if you
|
| 266 |
+
want it, that you can change the software or use pieces of it in new
|
| 267 |
+
free programs, and that you know you can do these things.
|
| 268 |
+
|
| 269 |
+
To protect your rights, we need to prevent others from denying you
|
| 270 |
+
these rights or asking you to surrender the rights. Therefore, you have
|
| 271 |
+
certain responsibilities if you distribute copies of the software, or if
|
| 272 |
+
you modify it: responsibilities to respect the freedom of others.
|
| 273 |
+
|
| 274 |
+
For example, if you distribute copies of such a program, whether
|
| 275 |
+
gratis or for a fee, you must pass on to the recipients the same
|
| 276 |
+
freedoms that you received. You must make sure that they, too, receive
|
| 277 |
+
or can get the source code. And you must show them these terms so they
|
| 278 |
+
know their rights.
|
| 279 |
+
|
| 280 |
+
Developers that use the GNU GPL protect your rights with two steps:
|
| 281 |
+
(1) assert copyright on the software, and (2) offer you this License
|
| 282 |
+
giving you legal permission to copy, distribute and/or modify it.
|
| 283 |
+
|
| 284 |
+
For the developers' and authors' protection, the GPL clearly explains
|
| 285 |
+
that there is no warranty for this free software. For both users' and
|
| 286 |
+
authors' sake, the GPL requires that modified versions be marked as
|
| 287 |
+
changed, so that their problems will not be attributed erroneously to
|
| 288 |
+
authors of previous versions.
|
| 289 |
+
|
| 290 |
+
Some devices are designed to deny users access to install or run
|
| 291 |
+
modified versions of the software inside them, although the manufacturer
|
| 292 |
+
can do so. This is fundamentally incompatible with the aim of
|
| 293 |
+
protecting users' freedom to change the software. The systematic
|
| 294 |
+
pattern of such abuse occurs in the area of products for individuals to
|
| 295 |
+
use, which is precisely where it is most unacceptable. Therefore, we
|
| 296 |
+
have designed this version of the GPL to prohibit the practice for those
|
| 297 |
+
products. If such problems arise substantially in other domains, we
|
| 298 |
+
stand ready to extend this provision to those domains in future versions
|
| 299 |
+
of the GPL, as needed to protect the freedom of users.
|
| 300 |
+
|
| 301 |
+
Finally, every program is threatened constantly by software patents.
|
| 302 |
+
States should not allow patents to restrict development and use of
|
| 303 |
+
software on general-purpose computers, but in those that do, we wish to
|
| 304 |
+
avoid the special danger that patents applied to a free program could
|
| 305 |
+
make it effectively proprietary. To prevent this, the GPL assures that
|
| 306 |
+
patents cannot be used to render the program non-free.
|
| 307 |
+
|
| 308 |
+
The precise terms and conditions for copying, distribution and
|
| 309 |
+
modification follow.
|
| 310 |
+
|
| 311 |
+
TERMS AND CONDITIONS
|
| 312 |
+
|
| 313 |
+
0. Definitions.
|
| 314 |
+
|
| 315 |
+
"This License" refers to version 3 of the GNU General Public License.
|
| 316 |
+
|
| 317 |
+
"Copyright" also means copyright-like laws that apply to other kinds of
|
| 318 |
+
works, such as semiconductor masks.
|
| 319 |
+
|
| 320 |
+
"The Program" refers to any copyrightable work licensed under this
|
| 321 |
+
License. Each licensee is addressed as "you". "Licensees" and
|
| 322 |
+
"recipients" may be individuals or organizations.
|
| 323 |
+
|
| 324 |
+
To "modify" a work means to copy from or adapt all or part of the work
|
| 325 |
+
in a fashion requiring copyright permission, other than the making of an
|
| 326 |
+
exact copy. The resulting work is called a "modified version" of the
|
| 327 |
+
earlier work or a work "based on" the earlier work.
|
| 328 |
+
|
| 329 |
+
A "covered work" means either the unmodified Program or a work based
|
| 330 |
+
on the Program.
|
| 331 |
+
|
| 332 |
+
To "propagate" a work means to do anything with it that, without
|
| 333 |
+
permission, would make you directly or secondarily liable for
|
| 334 |
+
infringement under applicable copyright law, except executing it on a
|
| 335 |
+
computer or modifying a private copy. Propagation includes copying,
|
| 336 |
+
distribution (with or without modification), making available to the
|
| 337 |
+
public, and in some countries other activities as well.
|
| 338 |
+
|
| 339 |
+
To "convey" a work means any kind of propagation that enables other
|
| 340 |
+
parties to make or receive copies. Mere interaction with a user through
|
| 341 |
+
a computer network, with no transfer of a copy, is not conveying.
|
| 342 |
+
|
| 343 |
+
An interactive user interface displays "Appropriate Legal Notices"
|
| 344 |
+
to the extent that it includes a convenient and prominently visible
|
| 345 |
+
feature that (1) displays an appropriate copyright notice, and (2)
|
| 346 |
+
tells the user that there is no warranty for the work (except to the
|
| 347 |
+
extent that warranties are provided), that licensees may convey the
|
| 348 |
+
work under this License, and how to view a copy of this License. If
|
| 349 |
+
the interface presents a list of user commands or options, such as a
|
| 350 |
+
menu, a prominent item in the list meets this criterion.
|
| 351 |
+
|
| 352 |
+
1. Source Code.
|
| 353 |
+
|
| 354 |
+
The "source code" for a work means the preferred form of the work
|
| 355 |
+
for making modifications to it. "Object code" means any non-source
|
| 356 |
+
form of a work.
|
| 357 |
+
|
| 358 |
+
A "Standard Interface" means an interface that either is an official
|
| 359 |
+
standard defined by a recognized standards body, or, in the case of
|
| 360 |
+
interfaces specified for a particular programming language, one that
|
| 361 |
+
is widely used among developers working in that language.
|
| 362 |
+
|
| 363 |
+
The "System Libraries" of an executable work include anything, other
|
| 364 |
+
than the work as a whole, that (a) is included in the normal form of
|
| 365 |
+
packaging a Major Component, but which is not part of that Major
|
| 366 |
+
Component, and (b) serves only to enable use of the work with that
|
| 367 |
+
Major Component, or to implement a Standard Interface for which an
|
| 368 |
+
implementation is available to the public in source code form. A
|
| 369 |
+
"Major Component", in this context, means a major essential component
|
| 370 |
+
(kernel, window system, and so on) of the specific operating system
|
| 371 |
+
(if any) on which the executable work runs, or a compiler used to
|
| 372 |
+
produce the work, or an object code interpreter used to run it.
|
| 373 |
+
|
| 374 |
+
The "Corresponding Source" for a work in object code form means all
|
| 375 |
+
the source code needed to generate, install, and (for an executable
|
| 376 |
+
work) run the object code and to modify the work, including scripts to
|
| 377 |
+
control those activities. However, it does not include the work's
|
| 378 |
+
System Libraries, or general-purpose tools or generally available free
|
| 379 |
+
programs which are used unmodified in performing those activities but
|
| 380 |
+
which are not part of the work. For example, Corresponding Source
|
| 381 |
+
includes interface definition files associated with source files for
|
| 382 |
+
the work, and the source code for shared libraries and dynamically
|
| 383 |
+
linked subprograms that the work is specifically designed to require,
|
| 384 |
+
such as by intimate data communication or control flow between those
|
| 385 |
+
subprograms and other parts of the work.
|
| 386 |
+
|
| 387 |
+
The Corresponding Source need not include anything that users
|
| 388 |
+
can regenerate automatically from other parts of the Corresponding
|
| 389 |
+
Source.
|
| 390 |
+
|
| 391 |
+
The Corresponding Source for a work in source code form is that
|
| 392 |
+
same work.
|
| 393 |
+
|
| 394 |
+
2. Basic Permissions.
|
| 395 |
+
|
| 396 |
+
All rights granted under this License are granted for the term of
|
| 397 |
+
copyright on the Program, and are irrevocable provided the stated
|
| 398 |
+
conditions are met. This License explicitly affirms your unlimited
|
| 399 |
+
permission to run the unmodified Program. The output from running a
|
| 400 |
+
covered work is covered by this License only if the output, given its
|
| 401 |
+
content, constitutes a covered work. This License acknowledges your
|
| 402 |
+
rights of fair use or other equivalent, as provided by copyright law.
|
| 403 |
+
|
| 404 |
+
You may make, run and propagate covered works that you do not
|
| 405 |
+
convey, without conditions so long as your license otherwise remains
|
| 406 |
+
in force. You may convey covered works to others for the sole purpose
|
| 407 |
+
of having them make modifications exclusively for you, or provide you
|
| 408 |
+
with facilities for running those works, provided that you comply with
|
| 409 |
+
the terms of this License in conveying all material for which you do
|
| 410 |
+
not control copyright. Those thus making or running the covered works
|
| 411 |
+
for you must do so exclusively on your behalf, under your direction
|
| 412 |
+
and control, on terms that prohibit them from making any copies of
|
| 413 |
+
your copyrighted material outside their relationship with you.
|
| 414 |
+
|
| 415 |
+
Conveying under any other circumstances is permitted solely under
|
| 416 |
+
the conditions stated below. Sublicensing is not allowed; section 10
|
| 417 |
+
makes it unnecessary.
|
| 418 |
+
|
| 419 |
+
3. Protecting Users' Legal Rights From Anti-Circumvention Law.
|
| 420 |
+
|
| 421 |
+
No covered work shall be deemed part of an effective technological
|
| 422 |
+
measure under any applicable law fulfilling obligations under article
|
| 423 |
+
11 of the WIPO copyright treaty adopted on 20 December 1996, or
|
| 424 |
+
similar laws prohibiting or restricting circumvention of such
|
| 425 |
+
measures.
|
| 426 |
+
|
| 427 |
+
When you convey a covered work, you waive any legal power to forbid
|
| 428 |
+
circumvention of technological measures to the extent such circumvention
|
| 429 |
+
is effected by exercising rights under this License with respect to
|
| 430 |
+
the covered work, and you disclaim any intention to limit operation or
|
| 431 |
+
modification of the work as a means of enforcing, against the work's
|
| 432 |
+
users, your or third parties' legal rights to forbid circumvention of
|
| 433 |
+
technological measures.
|
| 434 |
+
|
| 435 |
+
4. Conveying Verbatim Copies.
|
| 436 |
+
|
| 437 |
+
You may convey verbatim copies of the Program's source code as you
|
| 438 |
+
receive it, in any medium, provided that you conspicuously and
|
| 439 |
+
appropriately publish on each copy an appropriate copyright notice;
|
| 440 |
+
keep intact all notices stating that this License and any
|
| 441 |
+
non-permissive terms added in accord with section 7 apply to the code;
|
| 442 |
+
keep intact all notices of the absence of any warranty; and give all
|
| 443 |
+
recipients a copy of this License along with the Program.
|
| 444 |
+
|
| 445 |
+
You may charge any price or no price for each copy that you convey,
|
| 446 |
+
and you may offer support or warranty protection for a fee.
|
| 447 |
+
|
| 448 |
+
5. Conveying Modified Source Versions.
|
| 449 |
+
|
| 450 |
+
You may convey a work based on the Program, or the modifications to
|
| 451 |
+
produce it from the Program, in the form of source code under the
|
| 452 |
+
terms of section 4, provided that you also meet all of these conditions:
|
| 453 |
+
|
| 454 |
+
a) The work must carry prominent notices stating that you modified
|
| 455 |
+
it, and giving a relevant date.
|
| 456 |
+
|
| 457 |
+
b) The work must carry prominent notices stating that it is
|
| 458 |
+
released under this License and any conditions added under section
|
| 459 |
+
7. This requirement modifies the requirement in section 4 to
|
| 460 |
+
"keep intact all notices".
|
| 461 |
+
|
| 462 |
+
c) You must license the entire work, as a whole, under this
|
| 463 |
+
License to anyone who comes into possession of a copy. This
|
| 464 |
+
License will therefore apply, along with any applicable section 7
|
| 465 |
+
additional terms, to the whole of the work, and all its parts,
|
| 466 |
+
regardless of how they are packaged. This License gives no
|
| 467 |
+
permission to license the work in any other way, but it does not
|
| 468 |
+
invalidate such permission if you have separately received it.
|
| 469 |
+
|
| 470 |
+
d) If the work has interactive user interfaces, each must display
|
| 471 |
+
Appropriate Legal Notices; however, if the Program has interactive
|
| 472 |
+
interfaces that do not display Appropriate Legal Notices, your
|
| 473 |
+
work need not make them do so.
|
| 474 |
+
|
| 475 |
+
A compilation of a covered work with other separate and independent
|
| 476 |
+
works, which are not by their nature extensions of the covered work,
|
| 477 |
+
and which are not combined with it such as to form a larger program,
|
| 478 |
+
in or on a volume of a storage or distribution medium, is called an
|
| 479 |
+
"aggregate" if the compilation and its resulting copyright are not
|
| 480 |
+
used to limit the access or legal rights of the compilation's users
|
| 481 |
+
beyond what the individual works permit. Inclusion of a covered work
|
| 482 |
+
in an aggregate does not cause this License to apply to the other
|
| 483 |
+
parts of the aggregate.
|
| 484 |
+
|
| 485 |
+
6. Conveying Non-Source Forms.
|
| 486 |
+
|
| 487 |
+
You may convey a covered work in object code form under the terms
|
| 488 |
+
of sections 4 and 5, provided that you also convey the
|
| 489 |
+
machine-readable Corresponding Source under the terms of this License,
|
| 490 |
+
in one of these ways:
|
| 491 |
+
|
| 492 |
+
a) Convey the object code in, or embodied in, a physical product
|
| 493 |
+
(including a physical distribution medium), accompanied by the
|
| 494 |
+
Corresponding Source fixed on a durable physical medium
|
| 495 |
+
customarily used for software interchange.
|
| 496 |
+
|
| 497 |
+
b) Convey the object code in, or embodied in, a physical product
|
| 498 |
+
(including a physical distribution medium), accompanied by a
|
| 499 |
+
written offer, valid for at least three years and valid for as
|
| 500 |
+
long as you offer spare parts or customer support for that product
|
| 501 |
+
model, to give anyone who possesses the object code either (1) a
|
| 502 |
+
copy of the Corresponding Source for all the software in the
|
| 503 |
+
product that is covered by this License, on a durable physical
|
| 504 |
+
medium customarily used for software interchange, for a price no
|
| 505 |
+
more than your reasonable cost of physically performing this
|
| 506 |
+
conveying of source, or (2) access to copy the
|
| 507 |
+
Corresponding Source from a network server at no charge.
|
| 508 |
+
|
| 509 |
+
c) Convey individual copies of the object code with a copy of the
|
| 510 |
+
written offer to provide the Corresponding Source. This
|
| 511 |
+
alternative is allowed only occasionally and noncommercially, and
|
| 512 |
+
only if you received the object code with such an offer, in accord
|
| 513 |
+
with subsection 6b.
|
| 514 |
+
|
| 515 |
+
d) Convey the object code by offering access from a designated
|
| 516 |
+
place (gratis or for a charge), and offer equivalent access to the
|
| 517 |
+
Corresponding Source in the same way through the same place at no
|
| 518 |
+
further charge. You need not require recipients to copy the
|
| 519 |
+
Corresponding Source along with the object code. If the place to
|
| 520 |
+
copy the object code is a network server, the Corresponding Source
|
| 521 |
+
may be on a different server (operated by you or a third party)
|
| 522 |
+
that supports equivalent copying facilities, provided you maintain
|
| 523 |
+
clear directions next to the object code saying where to find the
|
| 524 |
+
Corresponding Source. Regardless of what server hosts the
|
| 525 |
+
Corresponding Source, you remain obligated to ensure that it is
|
| 526 |
+
available for as long as needed to satisfy these requirements.
|
| 527 |
+
|
| 528 |
+
e) Convey the object code using peer-to-peer transmission, provided
|
| 529 |
+
you inform other peers where the object code and Corresponding
|
| 530 |
+
Source of the work are being offered to the general public at no
|
| 531 |
+
charge under subsection 6d.
|
| 532 |
+
|
| 533 |
+
A separable portion of the object code, whose source code is excluded
|
| 534 |
+
from the Corresponding Source as a System Library, need not be
|
| 535 |
+
included in conveying the object code work.
|
| 536 |
+
|
| 537 |
+
A "User Product" is either (1) a "consumer product", which means any
|
| 538 |
+
tangible personal property which is normally used for personal, family,
|
| 539 |
+
or household purposes, or (2) anything designed or sold for incorporation
|
| 540 |
+
into a dwelling. In determining whether a product is a consumer product,
|
| 541 |
+
doubtful cases shall be resolved in favor of coverage. For a particular
|
| 542 |
+
product received by a particular user, "normally used" refers to a
|
| 543 |
+
typical or common use of that class of product, regardless of the status
|
| 544 |
+
of the particular user or of the way in which the particular user
|
| 545 |
+
actually uses, or expects or is expected to use, the product. A product
|
| 546 |
+
is a consumer product regardless of whether the product has substantial
|
| 547 |
+
commercial, industrial or non-consumer uses, unless such uses represent
|
| 548 |
+
the only significant mode of use of the product.
|
| 549 |
+
|
| 550 |
+
"Installation Information" for a User Product means any methods,
|
| 551 |
+
procedures, authorization keys, or other information required to install
|
| 552 |
+
and execute modified versions of a covered work in that User Product from
|
| 553 |
+
a modified version of its Corresponding Source. The information must
|
| 554 |
+
suffice to ensure that the continued functioning of the modified object
|
| 555 |
+
code is in no case prevented or interfered with solely because
|
| 556 |
+
modification has been made.
|
| 557 |
+
|
| 558 |
+
If you convey an object code work under this section in, or with, or
|
| 559 |
+
specifically for use in, a User Product, and the conveying occurs as
|
| 560 |
+
part of a transaction in which the right of possession and use of the
|
| 561 |
+
User Product is transferred to the recipient in perpetuity or for a
|
| 562 |
+
fixed term (regardless of how the transaction is characterized), the
|
| 563 |
+
Corresponding Source conveyed under this section must be accompanied
|
| 564 |
+
by the Installation Information. But this requirement does not apply
|
| 565 |
+
if neither you nor any third party retains the ability to install
|
| 566 |
+
modified object code on the User Product (for example, the work has
|
| 567 |
+
been installed in ROM).
|
| 568 |
+
|
| 569 |
+
The requirement to provide Installation Information does not include a
|
| 570 |
+
requirement to continue to provide support service, warranty, or updates
|
| 571 |
+
for a work that has been modified or installed by the recipient, or for
|
| 572 |
+
the User Product in which it has been modified or installed. Access to a
|
| 573 |
+
network may be denied when the modification itself materially and
|
| 574 |
+
adversely affects the operation of the network or violates the rules and
|
| 575 |
+
protocols for communication across the network.
|
| 576 |
+
|
| 577 |
+
Corresponding Source conveyed, and Installation Information provided,
|
| 578 |
+
in accord with this section must be in a format that is publicly
|
| 579 |
+
documented (and with an implementation available to the public in
|
| 580 |
+
source code form), and must require no special password or key for
|
| 581 |
+
unpacking, reading or copying.
|
| 582 |
+
|
| 583 |
+
7. Additional Terms.
|
| 584 |
+
|
| 585 |
+
"Additional permissions" are terms that supplement the terms of this
|
| 586 |
+
License by making exceptions from one or more of its conditions.
|
| 587 |
+
Additional permissions that are applicable to the entire Program shall
|
| 588 |
+
be treated as though they were included in this License, to the extent
|
| 589 |
+
that they are valid under applicable law. If additional permissions
|
| 590 |
+
apply only to part of the Program, that part may be used separately
|
| 591 |
+
under those permissions, but the entire Program remains governed by
|
| 592 |
+
this License without regard to the additional permissions.
|
| 593 |
+
|
| 594 |
+
When you convey a copy of a covered work, you may at your option
|
| 595 |
+
remove any additional permissions from that copy, or from any part of
|
| 596 |
+
it. (Additional permissions may be written to require their own
|
| 597 |
+
removal in certain cases when you modify the work.) You may place
|
| 598 |
+
additional permissions on material, added by you to a covered work,
|
| 599 |
+
for which you have or can give appropriate copyright permission.
|
| 600 |
+
|
| 601 |
+
Notwithstanding any other provision of this License, for material you
|
| 602 |
+
add to a covered work, you may (if authorized by the copyright holders of
|
| 603 |
+
that material) supplement the terms of this License with terms:
|
| 604 |
+
|
| 605 |
+
a) Disclaiming warranty or limiting liability differently from the
|
| 606 |
+
terms of sections 15 and 16 of this License; or
|
| 607 |
+
|
| 608 |
+
b) Requiring preservation of specified reasonable legal notices or
|
| 609 |
+
author attributions in that material or in the Appropriate Legal
|
| 610 |
+
Notices displayed by works containing it; or
|
| 611 |
+
|
| 612 |
+
c) Prohibiting misrepresentation of the origin of that material, or
|
| 613 |
+
requiring that modified versions of such material be marked in
|
| 614 |
+
reasonable ways as different from the original version; or
|
| 615 |
+
|
| 616 |
+
d) Limiting the use for publicity purposes of names of licensors or
|
| 617 |
+
authors of the material; or
|
| 618 |
+
|
| 619 |
+
e) Declining to grant rights under trademark law for use of some
|
| 620 |
+
trade names, trademarks, or service marks; or
|
| 621 |
+
|
| 622 |
+
f) Requiring indemnification of licensors and authors of that
|
| 623 |
+
material by anyone who conveys the material (or modified versions of
|
| 624 |
+
it) with contractual assumptions of liability to the recipient, for
|
| 625 |
+
any liability that these contractual assumptions directly impose on
|
| 626 |
+
those licensors and authors.
|
| 627 |
+
|
| 628 |
+
All other non-permissive additional terms are considered "further
|
| 629 |
+
restrictions" within the meaning of section 10. If the Program as you
|
| 630 |
+
received it, or any part of it, contains a notice stating that it is
|
| 631 |
+
governed by this License along with a term that is a further
|
| 632 |
+
restriction, you may remove that term. If a license document contains
|
| 633 |
+
a further restriction but permits relicensing or conveying under this
|
| 634 |
+
License, you may add to a covered work material governed by the terms
|
| 635 |
+
of that license document, provided that the further restriction does
|
| 636 |
+
not survive such relicensing or conveying.
|
| 637 |
+
|
| 638 |
+
If you add terms to a covered work in accord with this section, you
|
| 639 |
+
must place, in the relevant source files, a statement of the
|
| 640 |
+
additional terms that apply to those files, or a notice indicating
|
| 641 |
+
where to find the applicable terms.
|
| 642 |
+
|
| 643 |
+
Additional terms, permissive or non-permissive, may be stated in the
|
| 644 |
+
form of a separately written license, or stated as exceptions;
|
| 645 |
+
the above requirements apply either way.
|
| 646 |
+
|
| 647 |
+
8. Termination.
|
| 648 |
+
|
| 649 |
+
You may not propagate or modify a covered work except as expressly
|
| 650 |
+
provided under this License. Any attempt otherwise to propagate or
|
| 651 |
+
modify it is void, and will automatically terminate your rights under
|
| 652 |
+
this License (including any patent licenses granted under the third
|
| 653 |
+
paragraph of section 11).
|
| 654 |
+
|
| 655 |
+
However, if you cease all violation of this License, then your
|
| 656 |
+
license from a particular copyright holder is reinstated (a)
|
| 657 |
+
provisionally, unless and until the copyright holder explicitly and
|
| 658 |
+
finally terminates your license, and (b) permanently, if the copyright
|
| 659 |
+
holder fails to notify you of the violation by some reasonable means
|
| 660 |
+
prior to 60 days after the cessation.
|
| 661 |
+
|
| 662 |
+
Moreover, your license from a particular copyright holder is
|
| 663 |
+
reinstated permanently if the copyright holder notifies you of the
|
| 664 |
+
violation by some reasonable means, this is the first time you have
|
| 665 |
+
received notice of violation of this License (for any work) from that
|
| 666 |
+
copyright holder, and you cure the violation prior to 30 days after
|
| 667 |
+
your receipt of the notice.
|
| 668 |
+
|
| 669 |
+
Termination of your rights under this section does not terminate the
|
| 670 |
+
licenses of parties who have received copies or rights from you under
|
| 671 |
+
this License. If your rights have been terminated and not permanently
|
| 672 |
+
reinstated, you do not qualify to receive new licenses for the same
|
| 673 |
+
material under section 10.
|
| 674 |
+
|
| 675 |
+
9. Acceptance Not Required for Having Copies.
|
| 676 |
+
|
| 677 |
+
You are not required to accept this License in order to receive or
|
| 678 |
+
run a copy of the Program. Ancillary propagation of a covered work
|
| 679 |
+
occurring solely as a consequence of using peer-to-peer transmission
|
| 680 |
+
to receive a copy likewise does not require acceptance. However,
|
| 681 |
+
nothing other than this License grants you permission to propagate or
|
| 682 |
+
modify any covered work. These actions infringe copyright if you do
|
| 683 |
+
not accept this License. Therefore, by modifying or propagating a
|
| 684 |
+
covered work, you indicate your acceptance of this License to do so.
|
| 685 |
+
|
| 686 |
+
10. Automatic Licensing of Downstream Recipients.
|
| 687 |
+
|
| 688 |
+
Each time you convey a covered work, the recipient automatically
|
| 689 |
+
receives a license from the original licensors, to run, modify and
|
| 690 |
+
propagate that work, subject to this License. You are not responsible
|
| 691 |
+
for enforcing compliance by third parties with this License.
|
| 692 |
+
|
| 693 |
+
An "entity transaction" is a transaction transferring control of an
|
| 694 |
+
organization, or substantially all assets of one, or subdividing an
|
| 695 |
+
organization, or merging organizations. If propagation of a covered
|
| 696 |
+
work results from an entity transaction, each party to that
|
| 697 |
+
transaction who receives a copy of the work also receives whatever
|
| 698 |
+
licenses to the work the party's predecessor in interest had or could
|
| 699 |
+
give under the previous paragraph, plus a right to possession of the
|
| 700 |
+
Corresponding Source of the work from the predecessor in interest, if
|
| 701 |
+
the predecessor has it or can get it with reasonable efforts.
|
| 702 |
+
|
| 703 |
+
You may not impose any further restrictions on the exercise of the
|
| 704 |
+
rights granted or affirmed under this License. For example, you may
|
| 705 |
+
not impose a license fee, royalty, or other charge for exercise of
|
| 706 |
+
rights granted under this License, and you may not initiate litigation
|
| 707 |
+
(including a cross-claim or counterclaim in a lawsuit) alleging that
|
| 708 |
+
any patent claim is infringed by making, using, selling, offering for
|
| 709 |
+
sale, or importing the Program or any portion of it.
|
| 710 |
+
|
| 711 |
+
11. Patents.
|
| 712 |
+
|
| 713 |
+
A "contributor" is a copyright holder who authorizes use under this
|
| 714 |
+
License of the Program or a work on which the Program is based. The
|
| 715 |
+
work thus licensed is called the contributor's "contributor version".
|
| 716 |
+
|
| 717 |
+
A contributor's "essential patent claims" are all patent claims
|
| 718 |
+
owned or controlled by the contributor, whether already acquired or
|
| 719 |
+
hereafter acquired, that would be infringed by some manner, permitted
|
| 720 |
+
by this License, of making, using, or selling its contributor version,
|
| 721 |
+
but do not include claims that would be infringed only as a
|
| 722 |
+
consequence of further modification of the contributor version. For
|
| 723 |
+
purposes of this definition, "control" includes the right to grant
|
| 724 |
+
patent sublicenses in a manner consistent with the requirements of
|
| 725 |
+
this License.
|
| 726 |
+
|
| 727 |
+
Each contributor grants you a non-exclusive, worldwide, royalty-free
|
| 728 |
+
patent license under the contributor's essential patent claims, to
|
| 729 |
+
make, use, sell, offer for sale, import and otherwise run, modify and
|
| 730 |
+
propagate the contents of its contributor version.
|
| 731 |
+
|
| 732 |
+
In the following three paragraphs, a "patent license" is any express
|
| 733 |
+
agreement or commitment, however denominated, not to enforce a patent
|
| 734 |
+
(such as an express permission to practice a patent or covenant not to
|
| 735 |
+
sue for patent infringement). To "grant" such a patent license to a
|
| 736 |
+
party means to make such an agreement or commitment not to enforce a
|
| 737 |
+
patent against the party.
|
| 738 |
+
|
| 739 |
+
If you convey a covered work, knowingly relying on a patent license,
|
| 740 |
+
and the Corresponding Source of the work is not available for anyone
|
| 741 |
+
to copy, free of charge and under the terms of this License, through a
|
| 742 |
+
publicly available network server or other readily accessible means,
|
| 743 |
+
then you must either (1) cause the Corresponding Source to be so
|
| 744 |
+
available, or (2) arrange to deprive yourself of the benefit of the
|
| 745 |
+
patent license for this particular work, or (3) arrange, in a manner
|
| 746 |
+
consistent with the requirements of this License, to extend the patent
|
| 747 |
+
license to downstream recipients. "Knowingly relying" means you have
|
| 748 |
+
actual knowledge that, but for the patent license, your conveying the
|
| 749 |
+
covered work in a country, or your recipient's use of the covered work
|
| 750 |
+
in a country, would infringe one or more identifiable patents in that
|
| 751 |
+
country that you have reason to believe are valid.
|
| 752 |
+
|
| 753 |
+
If, pursuant to or in connection with a single transaction or
|
| 754 |
+
arrangement, you convey, or propagate by procuring conveyance of, a
|
| 755 |
+
covered work, and grant a patent license to some of the parties
|
| 756 |
+
receiving the covered work authorizing them to use, propagate, modify
|
| 757 |
+
or convey a specific copy of the covered work, then the patent license
|
| 758 |
+
you grant is automatically extended to all recipients of the covered
|
| 759 |
+
work and works based on it.
|
| 760 |
+
|
| 761 |
+
A patent license is "discriminatory" if it does not include within
|
| 762 |
+
the scope of its coverage, prohibits the exercise of, or is
|
| 763 |
+
conditioned on the non-exercise of one or more of the rights that are
|
| 764 |
+
specifically granted under this License. You may not convey a covered
|
| 765 |
+
work if you are a party to an arrangement with a third party that is
|
| 766 |
+
in the business of distributing software, under which you make payment
|
| 767 |
+
to the third party based on the extent of your activity of conveying
|
| 768 |
+
the work, and under which the third party grants, to any of the
|
| 769 |
+
parties who would receive the covered work from you, a discriminatory
|
| 770 |
+
patent license (a) in connection with copies of the covered work
|
| 771 |
+
conveyed by you (or copies made from those copies), or (b) primarily
|
| 772 |
+
for and in connection with specific products or compilations that
|
| 773 |
+
contain the covered work, unless you entered into that arrangement,
|
| 774 |
+
or that patent license was granted, prior to 28 March 2007.
|
| 775 |
+
|
| 776 |
+
Nothing in this License shall be construed as excluding or limiting
|
| 777 |
+
any implied license or other defenses to infringement that may
|
| 778 |
+
otherwise be available to you under applicable patent law.
|
| 779 |
+
|
| 780 |
+
12. No Surrender of Others' Freedom.
|
| 781 |
+
|
| 782 |
+
If conditions are imposed on you (whether by court order, agreement or
|
| 783 |
+
otherwise) that contradict the conditions of this License, they do not
|
| 784 |
+
excuse you from the conditions of this License. If you cannot convey a
|
| 785 |
+
covered work so as to satisfy simultaneously your obligations under this
|
| 786 |
+
License and any other pertinent obligations, then as a consequence you may
|
| 787 |
+
not convey it at all. For example, if you agree to terms that obligate you
|
| 788 |
+
to collect a royalty for further conveying from those to whom you convey
|
| 789 |
+
the Program, the only way you could satisfy both those terms and this
|
| 790 |
+
License would be to refrain entirely from conveying the Program.
|
| 791 |
+
|
| 792 |
+
13. Use with the GNU Affero General Public License.
|
| 793 |
+
|
| 794 |
+
Notwithstanding any other provision of this License, you have
|
| 795 |
+
permission to link or combine any covered work with a work licensed
|
| 796 |
+
under version 3 of the GNU Affero General Public License into a single
|
| 797 |
+
combined work, and to convey the resulting work. The terms of this
|
| 798 |
+
License will continue to apply to the part which is the covered work,
|
| 799 |
+
but the special requirements of the GNU Affero General Public License,
|
| 800 |
+
section 13, concerning interaction through a network will apply to the
|
| 801 |
+
combination as such.
|
| 802 |
+
|
| 803 |
+
14. Revised Versions of this License.
|
| 804 |
+
|
| 805 |
+
The Free Software Foundation may publish revised and/or new versions of
|
| 806 |
+
the GNU General Public License from time to time. Such new versions will
|
| 807 |
+
be similar in spirit to the present version, but may differ in detail to
|
| 808 |
+
address new problems or concerns.
|
| 809 |
+
|
| 810 |
+
Each version is given a distinguishing version number. If the
|
| 811 |
+
Program specifies that a certain numbered version of the GNU General
|
| 812 |
+
Public License "or any later version" applies to it, you have the
|
| 813 |
+
option of following the terms and conditions either of that numbered
|
| 814 |
+
version or of any later version published by the Free Software
|
| 815 |
+
Foundation. If the Program does not specify a version number of the
|
| 816 |
+
GNU General Public License, you may choose any version ever published
|
| 817 |
+
by the Free Software Foundation.
|
| 818 |
+
|
| 819 |
+
If the Program specifies that a proxy can decide which future
|
| 820 |
+
versions of the GNU General Public License can be used, that proxy's
|
| 821 |
+
public statement of acceptance of a version permanently authorizes you
|
| 822 |
+
to choose that version for the Program.
|
| 823 |
+
|
| 824 |
+
Later license versions may give you additional or different
|
| 825 |
+
permissions. However, no additional obligations are imposed on any
|
| 826 |
+
author or copyright holder as a result of your choosing to follow a
|
| 827 |
+
later version.
|
| 828 |
+
|
| 829 |
+
15. Disclaimer of Warranty.
|
| 830 |
+
|
| 831 |
+
THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY
|
| 832 |
+
APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT
|
| 833 |
+
HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY
|
| 834 |
+
OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO,
|
| 835 |
+
THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
|
| 836 |
+
PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM
|
| 837 |
+
IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF
|
| 838 |
+
ALL NECESSARY SERVICING, REPAIR OR CORRECTION.
|
| 839 |
+
|
| 840 |
+
16. Limitation of Liability.
|
| 841 |
+
|
| 842 |
+
IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
|
| 843 |
+
WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS
|
| 844 |
+
THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY
|
| 845 |
+
GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE
|
| 846 |
+
USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF
|
| 847 |
+
DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD
|
| 848 |
+
PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS),
|
| 849 |
+
EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF
|
| 850 |
+
SUCH DAMAGES.
|
| 851 |
+
|
| 852 |
+
17. Interpretation of Sections 15 and 16.
|
| 853 |
+
|
| 854 |
+
If the disclaimer of warranty and limitation of liability provided
|
| 855 |
+
above cannot be given local legal effect according to their terms,
|
| 856 |
+
reviewing courts shall apply local law that most closely approximates
|
| 857 |
+
an absolute waiver of all civil liability in connection with the
|
| 858 |
+
Program, unless a warranty or assumption of liability accompanies a
|
| 859 |
+
copy of the Program in return for a fee.
|
| 860 |
+
|
| 861 |
+
END OF TERMS AND CONDITIONS
|
| 862 |
+
|
| 863 |
+
How to Apply These Terms to Your New Programs
|
| 864 |
+
|
| 865 |
+
If you develop a new program, and you want it to be of the greatest
|
| 866 |
+
possible use to the public, the best way to achieve this is to make it
|
| 867 |
+
free software which everyone can redistribute and change under these terms.
|
| 868 |
+
|
| 869 |
+
To do so, attach the following notices to the program. It is safest
|
| 870 |
+
to attach them to the start of each source file to most effectively
|
| 871 |
+
state the exclusion of warranty; and each file should have at least
|
| 872 |
+
the "copyright" line and a pointer to where the full notice is found.
|
| 873 |
+
|
| 874 |
+
<one line to give the program's name and a brief idea of what it does.>
|
| 875 |
+
Copyright (C) <year> <name of author>
|
| 876 |
+
|
| 877 |
+
This program is free software: you can redistribute it and/or modify
|
| 878 |
+
it under the terms of the GNU General Public License as published by
|
| 879 |
+
the Free Software Foundation, either version 3 of the License, or
|
| 880 |
+
(at your option) any later version.
|
| 881 |
+
|
| 882 |
+
This program is distributed in the hope that it will be useful,
|
| 883 |
+
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
| 884 |
+
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
| 885 |
+
GNU General Public License for more details.
|
| 886 |
+
|
| 887 |
+
You should have received a copy of the GNU General Public License
|
| 888 |
+
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
| 889 |
+
|
| 890 |
+
Also add information on how to contact you by electronic and paper mail.
|
| 891 |
+
|
| 892 |
+
If the program does terminal interaction, make it output a short
|
| 893 |
+
notice like this when it starts in an interactive mode:
|
| 894 |
+
|
| 895 |
+
<program> Copyright (C) <year> <name of author>
|
| 896 |
+
This program comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
|
| 897 |
+
This is free software, and you are welcome to redistribute it
|
| 898 |
+
under certain conditions; type `show c' for details.
|
| 899 |
+
|
| 900 |
+
The hypothetical commands `show w' and `show c' should show the appropriate
|
| 901 |
+
parts of the General Public License. Of course, your program's commands
|
| 902 |
+
might be different; for a GUI interface, you would use an "about box".
|
| 903 |
+
|
| 904 |
+
You should also get your employer (if you work as a programmer) or school,
|
| 905 |
+
if any, to sign a "copyright disclaimer" for the program, if necessary.
|
| 906 |
+
For more information on this, and how to apply and follow the GNU GPL, see
|
| 907 |
+
<http://www.gnu.org/licenses/>.
|
| 908 |
+
|
| 909 |
+
The GNU General Public License does not permit incorporating your program
|
| 910 |
+
into proprietary programs. If your program is a subroutine library, you
|
| 911 |
+
may consider it more useful to permit linking proprietary applications with
|
| 912 |
+
the library. If this is what you want to do, use the GNU Lesser General
|
| 913 |
+
Public License instead of this License. But first, please read
|
| 914 |
+
<http://www.gnu.org/philosophy/why-not-lgpl.html>.
|
| 915 |
+
|
| 916 |
+
|
| 917 |
+
Name: libquadmath
|
| 918 |
+
Files: scipy.libs/libquadmath*.so
|
| 919 |
+
Description: dynamically linked to files compiled with gcc
|
| 920 |
+
Availability: https://gcc.gnu.org/git/?p=gcc.git;a=tree;f=libquadmath
|
| 921 |
+
License: LGPL-2.1-or-later
|
| 922 |
+
|
| 923 |
+
GCC Quad-Precision Math Library
|
| 924 |
+
Copyright (C) 2010-2019 Free Software Foundation, Inc.
|
| 925 |
+
Written by Francois-Xavier Coudert <fxcoudert@gcc.gnu.org>
|
| 926 |
+
|
| 927 |
+
This file is part of the libquadmath library.
|
| 928 |
+
Libquadmath is free software; you can redistribute it and/or
|
| 929 |
+
modify it under the terms of the GNU Library General Public
|
| 930 |
+
License as published by the Free Software Foundation; either
|
| 931 |
+
version 2.1 of the License, or (at your option) any later version.
|
| 932 |
+
|
| 933 |
+
Libquadmath is distributed in the hope that it will be useful,
|
| 934 |
+
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
| 935 |
+
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
| 936 |
+
Lesser General Public License for more details.
|
| 937 |
+
https://www.gnu.org/licenses/old-licenses/lgpl-2.1.html
|
venv/lib/python3.12/site-packages/scipy-1.18.0.dist-info/METADATA
ADDED
|
@@ -0,0 +1,1091 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
Metadata-Version: 2.1
|
| 2 |
+
Name: scipy
|
| 3 |
+
Version: 1.18.0
|
| 4 |
+
Summary: Fundamental algorithms for scientific computing in Python
|
| 5 |
+
Maintainer-Email: SciPy Developers <scipy-dev@python.org>
|
| 6 |
+
License: Copyright (c) 2001-2002 Enthought, Inc. 2003, SciPy Developers.
|
| 7 |
+
All rights reserved.
|
| 8 |
+
|
| 9 |
+
Redistribution and use in source and binary forms, with or without
|
| 10 |
+
modification, are permitted provided that the following conditions
|
| 11 |
+
are met:
|
| 12 |
+
|
| 13 |
+
1. Redistributions of source code must retain the above copyright
|
| 14 |
+
notice, this list of conditions and the following disclaimer.
|
| 15 |
+
|
| 16 |
+
2. Redistributions in binary form must reproduce the above
|
| 17 |
+
copyright notice, this list of conditions and the following
|
| 18 |
+
disclaimer in the documentation and/or other materials provided
|
| 19 |
+
with the distribution.
|
| 20 |
+
|
| 21 |
+
3. Neither the name of the copyright holder nor the names of its
|
| 22 |
+
contributors may be used to endorse or promote products derived
|
| 23 |
+
from this software without specific prior written permission.
|
| 24 |
+
|
| 25 |
+
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
| 26 |
+
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
| 27 |
+
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
| 28 |
+
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
| 29 |
+
OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
| 30 |
+
SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
| 31 |
+
LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
| 32 |
+
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
| 33 |
+
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
| 34 |
+
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
| 35 |
+
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
| 36 |
+
|
| 37 |
+
----
|
| 38 |
+
|
| 39 |
+
|
| 40 |
+
----
|
| 41 |
+
|
| 42 |
+
This binary distribution of SciPy can also bundle the following software
|
| 43 |
+
(depending on the build):
|
| 44 |
+
|
| 45 |
+
|
| 46 |
+
Name: OpenBLAS
|
| 47 |
+
Files: scipy.libs/libscipy_openblas*.so
|
| 48 |
+
Description: bundled as a dynamically linked library
|
| 49 |
+
Availability: https://github.com/OpenMathLib/OpenBLAS/
|
| 50 |
+
License: BSD-3-Clause
|
| 51 |
+
Copyright (c) 2011-2014, The OpenBLAS Project
|
| 52 |
+
All rights reserved.
|
| 53 |
+
|
| 54 |
+
Redistribution and use in source and binary forms, with or without
|
| 55 |
+
modification, are permitted provided that the following conditions are
|
| 56 |
+
met:
|
| 57 |
+
|
| 58 |
+
1. Redistributions of source code must retain the above copyright
|
| 59 |
+
notice, this list of conditions and the following disclaimer.
|
| 60 |
+
|
| 61 |
+
2. Redistributions in binary form must reproduce the above copyright
|
| 62 |
+
notice, this list of conditions and the following disclaimer in
|
| 63 |
+
the documentation and/or other materials provided with the
|
| 64 |
+
distribution.
|
| 65 |
+
3. Neither the name of the OpenBLAS project nor the names of
|
| 66 |
+
its contributors may be used to endorse or promote products
|
| 67 |
+
derived from this software without specific prior written
|
| 68 |
+
permission.
|
| 69 |
+
|
| 70 |
+
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
| 71 |
+
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
| 72 |
+
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
| 73 |
+
ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
|
| 74 |
+
LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
| 75 |
+
DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
| 76 |
+
SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
|
| 77 |
+
CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
|
| 78 |
+
OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE
|
| 79 |
+
USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
| 80 |
+
|
| 81 |
+
|
| 82 |
+
Name: LAPACK
|
| 83 |
+
Files: scipy.libs/libscipy_openblas*.so
|
| 84 |
+
Description: bundled in OpenBLAS
|
| 85 |
+
Availability: https://github.com/OpenMathLib/OpenBLAS/
|
| 86 |
+
License: BSD-3-Clause-Open-MPI
|
| 87 |
+
Copyright (c) 1992-2013 The University of Tennessee and The University
|
| 88 |
+
of Tennessee Research Foundation. All rights
|
| 89 |
+
reserved.
|
| 90 |
+
Copyright (c) 2000-2013 The University of California Berkeley. All
|
| 91 |
+
rights reserved.
|
| 92 |
+
Copyright (c) 2006-2013 The University of Colorado Denver. All rights
|
| 93 |
+
reserved.
|
| 94 |
+
|
| 95 |
+
$COPYRIGHT$
|
| 96 |
+
|
| 97 |
+
Additional copyrights may follow
|
| 98 |
+
|
| 99 |
+
$HEADER$
|
| 100 |
+
|
| 101 |
+
Redistribution and use in source and binary forms, with or without
|
| 102 |
+
modification, are permitted provided that the following conditions are
|
| 103 |
+
met:
|
| 104 |
+
|
| 105 |
+
- Redistributions of source code must retain the above copyright
|
| 106 |
+
notice, this list of conditions and the following disclaimer.
|
| 107 |
+
|
| 108 |
+
- Redistributions in binary form must reproduce the above copyright
|
| 109 |
+
notice, this list of conditions and the following disclaimer listed
|
| 110 |
+
in this license in the documentation and/or other materials
|
| 111 |
+
provided with the distribution.
|
| 112 |
+
|
| 113 |
+
- Neither the name of the copyright holders nor the names of its
|
| 114 |
+
contributors may be used to endorse or promote products derived from
|
| 115 |
+
this software without specific prior written permission.
|
| 116 |
+
|
| 117 |
+
The copyright holders provide no reassurances that the source code
|
| 118 |
+
provided does not infringe any patent, copyright, or any other
|
| 119 |
+
intellectual property rights of third parties. The copyright holders
|
| 120 |
+
disclaim any liability to any recipient for claims brought against
|
| 121 |
+
recipient by any third party for infringement of that parties
|
| 122 |
+
intellectual property rights.
|
| 123 |
+
|
| 124 |
+
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
| 125 |
+
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
| 126 |
+
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
| 127 |
+
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
| 128 |
+
OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
| 129 |
+
SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
| 130 |
+
LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
| 131 |
+
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
| 132 |
+
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
| 133 |
+
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
| 134 |
+
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
| 135 |
+
|
| 136 |
+
|
| 137 |
+
Name: GCC runtime library
|
| 138 |
+
Files: scipy.libs/libgfortran*.so
|
| 139 |
+
Description: dynamically linked to files compiled with gcc
|
| 140 |
+
Availability: https://gcc.gnu.org/git/?p=gcc.git;a=tree;f=libgfortran
|
| 141 |
+
License: GPL-3.0-or-later WITH GCC-exception-3.1
|
| 142 |
+
Copyright (C) 2002-2017 Free Software Foundation, Inc.
|
| 143 |
+
|
| 144 |
+
Libgfortran is free software; you can redistribute it and/or modify
|
| 145 |
+
it under the terms of the GNU General Public License as published by
|
| 146 |
+
the Free Software Foundation; either version 3, or (at your option)
|
| 147 |
+
any later version.
|
| 148 |
+
|
| 149 |
+
Libgfortran is distributed in the hope that it will be useful,
|
| 150 |
+
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
| 151 |
+
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
| 152 |
+
GNU General Public License for more details.
|
| 153 |
+
|
| 154 |
+
Under Section 7 of GPL version 3, you are granted additional
|
| 155 |
+
permissions described in the GCC Runtime Library Exception, version
|
| 156 |
+
3.1, as published by the Free Software Foundation.
|
| 157 |
+
|
| 158 |
+
You should have received a copy of the GNU General Public License and
|
| 159 |
+
a copy of the GCC Runtime Library Exception along with this program;
|
| 160 |
+
see the files COPYING3 and COPYING.RUNTIME respectively. If not, see
|
| 161 |
+
<http://www.gnu.org/licenses/>.
|
| 162 |
+
|
| 163 |
+
----
|
| 164 |
+
|
| 165 |
+
Full text of license texts referred to above follows (that they are
|
| 166 |
+
listed below does not necessarily imply the conditions apply to the
|
| 167 |
+
present binary release):
|
| 168 |
+
|
| 169 |
+
----
|
| 170 |
+
|
| 171 |
+
GCC RUNTIME LIBRARY EXCEPTION
|
| 172 |
+
|
| 173 |
+
Version 3.1, 31 March 2009
|
| 174 |
+
|
| 175 |
+
Copyright (C) 2009 Free Software Foundation, Inc. <http://fsf.org/>
|
| 176 |
+
|
| 177 |
+
Everyone is permitted to copy and distribute verbatim copies of this
|
| 178 |
+
license document, but changing it is not allowed.
|
| 179 |
+
|
| 180 |
+
This GCC Runtime Library Exception ("Exception") is an additional
|
| 181 |
+
permission under section 7 of the GNU General Public License, version
|
| 182 |
+
3 ("GPLv3"). It applies to a given file (the "Runtime Library") that
|
| 183 |
+
bears a notice placed by the copyright holder of the file stating that
|
| 184 |
+
the file is governed by GPLv3 along with this Exception.
|
| 185 |
+
|
| 186 |
+
When you use GCC to compile a program, GCC may combine portions of
|
| 187 |
+
certain GCC header files and runtime libraries with the compiled
|
| 188 |
+
program. The purpose of this Exception is to allow compilation of
|
| 189 |
+
non-GPL (including proprietary) programs to use, in this way, the
|
| 190 |
+
header files and runtime libraries covered by this Exception.
|
| 191 |
+
|
| 192 |
+
0. Definitions.
|
| 193 |
+
|
| 194 |
+
A file is an "Independent Module" if it either requires the Runtime
|
| 195 |
+
Library for execution after a Compilation Process, or makes use of an
|
| 196 |
+
interface provided by the Runtime Library, but is not otherwise based
|
| 197 |
+
on the Runtime Library.
|
| 198 |
+
|
| 199 |
+
"GCC" means a version of the GNU Compiler Collection, with or without
|
| 200 |
+
modifications, governed by version 3 (or a specified later version) of
|
| 201 |
+
the GNU General Public License (GPL) with the option of using any
|
| 202 |
+
subsequent versions published by the FSF.
|
| 203 |
+
|
| 204 |
+
"GPL-compatible Software" is software whose conditions of propagation,
|
| 205 |
+
modification and use would permit combination with GCC in accord with
|
| 206 |
+
the license of GCC.
|
| 207 |
+
|
| 208 |
+
"Target Code" refers to output from any compiler for a real or virtual
|
| 209 |
+
target processor architecture, in executable form or suitable for
|
| 210 |
+
input to an assembler, loader, linker and/or execution
|
| 211 |
+
phase. Notwithstanding that, Target Code does not include data in any
|
| 212 |
+
format that is used as a compiler intermediate representation, or used
|
| 213 |
+
for producing a compiler intermediate representation.
|
| 214 |
+
|
| 215 |
+
The "Compilation Process" transforms code entirely represented in
|
| 216 |
+
non-intermediate languages designed for human-written code, and/or in
|
| 217 |
+
Java Virtual Machine byte code, into Target Code. Thus, for example,
|
| 218 |
+
use of source code generators and preprocessors need not be considered
|
| 219 |
+
part of the Compilation Process, since the Compilation Process can be
|
| 220 |
+
understood as starting with the output of the generators or
|
| 221 |
+
preprocessors.
|
| 222 |
+
|
| 223 |
+
A Compilation Process is "Eligible" if it is done using GCC, alone or
|
| 224 |
+
with other GPL-compatible software, or if it is done without using any
|
| 225 |
+
work based on GCC. For example, using non-GPL-compatible Software to
|
| 226 |
+
optimize any GCC intermediate representations would not qualify as an
|
| 227 |
+
Eligible Compilation Process.
|
| 228 |
+
|
| 229 |
+
1. Grant of Additional Permission.
|
| 230 |
+
|
| 231 |
+
You have permission to propagate a work of Target Code formed by
|
| 232 |
+
combining the Runtime Library with Independent Modules, even if such
|
| 233 |
+
propagation would otherwise violate the terms of GPLv3, provided that
|
| 234 |
+
all Target Code was generated by Eligible Compilation Processes. You
|
| 235 |
+
may then convey such a combination under terms of your choice,
|
| 236 |
+
consistent with the licensing of the Independent Modules.
|
| 237 |
+
|
| 238 |
+
2. No Weakening of GCC Copyleft.
|
| 239 |
+
|
| 240 |
+
The availability of this Exception does not imply any general
|
| 241 |
+
presumption that third-party software is unaffected by the copyleft
|
| 242 |
+
requirements of the license of GCC.
|
| 243 |
+
|
| 244 |
+
----
|
| 245 |
+
|
| 246 |
+
GNU GENERAL PUBLIC LICENSE
|
| 247 |
+
Version 3, 29 June 2007
|
| 248 |
+
|
| 249 |
+
Copyright (C) 2007 Free Software Foundation, Inc. <http://fsf.org/>
|
| 250 |
+
Everyone is permitted to copy and distribute verbatim copies
|
| 251 |
+
of this license document, but changing it is not allowed.
|
| 252 |
+
|
| 253 |
+
Preamble
|
| 254 |
+
|
| 255 |
+
The GNU General Public License is a free, copyleft license for
|
| 256 |
+
software and other kinds of works.
|
| 257 |
+
|
| 258 |
+
The licenses for most software and other practical works are designed
|
| 259 |
+
to take away your freedom to share and change the works. By contrast,
|
| 260 |
+
the GNU General Public License is intended to guarantee your freedom to
|
| 261 |
+
share and change all versions of a program--to make sure it remains free
|
| 262 |
+
software for all its users. We, the Free Software Foundation, use the
|
| 263 |
+
GNU General Public License for most of our software; it applies also to
|
| 264 |
+
any other work released this way by its authors. You can apply it to
|
| 265 |
+
your programs, too.
|
| 266 |
+
|
| 267 |
+
When we speak of free software, we are referring to freedom, not
|
| 268 |
+
price. Our General Public Licenses are designed to make sure that you
|
| 269 |
+
have the freedom to distribute copies of free software (and charge for
|
| 270 |
+
them if you wish), that you receive source code or can get it if you
|
| 271 |
+
want it, that you can change the software or use pieces of it in new
|
| 272 |
+
free programs, and that you know you can do these things.
|
| 273 |
+
|
| 274 |
+
To protect your rights, we need to prevent others from denying you
|
| 275 |
+
these rights or asking you to surrender the rights. Therefore, you have
|
| 276 |
+
certain responsibilities if you distribute copies of the software, or if
|
| 277 |
+
you modify it: responsibilities to respect the freedom of others.
|
| 278 |
+
|
| 279 |
+
For example, if you distribute copies of such a program, whether
|
| 280 |
+
gratis or for a fee, you must pass on to the recipients the same
|
| 281 |
+
freedoms that you received. You must make sure that they, too, receive
|
| 282 |
+
or can get the source code. And you must show them these terms so they
|
| 283 |
+
know their rights.
|
| 284 |
+
|
| 285 |
+
Developers that use the GNU GPL protect your rights with two steps:
|
| 286 |
+
(1) assert copyright on the software, and (2) offer you this License
|
| 287 |
+
giving you legal permission to copy, distribute and/or modify it.
|
| 288 |
+
|
| 289 |
+
For the developers' and authors' protection, the GPL clearly explains
|
| 290 |
+
that there is no warranty for this free software. For both users' and
|
| 291 |
+
authors' sake, the GPL requires that modified versions be marked as
|
| 292 |
+
changed, so that their problems will not be attributed erroneously to
|
| 293 |
+
authors of previous versions.
|
| 294 |
+
|
| 295 |
+
Some devices are designed to deny users access to install or run
|
| 296 |
+
modified versions of the software inside them, although the manufacturer
|
| 297 |
+
can do so. This is fundamentally incompatible with the aim of
|
| 298 |
+
protecting users' freedom to change the software. The systematic
|
| 299 |
+
pattern of such abuse occurs in the area of products for individuals to
|
| 300 |
+
use, which is precisely where it is most unacceptable. Therefore, we
|
| 301 |
+
have designed this version of the GPL to prohibit the practice for those
|
| 302 |
+
products. If such problems arise substantially in other domains, we
|
| 303 |
+
stand ready to extend this provision to those domains in future versions
|
| 304 |
+
of the GPL, as needed to protect the freedom of users.
|
| 305 |
+
|
| 306 |
+
Finally, every program is threatened constantly by software patents.
|
| 307 |
+
States should not allow patents to restrict development and use of
|
| 308 |
+
software on general-purpose computers, but in those that do, we wish to
|
| 309 |
+
avoid the special danger that patents applied to a free program could
|
| 310 |
+
make it effectively proprietary. To prevent this, the GPL assures that
|
| 311 |
+
patents cannot be used to render the program non-free.
|
| 312 |
+
|
| 313 |
+
The precise terms and conditions for copying, distribution and
|
| 314 |
+
modification follow.
|
| 315 |
+
|
| 316 |
+
TERMS AND CONDITIONS
|
| 317 |
+
|
| 318 |
+
0. Definitions.
|
| 319 |
+
|
| 320 |
+
"This License" refers to version 3 of the GNU General Public License.
|
| 321 |
+
|
| 322 |
+
"Copyright" also means copyright-like laws that apply to other kinds of
|
| 323 |
+
works, such as semiconductor masks.
|
| 324 |
+
|
| 325 |
+
"The Program" refers to any copyrightable work licensed under this
|
| 326 |
+
License. Each licensee is addressed as "you". "Licensees" and
|
| 327 |
+
"recipients" may be individuals or organizations.
|
| 328 |
+
|
| 329 |
+
To "modify" a work means to copy from or adapt all or part of the work
|
| 330 |
+
in a fashion requiring copyright permission, other than the making of an
|
| 331 |
+
exact copy. The resulting work is called a "modified version" of the
|
| 332 |
+
earlier work or a work "based on" the earlier work.
|
| 333 |
+
|
| 334 |
+
A "covered work" means either the unmodified Program or a work based
|
| 335 |
+
on the Program.
|
| 336 |
+
|
| 337 |
+
To "propagate" a work means to do anything with it that, without
|
| 338 |
+
permission, would make you directly or secondarily liable for
|
| 339 |
+
infringement under applicable copyright law, except executing it on a
|
| 340 |
+
computer or modifying a private copy. Propagation includes copying,
|
| 341 |
+
distribution (with or without modification), making available to the
|
| 342 |
+
public, and in some countries other activities as well.
|
| 343 |
+
|
| 344 |
+
To "convey" a work means any kind of propagation that enables other
|
| 345 |
+
parties to make or receive copies. Mere interaction with a user through
|
| 346 |
+
a computer network, with no transfer of a copy, is not conveying.
|
| 347 |
+
|
| 348 |
+
An interactive user interface displays "Appropriate Legal Notices"
|
| 349 |
+
to the extent that it includes a convenient and prominently visible
|
| 350 |
+
feature that (1) displays an appropriate copyright notice, and (2)
|
| 351 |
+
tells the user that there is no warranty for the work (except to the
|
| 352 |
+
extent that warranties are provided), that licensees may convey the
|
| 353 |
+
work under this License, and how to view a copy of this License. If
|
| 354 |
+
the interface presents a list of user commands or options, such as a
|
| 355 |
+
menu, a prominent item in the list meets this criterion.
|
| 356 |
+
|
| 357 |
+
1. Source Code.
|
| 358 |
+
|
| 359 |
+
The "source code" for a work means the preferred form of the work
|
| 360 |
+
for making modifications to it. "Object code" means any non-source
|
| 361 |
+
form of a work.
|
| 362 |
+
|
| 363 |
+
A "Standard Interface" means an interface that either is an official
|
| 364 |
+
standard defined by a recognized standards body, or, in the case of
|
| 365 |
+
interfaces specified for a particular programming language, one that
|
| 366 |
+
is widely used among developers working in that language.
|
| 367 |
+
|
| 368 |
+
The "System Libraries" of an executable work include anything, other
|
| 369 |
+
than the work as a whole, that (a) is included in the normal form of
|
| 370 |
+
packaging a Major Component, but which is not part of that Major
|
| 371 |
+
Component, and (b) serves only to enable use of the work with that
|
| 372 |
+
Major Component, or to implement a Standard Interface for which an
|
| 373 |
+
implementation is available to the public in source code form. A
|
| 374 |
+
"Major Component", in this context, means a major essential component
|
| 375 |
+
(kernel, window system, and so on) of the specific operating system
|
| 376 |
+
(if any) on which the executable work runs, or a compiler used to
|
| 377 |
+
produce the work, or an object code interpreter used to run it.
|
| 378 |
+
|
| 379 |
+
The "Corresponding Source" for a work in object code form means all
|
| 380 |
+
the source code needed to generate, install, and (for an executable
|
| 381 |
+
work) run the object code and to modify the work, including scripts to
|
| 382 |
+
control those activities. However, it does not include the work's
|
| 383 |
+
System Libraries, or general-purpose tools or generally available free
|
| 384 |
+
programs which are used unmodified in performing those activities but
|
| 385 |
+
which are not part of the work. For example, Corresponding Source
|
| 386 |
+
includes interface definition files associated with source files for
|
| 387 |
+
the work, and the source code for shared libraries and dynamically
|
| 388 |
+
linked subprograms that the work is specifically designed to require,
|
| 389 |
+
such as by intimate data communication or control flow between those
|
| 390 |
+
subprograms and other parts of the work.
|
| 391 |
+
|
| 392 |
+
The Corresponding Source need not include anything that users
|
| 393 |
+
can regenerate automatically from other parts of the Corresponding
|
| 394 |
+
Source.
|
| 395 |
+
|
| 396 |
+
The Corresponding Source for a work in source code form is that
|
| 397 |
+
same work.
|
| 398 |
+
|
| 399 |
+
2. Basic Permissions.
|
| 400 |
+
|
| 401 |
+
All rights granted under this License are granted for the term of
|
| 402 |
+
copyright on the Program, and are irrevocable provided the stated
|
| 403 |
+
conditions are met. This License explicitly affirms your unlimited
|
| 404 |
+
permission to run the unmodified Program. The output from running a
|
| 405 |
+
covered work is covered by this License only if the output, given its
|
| 406 |
+
content, constitutes a covered work. This License acknowledges your
|
| 407 |
+
rights of fair use or other equivalent, as provided by copyright law.
|
| 408 |
+
|
| 409 |
+
You may make, run and propagate covered works that you do not
|
| 410 |
+
convey, without conditions so long as your license otherwise remains
|
| 411 |
+
in force. You may convey covered works to others for the sole purpose
|
| 412 |
+
of having them make modifications exclusively for you, or provide you
|
| 413 |
+
with facilities for running those works, provided that you comply with
|
| 414 |
+
the terms of this License in conveying all material for which you do
|
| 415 |
+
not control copyright. Those thus making or running the covered works
|
| 416 |
+
for you must do so exclusively on your behalf, under your direction
|
| 417 |
+
and control, on terms that prohibit them from making any copies of
|
| 418 |
+
your copyrighted material outside their relationship with you.
|
| 419 |
+
|
| 420 |
+
Conveying under any other circumstances is permitted solely under
|
| 421 |
+
the conditions stated below. Sublicensing is not allowed; section 10
|
| 422 |
+
makes it unnecessary.
|
| 423 |
+
|
| 424 |
+
3. Protecting Users' Legal Rights From Anti-Circumvention Law.
|
| 425 |
+
|
| 426 |
+
No covered work shall be deemed part of an effective technological
|
| 427 |
+
measure under any applicable law fulfilling obligations under article
|
| 428 |
+
11 of the WIPO copyright treaty adopted on 20 December 1996, or
|
| 429 |
+
similar laws prohibiting or restricting circumvention of such
|
| 430 |
+
measures.
|
| 431 |
+
|
| 432 |
+
When you convey a covered work, you waive any legal power to forbid
|
| 433 |
+
circumvention of technological measures to the extent such circumvention
|
| 434 |
+
is effected by exercising rights under this License with respect to
|
| 435 |
+
the covered work, and you disclaim any intention to limit operation or
|
| 436 |
+
modification of the work as a means of enforcing, against the work's
|
| 437 |
+
users, your or third parties' legal rights to forbid circumvention of
|
| 438 |
+
technological measures.
|
| 439 |
+
|
| 440 |
+
4. Conveying Verbatim Copies.
|
| 441 |
+
|
| 442 |
+
You may convey verbatim copies of the Program's source code as you
|
| 443 |
+
receive it, in any medium, provided that you conspicuously and
|
| 444 |
+
appropriately publish on each copy an appropriate copyright notice;
|
| 445 |
+
keep intact all notices stating that this License and any
|
| 446 |
+
non-permissive terms added in accord with section 7 apply to the code;
|
| 447 |
+
keep intact all notices of the absence of any warranty; and give all
|
| 448 |
+
recipients a copy of this License along with the Program.
|
| 449 |
+
|
| 450 |
+
You may charge any price or no price for each copy that you convey,
|
| 451 |
+
and you may offer support or warranty protection for a fee.
|
| 452 |
+
|
| 453 |
+
5. Conveying Modified Source Versions.
|
| 454 |
+
|
| 455 |
+
You may convey a work based on the Program, or the modifications to
|
| 456 |
+
produce it from the Program, in the form of source code under the
|
| 457 |
+
terms of section 4, provided that you also meet all of these conditions:
|
| 458 |
+
|
| 459 |
+
a) The work must carry prominent notices stating that you modified
|
| 460 |
+
it, and giving a relevant date.
|
| 461 |
+
|
| 462 |
+
b) The work must carry prominent notices stating that it is
|
| 463 |
+
released under this License and any conditions added under section
|
| 464 |
+
7. This requirement modifies the requirement in section 4 to
|
| 465 |
+
"keep intact all notices".
|
| 466 |
+
|
| 467 |
+
c) You must license the entire work, as a whole, under this
|
| 468 |
+
License to anyone who comes into possession of a copy. This
|
| 469 |
+
License will therefore apply, along with any applicable section 7
|
| 470 |
+
additional terms, to the whole of the work, and all its parts,
|
| 471 |
+
regardless of how they are packaged. This License gives no
|
| 472 |
+
permission to license the work in any other way, but it does not
|
| 473 |
+
invalidate such permission if you have separately received it.
|
| 474 |
+
|
| 475 |
+
d) If the work has interactive user interfaces, each must display
|
| 476 |
+
Appropriate Legal Notices; however, if the Program has interactive
|
| 477 |
+
interfaces that do not display Appropriate Legal Notices, your
|
| 478 |
+
work need not make them do so.
|
| 479 |
+
|
| 480 |
+
A compilation of a covered work with other separate and independent
|
| 481 |
+
works, which are not by their nature extensions of the covered work,
|
| 482 |
+
and which are not combined with it such as to form a larger program,
|
| 483 |
+
in or on a volume of a storage or distribution medium, is called an
|
| 484 |
+
"aggregate" if the compilation and its resulting copyright are not
|
| 485 |
+
used to limit the access or legal rights of the compilation's users
|
| 486 |
+
beyond what the individual works permit. Inclusion of a covered work
|
| 487 |
+
in an aggregate does not cause this License to apply to the other
|
| 488 |
+
parts of the aggregate.
|
| 489 |
+
|
| 490 |
+
6. Conveying Non-Source Forms.
|
| 491 |
+
|
| 492 |
+
You may convey a covered work in object code form under the terms
|
| 493 |
+
of sections 4 and 5, provided that you also convey the
|
| 494 |
+
machine-readable Corresponding Source under the terms of this License,
|
| 495 |
+
in one of these ways:
|
| 496 |
+
|
| 497 |
+
a) Convey the object code in, or embodied in, a physical product
|
| 498 |
+
(including a physical distribution medium), accompanied by the
|
| 499 |
+
Corresponding Source fixed on a durable physical medium
|
| 500 |
+
customarily used for software interchange.
|
| 501 |
+
|
| 502 |
+
b) Convey the object code in, or embodied in, a physical product
|
| 503 |
+
(including a physical distribution medium), accompanied by a
|
| 504 |
+
written offer, valid for at least three years and valid for as
|
| 505 |
+
long as you offer spare parts or customer support for that product
|
| 506 |
+
model, to give anyone who possesses the object code either (1) a
|
| 507 |
+
copy of the Corresponding Source for all the software in the
|
| 508 |
+
product that is covered by this License, on a durable physical
|
| 509 |
+
medium customarily used for software interchange, for a price no
|
| 510 |
+
more than your reasonable cost of physically performing this
|
| 511 |
+
conveying of source, or (2) access to copy the
|
| 512 |
+
Corresponding Source from a network server at no charge.
|
| 513 |
+
|
| 514 |
+
c) Convey individual copies of the object code with a copy of the
|
| 515 |
+
written offer to provide the Corresponding Source. This
|
| 516 |
+
alternative is allowed only occasionally and noncommercially, and
|
| 517 |
+
only if you received the object code with such an offer, in accord
|
| 518 |
+
with subsection 6b.
|
| 519 |
+
|
| 520 |
+
d) Convey the object code by offering access from a designated
|
| 521 |
+
place (gratis or for a charge), and offer equivalent access to the
|
| 522 |
+
Corresponding Source in the same way through the same place at no
|
| 523 |
+
further charge. You need not require recipients to copy the
|
| 524 |
+
Corresponding Source along with the object code. If the place to
|
| 525 |
+
copy the object code is a network server, the Corresponding Source
|
| 526 |
+
may be on a different server (operated by you or a third party)
|
| 527 |
+
that supports equivalent copying facilities, provided you maintain
|
| 528 |
+
clear directions next to the object code saying where to find the
|
| 529 |
+
Corresponding Source. Regardless of what server hosts the
|
| 530 |
+
Corresponding Source, you remain obligated to ensure that it is
|
| 531 |
+
available for as long as needed to satisfy these requirements.
|
| 532 |
+
|
| 533 |
+
e) Convey the object code using peer-to-peer transmission, provided
|
| 534 |
+
you inform other peers where the object code and Corresponding
|
| 535 |
+
Source of the work are being offered to the general public at no
|
| 536 |
+
charge under subsection 6d.
|
| 537 |
+
|
| 538 |
+
A separable portion of the object code, whose source code is excluded
|
| 539 |
+
from the Corresponding Source as a System Library, need not be
|
| 540 |
+
included in conveying the object code work.
|
| 541 |
+
|
| 542 |
+
A "User Product" is either (1) a "consumer product", which means any
|
| 543 |
+
tangible personal property which is normally used for personal, family,
|
| 544 |
+
or household purposes, or (2) anything designed or sold for incorporation
|
| 545 |
+
into a dwelling. In determining whether a product is a consumer product,
|
| 546 |
+
doubtful cases shall be resolved in favor of coverage. For a particular
|
| 547 |
+
product received by a particular user, "normally used" refers to a
|
| 548 |
+
typical or common use of that class of product, regardless of the status
|
| 549 |
+
of the particular user or of the way in which the particular user
|
| 550 |
+
actually uses, or expects or is expected to use, the product. A product
|
| 551 |
+
is a consumer product regardless of whether the product has substantial
|
| 552 |
+
commercial, industrial or non-consumer uses, unless such uses represent
|
| 553 |
+
the only significant mode of use of the product.
|
| 554 |
+
|
| 555 |
+
"Installation Information" for a User Product means any methods,
|
| 556 |
+
procedures, authorization keys, or other information required to install
|
| 557 |
+
and execute modified versions of a covered work in that User Product from
|
| 558 |
+
a modified version of its Corresponding Source. The information must
|
| 559 |
+
suffice to ensure that the continued functioning of the modified object
|
| 560 |
+
code is in no case prevented or interfered with solely because
|
| 561 |
+
modification has been made.
|
| 562 |
+
|
| 563 |
+
If you convey an object code work under this section in, or with, or
|
| 564 |
+
specifically for use in, a User Product, and the conveying occurs as
|
| 565 |
+
part of a transaction in which the right of possession and use of the
|
| 566 |
+
User Product is transferred to the recipient in perpetuity or for a
|
| 567 |
+
fixed term (regardless of how the transaction is characterized), the
|
| 568 |
+
Corresponding Source conveyed under this section must be accompanied
|
| 569 |
+
by the Installation Information. But this requirement does not apply
|
| 570 |
+
if neither you nor any third party retains the ability to install
|
| 571 |
+
modified object code on the User Product (for example, the work has
|
| 572 |
+
been installed in ROM).
|
| 573 |
+
|
| 574 |
+
The requirement to provide Installation Information does not include a
|
| 575 |
+
requirement to continue to provide support service, warranty, or updates
|
| 576 |
+
for a work that has been modified or installed by the recipient, or for
|
| 577 |
+
the User Product in which it has been modified or installed. Access to a
|
| 578 |
+
network may be denied when the modification itself materially and
|
| 579 |
+
adversely affects the operation of the network or violates the rules and
|
| 580 |
+
protocols for communication across the network.
|
| 581 |
+
|
| 582 |
+
Corresponding Source conveyed, and Installation Information provided,
|
| 583 |
+
in accord with this section must be in a format that is publicly
|
| 584 |
+
documented (and with an implementation available to the public in
|
| 585 |
+
source code form), and must require no special password or key for
|
| 586 |
+
unpacking, reading or copying.
|
| 587 |
+
|
| 588 |
+
7. Additional Terms.
|
| 589 |
+
|
| 590 |
+
"Additional permissions" are terms that supplement the terms of this
|
| 591 |
+
License by making exceptions from one or more of its conditions.
|
| 592 |
+
Additional permissions that are applicable to the entire Program shall
|
| 593 |
+
be treated as though they were included in this License, to the extent
|
| 594 |
+
that they are valid under applicable law. If additional permissions
|
| 595 |
+
apply only to part of the Program, that part may be used separately
|
| 596 |
+
under those permissions, but the entire Program remains governed by
|
| 597 |
+
this License without regard to the additional permissions.
|
| 598 |
+
|
| 599 |
+
When you convey a copy of a covered work, you may at your option
|
| 600 |
+
remove any additional permissions from that copy, or from any part of
|
| 601 |
+
it. (Additional permissions may be written to require their own
|
| 602 |
+
removal in certain cases when you modify the work.) You may place
|
| 603 |
+
additional permissions on material, added by you to a covered work,
|
| 604 |
+
for which you have or can give appropriate copyright permission.
|
| 605 |
+
|
| 606 |
+
Notwithstanding any other provision of this License, for material you
|
| 607 |
+
add to a covered work, you may (if authorized by the copyright holders of
|
| 608 |
+
that material) supplement the terms of this License with terms:
|
| 609 |
+
|
| 610 |
+
a) Disclaiming warranty or limiting liability differently from the
|
| 611 |
+
terms of sections 15 and 16 of this License; or
|
| 612 |
+
|
| 613 |
+
b) Requiring preservation of specified reasonable legal notices or
|
| 614 |
+
author attributions in that material or in the Appropriate Legal
|
| 615 |
+
Notices displayed by works containing it; or
|
| 616 |
+
|
| 617 |
+
c) Prohibiting misrepresentation of the origin of that material, or
|
| 618 |
+
requiring that modified versions of such material be marked in
|
| 619 |
+
reasonable ways as different from the original version; or
|
| 620 |
+
|
| 621 |
+
d) Limiting the use for publicity purposes of names of licensors or
|
| 622 |
+
authors of the material; or
|
| 623 |
+
|
| 624 |
+
e) Declining to grant rights under trademark law for use of some
|
| 625 |
+
trade names, trademarks, or service marks; or
|
| 626 |
+
|
| 627 |
+
f) Requiring indemnification of licensors and authors of that
|
| 628 |
+
material by anyone who conveys the material (or modified versions of
|
| 629 |
+
it) with contractual assumptions of liability to the recipient, for
|
| 630 |
+
any liability that these contractual assumptions directly impose on
|
| 631 |
+
those licensors and authors.
|
| 632 |
+
|
| 633 |
+
All other non-permissive additional terms are considered "further
|
| 634 |
+
restrictions" within the meaning of section 10. If the Program as you
|
| 635 |
+
received it, or any part of it, contains a notice stating that it is
|
| 636 |
+
governed by this License along with a term that is a further
|
| 637 |
+
restriction, you may remove that term. If a license document contains
|
| 638 |
+
a further restriction but permits relicensing or conveying under this
|
| 639 |
+
License, you may add to a covered work material governed by the terms
|
| 640 |
+
of that license document, provided that the further restriction does
|
| 641 |
+
not survive such relicensing or conveying.
|
| 642 |
+
|
| 643 |
+
If you add terms to a covered work in accord with this section, you
|
| 644 |
+
must place, in the relevant source files, a statement of the
|
| 645 |
+
additional terms that apply to those files, or a notice indicating
|
| 646 |
+
where to find the applicable terms.
|
| 647 |
+
|
| 648 |
+
Additional terms, permissive or non-permissive, may be stated in the
|
| 649 |
+
form of a separately written license, or stated as exceptions;
|
| 650 |
+
the above requirements apply either way.
|
| 651 |
+
|
| 652 |
+
8. Termination.
|
| 653 |
+
|
| 654 |
+
You may not propagate or modify a covered work except as expressly
|
| 655 |
+
provided under this License. Any attempt otherwise to propagate or
|
| 656 |
+
modify it is void, and will automatically terminate your rights under
|
| 657 |
+
this License (including any patent licenses granted under the third
|
| 658 |
+
paragraph of section 11).
|
| 659 |
+
|
| 660 |
+
However, if you cease all violation of this License, then your
|
| 661 |
+
license from a particular copyright holder is reinstated (a)
|
| 662 |
+
provisionally, unless and until the copyright holder explicitly and
|
| 663 |
+
finally terminates your license, and (b) permanently, if the copyright
|
| 664 |
+
holder fails to notify you of the violation by some reasonable means
|
| 665 |
+
prior to 60 days after the cessation.
|
| 666 |
+
|
| 667 |
+
Moreover, your license from a particular copyright holder is
|
| 668 |
+
reinstated permanently if the copyright holder notifies you of the
|
| 669 |
+
violation by some reasonable means, this is the first time you have
|
| 670 |
+
received notice of violation of this License (for any work) from that
|
| 671 |
+
copyright holder, and you cure the violation prior to 30 days after
|
| 672 |
+
your receipt of the notice.
|
| 673 |
+
|
| 674 |
+
Termination of your rights under this section does not terminate the
|
| 675 |
+
licenses of parties who have received copies or rights from you under
|
| 676 |
+
this License. If your rights have been terminated and not permanently
|
| 677 |
+
reinstated, you do not qualify to receive new licenses for the same
|
| 678 |
+
material under section 10.
|
| 679 |
+
|
| 680 |
+
9. Acceptance Not Required for Having Copies.
|
| 681 |
+
|
| 682 |
+
You are not required to accept this License in order to receive or
|
| 683 |
+
run a copy of the Program. Ancillary propagation of a covered work
|
| 684 |
+
occurring solely as a consequence of using peer-to-peer transmission
|
| 685 |
+
to receive a copy likewise does not require acceptance. However,
|
| 686 |
+
nothing other than this License grants you permission to propagate or
|
| 687 |
+
modify any covered work. These actions infringe copyright if you do
|
| 688 |
+
not accept this License. Therefore, by modifying or propagating a
|
| 689 |
+
covered work, you indicate your acceptance of this License to do so.
|
| 690 |
+
|
| 691 |
+
10. Automatic Licensing of Downstream Recipients.
|
| 692 |
+
|
| 693 |
+
Each time you convey a covered work, the recipient automatically
|
| 694 |
+
receives a license from the original licensors, to run, modify and
|
| 695 |
+
propagate that work, subject to this License. You are not responsible
|
| 696 |
+
for enforcing compliance by third parties with this License.
|
| 697 |
+
|
| 698 |
+
An "entity transaction" is a transaction transferring control of an
|
| 699 |
+
organization, or substantially all assets of one, or subdividing an
|
| 700 |
+
organization, or merging organizations. If propagation of a covered
|
| 701 |
+
work results from an entity transaction, each party to that
|
| 702 |
+
transaction who receives a copy of the work also receives whatever
|
| 703 |
+
licenses to the work the party's predecessor in interest had or could
|
| 704 |
+
give under the previous paragraph, plus a right to possession of the
|
| 705 |
+
Corresponding Source of the work from the predecessor in interest, if
|
| 706 |
+
the predecessor has it or can get it with reasonable efforts.
|
| 707 |
+
|
| 708 |
+
You may not impose any further restrictions on the exercise of the
|
| 709 |
+
rights granted or affirmed under this License. For example, you may
|
| 710 |
+
not impose a license fee, royalty, or other charge for exercise of
|
| 711 |
+
rights granted under this License, and you may not initiate litigation
|
| 712 |
+
(including a cross-claim or counterclaim in a lawsuit) alleging that
|
| 713 |
+
any patent claim is infringed by making, using, selling, offering for
|
| 714 |
+
sale, or importing the Program or any portion of it.
|
| 715 |
+
|
| 716 |
+
11. Patents.
|
| 717 |
+
|
| 718 |
+
A "contributor" is a copyright holder who authorizes use under this
|
| 719 |
+
License of the Program or a work on which the Program is based. The
|
| 720 |
+
work thus licensed is called the contributor's "contributor version".
|
| 721 |
+
|
| 722 |
+
A contributor's "essential patent claims" are all patent claims
|
| 723 |
+
owned or controlled by the contributor, whether already acquired or
|
| 724 |
+
hereafter acquired, that would be infringed by some manner, permitted
|
| 725 |
+
by this License, of making, using, or selling its contributor version,
|
| 726 |
+
but do not include claims that would be infringed only as a
|
| 727 |
+
consequence of further modification of the contributor version. For
|
| 728 |
+
purposes of this definition, "control" includes the right to grant
|
| 729 |
+
patent sublicenses in a manner consistent with the requirements of
|
| 730 |
+
this License.
|
| 731 |
+
|
| 732 |
+
Each contributor grants you a non-exclusive, worldwide, royalty-free
|
| 733 |
+
patent license under the contributor's essential patent claims, to
|
| 734 |
+
make, use, sell, offer for sale, import and otherwise run, modify and
|
| 735 |
+
propagate the contents of its contributor version.
|
| 736 |
+
|
| 737 |
+
In the following three paragraphs, a "patent license" is any express
|
| 738 |
+
agreement or commitment, however denominated, not to enforce a patent
|
| 739 |
+
(such as an express permission to practice a patent or covenant not to
|
| 740 |
+
sue for patent infringement). To "grant" such a patent license to a
|
| 741 |
+
party means to make such an agreement or commitment not to enforce a
|
| 742 |
+
patent against the party.
|
| 743 |
+
|
| 744 |
+
If you convey a covered work, knowingly relying on a patent license,
|
| 745 |
+
and the Corresponding Source of the work is not available for anyone
|
| 746 |
+
to copy, free of charge and under the terms of this License, through a
|
| 747 |
+
publicly available network server or other readily accessible means,
|
| 748 |
+
then you must either (1) cause the Corresponding Source to be so
|
| 749 |
+
available, or (2) arrange to deprive yourself of the benefit of the
|
| 750 |
+
patent license for this particular work, or (3) arrange, in a manner
|
| 751 |
+
consistent with the requirements of this License, to extend the patent
|
| 752 |
+
license to downstream recipients. "Knowingly relying" means you have
|
| 753 |
+
actual knowledge that, but for the patent license, your conveying the
|
| 754 |
+
covered work in a country, or your recipient's use of the covered work
|
| 755 |
+
in a country, would infringe one or more identifiable patents in that
|
| 756 |
+
country that you have reason to believe are valid.
|
| 757 |
+
|
| 758 |
+
If, pursuant to or in connection with a single transaction or
|
| 759 |
+
arrangement, you convey, or propagate by procuring conveyance of, a
|
| 760 |
+
covered work, and grant a patent license to some of the parties
|
| 761 |
+
receiving the covered work authorizing them to use, propagate, modify
|
| 762 |
+
or convey a specific copy of the covered work, then the patent license
|
| 763 |
+
you grant is automatically extended to all recipients of the covered
|
| 764 |
+
work and works based on it.
|
| 765 |
+
|
| 766 |
+
A patent license is "discriminatory" if it does not include within
|
| 767 |
+
the scope of its coverage, prohibits the exercise of, or is
|
| 768 |
+
conditioned on the non-exercise of one or more of the rights that are
|
| 769 |
+
specifically granted under this License. You may not convey a covered
|
| 770 |
+
work if you are a party to an arrangement with a third party that is
|
| 771 |
+
in the business of distributing software, under which you make payment
|
| 772 |
+
to the third party based on the extent of your activity of conveying
|
| 773 |
+
the work, and under which the third party grants, to any of the
|
| 774 |
+
parties who would receive the covered work from you, a discriminatory
|
| 775 |
+
patent license (a) in connection with copies of the covered work
|
| 776 |
+
conveyed by you (or copies made from those copies), or (b) primarily
|
| 777 |
+
for and in connection with specific products or compilations that
|
| 778 |
+
contain the covered work, unless you entered into that arrangement,
|
| 779 |
+
or that patent license was granted, prior to 28 March 2007.
|
| 780 |
+
|
| 781 |
+
Nothing in this License shall be construed as excluding or limiting
|
| 782 |
+
any implied license or other defenses to infringement that may
|
| 783 |
+
otherwise be available to you under applicable patent law.
|
| 784 |
+
|
| 785 |
+
12. No Surrender of Others' Freedom.
|
| 786 |
+
|
| 787 |
+
If conditions are imposed on you (whether by court order, agreement or
|
| 788 |
+
otherwise) that contradict the conditions of this License, they do not
|
| 789 |
+
excuse you from the conditions of this License. If you cannot convey a
|
| 790 |
+
covered work so as to satisfy simultaneously your obligations under this
|
| 791 |
+
License and any other pertinent obligations, then as a consequence you may
|
| 792 |
+
not convey it at all. For example, if you agree to terms that obligate you
|
| 793 |
+
to collect a royalty for further conveying from those to whom you convey
|
| 794 |
+
the Program, the only way you could satisfy both those terms and this
|
| 795 |
+
License would be to refrain entirely from conveying the Program.
|
| 796 |
+
|
| 797 |
+
13. Use with the GNU Affero General Public License.
|
| 798 |
+
|
| 799 |
+
Notwithstanding any other provision of this License, you have
|
| 800 |
+
permission to link or combine any covered work with a work licensed
|
| 801 |
+
under version 3 of the GNU Affero General Public License into a single
|
| 802 |
+
combined work, and to convey the resulting work. The terms of this
|
| 803 |
+
License will continue to apply to the part which is the covered work,
|
| 804 |
+
but the special requirements of the GNU Affero General Public License,
|
| 805 |
+
section 13, concerning interaction through a network will apply to the
|
| 806 |
+
combination as such.
|
| 807 |
+
|
| 808 |
+
14. Revised Versions of this License.
|
| 809 |
+
|
| 810 |
+
The Free Software Foundation may publish revised and/or new versions of
|
| 811 |
+
the GNU General Public License from time to time. Such new versions will
|
| 812 |
+
be similar in spirit to the present version, but may differ in detail to
|
| 813 |
+
address new problems or concerns.
|
| 814 |
+
|
| 815 |
+
Each version is given a distinguishing version number. If the
|
| 816 |
+
Program specifies that a certain numbered version of the GNU General
|
| 817 |
+
Public License "or any later version" applies to it, you have the
|
| 818 |
+
option of following the terms and conditions either of that numbered
|
| 819 |
+
version or of any later version published by the Free Software
|
| 820 |
+
Foundation. If the Program does not specify a version number of the
|
| 821 |
+
GNU General Public License, you may choose any version ever published
|
| 822 |
+
by the Free Software Foundation.
|
| 823 |
+
|
| 824 |
+
If the Program specifies that a proxy can decide which future
|
| 825 |
+
versions of the GNU General Public License can be used, that proxy's
|
| 826 |
+
public statement of acceptance of a version permanently authorizes you
|
| 827 |
+
to choose that version for the Program.
|
| 828 |
+
|
| 829 |
+
Later license versions may give you additional or different
|
| 830 |
+
permissions. However, no additional obligations are imposed on any
|
| 831 |
+
author or copyright holder as a result of your choosing to follow a
|
| 832 |
+
later version.
|
| 833 |
+
|
| 834 |
+
15. Disclaimer of Warranty.
|
| 835 |
+
|
| 836 |
+
THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY
|
| 837 |
+
APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT
|
| 838 |
+
HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY
|
| 839 |
+
OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO,
|
| 840 |
+
THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
|
| 841 |
+
PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM
|
| 842 |
+
IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF
|
| 843 |
+
ALL NECESSARY SERVICING, REPAIR OR CORRECTION.
|
| 844 |
+
|
| 845 |
+
16. Limitation of Liability.
|
| 846 |
+
|
| 847 |
+
IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
|
| 848 |
+
WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS
|
| 849 |
+
THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY
|
| 850 |
+
GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE
|
| 851 |
+
USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF
|
| 852 |
+
DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD
|
| 853 |
+
PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS),
|
| 854 |
+
EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF
|
| 855 |
+
SUCH DAMAGES.
|
| 856 |
+
|
| 857 |
+
17. Interpretation of Sections 15 and 16.
|
| 858 |
+
|
| 859 |
+
If the disclaimer of warranty and limitation of liability provided
|
| 860 |
+
above cannot be given local legal effect according to their terms,
|
| 861 |
+
reviewing courts shall apply local law that most closely approximates
|
| 862 |
+
an absolute waiver of all civil liability in connection with the
|
| 863 |
+
Program, unless a warranty or assumption of liability accompanies a
|
| 864 |
+
copy of the Program in return for a fee.
|
| 865 |
+
|
| 866 |
+
END OF TERMS AND CONDITIONS
|
| 867 |
+
|
| 868 |
+
How to Apply These Terms to Your New Programs
|
| 869 |
+
|
| 870 |
+
If you develop a new program, and you want it to be of the greatest
|
| 871 |
+
possible use to the public, the best way to achieve this is to make it
|
| 872 |
+
free software which everyone can redistribute and change under these terms.
|
| 873 |
+
|
| 874 |
+
To do so, attach the following notices to the program. It is safest
|
| 875 |
+
to attach them to the start of each source file to most effectively
|
| 876 |
+
state the exclusion of warranty; and each file should have at least
|
| 877 |
+
the "copyright" line and a pointer to where the full notice is found.
|
| 878 |
+
|
| 879 |
+
<one line to give the program's name and a brief idea of what it does.>
|
| 880 |
+
Copyright (C) <year> <name of author>
|
| 881 |
+
|
| 882 |
+
This program is free software: you can redistribute it and/or modify
|
| 883 |
+
it under the terms of the GNU General Public License as published by
|
| 884 |
+
the Free Software Foundation, either version 3 of the License, or
|
| 885 |
+
(at your option) any later version.
|
| 886 |
+
|
| 887 |
+
This program is distributed in the hope that it will be useful,
|
| 888 |
+
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
| 889 |
+
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
| 890 |
+
GNU General Public License for more details.
|
| 891 |
+
|
| 892 |
+
You should have received a copy of the GNU General Public License
|
| 893 |
+
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
| 894 |
+
|
| 895 |
+
Also add information on how to contact you by electronic and paper mail.
|
| 896 |
+
|
| 897 |
+
If the program does terminal interaction, make it output a short
|
| 898 |
+
notice like this when it starts in an interactive mode:
|
| 899 |
+
|
| 900 |
+
<program> Copyright (C) <year> <name of author>
|
| 901 |
+
This program comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
|
| 902 |
+
This is free software, and you are welcome to redistribute it
|
| 903 |
+
under certain conditions; type `show c' for details.
|
| 904 |
+
|
| 905 |
+
The hypothetical commands `show w' and `show c' should show the appropriate
|
| 906 |
+
parts of the General Public License. Of course, your program's commands
|
| 907 |
+
might be different; for a GUI interface, you would use an "about box".
|
| 908 |
+
|
| 909 |
+
You should also get your employer (if you work as a programmer) or school,
|
| 910 |
+
if any, to sign a "copyright disclaimer" for the program, if necessary.
|
| 911 |
+
For more information on this, and how to apply and follow the GNU GPL, see
|
| 912 |
+
<http://www.gnu.org/licenses/>.
|
| 913 |
+
|
| 914 |
+
The GNU General Public License does not permit incorporating your program
|
| 915 |
+
into proprietary programs. If your program is a subroutine library, you
|
| 916 |
+
may consider it more useful to permit linking proprietary applications with
|
| 917 |
+
the library. If this is what you want to do, use the GNU Lesser General
|
| 918 |
+
Public License instead of this License. But first, please read
|
| 919 |
+
<http://www.gnu.org/philosophy/why-not-lgpl.html>.
|
| 920 |
+
|
| 921 |
+
|
| 922 |
+
Name: libquadmath
|
| 923 |
+
Files: scipy.libs/libquadmath*.so
|
| 924 |
+
Description: dynamically linked to files compiled with gcc
|
| 925 |
+
Availability: https://gcc.gnu.org/git/?p=gcc.git;a=tree;f=libquadmath
|
| 926 |
+
License: LGPL-2.1-or-later
|
| 927 |
+
|
| 928 |
+
GCC Quad-Precision Math Library
|
| 929 |
+
Copyright (C) 2010-2019 Free Software Foundation, Inc.
|
| 930 |
+
Written by Francois-Xavier Coudert <fxcoudert@gcc.gnu.org>
|
| 931 |
+
|
| 932 |
+
This file is part of the libquadmath library.
|
| 933 |
+
Libquadmath is free software; you can redistribute it and/or
|
| 934 |
+
modify it under the terms of the GNU Library General Public
|
| 935 |
+
License as published by the Free Software Foundation; either
|
| 936 |
+
version 2.1 of the License, or (at your option) any later version.
|
| 937 |
+
|
| 938 |
+
Libquadmath is distributed in the hope that it will be useful,
|
| 939 |
+
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
| 940 |
+
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
| 941 |
+
Lesser General Public License for more details.
|
| 942 |
+
https://www.gnu.org/licenses/old-licenses/lgpl-2.1.html
|
| 943 |
+
|
| 944 |
+
Classifier: Development Status :: 5 - Production/Stable
|
| 945 |
+
Classifier: Intended Audience :: Science/Research
|
| 946 |
+
Classifier: Intended Audience :: Developers
|
| 947 |
+
Classifier: License :: OSI Approved :: BSD License
|
| 948 |
+
Classifier: Programming Language :: C
|
| 949 |
+
Classifier: Programming Language :: Python
|
| 950 |
+
Classifier: Programming Language :: Python :: 3
|
| 951 |
+
Classifier: Programming Language :: Python :: 3.12
|
| 952 |
+
Classifier: Programming Language :: Python :: 3.13
|
| 953 |
+
Classifier: Programming Language :: Python :: 3.14
|
| 954 |
+
Classifier: Topic :: Software Development :: Libraries
|
| 955 |
+
Classifier: Topic :: Scientific/Engineering
|
| 956 |
+
Classifier: Operating System :: Microsoft :: Windows
|
| 957 |
+
Classifier: Operating System :: POSIX :: Linux
|
| 958 |
+
Classifier: Operating System :: POSIX
|
| 959 |
+
Classifier: Operating System :: Unix
|
| 960 |
+
Classifier: Operating System :: MacOS
|
| 961 |
+
Project-URL: homepage, https://scipy.org/
|
| 962 |
+
Project-URL: documentation, https://docs.scipy.org/doc/scipy/
|
| 963 |
+
Project-URL: source, https://github.com/scipy/scipy
|
| 964 |
+
Project-URL: download, https://github.com/scipy/scipy/releases
|
| 965 |
+
Project-URL: tracker, https://github.com/scipy/scipy/issues
|
| 966 |
+
Requires-Python: >=3.12
|
| 967 |
+
Requires-Dist: numpy<2.8,>=2.0.0
|
| 968 |
+
Provides-Extra: test
|
| 969 |
+
Requires-Dist: pytest>=8.0.0; extra == "test"
|
| 970 |
+
Requires-Dist: pytest-cov; extra == "test"
|
| 971 |
+
Requires-Dist: pytest-timeout; extra == "test"
|
| 972 |
+
Requires-Dist: pytest-xdist; extra == "test"
|
| 973 |
+
Requires-Dist: asv; extra == "test"
|
| 974 |
+
Requires-Dist: mpmath; extra == "test"
|
| 975 |
+
Requires-Dist: gmpy2; extra == "test"
|
| 976 |
+
Requires-Dist: threadpoolctl; extra == "test"
|
| 977 |
+
Requires-Dist: scikit-umfpack; extra == "test"
|
| 978 |
+
Requires-Dist: pooch; extra == "test"
|
| 979 |
+
Requires-Dist: hypothesis>=6.30; extra == "test"
|
| 980 |
+
Requires-Dist: array-api-strict>=2.3.1; extra == "test"
|
| 981 |
+
Requires-Dist: Cython; extra == "test"
|
| 982 |
+
Requires-Dist: meson; extra == "test"
|
| 983 |
+
Requires-Dist: ninja; sys_platform != "emscripten" and extra == "test"
|
| 984 |
+
Requires-Dist: scipy-doctest>=2.0.0; extra == "test"
|
| 985 |
+
Provides-Extra: doc
|
| 986 |
+
Requires-Dist: sphinx<8.2.0,>=5.0.0; extra == "doc"
|
| 987 |
+
Requires-Dist: intersphinx_registry; extra == "doc"
|
| 988 |
+
Requires-Dist: pydata-sphinx-theme>=0.15.2; extra == "doc"
|
| 989 |
+
Requires-Dist: sphinx-copybutton; extra == "doc"
|
| 990 |
+
Requires-Dist: sphinx-design>=0.4.0; extra == "doc"
|
| 991 |
+
Requires-Dist: matplotlib>=3.5; extra == "doc"
|
| 992 |
+
Requires-Dist: numpydoc; extra == "doc"
|
| 993 |
+
Requires-Dist: jupytext; extra == "doc"
|
| 994 |
+
Requires-Dist: myst-nb>=1.2.0; extra == "doc"
|
| 995 |
+
Requires-Dist: pooch; extra == "doc"
|
| 996 |
+
Requires-Dist: jupyterlite-sphinx>=0.19.1; extra == "doc"
|
| 997 |
+
Requires-Dist: jupyterlite-pyodide-kernel; extra == "doc"
|
| 998 |
+
Requires-Dist: linkify-it-py; extra == "doc"
|
| 999 |
+
Requires-Dist: tabulate; extra == "doc"
|
| 1000 |
+
Provides-Extra: dev
|
| 1001 |
+
Requires-Dist: click<8.3.0; extra == "dev"
|
| 1002 |
+
Requires-Dist: spin; extra == "dev"
|
| 1003 |
+
Requires-Dist: mypy==1.19.1; extra == "dev"
|
| 1004 |
+
Requires-Dist: pyrefly==0.63.0; extra == "dev"
|
| 1005 |
+
Requires-Dist: typing_extensions; extra == "dev"
|
| 1006 |
+
Requires-Dist: types-psutil; extra == "dev"
|
| 1007 |
+
Requires-Dist: pycodestyle; extra == "dev"
|
| 1008 |
+
Requires-Dist: ruff>=0.12.0; extra == "dev"
|
| 1009 |
+
Requires-Dist: cython-lint>=0.12.2; extra == "dev"
|
| 1010 |
+
Description-Content-Type: text/x-rst
|
| 1011 |
+
|
| 1012 |
+
.. image:: https://raw.githubusercontent.com/scipy/scipy/main/doc/source/_static/logo.svg
|
| 1013 |
+
:target: https://scipy.org
|
| 1014 |
+
:width: 110
|
| 1015 |
+
:height: 110
|
| 1016 |
+
:align: left
|
| 1017 |
+
|
| 1018 |
+
.. image:: https://img.shields.io/badge/powered%20by-NumFOCUS-orange.svg?style=flat&colorA=E1523D&colorB=007D8A
|
| 1019 |
+
:target: https://numfocus.org
|
| 1020 |
+
|
| 1021 |
+
.. image:: https://img.shields.io/pypi/dm/scipy.svg?label=Pypi%20downloads
|
| 1022 |
+
:target: https://pypi.org/project/scipy/
|
| 1023 |
+
|
| 1024 |
+
.. image:: https://img.shields.io/conda/dn/conda-forge/scipy.svg?label=Conda%20downloads
|
| 1025 |
+
:target: https://anaconda.org/conda-forge/scipy
|
| 1026 |
+
|
| 1027 |
+
.. image:: https://img.shields.io/badge/stackoverflow-Ask%20questions-blue.svg
|
| 1028 |
+
:target: https://stackoverflow.com/questions/tagged/scipy
|
| 1029 |
+
|
| 1030 |
+
.. image:: https://img.shields.io/badge/DOI-10.1038%2Fs41592--019--0686--2-blue.svg
|
| 1031 |
+
:target: https://www.nature.com/articles/s41592-019-0686-2
|
| 1032 |
+
|
| 1033 |
+
.. image:: https://insights.linuxfoundation.org/api/badge/health-score?project=scipy
|
| 1034 |
+
:target: https://insights.linuxfoundation.org/project/scipy
|
| 1035 |
+
|
| 1036 |
+
SciPy (pronounced "Sigh Pie") is an open-source software for mathematics,
|
| 1037 |
+
science, and engineering. It includes modules for statistics, optimization,
|
| 1038 |
+
integration, linear algebra, Fourier transforms, signal and image processing,
|
| 1039 |
+
ODE solvers, and more.
|
| 1040 |
+
|
| 1041 |
+
- **Website:** https://scipy.org
|
| 1042 |
+
- **Documentation:** https://docs.scipy.org/doc/scipy/
|
| 1043 |
+
- **Development version of the documentation:** https://scipy.github.io/devdocs
|
| 1044 |
+
- **SciPy development forum:** https://discuss.scientific-python.org/c/contributor/scipy
|
| 1045 |
+
- **Stack Overflow:** https://stackoverflow.com/questions/tagged/scipy
|
| 1046 |
+
- **Source code:** https://github.com/scipy/scipy
|
| 1047 |
+
- **Contributing:** https://scipy.github.io/devdocs/dev/index.html
|
| 1048 |
+
- **Bug reports:** https://github.com/scipy/scipy/issues
|
| 1049 |
+
- **Code of Conduct:** https://docs.scipy.org/doc/scipy/dev/conduct/code_of_conduct.html
|
| 1050 |
+
- **Report a security vulnerability:** via Tidelift, as explained in
|
| 1051 |
+
`our docs on Security <https://scipy.github.io/devdocs/tutorial/security.html>`__
|
| 1052 |
+
- **Citing in your work:** https://www.scipy.org/citing-scipy/
|
| 1053 |
+
|
| 1054 |
+
SciPy is built to work with
|
| 1055 |
+
NumPy arrays, and provides many user-friendly and efficient numerical routines,
|
| 1056 |
+
such as routines for numerical integration and optimization. Together, they
|
| 1057 |
+
run on all popular operating systems, are quick to install, and are free of
|
| 1058 |
+
charge. NumPy and SciPy are easy to use, but powerful enough to be depended
|
| 1059 |
+
upon by some of the world's leading scientists and engineers. If you need to
|
| 1060 |
+
manipulate numbers on a computer and display or publish the results, give
|
| 1061 |
+
SciPy a try!
|
| 1062 |
+
|
| 1063 |
+
For the installation instructions, see `our install
|
| 1064 |
+
guide <https://scipy.org/install/>`__.
|
| 1065 |
+
|
| 1066 |
+
|
| 1067 |
+
Call for Contributions
|
| 1068 |
+
----------------------
|
| 1069 |
+
|
| 1070 |
+
We appreciate and welcome contributions. Small improvements or fixes are always appreciated; issues labeled as "good
|
| 1071 |
+
first issue" may be a good starting point. Have a look at `our contributing
|
| 1072 |
+
guide <https://scipy.github.io/devdocs/dev/index.html>`__.
|
| 1073 |
+
|
| 1074 |
+
Writing code isn’t the only way to contribute to SciPy. You can also:
|
| 1075 |
+
|
| 1076 |
+
- review pull requests
|
| 1077 |
+
- triage issues
|
| 1078 |
+
- develop tutorials, presentations, and other educational materials
|
| 1079 |
+
- maintain and improve `our website <https://github.com/scipy/scipy.org>`__
|
| 1080 |
+
- develop graphic design for our brand assets and promotional materials
|
| 1081 |
+
- help with outreach and onboard new contributors
|
| 1082 |
+
- write grant proposals and help with other fundraising efforts
|
| 1083 |
+
|
| 1084 |
+
If you’re unsure where to start or how your skills fit in, reach out! You can
|
| 1085 |
+
ask on the `forum <https://discuss.scientific-python.org/c/contributor/scipy>`__
|
| 1086 |
+
or here, on GitHub, by leaving a comment on a relevant issue that is already
|
| 1087 |
+
open.
|
| 1088 |
+
|
| 1089 |
+
If you are new to contributing to open source, `this
|
| 1090 |
+
guide <https://opensource.guide/how-to-contribute/>`__ helps explain why, what,
|
| 1091 |
+
and how to get involved.
|
venv/lib/python3.12/site-packages/scipy-1.18.0.dist-info/RECORD
ADDED
|
The diff for this file is too large to render.
See raw diff
|
|
|
venv/lib/python3.12/site-packages/scipy-1.18.0.dist-info/WHEEL
ADDED
|
@@ -0,0 +1,6 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
Wheel-Version: 1.0
|
| 2 |
+
Generator: meson
|
| 3 |
+
Root-Is-Purelib: false
|
| 4 |
+
Tag: cp312-cp312-manylinux_2_27_x86_64
|
| 5 |
+
Tag: cp312-cp312-manylinux_2_28_x86_64
|
| 6 |
+
|
venv/lib/python3.12/site-packages/scipy-1.18.0.dist-info/sboms/auditwheel.cdx.json
ADDED
|
@@ -0,0 +1 @@
|
|
|
|
|
|
|
| 1 |
+
{"bomFormat": "CycloneDX", "specVersion": "1.4", "version": 1, "metadata": {"component": {"type": "library", "bom-ref": "pkg:pypi/scipy@1.18.0?file_name=scipy-1.18.0-cp312-cp312-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", "name": "scipy", "version": "1.18.0", "purl": "pkg:pypi/scipy@1.18.0?file_name=scipy-1.18.0-cp312-cp312-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl"}, "tools": [{"name": "auditwheel", "version": "6.6.0"}]}, "components": [{"type": "library", "bom-ref": "pkg:pypi/scipy@1.18.0?file_name=scipy-1.18.0-cp312-cp312-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", "name": "scipy", "version": "1.18.0", "purl": "pkg:pypi/scipy@1.18.0?file_name=scipy-1.18.0-cp312-cp312-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl"}, {"type": "library", "bom-ref": "pkg:rpm/almalinux/libgfortran@8.5.0-28.el8_10.alma.1#3362720ce454cc402813e3cfe54f0eb4efaedcd690fa35129ddc4b3de40e0650", "name": "libgfortran", "version": "8.5.0-28.el8_10.alma.1", "purl": "pkg:rpm/almalinux/libgfortran@8.5.0-28.el8_10.alma.1"}, {"type": "library", "bom-ref": "pkg:rpm/almalinux/libquadmath@8.5.0-28.el8_10.alma.1#97b91febe2a1c7927c6482d6bd6567b83be3467f33c9d2764df1283f7ac9a5fa", "name": "libquadmath", "version": "8.5.0-28.el8_10.alma.1", "purl": "pkg:rpm/almalinux/libquadmath@8.5.0-28.el8_10.alma.1"}], "dependencies": [{"ref": "pkg:pypi/scipy@1.18.0?file_name=scipy-1.18.0-cp312-cp312-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", "dependsOn": ["pkg:rpm/almalinux/libgfortran@8.5.0-28.el8_10.alma.1#3362720ce454cc402813e3cfe54f0eb4efaedcd690fa35129ddc4b3de40e0650", "pkg:rpm/almalinux/libquadmath@8.5.0-28.el8_10.alma.1#97b91febe2a1c7927c6482d6bd6567b83be3467f33c9d2764df1283f7ac9a5fa"]}, {"ref": "pkg:rpm/almalinux/libgfortran@8.5.0-28.el8_10.alma.1#3362720ce454cc402813e3cfe54f0eb4efaedcd690fa35129ddc4b3de40e0650"}, {"ref": "pkg:rpm/almalinux/libquadmath@8.5.0-28.el8_10.alma.1#97b91febe2a1c7927c6482d6bd6567b83be3467f33c9d2764df1283f7ac9a5fa"}]}
|
venv/lib/python3.12/site-packages/scipy.libs/libgfortran-040039e1-0352e75f.so.5.0.0
ADDED
|
@@ -0,0 +1,3 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
version https://git-lfs.github.com/spec/v1
|
| 2 |
+
oid sha256:c6090048eccc763522c12ef016f81da6b627cb3a044f55cf0479a839c41c0980
|
| 3 |
+
size 2833617
|
venv/lib/python3.12/site-packages/scipy.libs/libgfortran-83c28eba.so.5.0.0
ADDED
|
@@ -0,0 +1,3 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
version https://git-lfs.github.com/spec/v1
|
| 2 |
+
oid sha256:e554879fee7eda80055b6ca1407a54d00050874f830cc86b2bf3f50df5c7bb2b
|
| 3 |
+
size 2714697
|
venv/lib/python3.12/site-packages/scipy.libs/libquadmath-2284e583.so.0.0.0
ADDED
|
@@ -0,0 +1,3 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
version https://git-lfs.github.com/spec/v1
|
| 2 |
+
oid sha256:a9307bbaa353623fa014e8b682d50c4629f5e5c7d61daa9a8652f7d165cd421a
|
| 3 |
+
size 272193
|
venv/lib/python3.12/site-packages/scipy.libs/libquadmath-96973f99-934c22de.so.0.0.0
ADDED
|
@@ -0,0 +1,3 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
version https://git-lfs.github.com/spec/v1
|
| 2 |
+
oid sha256:6ed5137f412781ad7863439fb543613f620b43c32b63292a0029246162f5bbc6
|
| 3 |
+
size 250985
|
venv/lib/python3.12/site-packages/scipy.libs/libscipy_openblas-5f890258.so
ADDED
|
@@ -0,0 +1,3 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
version https://git-lfs.github.com/spec/v1
|
| 2 |
+
oid sha256:2a5b4c1a6311873c59132b2ceaaf3c26258a17350b7cd27ea8782a47e3322981
|
| 3 |
+
size 25094609
|
venv/lib/python3.12/site-packages/scipy/signal/__pycache__/_filter_design.cpython-312.pyc
ADDED
|
@@ -0,0 +1,3 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
version https://git-lfs.github.com/spec/v1
|
| 2 |
+
oid sha256:55b921e2782ba8dd39a88c30f0018319dd4f72999e6b0fad987bcd6443c1da37
|
| 3 |
+
size 233862
|
venv/lib/python3.12/site-packages/scipy/signal/__pycache__/_fir_filter_design.cpython-312.pyc
ADDED
|
Binary file (67 kB). View file
|
|
|
venv/lib/python3.12/site-packages/scipy/signal/__pycache__/_lti_conversion.cpython-312.pyc
ADDED
|
Binary file (23.1 kB). View file
|
|
|
venv/lib/python3.12/site-packages/scipy/signal/__pycache__/_ltisys.cpython-312.pyc
ADDED
|
@@ -0,0 +1,3 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
version https://git-lfs.github.com/spec/v1
|
| 2 |
+
oid sha256:e3d43b2ac7e4040326b82b41dbbfb5a2581ef321e5e83d544f18dd4ebd289e2d
|
| 3 |
+
size 145690
|
venv/lib/python3.12/site-packages/scipy/signal/__pycache__/_max_len_seq.cpython-312.pyc
ADDED
|
Binary file (6.18 kB). View file
|
|
|
venv/lib/python3.12/site-packages/scipy/signal/__pycache__/_peak_finding.cpython-312.pyc
ADDED
|
Binary file (50.2 kB). View file
|
|
|
venv/lib/python3.12/site-packages/scipy/signal/__pycache__/_polyutils.cpython-312.pyc
ADDED
|
Binary file (10.9 kB). View file
|
|
|
venv/lib/python3.12/site-packages/scipy/signal/__pycache__/_savitzky_golay.cpython-312.pyc
ADDED
|
Binary file (14.8 kB). View file
|
|
|
venv/lib/python3.12/site-packages/scipy/signal/__pycache__/_short_time_fft.cpython-312.pyc
ADDED
|
@@ -0,0 +1,3 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
version https://git-lfs.github.com/spec/v1
|
| 2 |
+
oid sha256:954defa35a6f080d3bf7ff3f9f31555eb33020f918c684404d8b2f9c9d3e1e81
|
| 3 |
+
size 115538
|
venv/lib/python3.12/site-packages/scipy/signal/__pycache__/_signal_api.cpython-312.pyc
ADDED
|
Binary file (1.29 kB). View file
|
|
|
venv/lib/python3.12/site-packages/scipy/signal/__pycache__/_signaltools.cpython-312.pyc
ADDED
|
@@ -0,0 +1,3 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
version https://git-lfs.github.com/spec/v1
|
| 2 |
+
oid sha256:b989c729845c9a21a61a26113ca3ebd61813efbed4b8269a7c58bcb4ece0e6c9
|
| 3 |
+
size 216301
|
venv/lib/python3.12/site-packages/scipy/signal/__pycache__/_spectral_py.cpython-312.pyc
ADDED
|
@@ -0,0 +1,3 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
version https://git-lfs.github.com/spec/v1
|
| 2 |
+
oid sha256:461e16d5df558b5e59dee9847ba64640edbd082489ea5732f7bac9f29ed244df
|
| 3 |
+
size 100138
|
venv/lib/python3.12/site-packages/scipy/signal/__pycache__/_spline_filters.cpython-312.pyc
ADDED
|
Binary file (32.3 kB). View file
|
|
|
venv/lib/python3.12/site-packages/scipy/signal/__pycache__/_support_alternative_backends.cpython-312.pyc
ADDED
|
Binary file (11.9 kB). View file
|
|
|
venv/lib/python3.12/site-packages/scipy/signal/__pycache__/_upfirdn.cpython-312.pyc
ADDED
|
Binary file (8.09 kB). View file
|
|
|
venv/lib/python3.12/site-packages/scipy/signal/__pycache__/_waveforms.cpython-312.pyc
ADDED
|
Binary file (24.7 kB). View file
|
|
|
venv/lib/python3.12/site-packages/scipy/signal/__pycache__/_wavelets.cpython-312.pyc
ADDED
|
Binary file (1.88 kB). View file
|
|
|
venv/lib/python3.12/site-packages/scipy/signal/__pycache__/_whittaker.cpython-312.pyc
ADDED
|
Binary file (17.3 kB). View file
|
|
|
venv/lib/python3.12/site-packages/scipy/signal/__pycache__/bsplines.cpython-312.pyc
ADDED
|
Binary file (768 Bytes). View file
|
|
|
venv/lib/python3.12/site-packages/scipy/signal/__pycache__/filter_design.cpython-312.pyc
ADDED
|
Binary file (1.13 kB). View file
|
|
|
venv/lib/python3.12/site-packages/scipy/signal/__pycache__/fir_filter_design.cpython-312.pyc
ADDED
|
Binary file (781 Bytes). View file
|
|
|
venv/lib/python3.12/site-packages/scipy/signal/__pycache__/lti_conversion.cpython-312.pyc
ADDED
|
Binary file (765 Bytes). View file
|
|
|
venv/lib/python3.12/site-packages/scipy/signal/__pycache__/ltisys.cpython-312.pyc
ADDED
|
Binary file (924 Bytes). View file
|
|
|
venv/lib/python3.12/site-packages/scipy/signal/__pycache__/signaltools.cpython-312.pyc
ADDED
|
Binary file (1.08 kB). View file
|
|
|
venv/lib/python3.12/site-packages/scipy/signal/__pycache__/spectral.cpython-312.pyc
ADDED
|
Binary file (772 Bytes). View file
|
|
|
venv/lib/python3.12/site-packages/scipy/signal/__pycache__/spline.cpython-312.pyc
ADDED
|
Binary file (659 Bytes). View file
|
|
|
venv/lib/python3.12/site-packages/scipy/signal/__pycache__/waveforms.cpython-312.pyc
ADDED
|
Binary file (723 Bytes). View file
|
|
|
venv/lib/python3.12/site-packages/scipy/signal/__pycache__/wavelets.cpython-312.pyc
ADDED
|
Binary file (709 Bytes). View file
|
|
|
venv/lib/python3.12/site-packages/scipy/signal/_arraytools.py
ADDED
|
@@ -0,0 +1,264 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
"""
|
| 2 |
+
Functions for acting on a axis of an array.
|
| 3 |
+
"""
|
| 4 |
+
import numpy as np
|
| 5 |
+
|
| 6 |
+
|
| 7 |
+
def axis_slice(a, start=None, stop=None, step=None, axis=-1):
|
| 8 |
+
"""Take a slice along axis 'axis' from 'a'.
|
| 9 |
+
|
| 10 |
+
Parameters
|
| 11 |
+
----------
|
| 12 |
+
a : numpy.ndarray
|
| 13 |
+
The array to be sliced.
|
| 14 |
+
start, stop, step : int or None
|
| 15 |
+
The slice parameters.
|
| 16 |
+
axis : int, optional
|
| 17 |
+
The axis of `a` to be sliced.
|
| 18 |
+
|
| 19 |
+
Examples
|
| 20 |
+
--------
|
| 21 |
+
>>> import numpy as np
|
| 22 |
+
>>> from scipy.signal._arraytools import axis_slice
|
| 23 |
+
>>> a = np.array([[1, 2, 3], [4, 5, 6], [7, 8, 9]])
|
| 24 |
+
>>> axis_slice(a, start=0, stop=1, axis=1)
|
| 25 |
+
array([[1],
|
| 26 |
+
[4],
|
| 27 |
+
[7]])
|
| 28 |
+
>>> axis_slice(a, start=1, axis=0)
|
| 29 |
+
array([[4, 5, 6],
|
| 30 |
+
[7, 8, 9]])
|
| 31 |
+
|
| 32 |
+
Notes
|
| 33 |
+
-----
|
| 34 |
+
The keyword arguments start, stop and step are used by calling
|
| 35 |
+
slice(start, stop, step). This implies axis_slice() does not
|
| 36 |
+
handle its arguments the exactly the same as indexing. To select
|
| 37 |
+
a single index k, for example, use
|
| 38 |
+
axis_slice(a, start=k, stop=k+1)
|
| 39 |
+
In this case, the length of the axis 'axis' in the result will
|
| 40 |
+
be 1; the trivial dimension is not removed. (Use numpy.squeeze()
|
| 41 |
+
to remove trivial axes.)
|
| 42 |
+
"""
|
| 43 |
+
a_slice = [slice(None)] * a.ndim
|
| 44 |
+
a_slice[axis] = slice(start, stop, step)
|
| 45 |
+
b = a[tuple(a_slice)]
|
| 46 |
+
return b
|
| 47 |
+
|
| 48 |
+
|
| 49 |
+
def axis_reverse(a, axis=-1):
|
| 50 |
+
"""Reverse the 1-D slices of `a` along axis `axis`.
|
| 51 |
+
|
| 52 |
+
Returns axis_slice(a, step=-1, axis=axis).
|
| 53 |
+
"""
|
| 54 |
+
return axis_slice(a, step=-1, axis=axis)
|
| 55 |
+
|
| 56 |
+
|
| 57 |
+
def odd_ext(x, n, axis=-1):
|
| 58 |
+
"""
|
| 59 |
+
Odd extension at the boundaries of an array
|
| 60 |
+
|
| 61 |
+
Generate a new ndarray by making an odd extension of `x` along an axis.
|
| 62 |
+
|
| 63 |
+
Parameters
|
| 64 |
+
----------
|
| 65 |
+
x : ndarray
|
| 66 |
+
The array to be extended.
|
| 67 |
+
n : int
|
| 68 |
+
The number of elements by which to extend `x` at each end of the axis.
|
| 69 |
+
axis : int, optional
|
| 70 |
+
The axis along which to extend `x`. Default is -1.
|
| 71 |
+
|
| 72 |
+
Examples
|
| 73 |
+
--------
|
| 74 |
+
>>> import numpy as np
|
| 75 |
+
>>> from scipy.signal._arraytools import odd_ext
|
| 76 |
+
>>> a = np.array([[1, 2, 3, 4, 5], [0, 1, 4, 9, 16]])
|
| 77 |
+
>>> odd_ext(a, 2)
|
| 78 |
+
array([[-1, 0, 1, 2, 3, 4, 5, 6, 7],
|
| 79 |
+
[-4, -1, 0, 1, 4, 9, 16, 23, 28]])
|
| 80 |
+
|
| 81 |
+
Odd extension is a "180 degree rotation" at the endpoints of the original
|
| 82 |
+
array:
|
| 83 |
+
|
| 84 |
+
>>> t = np.linspace(0, 1.5, 100)
|
| 85 |
+
>>> a = 0.9 * np.sin(2 * np.pi * t**2)
|
| 86 |
+
>>> b = odd_ext(a, 40)
|
| 87 |
+
>>> import matplotlib.pyplot as plt
|
| 88 |
+
>>> plt.plot(np.arange(-40, 140), b, 'b', lw=1, label='odd extension')
|
| 89 |
+
>>> plt.plot(np.arange(100), a, 'r', lw=2, label='original')
|
| 90 |
+
>>> plt.legend(loc='best')
|
| 91 |
+
>>> plt.show()
|
| 92 |
+
"""
|
| 93 |
+
if n < 1:
|
| 94 |
+
return x
|
| 95 |
+
if n > x.shape[axis] - 1:
|
| 96 |
+
raise ValueError(("The extension length n (%d) is too big. " +
|
| 97 |
+
"It must not exceed x.shape[axis]-1, which is %d.")
|
| 98 |
+
% (n, x.shape[axis] - 1))
|
| 99 |
+
left_end = axis_slice(x, start=0, stop=1, axis=axis)
|
| 100 |
+
left_ext = axis_slice(x, start=n, stop=0, step=-1, axis=axis)
|
| 101 |
+
right_end = axis_slice(x, start=-1, axis=axis)
|
| 102 |
+
right_ext = axis_slice(x, start=-2, stop=-(n + 2), step=-1, axis=axis)
|
| 103 |
+
ext = np.concatenate((2 * left_end - left_ext,
|
| 104 |
+
x,
|
| 105 |
+
2 * right_end - right_ext),
|
| 106 |
+
axis=axis)
|
| 107 |
+
return ext
|
| 108 |
+
|
| 109 |
+
|
| 110 |
+
def even_ext(x, n, axis=-1):
|
| 111 |
+
"""
|
| 112 |
+
Even extension at the boundaries of an array
|
| 113 |
+
|
| 114 |
+
Generate a new ndarray by making an even extension of `x` along an axis.
|
| 115 |
+
|
| 116 |
+
Parameters
|
| 117 |
+
----------
|
| 118 |
+
x : ndarray
|
| 119 |
+
The array to be extended.
|
| 120 |
+
n : int
|
| 121 |
+
The number of elements by which to extend `x` at each end of the axis.
|
| 122 |
+
axis : int, optional
|
| 123 |
+
The axis along which to extend `x`. Default is -1.
|
| 124 |
+
|
| 125 |
+
Examples
|
| 126 |
+
--------
|
| 127 |
+
>>> import numpy as np
|
| 128 |
+
>>> from scipy.signal._arraytools import even_ext
|
| 129 |
+
>>> a = np.array([[1, 2, 3, 4, 5], [0, 1, 4, 9, 16]])
|
| 130 |
+
>>> even_ext(a, 2)
|
| 131 |
+
array([[ 3, 2, 1, 2, 3, 4, 5, 4, 3],
|
| 132 |
+
[ 4, 1, 0, 1, 4, 9, 16, 9, 4]])
|
| 133 |
+
|
| 134 |
+
Even extension is a "mirror image" at the boundaries of the original array:
|
| 135 |
+
|
| 136 |
+
>>> t = np.linspace(0, 1.5, 100)
|
| 137 |
+
>>> a = 0.9 * np.sin(2 * np.pi * t**2)
|
| 138 |
+
>>> b = even_ext(a, 40)
|
| 139 |
+
>>> import matplotlib.pyplot as plt
|
| 140 |
+
>>> plt.plot(np.arange(-40, 140), b, 'b', lw=1, label='even extension')
|
| 141 |
+
>>> plt.plot(np.arange(100), a, 'r', lw=2, label='original')
|
| 142 |
+
>>> plt.legend(loc='best')
|
| 143 |
+
>>> plt.show()
|
| 144 |
+
"""
|
| 145 |
+
if n < 1:
|
| 146 |
+
return x
|
| 147 |
+
if n > x.shape[axis] - 1:
|
| 148 |
+
raise ValueError(("The extension length n (%d) is too big. " +
|
| 149 |
+
"It must not exceed x.shape[axis]-1, which is %d.")
|
| 150 |
+
% (n, x.shape[axis] - 1))
|
| 151 |
+
left_ext = axis_slice(x, start=n, stop=0, step=-1, axis=axis)
|
| 152 |
+
right_ext = axis_slice(x, start=-2, stop=-(n + 2), step=-1, axis=axis)
|
| 153 |
+
ext = np.concatenate((left_ext,
|
| 154 |
+
x,
|
| 155 |
+
right_ext),
|
| 156 |
+
axis=axis)
|
| 157 |
+
return ext
|
| 158 |
+
|
| 159 |
+
|
| 160 |
+
def const_ext(x, n, axis=-1):
|
| 161 |
+
"""
|
| 162 |
+
Constant extension at the boundaries of an array
|
| 163 |
+
|
| 164 |
+
Generate a new ndarray that is a constant extension of `x` along an axis.
|
| 165 |
+
|
| 166 |
+
The extension repeats the values at the first and last element of
|
| 167 |
+
the axis.
|
| 168 |
+
|
| 169 |
+
Parameters
|
| 170 |
+
----------
|
| 171 |
+
x : ndarray
|
| 172 |
+
The array to be extended.
|
| 173 |
+
n : int
|
| 174 |
+
The number of elements by which to extend `x` at each end of the axis.
|
| 175 |
+
axis : int, optional
|
| 176 |
+
The axis along which to extend `x`. Default is -1.
|
| 177 |
+
|
| 178 |
+
Examples
|
| 179 |
+
--------
|
| 180 |
+
>>> import numpy as np
|
| 181 |
+
>>> from scipy.signal._arraytools import const_ext
|
| 182 |
+
>>> a = np.array([[1, 2, 3, 4, 5], [0, 1, 4, 9, 16]])
|
| 183 |
+
>>> const_ext(a, 2)
|
| 184 |
+
array([[ 1, 1, 1, 2, 3, 4, 5, 5, 5],
|
| 185 |
+
[ 0, 0, 0, 1, 4, 9, 16, 16, 16]])
|
| 186 |
+
|
| 187 |
+
Constant extension continues with the same values as the endpoints of the
|
| 188 |
+
array:
|
| 189 |
+
|
| 190 |
+
>>> t = np.linspace(0, 1.5, 100)
|
| 191 |
+
>>> a = 0.9 * np.sin(2 * np.pi * t**2)
|
| 192 |
+
>>> b = const_ext(a, 40)
|
| 193 |
+
>>> import matplotlib.pyplot as plt
|
| 194 |
+
>>> plt.plot(np.arange(-40, 140), b, 'b', lw=1, label='constant extension')
|
| 195 |
+
>>> plt.plot(np.arange(100), a, 'r', lw=2, label='original')
|
| 196 |
+
>>> plt.legend(loc='best')
|
| 197 |
+
>>> plt.show()
|
| 198 |
+
"""
|
| 199 |
+
if n < 1:
|
| 200 |
+
return x
|
| 201 |
+
left_end = axis_slice(x, start=0, stop=1, axis=axis)
|
| 202 |
+
ones_shape = [1] * x.ndim
|
| 203 |
+
ones_shape[axis] = n
|
| 204 |
+
ones = np.ones(ones_shape, dtype=x.dtype)
|
| 205 |
+
left_ext = ones * left_end
|
| 206 |
+
right_end = axis_slice(x, start=-1, axis=axis)
|
| 207 |
+
right_ext = ones * right_end
|
| 208 |
+
ext = np.concatenate((left_ext,
|
| 209 |
+
x,
|
| 210 |
+
right_ext),
|
| 211 |
+
axis=axis)
|
| 212 |
+
return ext
|
| 213 |
+
|
| 214 |
+
|
| 215 |
+
def zero_ext(x, n, axis=-1):
|
| 216 |
+
"""
|
| 217 |
+
Zero padding at the boundaries of an array
|
| 218 |
+
|
| 219 |
+
Generate a new ndarray that is a zero-padded extension of `x` along
|
| 220 |
+
an axis.
|
| 221 |
+
|
| 222 |
+
Parameters
|
| 223 |
+
----------
|
| 224 |
+
x : ndarray
|
| 225 |
+
The array to be extended.
|
| 226 |
+
n : int
|
| 227 |
+
The number of elements by which to extend `x` at each end of the
|
| 228 |
+
axis.
|
| 229 |
+
axis : int, optional
|
| 230 |
+
The axis along which to extend `x`. Default is -1.
|
| 231 |
+
|
| 232 |
+
Examples
|
| 233 |
+
--------
|
| 234 |
+
>>> import numpy as np
|
| 235 |
+
>>> from scipy.signal._arraytools import zero_ext
|
| 236 |
+
>>> a = np.array([[1, 2, 3, 4, 5], [0, 1, 4, 9, 16]])
|
| 237 |
+
>>> zero_ext(a, 2)
|
| 238 |
+
array([[ 0, 0, 1, 2, 3, 4, 5, 0, 0],
|
| 239 |
+
[ 0, 0, 0, 1, 4, 9, 16, 0, 0]])
|
| 240 |
+
"""
|
| 241 |
+
if n < 1:
|
| 242 |
+
return x
|
| 243 |
+
zeros_shape = list(x.shape)
|
| 244 |
+
zeros_shape[axis] = n
|
| 245 |
+
zeros = np.zeros(zeros_shape, dtype=x.dtype)
|
| 246 |
+
ext = np.concatenate((zeros, x, zeros), axis=axis)
|
| 247 |
+
return ext
|
| 248 |
+
|
| 249 |
+
|
| 250 |
+
def _validate_fs(fs, allow_none=True):
|
| 251 |
+
"""
|
| 252 |
+
Check if the given sampling frequency is a scalar and raises an exception
|
| 253 |
+
otherwise. If allow_none is False, also raises an exception for none
|
| 254 |
+
sampling rates. Returns the sampling frequency as float or none if the
|
| 255 |
+
input is none.
|
| 256 |
+
"""
|
| 257 |
+
if fs is None:
|
| 258 |
+
if not allow_none:
|
| 259 |
+
raise ValueError("Sampling frequency can not be none.")
|
| 260 |
+
else: # should be float
|
| 261 |
+
if not np.isscalar(fs):
|
| 262 |
+
raise ValueError("Sampling frequency fs must be a single scalar.")
|
| 263 |
+
fs = float(fs)
|
| 264 |
+
return fs
|
venv/lib/python3.12/site-packages/scipy/signal/_czt.py
ADDED
|
@@ -0,0 +1,580 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
# This program is public domain
|
| 2 |
+
# Authors: Paul Kienzle, Nadav Horesh
|
| 3 |
+
"""
|
| 4 |
+
Chirp z-transform.
|
| 5 |
+
|
| 6 |
+
We provide two interfaces to the chirp z-transform: an object interface
|
| 7 |
+
which precalculates part of the transform and can be applied efficiently
|
| 8 |
+
to many different data sets, and a functional interface which is applied
|
| 9 |
+
only to the given data set.
|
| 10 |
+
|
| 11 |
+
Transforms
|
| 12 |
+
----------
|
| 13 |
+
|
| 14 |
+
CZT : callable (x, axis=-1) -> array
|
| 15 |
+
Define a chirp z-transform that can be applied to different signals.
|
| 16 |
+
ZoomFFT : callable (x, axis=-1) -> array
|
| 17 |
+
Define a Fourier transform on a range of frequencies.
|
| 18 |
+
|
| 19 |
+
Functions
|
| 20 |
+
---------
|
| 21 |
+
|
| 22 |
+
czt : array
|
| 23 |
+
Compute the chirp z-transform for a signal.
|
| 24 |
+
zoom_fft : array
|
| 25 |
+
Compute the Fourier transform on a range of frequencies.
|
| 26 |
+
"""
|
| 27 |
+
|
| 28 |
+
import cmath
|
| 29 |
+
import numbers
|
| 30 |
+
import numpy as np
|
| 31 |
+
from numpy import pi, arange
|
| 32 |
+
from scipy.fft import fft, ifft, next_fast_len
|
| 33 |
+
|
| 34 |
+
__all__ = ['czt', 'zoom_fft', 'CZT', 'ZoomFFT', 'czt_points']
|
| 35 |
+
|
| 36 |
+
|
| 37 |
+
def _validate_sizes(n, m):
|
| 38 |
+
if n < 1 or not isinstance(n, numbers.Integral):
|
| 39 |
+
raise ValueError('Invalid number of CZT data '
|
| 40 |
+
f'points ({n}) specified. '
|
| 41 |
+
'n must be positive and integer type.')
|
| 42 |
+
|
| 43 |
+
if m is None:
|
| 44 |
+
m = n
|
| 45 |
+
elif m < 1 or not isinstance(m, numbers.Integral):
|
| 46 |
+
raise ValueError('Invalid number of CZT output '
|
| 47 |
+
f'points ({m}) specified. '
|
| 48 |
+
'm must be positive and integer type.')
|
| 49 |
+
|
| 50 |
+
return m
|
| 51 |
+
|
| 52 |
+
|
| 53 |
+
def czt_points(m, w=None, a=1+0j):
|
| 54 |
+
"""
|
| 55 |
+
Return the points at which the chirp z-transform is computed.
|
| 56 |
+
|
| 57 |
+
Parameters
|
| 58 |
+
----------
|
| 59 |
+
m : int
|
| 60 |
+
The number of points desired.
|
| 61 |
+
w : complex, optional
|
| 62 |
+
The ratio between points in each step.
|
| 63 |
+
Defaults to equally spaced points around the entire unit circle.
|
| 64 |
+
a : complex, optional
|
| 65 |
+
The starting point in the complex plane. Default is 1+0j.
|
| 66 |
+
|
| 67 |
+
Returns
|
| 68 |
+
-------
|
| 69 |
+
out : ndarray
|
| 70 |
+
The points in the Z plane at which `CZT` samples the z-transform,
|
| 71 |
+
when called with arguments `m`, `w`, and `a`, as complex numbers.
|
| 72 |
+
|
| 73 |
+
See Also
|
| 74 |
+
--------
|
| 75 |
+
CZT : Class that creates a callable chirp z-transform function.
|
| 76 |
+
czt : Convenience function for quickly calculating CZT.
|
| 77 |
+
|
| 78 |
+
Examples
|
| 79 |
+
--------
|
| 80 |
+
Plot the points of a 16-point FFT:
|
| 81 |
+
|
| 82 |
+
>>> import numpy as np
|
| 83 |
+
>>> from scipy.signal import czt_points
|
| 84 |
+
>>> points = czt_points(16)
|
| 85 |
+
>>> import matplotlib.pyplot as plt
|
| 86 |
+
>>> plt.plot(points.real, points.imag, 'o')
|
| 87 |
+
>>> plt.gca().add_patch(plt.Circle((0,0), radius=1, fill=False, alpha=.3))
|
| 88 |
+
>>> plt.axis('equal')
|
| 89 |
+
>>> plt.show()
|
| 90 |
+
|
| 91 |
+
and a 91-point logarithmic spiral that crosses the unit circle:
|
| 92 |
+
|
| 93 |
+
>>> m, w, a = 91, 0.995*np.exp(-1j*np.pi*.05), 0.8*np.exp(1j*np.pi/6)
|
| 94 |
+
>>> points = czt_points(m, w, a)
|
| 95 |
+
>>> plt.plot(points.real, points.imag, 'o')
|
| 96 |
+
>>> plt.gca().add_patch(plt.Circle((0,0), radius=1, fill=False, alpha=.3))
|
| 97 |
+
>>> plt.axis('equal')
|
| 98 |
+
>>> plt.show()
|
| 99 |
+
"""
|
| 100 |
+
m = _validate_sizes(1, m)
|
| 101 |
+
|
| 102 |
+
k = arange(m)
|
| 103 |
+
|
| 104 |
+
a = 1.0 * a # at least float
|
| 105 |
+
|
| 106 |
+
if w is None:
|
| 107 |
+
# Nothing specified, default to FFT
|
| 108 |
+
return a * np.exp(2j * pi * k / m)
|
| 109 |
+
else:
|
| 110 |
+
# w specified
|
| 111 |
+
w = 1.0 * w # at least float
|
| 112 |
+
return a * w**-k
|
| 113 |
+
|
| 114 |
+
|
| 115 |
+
class CZT:
|
| 116 |
+
"""
|
| 117 |
+
Create a callable chirp z-transform function.
|
| 118 |
+
|
| 119 |
+
Transform to compute the frequency response around a spiral.
|
| 120 |
+
Objects of this class are callables which can compute the
|
| 121 |
+
chirp z-transform on their inputs. This object precalculates the constant
|
| 122 |
+
chirps used in the given transform.
|
| 123 |
+
|
| 124 |
+
Parameters
|
| 125 |
+
----------
|
| 126 |
+
n : int
|
| 127 |
+
The size of the signal.
|
| 128 |
+
m : int, optional
|
| 129 |
+
The number of output points desired. Default is `n`.
|
| 130 |
+
w : complex, optional
|
| 131 |
+
The ratio between points in each step. This must be precise or the
|
| 132 |
+
accumulated error will degrade the tail of the output sequence.
|
| 133 |
+
Defaults to equally spaced points around the entire unit circle.
|
| 134 |
+
a : complex, optional
|
| 135 |
+
The starting point in the complex plane. Default is 1+0j.
|
| 136 |
+
|
| 137 |
+
Returns
|
| 138 |
+
-------
|
| 139 |
+
f : CZT
|
| 140 |
+
Callable object ``f(x, axis=-1)`` for computing the chirp z-transform
|
| 141 |
+
on `x`.
|
| 142 |
+
|
| 143 |
+
See Also
|
| 144 |
+
--------
|
| 145 |
+
czt : Convenience function for quickly calculating CZT.
|
| 146 |
+
ZoomFFT : Class that creates a callable partial FFT function.
|
| 147 |
+
|
| 148 |
+
Notes
|
| 149 |
+
-----
|
| 150 |
+
The defaults are chosen such that ``f(x)`` is equivalent to
|
| 151 |
+
``fft.fft(x)`` and, if ``m > len(x)``, that ``f(x, m)`` is equivalent to
|
| 152 |
+
``fft.fft(x, m)``.
|
| 153 |
+
|
| 154 |
+
If `w` does not lie on the unit circle, then the transform will be
|
| 155 |
+
around a spiral with exponentially-increasing radius. Regardless,
|
| 156 |
+
angle will increase linearly.
|
| 157 |
+
|
| 158 |
+
For transforms that do lie on the unit circle, accuracy is better when
|
| 159 |
+
using `ZoomFFT`, since any numerical error in `w` is
|
| 160 |
+
accumulated for long data lengths, drifting away from the unit circle.
|
| 161 |
+
|
| 162 |
+
The chirp z-transform can be faster than an equivalent FFT with
|
| 163 |
+
zero padding. Try it with your own array sizes to see.
|
| 164 |
+
|
| 165 |
+
However, the chirp z-transform is considerably less precise than the
|
| 166 |
+
equivalent zero-padded FFT.
|
| 167 |
+
|
| 168 |
+
As this CZT is implemented using the Bluestein algorithm, it can compute
|
| 169 |
+
large prime-length Fourier transforms in O(N log N) time, rather than the
|
| 170 |
+
O(N**2) time required by the direct DFT calculation. (`scipy.fft` also
|
| 171 |
+
uses Bluestein's algorithm'.)
|
| 172 |
+
|
| 173 |
+
(The name "chirp z-transform" comes from the use of a chirp in the
|
| 174 |
+
Bluestein algorithm. It does not decompose signals into chirps, like
|
| 175 |
+
other transforms with "chirp" in the name.)
|
| 176 |
+
|
| 177 |
+
References
|
| 178 |
+
----------
|
| 179 |
+
.. [1] Leo I. Bluestein, "A linear filtering approach to the computation
|
| 180 |
+
of the discrete Fourier transform," Northeast Electronics Research
|
| 181 |
+
and Engineering Meeting Record 10, 218-219 (1968).
|
| 182 |
+
.. [2] Rabiner, Schafer, and Rader, "The chirp z-transform algorithm and
|
| 183 |
+
its application," Bell Syst. Tech. J. 48, 1249-1292 (1969).
|
| 184 |
+
|
| 185 |
+
Examples
|
| 186 |
+
--------
|
| 187 |
+
Compute multiple prime-length FFTs:
|
| 188 |
+
|
| 189 |
+
>>> from scipy.signal import CZT
|
| 190 |
+
>>> import numpy as np
|
| 191 |
+
>>> a = np.random.rand(7)
|
| 192 |
+
>>> b = np.random.rand(7)
|
| 193 |
+
>>> c = np.random.rand(7)
|
| 194 |
+
>>> czt_7 = CZT(n=7)
|
| 195 |
+
>>> A = czt_7(a)
|
| 196 |
+
>>> B = czt_7(b)
|
| 197 |
+
>>> C = czt_7(c)
|
| 198 |
+
|
| 199 |
+
Display the points at which the FFT is calculated:
|
| 200 |
+
|
| 201 |
+
>>> czt_7.points()
|
| 202 |
+
array([ 1.00000000+0.j , 0.62348980+0.78183148j,
|
| 203 |
+
-0.22252093+0.97492791j, -0.90096887+0.43388374j,
|
| 204 |
+
-0.90096887-0.43388374j, -0.22252093-0.97492791j,
|
| 205 |
+
0.62348980-0.78183148j])
|
| 206 |
+
>>> import matplotlib.pyplot as plt
|
| 207 |
+
>>> plt.plot(czt_7.points().real, czt_7.points().imag, 'o')
|
| 208 |
+
>>> plt.gca().add_patch(plt.Circle((0,0), radius=1, fill=False, alpha=.3))
|
| 209 |
+
>>> plt.axis('equal')
|
| 210 |
+
>>> plt.show()
|
| 211 |
+
"""
|
| 212 |
+
|
| 213 |
+
def __init__(self, n, m=None, w=None, a=1+0j):
|
| 214 |
+
m = _validate_sizes(n, m)
|
| 215 |
+
|
| 216 |
+
k = arange(max(m, n), dtype=np.min_scalar_type(-max(m, n)**2))
|
| 217 |
+
|
| 218 |
+
if w is None:
|
| 219 |
+
# Nothing specified, default to FFT-like
|
| 220 |
+
w = cmath.exp(-2j*pi/m)
|
| 221 |
+
wk2 = np.exp(-(1j * pi * ((k**2) % (2*m))) / m)
|
| 222 |
+
else:
|
| 223 |
+
# w specified
|
| 224 |
+
wk2 = w**(k**2/2.)
|
| 225 |
+
|
| 226 |
+
a = 1.0 * a # at least float
|
| 227 |
+
|
| 228 |
+
self.w, self.a = w, a
|
| 229 |
+
self.m, self.n = m, n
|
| 230 |
+
|
| 231 |
+
nfft = next_fast_len(n + m - 1)
|
| 232 |
+
self._Awk2 = a**-k[:n] * wk2[:n]
|
| 233 |
+
self._nfft = nfft
|
| 234 |
+
self._Fwk2 = fft(1/np.hstack((wk2[n-1:0:-1], wk2[:m])), nfft)
|
| 235 |
+
self._wk2 = wk2[:m]
|
| 236 |
+
self._yidx = slice(n-1, n+m-1)
|
| 237 |
+
|
| 238 |
+
def __call__(self, x, *, axis=-1):
|
| 239 |
+
"""
|
| 240 |
+
Calculate the chirp z-transform of a signal.
|
| 241 |
+
|
| 242 |
+
Parameters
|
| 243 |
+
----------
|
| 244 |
+
x : array
|
| 245 |
+
The signal to transform.
|
| 246 |
+
axis : int, optional
|
| 247 |
+
Axis over which to compute the FFT. If not given, the last axis is
|
| 248 |
+
used.
|
| 249 |
+
|
| 250 |
+
Returns
|
| 251 |
+
-------
|
| 252 |
+
out : ndarray
|
| 253 |
+
An array of the same dimensions as `x`, but with the length of the
|
| 254 |
+
transformed axis set to `m`.
|
| 255 |
+
"""
|
| 256 |
+
x = np.asarray(x)
|
| 257 |
+
if x.shape[axis] != self.n:
|
| 258 |
+
raise ValueError(f"CZT defined for length {self.n}, not "
|
| 259 |
+
f"{x.shape[axis]}")
|
| 260 |
+
# Calculate transpose coordinates, to allow operation on any given axis
|
| 261 |
+
trnsp = np.arange(x.ndim)
|
| 262 |
+
trnsp[[axis, -1]] = [-1, axis]
|
| 263 |
+
x = x.transpose(*trnsp)
|
| 264 |
+
y = ifft(self._Fwk2 * fft(x*self._Awk2, self._nfft))
|
| 265 |
+
y = y[..., self._yidx] * self._wk2
|
| 266 |
+
return y.transpose(*trnsp)
|
| 267 |
+
|
| 268 |
+
def points(self):
|
| 269 |
+
"""
|
| 270 |
+
Return the points at which the chirp z-transform is computed.
|
| 271 |
+
|
| 272 |
+
Returns
|
| 273 |
+
-------
|
| 274 |
+
ndarray
|
| 275 |
+
The points in the Z plane at which `CZT` samples the z-transform.
|
| 276 |
+
"""
|
| 277 |
+
return czt_points(self.m, self.w, self.a)
|
| 278 |
+
|
| 279 |
+
|
| 280 |
+
class ZoomFFT(CZT):
|
| 281 |
+
"""
|
| 282 |
+
Create a callable zoom FFT transform function.
|
| 283 |
+
|
| 284 |
+
This is a specialization of the chirp z-transform (`CZT`) for a set of
|
| 285 |
+
equally-spaced frequencies around the unit circle, used to calculate a
|
| 286 |
+
section of the FFT more efficiently than calculating the entire FFT and
|
| 287 |
+
truncating.
|
| 288 |
+
|
| 289 |
+
Parameters
|
| 290 |
+
----------
|
| 291 |
+
n : int
|
| 292 |
+
The size of the signal.
|
| 293 |
+
fn : array_like
|
| 294 |
+
A length-2 sequence [`f1`, `f2`] giving the frequency range, or a
|
| 295 |
+
scalar, for which the range [0, `fn`] is assumed.
|
| 296 |
+
m : int, optional
|
| 297 |
+
The number of points to evaluate. Default is `n`.
|
| 298 |
+
fs : float, optional
|
| 299 |
+
The sampling frequency. If ``fs=10`` represented 10 kHz, for example,
|
| 300 |
+
then `f1` and `f2` would also be given in kHz.
|
| 301 |
+
The default sampling frequency is 2, so `f1` and `f2` should be
|
| 302 |
+
in the range [0, 1] to keep the transform below the Nyquist
|
| 303 |
+
frequency.
|
| 304 |
+
endpoint : bool, optional
|
| 305 |
+
If True, `f2` is the last sample. Otherwise, it is not included.
|
| 306 |
+
Default is False.
|
| 307 |
+
|
| 308 |
+
Returns
|
| 309 |
+
-------
|
| 310 |
+
f : ZoomFFT
|
| 311 |
+
Callable object ``f(x, axis=-1)`` for computing the zoom FFT on `x`.
|
| 312 |
+
|
| 313 |
+
See Also
|
| 314 |
+
--------
|
| 315 |
+
zoom_fft : Convenience function for calculating a zoom FFT.
|
| 316 |
+
|
| 317 |
+
Notes
|
| 318 |
+
-----
|
| 319 |
+
The defaults are chosen such that ``f(x, 2)`` is equivalent to
|
| 320 |
+
``fft.fft(x)`` and, if ``m > len(x)``, that ``f(x, 2, m)`` is equivalent to
|
| 321 |
+
``fft.fft(x, m)``.
|
| 322 |
+
|
| 323 |
+
Sampling frequency is 1/dt, the time step between samples in the
|
| 324 |
+
signal `x`. The unit circle corresponds to frequencies from 0 up
|
| 325 |
+
to the sampling frequency. The default sampling frequency of 2
|
| 326 |
+
means that `f1`, `f2` values up to the Nyquist frequency are in the
|
| 327 |
+
range [0, 1). For `f1`, `f2` values expressed in radians, a sampling
|
| 328 |
+
frequency of 2*pi should be used.
|
| 329 |
+
|
| 330 |
+
Remember that a zoom FFT can only interpolate the points of the existing
|
| 331 |
+
FFT. It cannot help to resolve two separate nearby frequencies.
|
| 332 |
+
Frequency resolution can only be increased by increasing acquisition
|
| 333 |
+
time.
|
| 334 |
+
|
| 335 |
+
These functions are implemented using Bluestein's algorithm (as is
|
| 336 |
+
`scipy.fft`). [2]_
|
| 337 |
+
|
| 338 |
+
References
|
| 339 |
+
----------
|
| 340 |
+
.. [1] Steve Alan Shilling, "A study of the chirp z-transform and its
|
| 341 |
+
applications", pg 29 (1970)
|
| 342 |
+
https://krex.k-state.edu/dspace/bitstream/handle/2097/7844/LD2668R41972S43.pdf
|
| 343 |
+
.. [2] Leo I. Bluestein, "A linear filtering approach to the computation
|
| 344 |
+
of the discrete Fourier transform," Northeast Electronics Research
|
| 345 |
+
and Engineering Meeting Record 10, 218-219 (1968).
|
| 346 |
+
|
| 347 |
+
Examples
|
| 348 |
+
--------
|
| 349 |
+
To plot the transform results use something like the following:
|
| 350 |
+
|
| 351 |
+
>>> import numpy as np
|
| 352 |
+
>>> from scipy.signal import ZoomFFT
|
| 353 |
+
>>> t = np.linspace(0, 1, 1021)
|
| 354 |
+
>>> x = np.cos(2*np.pi*15*t) + np.sin(2*np.pi*17*t)
|
| 355 |
+
>>> f1, f2 = 5, 27
|
| 356 |
+
>>> transform = ZoomFFT(len(x), [f1, f2], len(x), fs=1021)
|
| 357 |
+
>>> X = transform(x)
|
| 358 |
+
>>> f = np.linspace(f1, f2, len(x))
|
| 359 |
+
>>> import matplotlib.pyplot as plt
|
| 360 |
+
>>> plt.plot(f, 20*np.log10(np.abs(X)))
|
| 361 |
+
>>> plt.show()
|
| 362 |
+
"""
|
| 363 |
+
|
| 364 |
+
def __init__(self, n, fn, m=None, *, fs=2, endpoint=False):
|
| 365 |
+
m = _validate_sizes(n, m)
|
| 366 |
+
|
| 367 |
+
k = arange(max(m, n), dtype=np.min_scalar_type(-max(m, n)**2))
|
| 368 |
+
|
| 369 |
+
if np.size(fn) == 2:
|
| 370 |
+
f1, f2 = fn
|
| 371 |
+
elif np.size(fn) == 1:
|
| 372 |
+
f1, f2 = 0.0, fn
|
| 373 |
+
else:
|
| 374 |
+
raise ValueError('fn must be a scalar or 2-length sequence')
|
| 375 |
+
|
| 376 |
+
self.f1, self.f2, self.fs = f1, f2, fs
|
| 377 |
+
|
| 378 |
+
if endpoint:
|
| 379 |
+
scale = ((f2 - f1) * m) / (fs * (m - 1))
|
| 380 |
+
else:
|
| 381 |
+
scale = (f2 - f1) / fs
|
| 382 |
+
a = cmath.exp(2j * pi * f1/fs)
|
| 383 |
+
wk2 = np.exp(-(1j * pi * scale * k**2) / m)
|
| 384 |
+
|
| 385 |
+
self.w = cmath.exp(-2j*pi/m * scale)
|
| 386 |
+
self.a = a
|
| 387 |
+
self.m, self.n = m, n
|
| 388 |
+
|
| 389 |
+
ak = np.exp(-2j * pi * f1/fs * k[:n])
|
| 390 |
+
self._Awk2 = ak * wk2[:n]
|
| 391 |
+
|
| 392 |
+
nfft = next_fast_len(n + m - 1)
|
| 393 |
+
self._nfft = nfft
|
| 394 |
+
self._Fwk2 = fft(1/np.hstack((wk2[n-1:0:-1], wk2[:m])), nfft)
|
| 395 |
+
self._wk2 = wk2[:m]
|
| 396 |
+
self._yidx = slice(n-1, n+m-1)
|
| 397 |
+
|
| 398 |
+
|
| 399 |
+
def czt(x, m=None, w=None, a=1+0j, *, axis=-1):
|
| 400 |
+
"""
|
| 401 |
+
Compute the frequency response around a spiral in the Z plane.
|
| 402 |
+
|
| 403 |
+
Parameters
|
| 404 |
+
----------
|
| 405 |
+
x : array
|
| 406 |
+
The signal to transform.
|
| 407 |
+
m : int, optional
|
| 408 |
+
The number of output points desired. Default is the length of the
|
| 409 |
+
input data.
|
| 410 |
+
w : complex, optional
|
| 411 |
+
The ratio between points in each step. This must be precise or the
|
| 412 |
+
accumulated error will degrade the tail of the output sequence.
|
| 413 |
+
Defaults to equally spaced points around the entire unit circle.
|
| 414 |
+
a : complex, optional
|
| 415 |
+
The starting point in the complex plane. Default is 1+0j.
|
| 416 |
+
axis : int, optional
|
| 417 |
+
Axis over which to compute the FFT. If not given, the last axis is
|
| 418 |
+
used.
|
| 419 |
+
|
| 420 |
+
Returns
|
| 421 |
+
-------
|
| 422 |
+
out : ndarray
|
| 423 |
+
An array of the same dimensions as `x`, but with the length of the
|
| 424 |
+
transformed axis set to `m`.
|
| 425 |
+
|
| 426 |
+
See Also
|
| 427 |
+
--------
|
| 428 |
+
CZT : Class that creates a callable chirp z-transform function.
|
| 429 |
+
zoom_fft : Convenience function for partial FFT calculations.
|
| 430 |
+
|
| 431 |
+
Notes
|
| 432 |
+
-----
|
| 433 |
+
The defaults are chosen such that ``signal.czt(x)`` is equivalent to
|
| 434 |
+
``fft.fft(x)`` and, if ``m > len(x)``, that ``signal.czt(x, m)`` is
|
| 435 |
+
equivalent to ``fft.fft(x, m)``.
|
| 436 |
+
|
| 437 |
+
If the transform needs to be repeated, use `CZT` to construct a
|
| 438 |
+
specialized transform function which can be reused without
|
| 439 |
+
recomputing constants.
|
| 440 |
+
|
| 441 |
+
An example application is in system identification, repeatedly evaluating
|
| 442 |
+
small slices of the z-transform of a system, around where a pole is
|
| 443 |
+
expected to exist, to refine the estimate of the pole's true location. [1]_
|
| 444 |
+
|
| 445 |
+
References
|
| 446 |
+
----------
|
| 447 |
+
.. [1] Steve Alan Shilling, "A study of the chirp z-transform and its
|
| 448 |
+
applications", pg 20 (1970)
|
| 449 |
+
https://krex.k-state.edu/dspace/bitstream/handle/2097/7844/LD2668R41972S43.pdf
|
| 450 |
+
|
| 451 |
+
Examples
|
| 452 |
+
--------
|
| 453 |
+
Generate a sinusoid:
|
| 454 |
+
|
| 455 |
+
>>> import numpy as np
|
| 456 |
+
>>> f1, f2, fs = 8, 10, 200 # Hz
|
| 457 |
+
>>> t = np.linspace(0, 1, fs, endpoint=False)
|
| 458 |
+
>>> x = np.sin(2*np.pi*t*f2)
|
| 459 |
+
>>> import matplotlib.pyplot as plt
|
| 460 |
+
>>> plt.plot(t, x)
|
| 461 |
+
>>> plt.axis([0, 1, -1.1, 1.1])
|
| 462 |
+
>>> plt.show()
|
| 463 |
+
|
| 464 |
+
Its discrete Fourier transform has all of its energy in a single frequency
|
| 465 |
+
bin:
|
| 466 |
+
|
| 467 |
+
>>> from scipy.fft import rfft, rfftfreq
|
| 468 |
+
>>> from scipy.signal import czt, czt_points
|
| 469 |
+
>>> plt.plot(rfftfreq(fs, 1/fs), abs(rfft(x)))
|
| 470 |
+
>>> plt.margins(0, 0.1)
|
| 471 |
+
>>> plt.show()
|
| 472 |
+
|
| 473 |
+
However, if the sinusoid is logarithmically-decaying:
|
| 474 |
+
|
| 475 |
+
>>> x = np.exp(-t*f1) * np.sin(2*np.pi*t*f2)
|
| 476 |
+
>>> plt.plot(t, x)
|
| 477 |
+
>>> plt.axis([0, 1, -1.1, 1.1])
|
| 478 |
+
>>> plt.show()
|
| 479 |
+
|
| 480 |
+
the DFT will have spectral leakage:
|
| 481 |
+
|
| 482 |
+
>>> plt.plot(rfftfreq(fs, 1/fs), abs(rfft(x)))
|
| 483 |
+
>>> plt.margins(0, 0.1)
|
| 484 |
+
>>> plt.show()
|
| 485 |
+
|
| 486 |
+
While the DFT always samples the z-transform around the unit circle, the
|
| 487 |
+
chirp z-transform allows us to sample the Z-transform along any
|
| 488 |
+
logarithmic spiral, such as a circle with radius smaller than unity:
|
| 489 |
+
|
| 490 |
+
>>> M = fs // 2 # Just positive frequencies, like rfft
|
| 491 |
+
>>> a = np.exp(-f1/fs) # Starting point of the circle, radius < 1
|
| 492 |
+
>>> w = np.exp(-1j*np.pi/M) # "Step size" of circle
|
| 493 |
+
>>> points = czt_points(M + 1, w, a) # M + 1 to include Nyquist
|
| 494 |
+
>>> plt.plot(points.real, points.imag, '.')
|
| 495 |
+
>>> plt.gca().add_patch(plt.Circle((0,0), radius=1, fill=False, alpha=.3))
|
| 496 |
+
>>> plt.axis('equal'); plt.axis([-1.05, 1.05, -0.05, 1.05])
|
| 497 |
+
>>> plt.show()
|
| 498 |
+
|
| 499 |
+
With the correct radius, this transforms the decaying sinusoid (and others
|
| 500 |
+
with the same decay rate) without spectral leakage:
|
| 501 |
+
|
| 502 |
+
>>> z_vals = czt(x, M + 1, w, a) # Include Nyquist for comparison to rfft
|
| 503 |
+
>>> freqs = np.angle(points)*fs/(2*np.pi) # angle = omega, radius = sigma
|
| 504 |
+
>>> plt.plot(freqs, abs(z_vals))
|
| 505 |
+
>>> plt.margins(0, 0.1)
|
| 506 |
+
>>> plt.show()
|
| 507 |
+
"""
|
| 508 |
+
x = np.asarray(x)
|
| 509 |
+
transform = CZT(x.shape[axis], m=m, w=w, a=a)
|
| 510 |
+
return transform(x, axis=axis)
|
| 511 |
+
|
| 512 |
+
|
| 513 |
+
def zoom_fft(x, fn, m=None, *, fs=2, endpoint=False, axis=-1):
|
| 514 |
+
"""
|
| 515 |
+
Compute the DFT of `x` only for frequencies in range `fn`.
|
| 516 |
+
|
| 517 |
+
Parameters
|
| 518 |
+
----------
|
| 519 |
+
x : array
|
| 520 |
+
The signal to transform.
|
| 521 |
+
fn : array_like
|
| 522 |
+
A length-2 sequence [`f1`, `f2`] giving the frequency range, or a
|
| 523 |
+
scalar, for which the range [0, `fn`] is assumed.
|
| 524 |
+
m : int, optional
|
| 525 |
+
The number of points to evaluate. The default is the length of `x`.
|
| 526 |
+
fs : float, optional
|
| 527 |
+
The sampling frequency. If ``fs=10`` represented 10 kHz, for example,
|
| 528 |
+
then `f1` and `f2` would also be given in kHz.
|
| 529 |
+
The default sampling frequency is 2, so `f1` and `f2` should be
|
| 530 |
+
in the range [0, 1] to keep the transform below the Nyquist
|
| 531 |
+
frequency.
|
| 532 |
+
endpoint : bool, optional
|
| 533 |
+
If True, `f2` is the last sample. Otherwise, it is not included.
|
| 534 |
+
Default is False.
|
| 535 |
+
axis : int, optional
|
| 536 |
+
Axis over which to compute the FFT. If not given, the last axis is
|
| 537 |
+
used.
|
| 538 |
+
|
| 539 |
+
Returns
|
| 540 |
+
-------
|
| 541 |
+
out : ndarray
|
| 542 |
+
The transformed signal. The Fourier transform will be calculated
|
| 543 |
+
at the points f1, f1+df, f1+2df, ..., f2, where df=(f2-f1)/m.
|
| 544 |
+
|
| 545 |
+
See Also
|
| 546 |
+
--------
|
| 547 |
+
ZoomFFT : Class that creates a callable partial FFT function.
|
| 548 |
+
|
| 549 |
+
Notes
|
| 550 |
+
-----
|
| 551 |
+
The defaults are chosen such that ``signal.zoom_fft(x, 2)`` is equivalent
|
| 552 |
+
to ``fft.fft(x)`` and, if ``m > len(x)``, that ``signal.zoom_fft(x, 2, m)``
|
| 553 |
+
is equivalent to ``fft.fft(x, m)``.
|
| 554 |
+
|
| 555 |
+
To graph the magnitude of the resulting transform, use::
|
| 556 |
+
|
| 557 |
+
plot(linspace(f1, f2, m, endpoint=False), abs(zoom_fft(x, [f1, f2], m)))
|
| 558 |
+
|
| 559 |
+
If the transform needs to be repeated, use `ZoomFFT` to construct
|
| 560 |
+
a specialized transform function which can be reused without
|
| 561 |
+
recomputing constants.
|
| 562 |
+
|
| 563 |
+
Examples
|
| 564 |
+
--------
|
| 565 |
+
To plot the transform results use something like the following:
|
| 566 |
+
|
| 567 |
+
>>> import numpy as np
|
| 568 |
+
>>> from scipy.signal import zoom_fft
|
| 569 |
+
>>> t = np.linspace(0, 1, 1021)
|
| 570 |
+
>>> x = np.cos(2*np.pi*15*t) + np.sin(2*np.pi*17*t)
|
| 571 |
+
>>> f1, f2 = 5, 27
|
| 572 |
+
>>> X = zoom_fft(x, [f1, f2], len(x), fs=1021)
|
| 573 |
+
>>> f = np.linspace(f1, f2, len(x))
|
| 574 |
+
>>> import matplotlib.pyplot as plt
|
| 575 |
+
>>> plt.plot(f, 20*np.log10(np.abs(X)))
|
| 576 |
+
>>> plt.show()
|
| 577 |
+
"""
|
| 578 |
+
x = np.asarray(x)
|
| 579 |
+
transform = ZoomFFT(x.shape[axis], fn, m=m, fs=fs, endpoint=endpoint)
|
| 580 |
+
return transform(x, axis=axis)
|
venv/lib/python3.12/site-packages/scipy/signal/_delegators.py
ADDED
|
@@ -0,0 +1,573 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
"""Delegators for alternative backends in scipy.signal.
|
| 2 |
+
|
| 3 |
+
The signature of `func_signature` must match the signature of signal.func.
|
| 4 |
+
The job of a `func_signature` is to know which arguments of `signal.func`
|
| 5 |
+
are arrays.
|
| 6 |
+
|
| 7 |
+
* signatures are generated by
|
| 8 |
+
|
| 9 |
+
--------------
|
| 10 |
+
import inspect
|
| 11 |
+
from scipy import signal
|
| 12 |
+
|
| 13 |
+
names = [x for x in dir(signal) if not x.startswith('_')]
|
| 14 |
+
objs = [getattr(signal, name) for name in names]
|
| 15 |
+
funcs = [obj for obj in objs if inspect.isroutine(obj)]
|
| 16 |
+
|
| 17 |
+
for func in funcs:
|
| 18 |
+
try:
|
| 19 |
+
sig = inspect.signature(func)
|
| 20 |
+
except ValueError:
|
| 21 |
+
sig = "( FIXME )"
|
| 22 |
+
print(f"def {func.__name__}_signature{sig}:\n\treturn array_namespace(...
|
| 23 |
+
)\n\n")
|
| 24 |
+
---------------
|
| 25 |
+
|
| 26 |
+
* which arguments to delegate on: manually trawled the documentation for
|
| 27 |
+
array-like and array arguments
|
| 28 |
+
|
| 29 |
+
"""
|
| 30 |
+
import numpy as np
|
| 31 |
+
from scipy._lib._array_api import array_namespace, np_compat, is_jax
|
| 32 |
+
|
| 33 |
+
|
| 34 |
+
def _skip_if_lti(arg):
|
| 35 |
+
"""Handle `system` arg overloads.
|
| 36 |
+
|
| 37 |
+
ATM, only pass tuples through. Consider updating when cupyx.lti class
|
| 38 |
+
is supported.
|
| 39 |
+
"""
|
| 40 |
+
if isinstance(arg, tuple):
|
| 41 |
+
return arg
|
| 42 |
+
else:
|
| 43 |
+
return (None,)
|
| 44 |
+
|
| 45 |
+
|
| 46 |
+
def _skip_if_str_or_tuple(window):
|
| 47 |
+
"""Handle `window` being a str or a tuple or an array-like.
|
| 48 |
+
"""
|
| 49 |
+
if isinstance(window, str) or isinstance(window, tuple) or callable(window):
|
| 50 |
+
return None
|
| 51 |
+
else:
|
| 52 |
+
return window
|
| 53 |
+
|
| 54 |
+
|
| 55 |
+
def _skip_if_poly1d(arg):
|
| 56 |
+
return None if isinstance(arg, np.poly1d) else arg
|
| 57 |
+
|
| 58 |
+
|
| 59 |
+
###################
|
| 60 |
+
|
| 61 |
+
def abcd_normalize_signature(A=None, B=None, C=None, D=None):
|
| 62 |
+
return array_namespace(A, B, C, D)
|
| 63 |
+
|
| 64 |
+
def argrelextrema_signature(data, *args, **kwds):
|
| 65 |
+
return array_namespace(data)
|
| 66 |
+
|
| 67 |
+
argrelmax_signature = argrelextrema_signature
|
| 68 |
+
argrelmin_signature = argrelextrema_signature
|
| 69 |
+
|
| 70 |
+
|
| 71 |
+
def band_stop_obj_signature(wp, ind, passb, stopb, gpass, gstop, type):
|
| 72 |
+
return array_namespace(passb, stopb)
|
| 73 |
+
|
| 74 |
+
|
| 75 |
+
def bessel_signature(N, Wn, *args, **kwds):
|
| 76 |
+
return array_namespace(Wn)
|
| 77 |
+
|
| 78 |
+
butter_signature = bessel_signature
|
| 79 |
+
|
| 80 |
+
|
| 81 |
+
def cheby2_signature(N, rs, Wn, *args, **kwds):
|
| 82 |
+
return array_namespace(Wn)
|
| 83 |
+
|
| 84 |
+
|
| 85 |
+
def cheby1_signature(N, rp, Wn, *args, **kwds):
|
| 86 |
+
return array_namespace(Wn)
|
| 87 |
+
|
| 88 |
+
|
| 89 |
+
def ellip_signature(N, rp, rs, Wn, *args, **kwds):
|
| 90 |
+
return array_namespace(Wn)
|
| 91 |
+
|
| 92 |
+
|
| 93 |
+
########################## XXX: no arrays in, arrays out
|
| 94 |
+
def besselap_signature(N, norm='phase', *, xp=None, device=None):
|
| 95 |
+
return np if xp is None else xp
|
| 96 |
+
|
| 97 |
+
|
| 98 |
+
def buttap_signature(N, *, xp=None, device=None):
|
| 99 |
+
return np if xp is None else xp
|
| 100 |
+
|
| 101 |
+
|
| 102 |
+
def cheb1ap_signature(N, rp, *, xp=None, device=None):
|
| 103 |
+
return np if xp is None else xp
|
| 104 |
+
|
| 105 |
+
|
| 106 |
+
def cheb2ap_signature(N, rs, *, xp=None, device=None):
|
| 107 |
+
return np if xp is None else xp
|
| 108 |
+
|
| 109 |
+
def ellipap_signature(N, rp, rs, *, xp=None, device=None):
|
| 110 |
+
return np if xp is None else xp
|
| 111 |
+
|
| 112 |
+
def correlation_lags_signature(in1_len, in2_len, mode='full'):
|
| 113 |
+
return np
|
| 114 |
+
|
| 115 |
+
|
| 116 |
+
def czt_points_signature(m, w=None, a=(1+0j)):
|
| 117 |
+
return np
|
| 118 |
+
|
| 119 |
+
|
| 120 |
+
def gammatone_signature(
|
| 121 |
+
freq, ftype, order=None, numtaps=None, fs=None, *, xp=None, device=None
|
| 122 |
+
):
|
| 123 |
+
return np_compat if xp is None else xp
|
| 124 |
+
|
| 125 |
+
|
| 126 |
+
def iircomb_signature(
|
| 127 |
+
w0, Q, ftype='notch', fs=2.0, *, pass_zero=False, xp=None, device=None
|
| 128 |
+
):
|
| 129 |
+
return np_compat if xp is None else xp
|
| 130 |
+
|
| 131 |
+
|
| 132 |
+
def iirnotch_signature(w0, Q, fs=2.0, *, xp=None, device=None):
|
| 133 |
+
return np if xp is None else xp
|
| 134 |
+
|
| 135 |
+
iirpeak_signature = iirnotch_signature
|
| 136 |
+
|
| 137 |
+
|
| 138 |
+
def savgol_coeffs_signature(
|
| 139 |
+
window_length, polyorder, deriv=0, delta=1.0, pos=None, use='conv',
|
| 140 |
+
*, xp=None, device=None
|
| 141 |
+
):
|
| 142 |
+
return np if xp is None else xp
|
| 143 |
+
|
| 144 |
+
|
| 145 |
+
|
| 146 |
+
def unit_impulse_signature(shape, idx=None, dtype=float):
|
| 147 |
+
return np
|
| 148 |
+
############################
|
| 149 |
+
|
| 150 |
+
|
| 151 |
+
def buttord_signature(wp, ws, gpass, gstop, analog=False, fs=None):
|
| 152 |
+
return array_namespace(wp, ws)
|
| 153 |
+
|
| 154 |
+
cheb1ord_signature = buttord_signature
|
| 155 |
+
cheb2ord_signature = buttord_signature
|
| 156 |
+
ellipord_signature = buttord_signature
|
| 157 |
+
|
| 158 |
+
|
| 159 |
+
########### NB: scalars in, scalars out
|
| 160 |
+
def kaiser_atten_signature(numtaps, width):
|
| 161 |
+
return np
|
| 162 |
+
|
| 163 |
+
def kaiser_beta_signature(a):
|
| 164 |
+
return np
|
| 165 |
+
|
| 166 |
+
def kaiserord_signature(ripple, width):
|
| 167 |
+
return np
|
| 168 |
+
|
| 169 |
+
def get_window_signature(window, Nx, fftbins=True, *, xp=None, device=None):
|
| 170 |
+
return np if xp is None else xp
|
| 171 |
+
#################################
|
| 172 |
+
|
| 173 |
+
|
| 174 |
+
def bode_signature(system, w=None, n=100):
|
| 175 |
+
return array_namespace(*_skip_if_lti(system), w)
|
| 176 |
+
|
| 177 |
+
dbode_signature = bode_signature
|
| 178 |
+
|
| 179 |
+
|
| 180 |
+
def freqresp_signature(system, w=None, n=10000):
|
| 181 |
+
return array_namespace(*_skip_if_lti(system), w)
|
| 182 |
+
|
| 183 |
+
dfreqresp_signature = freqresp_signature
|
| 184 |
+
|
| 185 |
+
|
| 186 |
+
def impulse_signature(system, X0=None, T=None, N=None):
|
| 187 |
+
return array_namespace(*_skip_if_lti(system), X0, T)
|
| 188 |
+
|
| 189 |
+
|
| 190 |
+
def dimpulse_signature(system, x0=None, t=None, n=None):
|
| 191 |
+
return array_namespace(*_skip_if_lti(system), x0, t)
|
| 192 |
+
|
| 193 |
+
|
| 194 |
+
def lsim_signature(system, U, T, X0=None, interp=True):
|
| 195 |
+
return array_namespace(*_skip_if_lti(system), U, T, X0)
|
| 196 |
+
|
| 197 |
+
|
| 198 |
+
def dlsim_signature(system, u, t=None, x0=None):
|
| 199 |
+
return array_namespace(*_skip_if_lti(system), u, t, x0)
|
| 200 |
+
|
| 201 |
+
|
| 202 |
+
def step_signature(system, X0=None, T=None, N=None):
|
| 203 |
+
return array_namespace(*_skip_if_lti(system), X0, T)
|
| 204 |
+
|
| 205 |
+
def dstep_signature(system, x0=None, t=None, n=None):
|
| 206 |
+
return array_namespace(*_skip_if_lti(system), x0, t)
|
| 207 |
+
|
| 208 |
+
|
| 209 |
+
def cont2discrete_signature(system, dt, method='zoh', alpha=None):
|
| 210 |
+
return array_namespace(*_skip_if_lti(system))
|
| 211 |
+
|
| 212 |
+
|
| 213 |
+
def bilinear_signature(b, a, fs=1.0):
|
| 214 |
+
return array_namespace(b, a)
|
| 215 |
+
|
| 216 |
+
|
| 217 |
+
def bilinear_zpk_signature(z, p, k, fs):
|
| 218 |
+
return array_namespace(z, p)
|
| 219 |
+
|
| 220 |
+
|
| 221 |
+
def chirp_signature(t,*args, **kwds):
|
| 222 |
+
return array_namespace(t)
|
| 223 |
+
|
| 224 |
+
|
| 225 |
+
############## XXX: array-likes in, str out
|
| 226 |
+
def choose_conv_method_signature(in1, in2, *args, **kwds):
|
| 227 |
+
return array_namespace(in1, in2)
|
| 228 |
+
############################################
|
| 229 |
+
|
| 230 |
+
|
| 231 |
+
def convolve_signature(in1, in2, *args, **kwds):
|
| 232 |
+
return array_namespace(in1, in2)
|
| 233 |
+
|
| 234 |
+
fftconvolve_signature = convolve_signature
|
| 235 |
+
oaconvolve_signature = convolve_signature
|
| 236 |
+
correlate_signature = convolve_signature
|
| 237 |
+
correlate_signature = convolve_signature
|
| 238 |
+
convolve2d_signature = convolve_signature
|
| 239 |
+
correlate2d_signature = convolve_signature
|
| 240 |
+
|
| 241 |
+
|
| 242 |
+
def coherence_signature(x, y, fs=1.0, window='hann_periodic', *args, **kwds):
|
| 243 |
+
return array_namespace(x, y, _skip_if_str_or_tuple(window))
|
| 244 |
+
|
| 245 |
+
|
| 246 |
+
def csd_signature(x, y, fs=1.0, window='hann_periodic', *args, **kwds):
|
| 247 |
+
return array_namespace(x, y, _skip_if_str_or_tuple(window))
|
| 248 |
+
|
| 249 |
+
|
| 250 |
+
def periodogram_signature(x, fs=1.0, window='boxcar', *args, **kwds):
|
| 251 |
+
return array_namespace(x, _skip_if_str_or_tuple(window))
|
| 252 |
+
|
| 253 |
+
|
| 254 |
+
def welch_signature(x, fs=1.0, window='hann_periodic', *args, **kwds):
|
| 255 |
+
return array_namespace(x, _skip_if_str_or_tuple(window))
|
| 256 |
+
|
| 257 |
+
|
| 258 |
+
def spectrogram_signature(x, fs=1.0, window=('tukey_periodic', 0.25), *args, **kwds):
|
| 259 |
+
return array_namespace(x, _skip_if_str_or_tuple(window))
|
| 260 |
+
|
| 261 |
+
|
| 262 |
+
def stft_signature(x, fs=1.0, window='hann_periodic', *args, **kwds):
|
| 263 |
+
return array_namespace(x, _skip_if_str_or_tuple(window))
|
| 264 |
+
|
| 265 |
+
|
| 266 |
+
def istft_signature(Zxx, fs=1.0, window='hann_periodic', *args, **kwds):
|
| 267 |
+
return array_namespace(Zxx, _skip_if_str_or_tuple(window))
|
| 268 |
+
|
| 269 |
+
|
| 270 |
+
def resample_signature(x, num, t=None, axis=0, window=None, domain='time'):
|
| 271 |
+
return array_namespace(x, t, _skip_if_str_or_tuple(window))
|
| 272 |
+
|
| 273 |
+
|
| 274 |
+
def resample_poly_signature(x, up, down, axis=0, window=('kaiser', 5.0), *args, **kwds):
|
| 275 |
+
return array_namespace(x, _skip_if_str_or_tuple(window))
|
| 276 |
+
|
| 277 |
+
|
| 278 |
+
def check_COLA_signature(window, nperseg, noverlap, tol=1e-10):
|
| 279 |
+
return array_namespace(_skip_if_str_or_tuple(window))
|
| 280 |
+
|
| 281 |
+
|
| 282 |
+
def check_NOLA_signature(window, nperseg, noverlap, tol=1e-10):
|
| 283 |
+
return array_namespace(_skip_if_str_or_tuple(window))
|
| 284 |
+
|
| 285 |
+
|
| 286 |
+
def czt_signature(x, *args, **kwds):
|
| 287 |
+
return array_namespace(x)
|
| 288 |
+
|
| 289 |
+
decimate_signature = czt_signature
|
| 290 |
+
gauss_spline_signature = czt_signature
|
| 291 |
+
|
| 292 |
+
|
| 293 |
+
def deconvolve_signature(signal, divisor):
|
| 294 |
+
return array_namespace(signal, divisor)
|
| 295 |
+
|
| 296 |
+
|
| 297 |
+
def detrend_signature(data, axis=1, type='linear', bp=0, *args, **kwds):
|
| 298 |
+
xp = array_namespace(data)
|
| 299 |
+
# JAX doesn't accept JAX arrays for bp, only ints, lists and NumPy
|
| 300 |
+
# arrays.
|
| 301 |
+
return xp if is_jax(xp) else array_namespace(data, bp)
|
| 302 |
+
|
| 303 |
+
|
| 304 |
+
def filtfilt_signature(b, a, x, *args, **kwds):
|
| 305 |
+
return array_namespace(b, a, x)
|
| 306 |
+
|
| 307 |
+
|
| 308 |
+
def lfilter_signature(b, a, x, axis=-1, zi=None):
|
| 309 |
+
return array_namespace(b, a, x, zi)
|
| 310 |
+
|
| 311 |
+
|
| 312 |
+
def envelope_signature(z, *args, **kwds):
|
| 313 |
+
return array_namespace(z)
|
| 314 |
+
|
| 315 |
+
|
| 316 |
+
def find_peaks_signature(
|
| 317 |
+
x, height=None, threshold=None, distance=None, prominence=None, width=None,
|
| 318 |
+
wlen=None, rel_height=0.5, plateau_size=None
|
| 319 |
+
):
|
| 320 |
+
# TODO: fix me - `prominence` is not necessarily an array.
|
| 321 |
+
# return array_namespace(x, height, threshold, prominence, width, plateau_size)
|
| 322 |
+
# See https://github.com/scipy/scipy/pull/22644#issuecomment-3568443768. For now:
|
| 323 |
+
return np_compat
|
| 324 |
+
|
| 325 |
+
def find_peaks_cwt_signature(
|
| 326 |
+
vector, widths, wavelet=None, max_distances=None, *args, **kwds
|
| 327 |
+
):
|
| 328 |
+
return array_namespace(vector, widths, max_distances)
|
| 329 |
+
|
| 330 |
+
|
| 331 |
+
def findfreqs_signature(num, den, N, kind='ba'):
|
| 332 |
+
return array_namespace(num, den)
|
| 333 |
+
|
| 334 |
+
|
| 335 |
+
def firls_signature(numtaps, bands, desired, *, weight=None, fs=None):
|
| 336 |
+
return array_namespace(bands, desired, weight)
|
| 337 |
+
|
| 338 |
+
|
| 339 |
+
def firwin_signature(numtaps, cutoff, *args, **kwds):
|
| 340 |
+
if isinstance(cutoff, int | float):
|
| 341 |
+
xp = np_compat
|
| 342 |
+
else:
|
| 343 |
+
xp = array_namespace(cutoff)
|
| 344 |
+
return xp
|
| 345 |
+
|
| 346 |
+
|
| 347 |
+
def firwin2_signature(numtaps, freq, gain, *args, **kwds):
|
| 348 |
+
return array_namespace(freq, gain)
|
| 349 |
+
|
| 350 |
+
|
| 351 |
+
def freqs_zpk_signature(z, p, k, worN=200, *args, **kwds):
|
| 352 |
+
return array_namespace(z, p, worN)
|
| 353 |
+
|
| 354 |
+
freqz_zpk_signature = freqs_zpk_signature
|
| 355 |
+
|
| 356 |
+
|
| 357 |
+
def freqs_signature(b, a, worN=200, *args, **kwds):
|
| 358 |
+
return array_namespace(b, a, worN)
|
| 359 |
+
|
| 360 |
+
|
| 361 |
+
def freqz_signature(b, a=1, worN=512, *args, **kwds):
|
| 362 |
+
# differs from freqs: `a` has a default value
|
| 363 |
+
return array_namespace(b, a, worN)
|
| 364 |
+
|
| 365 |
+
|
| 366 |
+
def freqz_sos_signature(sos, worN=512, *args, **kwds):
|
| 367 |
+
return array_namespace(sos, worN)
|
| 368 |
+
|
| 369 |
+
sosfreqz_signature = freqz_sos_signature
|
| 370 |
+
|
| 371 |
+
|
| 372 |
+
def gausspulse_signature(t, *args, **kwds):
|
| 373 |
+
arr_t = None if isinstance(t, str) else t
|
| 374 |
+
return array_namespace(arr_t)
|
| 375 |
+
|
| 376 |
+
|
| 377 |
+
def group_delay_signature(system, w=512, whole=False, fs=6.283185307179586):
|
| 378 |
+
return array_namespace(*system, w)
|
| 379 |
+
|
| 380 |
+
|
| 381 |
+
def hilbert_signature(x, *args, **kwds):
|
| 382 |
+
return array_namespace(x)
|
| 383 |
+
|
| 384 |
+
hilbert2_signature = hilbert_signature
|
| 385 |
+
|
| 386 |
+
|
| 387 |
+
def iirdesign_signature(wp, ws, *args, **kwds):
|
| 388 |
+
return array_namespace(wp, ws)
|
| 389 |
+
|
| 390 |
+
|
| 391 |
+
def iirfilter_signature(N, Wn, *args, **kwds):
|
| 392 |
+
return array_namespace(Wn)
|
| 393 |
+
|
| 394 |
+
|
| 395 |
+
def invres_signature(r, p, k, tol=0.001, rtype='avg'):
|
| 396 |
+
return array_namespace(r, p, k)
|
| 397 |
+
|
| 398 |
+
invresz_signature = invres_signature
|
| 399 |
+
|
| 400 |
+
|
| 401 |
+
############################### XXX: excluded, blacklisted on CuPy (mismatched API)
|
| 402 |
+
def lfilter_zi_signature(b, a):
|
| 403 |
+
return array_namespace(b, a)
|
| 404 |
+
|
| 405 |
+
def sosfilt_zi_signature(sos):
|
| 406 |
+
return array_namespace(sos)
|
| 407 |
+
|
| 408 |
+
# needs to be blacklisted on CuPy (is not implemented)
|
| 409 |
+
def remez_signature(numtaps, bands, desired, *, weight=None, **kwds):
|
| 410 |
+
return array_namespace(bands, desired, weight)
|
| 411 |
+
#############################################
|
| 412 |
+
|
| 413 |
+
def lfiltic_signature(b, a, y, x=None):
|
| 414 |
+
return array_namespace(b, a, y, x)
|
| 415 |
+
|
| 416 |
+
|
| 417 |
+
def lombscargle_signature(
|
| 418 |
+
x, y, freqs, precenter=False, normalize=False, *,
|
| 419 |
+
weights=None, floating_mean=False
|
| 420 |
+
):
|
| 421 |
+
return array_namespace(x, y, freqs, weights)
|
| 422 |
+
|
| 423 |
+
|
| 424 |
+
def lp2bp_signature(b, a, *args, **kwds):
|
| 425 |
+
return array_namespace(b, a)
|
| 426 |
+
|
| 427 |
+
lp2bs_signature = lp2bp_signature
|
| 428 |
+
lp2hp_signature = lp2bp_signature
|
| 429 |
+
lp2lp_signature = lp2bp_signature
|
| 430 |
+
|
| 431 |
+
tf2zpk_signature = lp2bp_signature
|
| 432 |
+
tf2sos_signature = lp2bp_signature
|
| 433 |
+
|
| 434 |
+
normalize_signature = lp2bp_signature
|
| 435 |
+
residue_signature = lp2bp_signature
|
| 436 |
+
residuez_signature = residue_signature
|
| 437 |
+
|
| 438 |
+
|
| 439 |
+
def lp2bp_zpk_signature(z, p, k, *args, **kwds):
|
| 440 |
+
return array_namespace(z, p)
|
| 441 |
+
|
| 442 |
+
lp2bs_zpk_signature = lp2bp_zpk_signature
|
| 443 |
+
lp2hp_zpk_signature = lp2bs_zpk_signature
|
| 444 |
+
lp2lp_zpk_signature = lp2bs_zpk_signature
|
| 445 |
+
|
| 446 |
+
|
| 447 |
+
def zpk2sos_signature(z, p, k, *args, **kwds):
|
| 448 |
+
return array_namespace(z, p)
|
| 449 |
+
|
| 450 |
+
zpk2ss_signature = zpk2sos_signature
|
| 451 |
+
zpk2tf_signature = zpk2sos_signature
|
| 452 |
+
|
| 453 |
+
|
| 454 |
+
def max_len_seq_signature(nbits, state=None, length=None, taps=None):
|
| 455 |
+
return array_namespace(state, taps)
|
| 456 |
+
|
| 457 |
+
|
| 458 |
+
def medfilt_signature(volume, kernel_size=None):
|
| 459 |
+
return array_namespace(volume)
|
| 460 |
+
|
| 461 |
+
|
| 462 |
+
def medfilt2d_signature(input, kernel_size=3):
|
| 463 |
+
return array_namespace(input)
|
| 464 |
+
|
| 465 |
+
|
| 466 |
+
def minimum_phase_signature(h, *args, **kwds):
|
| 467 |
+
return array_namespace(h)
|
| 468 |
+
|
| 469 |
+
|
| 470 |
+
def order_filter_signature(a, domain, rank):
|
| 471 |
+
return array_namespace(a, domain)
|
| 472 |
+
|
| 473 |
+
|
| 474 |
+
def peak_prominences_signature(x, peaks, *args, **kwds):
|
| 475 |
+
return array_namespace(x, peaks)
|
| 476 |
+
|
| 477 |
+
|
| 478 |
+
peak_widths_signature = peak_prominences_signature
|
| 479 |
+
|
| 480 |
+
|
| 481 |
+
def place_poles_signature(A, B, poles, method='YT', rtol=0.001, maxiter=30):
|
| 482 |
+
return array_namespace(A, B, poles)
|
| 483 |
+
|
| 484 |
+
|
| 485 |
+
def savgol_filter_signature(x, *args, **kwds):
|
| 486 |
+
return array_namespace(x)
|
| 487 |
+
|
| 488 |
+
|
| 489 |
+
def sawtooth_signature(t, width=1):
|
| 490 |
+
return array_namespace(t)
|
| 491 |
+
|
| 492 |
+
|
| 493 |
+
def sepfir2d_signature(input, hrow, hcol):
|
| 494 |
+
return array_namespace(input, hrow, hcol)
|
| 495 |
+
|
| 496 |
+
|
| 497 |
+
def sos2tf_signature(sos):
|
| 498 |
+
return array_namespace(sos)
|
| 499 |
+
|
| 500 |
+
|
| 501 |
+
sos2zpk_signature = sos2tf_signature
|
| 502 |
+
|
| 503 |
+
|
| 504 |
+
def sosfilt_signature(sos, x, axis=-1, zi=None):
|
| 505 |
+
return array_namespace(sos, x, zi)
|
| 506 |
+
|
| 507 |
+
|
| 508 |
+
def sosfiltfilt_signature(sos, x, *args, **kwds):
|
| 509 |
+
return array_namespace(sos, x)
|
| 510 |
+
|
| 511 |
+
|
| 512 |
+
def spline_filter_signature(Iin, lmbda=5.0):
|
| 513 |
+
return array_namespace(Iin)
|
| 514 |
+
|
| 515 |
+
|
| 516 |
+
def square_signature(t, duty=0.5):
|
| 517 |
+
return array_namespace(t, duty)
|
| 518 |
+
|
| 519 |
+
|
| 520 |
+
def ss2tf_signature(A, B, C, D, input=0):
|
| 521 |
+
return array_namespace(A, B, C, D)
|
| 522 |
+
|
| 523 |
+
ss2zpk_signature = ss2tf_signature
|
| 524 |
+
|
| 525 |
+
|
| 526 |
+
def sweep_poly_signature(t, poly, phi=0):
|
| 527 |
+
return array_namespace(t, _skip_if_poly1d(poly))
|
| 528 |
+
|
| 529 |
+
|
| 530 |
+
def symiirorder1_signature(signal, c0, z1, precision=-1.0):
|
| 531 |
+
return array_namespace(signal)
|
| 532 |
+
|
| 533 |
+
|
| 534 |
+
def symiirorder2_signature(input, r, omega, precision=-1.0):
|
| 535 |
+
return array_namespace(input, r, omega)
|
| 536 |
+
|
| 537 |
+
|
| 538 |
+
def cspline1d_signature(signal, *args, **kwds):
|
| 539 |
+
return array_namespace(signal)
|
| 540 |
+
|
| 541 |
+
qspline1d_signature = cspline1d_signature
|
| 542 |
+
cspline2d_signature = cspline1d_signature
|
| 543 |
+
qspline2d_signature = qspline1d_signature
|
| 544 |
+
|
| 545 |
+
|
| 546 |
+
def cspline1d_eval_signature(cj, newx, *args, **kwds):
|
| 547 |
+
return array_namespace(cj, newx)
|
| 548 |
+
|
| 549 |
+
qspline1d_eval_signature = cspline1d_eval_signature
|
| 550 |
+
|
| 551 |
+
|
| 552 |
+
def tf2ss_signature(num, den):
|
| 553 |
+
return array_namespace(num, den)
|
| 554 |
+
|
| 555 |
+
|
| 556 |
+
def unique_roots_signature(p, tol=0.001, rtype='min'):
|
| 557 |
+
return array_namespace(p)
|
| 558 |
+
|
| 559 |
+
|
| 560 |
+
def upfirdn_signature(h, x, up=1, down=1, axis=-1, mode='constant', cval=0):
|
| 561 |
+
return array_namespace(h, x)
|
| 562 |
+
|
| 563 |
+
|
| 564 |
+
def vectorstrength_signature(events, period):
|
| 565 |
+
return array_namespace(events, period)
|
| 566 |
+
|
| 567 |
+
|
| 568 |
+
def wiener_signature(im, mysize=None, noise=None):
|
| 569 |
+
return array_namespace(im)
|
| 570 |
+
|
| 571 |
+
|
| 572 |
+
def zoom_fft_signature(x, fn, m=None, *, fs=2, endpoint=False, axis=-1):
|
| 573 |
+
return array_namespace(x, fn)
|
venv/lib/python3.12/site-packages/scipy/signal/_filter_design.py
ADDED
|
The diff for this file is too large to render.
See raw diff
|
|
|
venv/lib/python3.12/site-packages/scipy/signal/_fir_filter_design.py
ADDED
|
@@ -0,0 +1,1553 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
"""Functions for FIR filter design."""
|
| 2 |
+
|
| 3 |
+
from math import ceil, log, log2
|
| 4 |
+
import warnings
|
| 5 |
+
from typing import Literal
|
| 6 |
+
|
| 7 |
+
import numpy as np
|
| 8 |
+
from scipy.fft import irfft, fft, ifft
|
| 9 |
+
from scipy.linalg import (toeplitz, hankel, solve, LinAlgError, LinAlgWarning,
|
| 10 |
+
lstsq)
|
| 11 |
+
from scipy.signal._arraytools import _validate_fs
|
| 12 |
+
from .windows import get_window
|
| 13 |
+
from . import _sigtools
|
| 14 |
+
|
| 15 |
+
from scipy._lib._array_api import array_namespace, xp_size, xp_default_dtype
|
| 16 |
+
import scipy._external.array_api_extra as xpx
|
| 17 |
+
|
| 18 |
+
|
| 19 |
+
__all__ = ['kaiser_beta', 'kaiser_atten', 'kaiserord',
|
| 20 |
+
'firwin', 'firwin2', 'firwin_2d', 'remez', 'firls', 'minimum_phase']
|
| 21 |
+
|
| 22 |
+
|
| 23 |
+
# Some notes on function parameters:
|
| 24 |
+
#
|
| 25 |
+
# `cutoff` and `width` are given as numbers between 0 and 1. These are
|
| 26 |
+
# relative frequencies, expressed as a fraction of the Nyquist frequency.
|
| 27 |
+
# For example, if the Nyquist frequency is 2 KHz, then width=0.15 is a width
|
| 28 |
+
# of 300 Hz.
|
| 29 |
+
#
|
| 30 |
+
# The `order` of a FIR filter is one less than the number of taps.
|
| 31 |
+
# This is a potential source of confusion, so in the following code,
|
| 32 |
+
# we will always use the number of taps as the parameterization of
|
| 33 |
+
# the 'size' of the filter. The "number of taps" means the number
|
| 34 |
+
# of coefficients, which is the same as the length of the impulse
|
| 35 |
+
# response of the filter.
|
| 36 |
+
|
| 37 |
+
|
| 38 |
+
def kaiser_beta(a):
|
| 39 |
+
"""Compute the Kaiser parameter `beta`, given the attenuation `a`.
|
| 40 |
+
|
| 41 |
+
Parameters
|
| 42 |
+
----------
|
| 43 |
+
a : float
|
| 44 |
+
The desired attenuation in the stopband and maximum ripple in
|
| 45 |
+
the passband, in dB. This should be a *positive* number.
|
| 46 |
+
|
| 47 |
+
Returns
|
| 48 |
+
-------
|
| 49 |
+
beta : float
|
| 50 |
+
The `beta` parameter to be used in the formula for a Kaiser window.
|
| 51 |
+
|
| 52 |
+
References
|
| 53 |
+
----------
|
| 54 |
+
Oppenheim, Schafer, "Discrete-Time Signal Processing", p.475-476.
|
| 55 |
+
|
| 56 |
+
Examples
|
| 57 |
+
--------
|
| 58 |
+
Suppose we want to design a lowpass filter, with 65 dB attenuation
|
| 59 |
+
in the stop band. The Kaiser window parameter to be used in the
|
| 60 |
+
window method is computed by ``kaiser_beta(65)``:
|
| 61 |
+
|
| 62 |
+
>>> from scipy.signal import kaiser_beta
|
| 63 |
+
>>> kaiser_beta(65)
|
| 64 |
+
6.20426
|
| 65 |
+
|
| 66 |
+
"""
|
| 67 |
+
if a > 50:
|
| 68 |
+
beta = 0.1102 * (a - 8.7)
|
| 69 |
+
elif a > 21:
|
| 70 |
+
beta = 0.5842 * (a - 21) ** 0.4 + 0.07886 * (a - 21)
|
| 71 |
+
else:
|
| 72 |
+
beta = 0.0
|
| 73 |
+
return beta
|
| 74 |
+
|
| 75 |
+
|
| 76 |
+
def kaiser_atten(numtaps, width):
|
| 77 |
+
"""Compute the attenuation of a Kaiser FIR filter.
|
| 78 |
+
|
| 79 |
+
Given the number of taps `N` and the transition width `width`, compute the
|
| 80 |
+
attenuation `a` in dB, given by Kaiser's formula:
|
| 81 |
+
|
| 82 |
+
a = 2.285 * (N - 1) * pi * width + 7.95
|
| 83 |
+
|
| 84 |
+
Parameters
|
| 85 |
+
----------
|
| 86 |
+
numtaps : int
|
| 87 |
+
The number of taps in the FIR filter.
|
| 88 |
+
width : float
|
| 89 |
+
The desired width of the transition region between passband and
|
| 90 |
+
stopband (or, in general, at any discontinuity) for the filter,
|
| 91 |
+
expressed as a fraction of the Nyquist frequency.
|
| 92 |
+
|
| 93 |
+
Returns
|
| 94 |
+
-------
|
| 95 |
+
a : float
|
| 96 |
+
The attenuation of the ripple, in dB.
|
| 97 |
+
|
| 98 |
+
See Also
|
| 99 |
+
--------
|
| 100 |
+
kaiserord, kaiser_beta
|
| 101 |
+
|
| 102 |
+
Examples
|
| 103 |
+
--------
|
| 104 |
+
Suppose we want to design a FIR filter using the Kaiser window method
|
| 105 |
+
that will have 211 taps and a transition width of 9 Hz for a signal that
|
| 106 |
+
is sampled at 480 Hz. Expressed as a fraction of the Nyquist frequency,
|
| 107 |
+
the width is 9/(0.5*480) = 0.0375. The approximate attenuation (in dB)
|
| 108 |
+
is computed as follows:
|
| 109 |
+
|
| 110 |
+
>>> from scipy.signal import kaiser_atten
|
| 111 |
+
>>> kaiser_atten(211, 0.0375)
|
| 112 |
+
64.48099630593983
|
| 113 |
+
|
| 114 |
+
"""
|
| 115 |
+
a = 2.285 * (numtaps - 1) * np.pi * width + 7.95
|
| 116 |
+
return a
|
| 117 |
+
|
| 118 |
+
|
| 119 |
+
def kaiserord(ripple, width):
|
| 120 |
+
"""
|
| 121 |
+
Determine the filter window parameters for the Kaiser window method.
|
| 122 |
+
|
| 123 |
+
The parameters returned by this function are generally used to create
|
| 124 |
+
a finite impulse response filter using the window method, with either
|
| 125 |
+
`firwin` or `firwin2`.
|
| 126 |
+
|
| 127 |
+
Parameters
|
| 128 |
+
----------
|
| 129 |
+
ripple : float
|
| 130 |
+
Upper bound for the deviation (in dB) of the magnitude of the
|
| 131 |
+
filter's frequency response from that of the desired filter (not
|
| 132 |
+
including frequencies in any transition intervals). That is, if w
|
| 133 |
+
is the frequency expressed as a fraction of the Nyquist frequency,
|
| 134 |
+
A(w) is the actual frequency response of the filter and D(w) is the
|
| 135 |
+
desired frequency response, the design requirement is that::
|
| 136 |
+
|
| 137 |
+
abs(A(w) - D(w))) < 10**(-ripple/20)
|
| 138 |
+
|
| 139 |
+
for 0 <= w <= 1 and w not in a transition interval.
|
| 140 |
+
width : float
|
| 141 |
+
Width of transition region, normalized so that 1 corresponds to pi
|
| 142 |
+
radians / sample. That is, the frequency is expressed as a fraction
|
| 143 |
+
of the Nyquist frequency.
|
| 144 |
+
|
| 145 |
+
Returns
|
| 146 |
+
-------
|
| 147 |
+
numtaps : int
|
| 148 |
+
The length of the Kaiser window.
|
| 149 |
+
beta : float
|
| 150 |
+
The beta parameter for the Kaiser window.
|
| 151 |
+
|
| 152 |
+
See Also
|
| 153 |
+
--------
|
| 154 |
+
kaiser_beta, kaiser_atten
|
| 155 |
+
|
| 156 |
+
Notes
|
| 157 |
+
-----
|
| 158 |
+
There are several ways to obtain the Kaiser window:
|
| 159 |
+
|
| 160 |
+
- ``signal.windows.kaiser(numtaps, beta, sym=True)``
|
| 161 |
+
- ``signal.get_window(beta, numtaps)``
|
| 162 |
+
- ``signal.get_window(('kaiser', beta), numtaps)``
|
| 163 |
+
|
| 164 |
+
The empirical equations discovered by Kaiser are used.
|
| 165 |
+
|
| 166 |
+
References
|
| 167 |
+
----------
|
| 168 |
+
Oppenheim, Schafer, "Discrete-Time Signal Processing", pp.475-476.
|
| 169 |
+
|
| 170 |
+
Examples
|
| 171 |
+
--------
|
| 172 |
+
We will use the Kaiser window method to design a lowpass FIR filter
|
| 173 |
+
for a signal that is sampled at 1000 Hz.
|
| 174 |
+
|
| 175 |
+
We want at least 65 dB rejection in the stop band, and in the pass
|
| 176 |
+
band the gain should vary no more than 0.5%.
|
| 177 |
+
|
| 178 |
+
We want a cutoff frequency of 175 Hz, with a transition between the
|
| 179 |
+
pass band and the stop band of 24 Hz. That is, in the band [0, 163],
|
| 180 |
+
the gain varies no more than 0.5%, and in the band [187, 500], the
|
| 181 |
+
signal is attenuated by at least 65 dB.
|
| 182 |
+
|
| 183 |
+
>>> import numpy as np
|
| 184 |
+
>>> from scipy.signal import kaiserord, firwin, freqz
|
| 185 |
+
>>> import matplotlib.pyplot as plt
|
| 186 |
+
>>> fs = 1000.0
|
| 187 |
+
>>> cutoff = 175
|
| 188 |
+
>>> width = 24
|
| 189 |
+
|
| 190 |
+
The Kaiser method accepts just a single parameter to control the pass
|
| 191 |
+
band ripple and the stop band rejection, so we use the more restrictive
|
| 192 |
+
of the two. In this case, the pass band ripple is 0.005, or 46.02 dB,
|
| 193 |
+
so we will use 65 dB as the design parameter.
|
| 194 |
+
|
| 195 |
+
Use `kaiserord` to determine the length of the filter and the
|
| 196 |
+
parameter for the Kaiser window.
|
| 197 |
+
|
| 198 |
+
>>> numtaps, beta = kaiserord(65, width/(0.5*fs))
|
| 199 |
+
>>> numtaps
|
| 200 |
+
167
|
| 201 |
+
>>> beta
|
| 202 |
+
6.20426
|
| 203 |
+
|
| 204 |
+
Use `firwin` to create the FIR filter.
|
| 205 |
+
|
| 206 |
+
>>> taps = firwin(numtaps, cutoff, window=('kaiser', beta),
|
| 207 |
+
... scale=False, fs=fs)
|
| 208 |
+
|
| 209 |
+
Compute the frequency response of the filter. ``w`` is the array of
|
| 210 |
+
frequencies, and ``h`` is the corresponding complex array of frequency
|
| 211 |
+
responses.
|
| 212 |
+
|
| 213 |
+
>>> w, h = freqz(taps, worN=8000)
|
| 214 |
+
>>> w *= 0.5*fs/np.pi # Convert w to Hz.
|
| 215 |
+
|
| 216 |
+
Compute the deviation of the magnitude of the filter's response from
|
| 217 |
+
that of the ideal lowpass filter. Values in the transition region are
|
| 218 |
+
set to ``nan``, so they won't appear in the plot.
|
| 219 |
+
|
| 220 |
+
>>> ideal = w < cutoff # The "ideal" frequency response.
|
| 221 |
+
>>> deviation = np.abs(np.abs(h) - ideal)
|
| 222 |
+
>>> deviation[(w > cutoff - 0.5*width) & (w < cutoff + 0.5*width)] = np.nan
|
| 223 |
+
|
| 224 |
+
Plot the deviation. A close look at the left end of the stop band shows
|
| 225 |
+
that the requirement for 65 dB attenuation is violated in the first lobe
|
| 226 |
+
by about 0.125 dB. This is not unusual for the Kaiser window method.
|
| 227 |
+
|
| 228 |
+
>>> plt.plot(w, 20*np.log10(np.abs(deviation)))
|
| 229 |
+
>>> plt.xlim(0, 0.5*fs)
|
| 230 |
+
>>> plt.ylim(-90, -60)
|
| 231 |
+
>>> plt.grid(alpha=0.25)
|
| 232 |
+
>>> plt.axhline(-65, color='r', ls='--', alpha=0.3)
|
| 233 |
+
>>> plt.xlabel('Frequency (Hz)')
|
| 234 |
+
>>> plt.ylabel('Deviation from ideal (dB)')
|
| 235 |
+
>>> plt.title('Lowpass Filter Frequency Response')
|
| 236 |
+
>>> plt.show()
|
| 237 |
+
|
| 238 |
+
"""
|
| 239 |
+
A = abs(ripple) # in case somebody is confused as to what's meant
|
| 240 |
+
if A < 8:
|
| 241 |
+
# Formula for N is not valid in this range.
|
| 242 |
+
raise ValueError("Requested maximum ripple attenuation "
|
| 243 |
+
f"{A:f} is too small for the Kaiser formula.")
|
| 244 |
+
beta = kaiser_beta(A)
|
| 245 |
+
|
| 246 |
+
# Kaiser's formula (as given in Oppenheim and Schafer) is for the filter
|
| 247 |
+
# order, so we have to add 1 to get the number of taps.
|
| 248 |
+
numtaps = (A - 7.95) / 2.285 / (np.pi * width) + 1
|
| 249 |
+
|
| 250 |
+
return int(ceil(numtaps)), beta
|
| 251 |
+
|
| 252 |
+
|
| 253 |
+
def firwin(numtaps, cutoff, *, width=None, window='hamming', pass_zero=True,
|
| 254 |
+
scale=True, fs=None):
|
| 255 |
+
r"""FIR filter design using the window method.
|
| 256 |
+
|
| 257 |
+
This function computes the coefficients of a finite impulse response
|
| 258 |
+
filter. The filter will have linear phase; it will be Type I if
|
| 259 |
+
`numtaps` is odd and Type II if `numtaps` is even.
|
| 260 |
+
|
| 261 |
+
Type II filters always have zero response at the Nyquist frequency, so a
|
| 262 |
+
ValueError exception is raised if firwin is called with `numtaps` even and
|
| 263 |
+
having a passband whose right end is at the Nyquist frequency.
|
| 264 |
+
|
| 265 |
+
Parameters
|
| 266 |
+
----------
|
| 267 |
+
numtaps : int
|
| 268 |
+
Length of the filter (number of coefficients, i.e., the filter
|
| 269 |
+
order + 1). `numtaps` must be odd if a passband includes the
|
| 270 |
+
Nyquist frequency.
|
| 271 |
+
cutoff : float or 1-D array_like
|
| 272 |
+
Cutoff frequency of filter (expressed in the same units as `fs`)
|
| 273 |
+
or an array of cutoff frequencies (that is, band edges). In the
|
| 274 |
+
former case, as a float, the cutoff frequency should correspond
|
| 275 |
+
with the half-amplitude point, where the attenuation will be -6 dB.
|
| 276 |
+
In the latter case, the frequencies in `cutoff` should be positive
|
| 277 |
+
and monotonically increasing between 0 and `fs/2`. The values 0
|
| 278 |
+
and `fs/2` must not be included in `cutoff`. It should be noted
|
| 279 |
+
that this is different from the behavior of `~scipy.signal.iirdesign`,
|
| 280 |
+
where the cutoff is the half-power point (-3 dB).
|
| 281 |
+
width : float or None, optional
|
| 282 |
+
If not ``None``, then a `~scipy.signal.windows.kaiser` window is calculated
|
| 283 |
+
where `width` specifies the approximate width of the transition region
|
| 284 |
+
(expressed in the same unit as `fs`). This is achieved by utilizing
|
| 285 |
+
`~scipy.signal.kaiser_atten` to calculate an attenuation which is passed to
|
| 286 |
+
`~scipy.signal.kaiser_beta` for determining the β parameter for the kaiser
|
| 287 |
+
window. In this case, the `window` argument is ignored.
|
| 288 |
+
window : str or tuple of str and parameter values, optional
|
| 289 |
+
Desired window to use. Default is ``'hamming'``. The window will be symmetric,
|
| 290 |
+
unless a suffix ``'_periodic'`` is appended to the window name (e.g.,
|
| 291 |
+
``'hamming_perodic'``) Consult `~scipy.signal.get_window` for a list of windows
|
| 292 |
+
and required parameters.
|
| 293 |
+
pass_zero : {True, False, 'bandpass', 'lowpass', 'highpass', 'bandstop'}, optional
|
| 294 |
+
Toggles the zero frequency bin (or DC gain) to be in the passband (``True``) or
|
| 295 |
+
in the stopband (``False``). ``'bandstop'``, ``'lowpass'`` are synonyms for
|
| 296 |
+
``True`` and ``'bandpass'``, ``'highpass'`` are synonyms for ``False``.
|
| 297 |
+
``'lowpass'``, ``'highpass'`` additionally require `cutoff` to be a scalar
|
| 298 |
+
value or a length-one array. Default: ``True``.
|
| 299 |
+
|
| 300 |
+
.. versionadded:: 1.3.0
|
| 301 |
+
Support for string arguments.
|
| 302 |
+
scale : bool, optional
|
| 303 |
+
Set to ``True`` to scale the coefficients so that the frequency response is
|
| 304 |
+
exactly unity at a certain frequency. That frequency is either:
|
| 305 |
+
|
| 306 |
+
- 0 (DC) if the first passband starts at 0 (i.e., `pass_zero` is ``True``)
|
| 307 |
+
- `fs/2` (the Nyquist frequency) if the first passband ends at `fs/2`
|
| 308 |
+
(i.e., the filter is a single band highpass filter); center of first
|
| 309 |
+
passband otherwise
|
| 310 |
+
|
| 311 |
+
fs : float, optional
|
| 312 |
+
The sampling frequency of the signal. Each frequency in `cutoff`
|
| 313 |
+
must be between 0 and ``fs/2``. Default is 2.
|
| 314 |
+
|
| 315 |
+
Returns
|
| 316 |
+
-------
|
| 317 |
+
h : ndarray
|
| 318 |
+
FIR filter coefficients as 1d array with `numtaps` entries.
|
| 319 |
+
|
| 320 |
+
Raises
|
| 321 |
+
------
|
| 322 |
+
ValueError
|
| 323 |
+
If any value in `cutoff` is less than or equal to 0 or greater
|
| 324 |
+
than or equal to ``fs/2``, if the values in `cutoff` are not strictly
|
| 325 |
+
monotonically increasing, or if `numtaps` is even but a passband
|
| 326 |
+
includes the Nyquist frequency.
|
| 327 |
+
|
| 328 |
+
See Also
|
| 329 |
+
--------
|
| 330 |
+
firwin2: Window method FIR filter design specifying gain-frequency pairs.
|
| 331 |
+
firwin_2d: 2D FIR filter design using the window method.
|
| 332 |
+
firls: FIR filter design using least-squares error minimization.
|
| 333 |
+
minimum_phase: Convert a FIR filter to minimum phase
|
| 334 |
+
remez: Calculate the minimax optimal filter using the Remez exchange algorithm.
|
| 335 |
+
|
| 336 |
+
Examples
|
| 337 |
+
--------
|
| 338 |
+
The following example calculates frequency responses of a 30 Hz low-pass filter
|
| 339 |
+
with various numbers of taps. The transition region width is 20 Hz. The upper plot
|
| 340 |
+
shows the gain and the lower plot the phase. The vertical dashed line marks the
|
| 341 |
+
corner frequency and the gray background the transition region.
|
| 342 |
+
|
| 343 |
+
>>> import matplotlib.pyplot as plt
|
| 344 |
+
>>> import numpy as np
|
| 345 |
+
>>> import scipy.signal as signal
|
| 346 |
+
...
|
| 347 |
+
>>> fs = 200 # sampling frequency and number of taps
|
| 348 |
+
>>> f_c, width = 30, 20 # corner frequency (-6 dB gain)
|
| 349 |
+
>>> taps = [20, 40, 60] # number of taps
|
| 350 |
+
...
|
| 351 |
+
>>> fg, (ax0, ax1) = plt.subplots(2, 1, sharex='all', layout="constrained",
|
| 352 |
+
... figsize=(5, 4))
|
| 353 |
+
>>> ax0.set_title(rf"Response of ${f_c}\,$Hz low-pass Filter with " +
|
| 354 |
+
... rf"${width}\,$Hz transition region")
|
| 355 |
+
>>> ax0.set(ylabel="Gain in dB", xlim=(0, fs/2))
|
| 356 |
+
>>> ax1.set(xlabel=rf"Frequency $f\,$ in hertz (sampling frequency $f_S={fs}\,$Hz)",
|
| 357 |
+
... ylabel="Phase in Degrees")
|
| 358 |
+
...
|
| 359 |
+
>>> for n in taps: # calculate filter and plot response:
|
| 360 |
+
... bb = signal.firwin(n, f_c, width=width, fs=fs)
|
| 361 |
+
... f, H = signal.freqz(bb, fs=fs) # calculate frequency response
|
| 362 |
+
... H_dB, H_ph = 20 * np.log10(abs(H)), np.rad2deg(np.unwrap(np.angle(H)))
|
| 363 |
+
... H_ph[H_dB<-150] = np.nan
|
| 364 |
+
... ax0.plot(f, H_dB, alpha=.5, label=rf"{n} taps")
|
| 365 |
+
... ax1.plot(f, H_ph, alpha=.5, label=rf"{n} taps")
|
| 366 |
+
>>> for ax_ in (ax0, ax1):
|
| 367 |
+
... ax_.axvspan(f_c-width/2, f_c+width/2,color='gray', alpha=.25)
|
| 368 |
+
... ax_.axvline(f_c, color='gray', linestyle='--', alpha=.5)
|
| 369 |
+
... ax_.grid()
|
| 370 |
+
... ax_.legend()
|
| 371 |
+
>>> plt.show()
|
| 372 |
+
|
| 373 |
+
The plots show that with increasing number of taps, the suppression in the stopband
|
| 374 |
+
increases and the (negative) slope of the phase steepens, which signifies a longer
|
| 375 |
+
signal delay in the filter. Note that the plots contain numeric artifacts caused by
|
| 376 |
+
the limited frequency resolution: The phase jumps are not real---in reality the
|
| 377 |
+
phase is a straight line with a constant negative slope. Furthermore, the gains
|
| 378 |
+
contain zero values (i.e., -∞ dB), which are also not depicted.
|
| 379 |
+
|
| 380 |
+
The second example determines the frequency responses of a 30 Hz low-pass filter
|
| 381 |
+
with 40 taps. This time the width of the transition region varies:
|
| 382 |
+
|
| 383 |
+
>>> import matplotlib.pyplot as plt
|
| 384 |
+
>>> import numpy as np
|
| 385 |
+
>>> import scipy.signal as signal
|
| 386 |
+
...
|
| 387 |
+
>>> fs = 200 # sampling frequency and number of taps
|
| 388 |
+
>>> n, f_c = 40, 30 # number of taps and corner frequency (-6 dB gain)
|
| 389 |
+
>>> widths = (2, 10, 25) # width of transition region
|
| 390 |
+
...
|
| 391 |
+
>>> fg, ax = plt.subplots(1, 1, layout="constrained",)
|
| 392 |
+
>>> ax.set(title=rf"Response of {n}-tap ${f_c}\,$Hz low-pass Filter",
|
| 393 |
+
... xlabel=rf"Frequency $f\,$ in hertz (sampling frequency $f_S={fs}\,$Hz)",
|
| 394 |
+
... ylabel="Gain in dB", xlim=(0, fs/2))
|
| 395 |
+
>>> ax.axvline(f_c, color='gray', linestyle='--', alpha=.7) # mark corner frequency
|
| 396 |
+
...
|
| 397 |
+
>>> for width in widths: # calculate filter and plot response:
|
| 398 |
+
... bb = signal.firwin(n, f_c, width=width, fs=fs)
|
| 399 |
+
... f, H = signal.freqz(bb, fs=fs) # calculate frequency response
|
| 400 |
+
... H_dB= 20 * np.log10(abs(H)) # convert to dB
|
| 401 |
+
... ax.plot(f, H_dB, alpha=.5, label=rf"width$={width}\,$Hz")
|
| 402 |
+
...
|
| 403 |
+
>>> ax.grid()
|
| 404 |
+
>>> ax.legend()
|
| 405 |
+
>>> plt.show()
|
| 406 |
+
|
| 407 |
+
It can be seen in the plot above that with increasing width of the transition
|
| 408 |
+
region the suppression in the stopband increases. Since the phase does not vary, it
|
| 409 |
+
is not depicted.
|
| 410 |
+
|
| 411 |
+
Instead of defining a transition region width, a window function can also be
|
| 412 |
+
specified. The plot below depicts the response of an 80 tap band-pass filter having
|
| 413 |
+
a passband ranging form 40 Hz to 60 Hz (denoted by a gray background) with
|
| 414 |
+
different windows:
|
| 415 |
+
|
| 416 |
+
>>> import matplotlib.pyplot as plt
|
| 417 |
+
>>> import numpy as np
|
| 418 |
+
>>> import scipy.signal as signal
|
| 419 |
+
...
|
| 420 |
+
>>> fs, n = 200, 80 # sampling frequency and number of taps
|
| 421 |
+
>>> cutoff = [40, 60] # corner frequencies (-6 dB gain)
|
| 422 |
+
>>> windows = ('boxcar', 'hamming', 'hann', 'blackman')
|
| 423 |
+
...
|
| 424 |
+
>>> fg, ax = plt.subplots(1, 1, layout="constrained") # set up plotting
|
| 425 |
+
>>> ax.set(title=rf"Response of {n}-tap Filter with ${cutoff}\,$Hz passband",
|
| 426 |
+
... xlabel=rf"Frequency $f\,$ in hertz (sampling frequency $f_S={fs}\,$Hz)",
|
| 427 |
+
... ylabel="Gain in dB", xlim=(0, fs/2))
|
| 428 |
+
>>> ax.axvspan(*cutoff, color='gray', alpha=.25) # mark passband
|
| 429 |
+
...
|
| 430 |
+
>>> for win in windows: # calculate filter and plot response:
|
| 431 |
+
... bb = signal.firwin(n, cutoff, window=win, pass_zero=False, fs=fs)
|
| 432 |
+
... f, H = signal.freqz(bb, fs=fs) # calculate frequency response
|
| 433 |
+
... H_dB = 20 * np.log10(abs(H)) # convert to dB
|
| 434 |
+
... ax.plot(f, H_dB, alpha=.5, label=win)
|
| 435 |
+
...
|
| 436 |
+
>>> ax.grid()
|
| 437 |
+
>>> ax.legend()
|
| 438 |
+
>>> plt.show()
|
| 439 |
+
|
| 440 |
+
The plot shows that the choice of window mainly influences the balance of the
|
| 441 |
+
suppression in the stopband against the width of the transition region. Note that
|
| 442 |
+
utilizing the `~scipy.signal.windows.boxcar` window corresponds to just truncating
|
| 443 |
+
the ideal infinite impulse response to the length of `numtaps` samples.
|
| 444 |
+
|
| 445 |
+
The last example illustrates how to use the `cutoff` and `pass_zero` parameters to
|
| 446 |
+
create a low-pass, a high-pass, a band-stop and a band-pass filter. The desired
|
| 447 |
+
ideal frequency gain is drawn as a gray dashed line whereas the response of the FIR
|
| 448 |
+
filter is depicted as a blue continuous line:
|
| 449 |
+
|
| 450 |
+
>>> from itertools import product
|
| 451 |
+
>>> import matplotlib.pyplot as plt
|
| 452 |
+
>>> import numpy as np
|
| 453 |
+
>>> import scipy.signal as signal
|
| 454 |
+
...
|
| 455 |
+
>>> cutoffs = [0.5, (.25, .75)] # cutoff parameters
|
| 456 |
+
>>> fg, axx = plt.subplots(4, 1, sharex='all', layout="constrained",
|
| 457 |
+
... figsize=(5, 4))
|
| 458 |
+
>>> for ax, (cutoff, pass_zero) in zip(axx, product(cutoffs, (True, False))):
|
| 459 |
+
... ax.set(title=f"firwin(41, {cutoff=}, {pass_zero=}, fs=2)", ylabel="Gain")
|
| 460 |
+
... ax.set_yticks([0.5], minor=True) # mark gain of 0.5 (= -6 dB)
|
| 461 |
+
... ax.grid(which='minor', axis='y')
|
| 462 |
+
...
|
| 463 |
+
... bb = signal.firwin(41, cutoff, pass_zero=pass_zero, fs=2)
|
| 464 |
+
... ff, HH = signal.freqz(bb, fs=2)
|
| 465 |
+
... ax.plot(ff, abs(HH), 'C0-', label="FIR Response")
|
| 466 |
+
...
|
| 467 |
+
... f_d = np.hstack(([0], np.atleast_1d(cutoff), [1]))
|
| 468 |
+
... H_d = np.tile([1, 0] if pass_zero else [0, 1], 2)[:len(f_d)]
|
| 469 |
+
... H_d[-1] = H_d[-2] # account for symmetry at Nyquist frequency
|
| 470 |
+
... ax.step(f_d, H_d, 'k--', where='post', alpha=.3, label="Desired Response")
|
| 471 |
+
>>> axx[-1].set(xlabel=r"Frequency $f\,$ in hertz (sampling frequency $f_S=2\,$Hz)",
|
| 472 |
+
... xlim=(0, 1))
|
| 473 |
+
>>> plt.show()
|
| 474 |
+
"""
|
| 475 |
+
# NB: scipy's version of array_namespace returns `np_compat` for int or floats
|
| 476 |
+
xp = array_namespace(cutoff)
|
| 477 |
+
|
| 478 |
+
# The major enhancements to this function added in November 2010 were
|
| 479 |
+
# developed by Tom Krauss (see ticket #902).
|
| 480 |
+
fs = _validate_fs(fs, allow_none=True)
|
| 481 |
+
fs = 2 if fs is None else fs
|
| 482 |
+
|
| 483 |
+
nyq = 0.5 * fs
|
| 484 |
+
|
| 485 |
+
cutoff = xp.asarray(cutoff, dtype=xp_default_dtype(xp))
|
| 486 |
+
cutoff = xpx.atleast_nd(cutoff, ndim=1, xp=xp) / float(nyq)
|
| 487 |
+
|
| 488 |
+
# Check for invalid input.
|
| 489 |
+
if cutoff.ndim > 1:
|
| 490 |
+
raise ValueError("The cutoff argument must be at most "
|
| 491 |
+
"one-dimensional.")
|
| 492 |
+
if xp_size(cutoff) == 0:
|
| 493 |
+
raise ValueError("At least one cutoff frequency must be given.")
|
| 494 |
+
if xp.min(cutoff) <= 0 or xp.max(cutoff) >= 1:
|
| 495 |
+
raise ValueError("Invalid cutoff frequency: frequencies must be "
|
| 496 |
+
"greater than 0 and less than fs/2.")
|
| 497 |
+
if xp.any(cutoff[1:] - cutoff[:-1] <= 0):
|
| 498 |
+
raise ValueError("Invalid cutoff frequencies: the frequencies "
|
| 499 |
+
"must be strictly increasing.")
|
| 500 |
+
|
| 501 |
+
if width is not None:
|
| 502 |
+
# A width was given. Find the beta parameter of the Kaiser window
|
| 503 |
+
# and set `window`. This overrides the value of `window` passed in.
|
| 504 |
+
atten = kaiser_atten(numtaps, float(width) / nyq)
|
| 505 |
+
beta = kaiser_beta(atten)
|
| 506 |
+
window = ('kaiser', beta)
|
| 507 |
+
|
| 508 |
+
if pass_zero in ('bandstop', 'lowpass'):
|
| 509 |
+
if pass_zero == 'lowpass':
|
| 510 |
+
if xp_size(cutoff) != 1:
|
| 511 |
+
raise ValueError('cutoff must have one element if '
|
| 512 |
+
f'pass_zero=="lowpass", got {cutoff.shape}')
|
| 513 |
+
elif xp_size(cutoff) <= 1:
|
| 514 |
+
raise ValueError('cutoff must have at least two elements if '
|
| 515 |
+
f'pass_zero=="bandstop", got {cutoff.shape}')
|
| 516 |
+
pass_zero = True
|
| 517 |
+
elif pass_zero in ('bandpass', 'highpass'):
|
| 518 |
+
if pass_zero == 'highpass':
|
| 519 |
+
if xp_size(cutoff) != 1:
|
| 520 |
+
raise ValueError('cutoff must have one element if '
|
| 521 |
+
f'pass_zero=="highpass", got {cutoff.shape}')
|
| 522 |
+
elif xp_size(cutoff) <= 1:
|
| 523 |
+
raise ValueError('cutoff must have at least two elements if '
|
| 524 |
+
f'pass_zero=="bandpass", got {cutoff.shape}')
|
| 525 |
+
pass_zero = False
|
| 526 |
+
elif not (pass_zero is True or pass_zero is False):
|
| 527 |
+
raise ValueError(f"Parameter {pass_zero=} not in (True, False, 'bandpass', " +
|
| 528 |
+
"'lowpass', 'highpass', 'bandstop')")
|
| 529 |
+
|
| 530 |
+
pass_nyquist = (xp_size(cutoff) % 2 == 0) == pass_zero
|
| 531 |
+
if pass_nyquist and numtaps % 2 == 0:
|
| 532 |
+
raise ValueError("A filter with an even number of coefficients must "
|
| 533 |
+
"have zero response at the Nyquist frequency.")
|
| 534 |
+
|
| 535 |
+
# Insert 0 and/or 1 at the ends of cutoff so that the length of cutoff
|
| 536 |
+
# is even, and each pair in cutoff corresponds to passband.
|
| 537 |
+
cutoff = xp.concat((xp.zeros(int(pass_zero)), cutoff, xp.ones(int(pass_nyquist))))
|
| 538 |
+
|
| 539 |
+
|
| 540 |
+
# `bands` is a 2-D array; each row gives the left and right edges of
|
| 541 |
+
# a passband.
|
| 542 |
+
bands = xp.reshape(cutoff, (-1, 2))
|
| 543 |
+
|
| 544 |
+
# Build up the coefficients.
|
| 545 |
+
alpha = 0.5 * (numtaps - 1)
|
| 546 |
+
m = xp.arange(0, numtaps, dtype=cutoff.dtype) - alpha
|
| 547 |
+
h = 0
|
| 548 |
+
for j in range(bands.shape[0]):
|
| 549 |
+
left, right = bands[j, 0], bands[j, 1]
|
| 550 |
+
h += right * xpx.sinc(right * m, xp=xp)
|
| 551 |
+
h -= left * xpx.sinc(left * m, xp=xp)
|
| 552 |
+
|
| 553 |
+
# Get and apply the window function.
|
| 554 |
+
win = get_window(window, numtaps, fftbins=False, xp=xp)
|
| 555 |
+
h *= win
|
| 556 |
+
|
| 557 |
+
# Now handle scaling if desired.
|
| 558 |
+
if scale:
|
| 559 |
+
# Get the first passband.
|
| 560 |
+
left, right = bands[0, ...]
|
| 561 |
+
if left == 0:
|
| 562 |
+
scale_frequency = 0.0
|
| 563 |
+
elif right == 1:
|
| 564 |
+
scale_frequency = 1.0
|
| 565 |
+
else:
|
| 566 |
+
scale_frequency = 0.5 * (left + right)
|
| 567 |
+
c = xp.cos(xp.pi * m * scale_frequency)
|
| 568 |
+
s = xp.sum(h * c)
|
| 569 |
+
h /= s
|
| 570 |
+
|
| 571 |
+
return h
|
| 572 |
+
|
| 573 |
+
|
| 574 |
+
# Original version of firwin2 from scipy ticket #457, submitted by "tash".
|
| 575 |
+
#
|
| 576 |
+
# Rewritten by Warren Weckesser, 2010.
|
| 577 |
+
def firwin2(numtaps, freq, gain, *, nfreqs=None, window='hamming',
|
| 578 |
+
antisymmetric=False, fs=None):
|
| 579 |
+
"""
|
| 580 |
+
FIR filter design using the window method.
|
| 581 |
+
|
| 582 |
+
From the given frequencies `freq` and corresponding gains `gain`,
|
| 583 |
+
this function constructs an FIR filter with linear phase and
|
| 584 |
+
(approximately) the given frequency response.
|
| 585 |
+
|
| 586 |
+
Parameters
|
| 587 |
+
----------
|
| 588 |
+
numtaps : int
|
| 589 |
+
The number of taps in the FIR filter. `numtaps` must be less than
|
| 590 |
+
`nfreqs`.
|
| 591 |
+
freq : array_like, 1-D
|
| 592 |
+
The frequency sampling points. Typically 0.0 to 1.0 with 1.0 being
|
| 593 |
+
Nyquist. The Nyquist frequency is half `fs`.
|
| 594 |
+
The values in `freq` must be nondecreasing. A value can be repeated
|
| 595 |
+
once to implement a discontinuity. The first value in `freq` must
|
| 596 |
+
be 0, and the last value must be ``fs/2``. Values 0 and ``fs/2`` must
|
| 597 |
+
not be repeated.
|
| 598 |
+
gain : array_like
|
| 599 |
+
The filter gains at the frequency sampling points. Certain
|
| 600 |
+
constraints to gain values, depending on the filter type, are applied,
|
| 601 |
+
see Notes for details.
|
| 602 |
+
nfreqs : int, optional
|
| 603 |
+
The size of the interpolation mesh used to construct the filter.
|
| 604 |
+
For most efficient behavior, this should be a power of 2 plus 1
|
| 605 |
+
(e.g, 129, 257, etc). The default is one more than the smallest
|
| 606 |
+
power of 2 that is not less than `numtaps`. `nfreqs` must be greater
|
| 607 |
+
than `numtaps`.
|
| 608 |
+
window : str or (str, float) or float, or None, optional
|
| 609 |
+
Desired window to use. Default is ``'hamming'``. The window will be symmetric,
|
| 610 |
+
unless a suffix ``'_periodic'`` is appended to the window name (e.g.,
|
| 611 |
+
``'hamming_perodic'``) Consult `~scipy.signal.get_window` for a list of windows
|
| 612 |
+
and required parameters. If ``None``, no window function is applied.
|
| 613 |
+
antisymmetric : bool, optional
|
| 614 |
+
Whether resulting impulse response is symmetric/antisymmetric.
|
| 615 |
+
See Notes for more details.
|
| 616 |
+
fs : float, optional
|
| 617 |
+
The sampling frequency of the signal. Each frequency in `cutoff`
|
| 618 |
+
must be between 0 and ``fs/2``. Default is 2.
|
| 619 |
+
|
| 620 |
+
Returns
|
| 621 |
+
-------
|
| 622 |
+
taps : ndarray
|
| 623 |
+
The filter coefficients of the FIR filter, as a 1-D array of length
|
| 624 |
+
`numtaps`.
|
| 625 |
+
|
| 626 |
+
See Also
|
| 627 |
+
--------
|
| 628 |
+
firls
|
| 629 |
+
firwin
|
| 630 |
+
minimum_phase
|
| 631 |
+
remez
|
| 632 |
+
|
| 633 |
+
Notes
|
| 634 |
+
-----
|
| 635 |
+
From the given set of frequencies and gains, the desired response is
|
| 636 |
+
constructed in the frequency domain. The inverse FFT is applied to the
|
| 637 |
+
desired response to create the associated convolution kernel, and the
|
| 638 |
+
first `numtaps` coefficients of this kernel, scaled by `window`, are
|
| 639 |
+
returned.
|
| 640 |
+
|
| 641 |
+
The FIR filter will have linear phase. The type of filter is determined by
|
| 642 |
+
the value of 'numtaps` and `antisymmetric` flag.
|
| 643 |
+
There are four possible combinations:
|
| 644 |
+
|
| 645 |
+
- odd `numtaps`, `antisymmetric` is False, type I filter is produced
|
| 646 |
+
- even `numtaps`, `antisymmetric` is False, type II filter is produced
|
| 647 |
+
- odd `numtaps`, `antisymmetric` is True, type III filter is produced
|
| 648 |
+
- even `numtaps`, `antisymmetric` is True, type IV filter is produced
|
| 649 |
+
|
| 650 |
+
Magnitude response of all but type I filters are subjects to following
|
| 651 |
+
constraints:
|
| 652 |
+
|
| 653 |
+
- type II -- zero at the Nyquist frequency
|
| 654 |
+
- type III -- zero at zero and Nyquist frequencies
|
| 655 |
+
- type IV -- zero at zero frequency
|
| 656 |
+
|
| 657 |
+
.. versionadded:: 0.9.0
|
| 658 |
+
|
| 659 |
+
References
|
| 660 |
+
----------
|
| 661 |
+
.. [1] Oppenheim, A. V. and Schafer, R. W., "Discrete-Time Signal
|
| 662 |
+
Processing", Prentice-Hall, Englewood Cliffs, New Jersey (1989).
|
| 663 |
+
(See, for example, Section 7.4.)
|
| 664 |
+
|
| 665 |
+
.. [2] Smith, Steven W., "The Scientist and Engineer's Guide to Digital
|
| 666 |
+
Signal Processing", Ch. 17. http://www.dspguide.com/ch17/1.htm
|
| 667 |
+
|
| 668 |
+
Examples
|
| 669 |
+
--------
|
| 670 |
+
A lowpass FIR filter with a response that is 1 on [0.0, 0.5], and
|
| 671 |
+
that decreases linearly on [0.5, 1.0] from 1 to 0:
|
| 672 |
+
|
| 673 |
+
>>> from scipy import signal
|
| 674 |
+
>>> taps = signal.firwin2(150, [0.0, 0.5, 1.0], [1.0, 1.0, 0.0])
|
| 675 |
+
>>> print(taps[72:78])
|
| 676 |
+
[-0.02286961 -0.06362756 0.57310236 0.57310236 -0.06362756 -0.02286961]
|
| 677 |
+
|
| 678 |
+
"""
|
| 679 |
+
xp = array_namespace(freq, gain)
|
| 680 |
+
freq, gain = xp.asarray(freq), xp.asarray(gain)
|
| 681 |
+
|
| 682 |
+
fs = _validate_fs(fs, allow_none=True)
|
| 683 |
+
fs = 2 if fs is None else fs
|
| 684 |
+
nyq = 0.5 * fs
|
| 685 |
+
|
| 686 |
+
if freq.shape[0] != gain.shape[0]:
|
| 687 |
+
raise ValueError('freq and gain must be of same length.')
|
| 688 |
+
|
| 689 |
+
if nfreqs is not None and numtaps >= nfreqs:
|
| 690 |
+
raise ValueError(
|
| 691 |
+
f'ntaps must be less than nfreqs, but firwin2 was called with '
|
| 692 |
+
f'ntaps={numtaps} and nfreqs={nfreqs}'
|
| 693 |
+
)
|
| 694 |
+
|
| 695 |
+
if freq[0] != 0 or freq[-1] != nyq:
|
| 696 |
+
raise ValueError('freq must start with 0 and end with fs/2.')
|
| 697 |
+
d = freq[1:] - freq[:-1]
|
| 698 |
+
if xp.any(d < 0):
|
| 699 |
+
raise ValueError('The values in freq must be nondecreasing.')
|
| 700 |
+
d2 = d[:-1] + d[1:]
|
| 701 |
+
if xp.any(d2 == 0):
|
| 702 |
+
raise ValueError('A value in freq must not occur more than twice.')
|
| 703 |
+
if freq[1] == 0:
|
| 704 |
+
raise ValueError('Value 0 must not be repeated in freq')
|
| 705 |
+
if freq[-2] == nyq:
|
| 706 |
+
raise ValueError('Value fs/2 must not be repeated in freq')
|
| 707 |
+
|
| 708 |
+
if antisymmetric:
|
| 709 |
+
if numtaps % 2 == 0:
|
| 710 |
+
ftype = 4
|
| 711 |
+
else:
|
| 712 |
+
ftype = 3
|
| 713 |
+
else:
|
| 714 |
+
if numtaps % 2 == 0:
|
| 715 |
+
ftype = 2
|
| 716 |
+
else:
|
| 717 |
+
ftype = 1
|
| 718 |
+
|
| 719 |
+
if ftype == 2 and gain[-1] != 0.0:
|
| 720 |
+
raise ValueError("A Type II filter must have zero gain at the "
|
| 721 |
+
"Nyquist frequency.")
|
| 722 |
+
elif ftype == 3 and (gain[0] != 0.0 or gain[-1] != 0.0):
|
| 723 |
+
raise ValueError("A Type III filter must have zero gain at zero "
|
| 724 |
+
"and Nyquist frequencies.")
|
| 725 |
+
elif ftype == 4 and gain[0] != 0.0:
|
| 726 |
+
raise ValueError("A Type IV filter must have zero gain at zero "
|
| 727 |
+
"frequency.")
|
| 728 |
+
|
| 729 |
+
if nfreqs is None:
|
| 730 |
+
nfreqs = 1 + 2 ** int(ceil(log(numtaps, 2)))
|
| 731 |
+
|
| 732 |
+
if xp.any(d == 0):
|
| 733 |
+
# Tweak any repeated values in freq so that interp works.
|
| 734 |
+
freq = xp.asarray(freq, copy=True)
|
| 735 |
+
eps = xp.finfo(xp_default_dtype(xp)).eps * nyq
|
| 736 |
+
for k in range(freq.shape[0] - 1):
|
| 737 |
+
if freq[k] == freq[k + 1]:
|
| 738 |
+
freq[k] = freq[k] - eps
|
| 739 |
+
freq[k + 1] = freq[k + 1] + eps
|
| 740 |
+
# Check if freq is strictly increasing after tweak
|
| 741 |
+
d = freq[1:] - freq[:-1]
|
| 742 |
+
if xp.any(d <= 0):
|
| 743 |
+
raise ValueError("freq cannot contain numbers that are too close "
|
| 744 |
+
"(within eps * (fs/2): "
|
| 745 |
+
f"{eps}) to a repeated value")
|
| 746 |
+
|
| 747 |
+
# Linearly interpolate the desired response on a uniform mesh `x`.
|
| 748 |
+
x = np.linspace(0.0, nyq, nfreqs)
|
| 749 |
+
fx = np.interp(x, np.asarray(freq), np.asarray(gain)) # XXX array-api-extra#193
|
| 750 |
+
x = xp.asarray(x)
|
| 751 |
+
fx = xp.asarray(fx)
|
| 752 |
+
|
| 753 |
+
# Adjust the phases of the coefficients so that the first `ntaps` of the
|
| 754 |
+
# inverse FFT are the desired filter coefficients.
|
| 755 |
+
shift = xp.exp(-(numtaps - 1) / 2. * 1j * xp.pi * x / nyq)
|
| 756 |
+
if ftype > 2:
|
| 757 |
+
shift *= 1j
|
| 758 |
+
|
| 759 |
+
fx2 = fx * shift
|
| 760 |
+
|
| 761 |
+
# Use irfft to compute the inverse FFT.
|
| 762 |
+
out_full = irfft(fx2)
|
| 763 |
+
|
| 764 |
+
if window is not None:
|
| 765 |
+
# Create the window to apply to the filter coefficients.
|
| 766 |
+
wind = get_window(window, numtaps, fftbins=False, xp=xp)
|
| 767 |
+
else:
|
| 768 |
+
wind = 1
|
| 769 |
+
|
| 770 |
+
# Keep only the first `numtaps` coefficients in `out`, and multiply by
|
| 771 |
+
# the window.
|
| 772 |
+
out = out_full[:numtaps] * wind
|
| 773 |
+
|
| 774 |
+
if ftype == 3:
|
| 775 |
+
out[xp_size(out) // 2] = 0.0
|
| 776 |
+
|
| 777 |
+
return out
|
| 778 |
+
|
| 779 |
+
|
| 780 |
+
def remez(numtaps, bands, desired, *, weight=None, type='bandpass',
|
| 781 |
+
maxiter=25, grid_density=16, fs=None):
|
| 782 |
+
"""
|
| 783 |
+
Calculate the minimax optimal filter using the Remez exchange algorithm.
|
| 784 |
+
|
| 785 |
+
Calculate the filter-coefficients for the finite impulse response
|
| 786 |
+
(FIR) filter whose transfer function minimizes the maximum error
|
| 787 |
+
between the desired gain and the realized gain in the specified
|
| 788 |
+
frequency bands using the Remez exchange algorithm.
|
| 789 |
+
|
| 790 |
+
Parameters
|
| 791 |
+
----------
|
| 792 |
+
numtaps : int
|
| 793 |
+
The desired number of taps in the filter. The number of taps is
|
| 794 |
+
the number of terms in the filter, or the filter order plus one.
|
| 795 |
+
bands : array_like
|
| 796 |
+
A monotonic sequence containing the band edges.
|
| 797 |
+
All elements must be non-negative and less than half the sampling
|
| 798 |
+
frequency as given by `fs`.
|
| 799 |
+
desired : array_like
|
| 800 |
+
A sequence half the size of bands containing the desired gain
|
| 801 |
+
in each of the specified bands.
|
| 802 |
+
weight : array_like, optional
|
| 803 |
+
A relative weighting to give to each band region. The length of
|
| 804 |
+
`weight` has to be half the length of `bands`.
|
| 805 |
+
type : {'bandpass', 'differentiator', 'hilbert'}, optional
|
| 806 |
+
The type of filter:
|
| 807 |
+
|
| 808 |
+
* 'bandpass' : flat response in bands. This is the default.
|
| 809 |
+
* 'differentiator' : frequency proportional response in bands.
|
| 810 |
+
* 'hilbert' : filter with odd symmetry, that is, type III
|
| 811 |
+
(for even order) or type IV (for odd order) linear phase filters.
|
| 812 |
+
|
| 813 |
+
maxiter : int, optional
|
| 814 |
+
Maximum number of iterations of the algorithm. Default is 25.
|
| 815 |
+
grid_density : int, optional
|
| 816 |
+
Grid density. The dense grid used in `remez` is of size
|
| 817 |
+
``(numtaps + 1) * grid_density``. Default is 16.
|
| 818 |
+
fs : float, optional
|
| 819 |
+
The sampling frequency of the signal. Default is 1.
|
| 820 |
+
|
| 821 |
+
Returns
|
| 822 |
+
-------
|
| 823 |
+
out : ndarray
|
| 824 |
+
A rank-1 array containing the coefficients of the optimal
|
| 825 |
+
(in a minimax sense) filter.
|
| 826 |
+
|
| 827 |
+
See Also
|
| 828 |
+
--------
|
| 829 |
+
firls
|
| 830 |
+
firwin
|
| 831 |
+
firwin2
|
| 832 |
+
minimum_phase
|
| 833 |
+
|
| 834 |
+
References
|
| 835 |
+
----------
|
| 836 |
+
.. [1] J. H. McClellan and T. W. Parks, "A unified approach to the
|
| 837 |
+
design of optimum FIR linear phase digital filters",
|
| 838 |
+
IEEE Trans. Circuit Theory, vol. CT-20, pp. 697-701, 1973.
|
| 839 |
+
.. [2] J. H. McClellan, T. W. Parks and L. R. Rabiner, "A Computer
|
| 840 |
+
Program for Designing Optimum FIR Linear Phase Digital
|
| 841 |
+
Filters", IEEE Trans. Audio Electroacoust., vol. AU-21,
|
| 842 |
+
pp. 506-525, 1973.
|
| 843 |
+
|
| 844 |
+
Examples
|
| 845 |
+
--------
|
| 846 |
+
In these examples, `remez` is used to design low-pass, high-pass,
|
| 847 |
+
band-pass and band-stop filters. The parameters that define each filter
|
| 848 |
+
are the filter order, the band boundaries, the transition widths of the
|
| 849 |
+
boundaries, the desired gains in each band, and the sampling frequency.
|
| 850 |
+
|
| 851 |
+
We'll use a sample frequency of 22050 Hz in all the examples. In each
|
| 852 |
+
example, the desired gain in each band is either 0 (for a stop band)
|
| 853 |
+
or 1 (for a pass band).
|
| 854 |
+
|
| 855 |
+
`freqz` is used to compute the frequency response of each filter, and
|
| 856 |
+
the utility function ``plot_response`` defined below is used to plot
|
| 857 |
+
the response.
|
| 858 |
+
|
| 859 |
+
>>> import numpy as np
|
| 860 |
+
>>> from scipy import signal
|
| 861 |
+
>>> import matplotlib.pyplot as plt
|
| 862 |
+
|
| 863 |
+
>>> fs = 22050 # Sample rate, Hz
|
| 864 |
+
|
| 865 |
+
>>> def plot_response(w, h, title):
|
| 866 |
+
... "Utility function to plot response functions"
|
| 867 |
+
... fig = plt.figure()
|
| 868 |
+
... ax = fig.add_subplot(111)
|
| 869 |
+
... ax.plot(w, 20*np.log10(np.abs(h)))
|
| 870 |
+
... ax.set_ylim(-40, 5)
|
| 871 |
+
... ax.grid(True)
|
| 872 |
+
... ax.set_xlabel('Frequency (Hz)')
|
| 873 |
+
... ax.set_ylabel('Gain (dB)')
|
| 874 |
+
... ax.set_title(title)
|
| 875 |
+
|
| 876 |
+
The first example is a low-pass filter, with cutoff frequency 8 kHz.
|
| 877 |
+
The filter length is 325, and the transition width from pass to stop
|
| 878 |
+
is 100 Hz.
|
| 879 |
+
|
| 880 |
+
>>> cutoff = 8000.0 # Desired cutoff frequency, Hz
|
| 881 |
+
>>> trans_width = 100 # Width of transition from pass to stop, Hz
|
| 882 |
+
>>> numtaps = 325 # Size of the FIR filter.
|
| 883 |
+
>>> taps = signal.remez(numtaps, [0, cutoff, cutoff + trans_width, 0.5*fs],
|
| 884 |
+
... [1, 0], fs=fs)
|
| 885 |
+
>>> w, h = signal.freqz(taps, [1], worN=2000, fs=fs)
|
| 886 |
+
>>> plot_response(w, h, "Low-pass Filter")
|
| 887 |
+
>>> plt.show()
|
| 888 |
+
|
| 889 |
+
This example shows a high-pass filter:
|
| 890 |
+
|
| 891 |
+
>>> cutoff = 2000.0 # Desired cutoff frequency, Hz
|
| 892 |
+
>>> trans_width = 250 # Width of transition from pass to stop, Hz
|
| 893 |
+
>>> numtaps = 125 # Size of the FIR filter.
|
| 894 |
+
>>> taps = signal.remez(numtaps, [0, cutoff - trans_width, cutoff, 0.5*fs],
|
| 895 |
+
... [0, 1], fs=fs)
|
| 896 |
+
>>> w, h = signal.freqz(taps, [1], worN=2000, fs=fs)
|
| 897 |
+
>>> plot_response(w, h, "High-pass Filter")
|
| 898 |
+
>>> plt.show()
|
| 899 |
+
|
| 900 |
+
This example shows a band-pass filter with a pass-band from 2 kHz to
|
| 901 |
+
5 kHz. The transition width is 260 Hz and the length of the filter
|
| 902 |
+
is 63, which is smaller than in the other examples:
|
| 903 |
+
|
| 904 |
+
>>> band = [2000, 5000] # Desired pass band, Hz
|
| 905 |
+
>>> trans_width = 260 # Width of transition from pass to stop, Hz
|
| 906 |
+
>>> numtaps = 63 # Size of the FIR filter.
|
| 907 |
+
>>> edges = [0, band[0] - trans_width, band[0], band[1],
|
| 908 |
+
... band[1] + trans_width, 0.5*fs]
|
| 909 |
+
>>> taps = signal.remez(numtaps, edges, [0, 1, 0], fs=fs)
|
| 910 |
+
>>> w, h = signal.freqz(taps, [1], worN=2000, fs=fs)
|
| 911 |
+
>>> plot_response(w, h, "Band-pass Filter")
|
| 912 |
+
>>> plt.show()
|
| 913 |
+
|
| 914 |
+
The low order leads to higher ripple and less steep transitions.
|
| 915 |
+
|
| 916 |
+
The next example shows a band-stop filter.
|
| 917 |
+
|
| 918 |
+
>>> band = [6000, 8000] # Desired stop band, Hz
|
| 919 |
+
>>> trans_width = 200 # Width of transition from pass to stop, Hz
|
| 920 |
+
>>> numtaps = 175 # Size of the FIR filter.
|
| 921 |
+
>>> edges = [0, band[0] - trans_width, band[0], band[1],
|
| 922 |
+
... band[1] + trans_width, 0.5*fs]
|
| 923 |
+
>>> taps = signal.remez(numtaps, edges, [1, 0, 1], fs=fs)
|
| 924 |
+
>>> w, h = signal.freqz(taps, [1], worN=2000, fs=fs)
|
| 925 |
+
>>> plot_response(w, h, "Band-stop Filter")
|
| 926 |
+
>>> plt.show()
|
| 927 |
+
|
| 928 |
+
"""
|
| 929 |
+
xp = array_namespace(bands, desired, weight)
|
| 930 |
+
bands = np.asarray(bands)
|
| 931 |
+
desired = np.asarray(desired)
|
| 932 |
+
if weight is not None:
|
| 933 |
+
weight = np.asarray(weight)
|
| 934 |
+
|
| 935 |
+
fs = _validate_fs(fs, allow_none=True)
|
| 936 |
+
fs = 1.0 if fs is None else fs
|
| 937 |
+
|
| 938 |
+
# Convert type
|
| 939 |
+
try:
|
| 940 |
+
tnum = {'bandpass': 1, 'differentiator': 2, 'hilbert': 3}[type]
|
| 941 |
+
except KeyError as e:
|
| 942 |
+
raise ValueError("Type must be 'bandpass', 'differentiator', "
|
| 943 |
+
"or 'hilbert'") from e
|
| 944 |
+
|
| 945 |
+
# Convert weight
|
| 946 |
+
if weight is None:
|
| 947 |
+
weight = [1] * len(desired)
|
| 948 |
+
|
| 949 |
+
bands = np.asarray(bands).copy()
|
| 950 |
+
result = _sigtools._remez(numtaps, bands, desired, weight, tnum, fs,
|
| 951 |
+
maxiter, grid_density)
|
| 952 |
+
return xp.asarray(result)
|
| 953 |
+
|
| 954 |
+
|
| 955 |
+
def firls(numtaps, bands, desired, *, weight=None, fs=None):
|
| 956 |
+
"""
|
| 957 |
+
FIR filter design using least-squares error minimization.
|
| 958 |
+
|
| 959 |
+
Calculate the filter coefficients for the linear-phase finite
|
| 960 |
+
impulse response (FIR) filter which has the best approximation
|
| 961 |
+
to the desired frequency response described by `bands` and
|
| 962 |
+
`desired` in the least squares sense (i.e., the integral of the
|
| 963 |
+
weighted mean-squared error within the specified bands is
|
| 964 |
+
minimized).
|
| 965 |
+
|
| 966 |
+
Parameters
|
| 967 |
+
----------
|
| 968 |
+
numtaps : int
|
| 969 |
+
The number of taps in the FIR filter. `numtaps` must be odd.
|
| 970 |
+
bands : array_like
|
| 971 |
+
A monotonic nondecreasing sequence containing the band edges in
|
| 972 |
+
Hz. All elements must be non-negative and less than or equal to
|
| 973 |
+
the Nyquist frequency given by `nyq`. The bands are specified as
|
| 974 |
+
frequency pairs, thus, if using a 1D array, its length must be
|
| 975 |
+
even, e.g., `np.array([0, 1, 2, 3, 4, 5])`. Alternatively, the
|
| 976 |
+
bands can be specified as an nx2 sized 2D array, where n is the
|
| 977 |
+
number of bands, e.g, `np.array([[0, 1], [2, 3], [4, 5]])`.
|
| 978 |
+
desired : array_like
|
| 979 |
+
A sequence the same size as `bands` containing the desired gain
|
| 980 |
+
at the start and end point of each band.
|
| 981 |
+
weight : array_like, optional
|
| 982 |
+
A relative weighting to give to each band region when solving
|
| 983 |
+
the least squares problem. `weight` has to be half the size of
|
| 984 |
+
`bands`.
|
| 985 |
+
fs : float, optional
|
| 986 |
+
The sampling frequency of the signal. Each frequency in `bands`
|
| 987 |
+
must be between 0 and ``fs/2`` (inclusive). Default is 2.
|
| 988 |
+
|
| 989 |
+
Returns
|
| 990 |
+
-------
|
| 991 |
+
coeffs : ndarray
|
| 992 |
+
Coefficients of the optimal (in a least squares sense) FIR filter.
|
| 993 |
+
|
| 994 |
+
See Also
|
| 995 |
+
--------
|
| 996 |
+
firwin
|
| 997 |
+
firwin2
|
| 998 |
+
minimum_phase
|
| 999 |
+
remez
|
| 1000 |
+
|
| 1001 |
+
Notes
|
| 1002 |
+
-----
|
| 1003 |
+
This implementation follows the algorithm given in [1]_.
|
| 1004 |
+
As noted there, least squares design has multiple advantages:
|
| 1005 |
+
|
| 1006 |
+
1. Optimal in a least-squares sense.
|
| 1007 |
+
2. Simple, non-iterative method.
|
| 1008 |
+
3. The general solution can obtained by solving a linear
|
| 1009 |
+
system of equations.
|
| 1010 |
+
4. Allows the use of a frequency dependent weighting function.
|
| 1011 |
+
|
| 1012 |
+
This function constructs a Type I linear phase FIR filter, which
|
| 1013 |
+
contains an odd number of `coeffs` satisfying for :math:`n < numtaps`:
|
| 1014 |
+
|
| 1015 |
+
.. math:: coeffs(n) = coeffs(numtaps - 1 - n)
|
| 1016 |
+
|
| 1017 |
+
The odd number of coefficients and filter symmetry avoid boundary
|
| 1018 |
+
conditions that could otherwise occur at the Nyquist and 0 frequencies
|
| 1019 |
+
(e.g., for Type II, III, or IV variants).
|
| 1020 |
+
|
| 1021 |
+
.. versionadded:: 0.18
|
| 1022 |
+
|
| 1023 |
+
References
|
| 1024 |
+
----------
|
| 1025 |
+
.. [1] Ivan Selesnick, Linear-Phase Fir Filter Design By Least Squares.
|
| 1026 |
+
OpenStax CNX. Aug 9, 2005.
|
| 1027 |
+
https://eeweb.engineering.nyu.edu/iselesni/EL713/firls/firls.pdf
|
| 1028 |
+
|
| 1029 |
+
Examples
|
| 1030 |
+
--------
|
| 1031 |
+
We want to construct a band-pass filter. Note that the behavior in the
|
| 1032 |
+
frequency ranges between our stop bands and pass bands is unspecified,
|
| 1033 |
+
and thus may overshoot depending on the parameters of our filter:
|
| 1034 |
+
|
| 1035 |
+
>>> import numpy as np
|
| 1036 |
+
>>> from scipy import signal
|
| 1037 |
+
>>> import matplotlib.pyplot as plt
|
| 1038 |
+
>>> fig, axs = plt.subplots(2)
|
| 1039 |
+
>>> fs = 10.0 # Hz
|
| 1040 |
+
>>> desired = (0, 0, 1, 1, 0, 0)
|
| 1041 |
+
>>> for bi, bands in enumerate(((0, 1, 2, 3, 4, 5), (0, 1, 2, 4, 4.5, 5))):
|
| 1042 |
+
... fir_firls = signal.firls(73, bands, desired, fs=fs)
|
| 1043 |
+
... fir_remez = signal.remez(73, bands, desired[::2], fs=fs)
|
| 1044 |
+
... fir_firwin2 = signal.firwin2(73, bands, desired, fs=fs)
|
| 1045 |
+
... hs = list()
|
| 1046 |
+
... ax = axs[bi]
|
| 1047 |
+
... for fir in (fir_firls, fir_remez, fir_firwin2):
|
| 1048 |
+
... freq, response = signal.freqz(fir)
|
| 1049 |
+
... hs.append(ax.semilogy(0.5*fs*freq/np.pi, np.abs(response))[0])
|
| 1050 |
+
... for band, gains in zip(zip(bands[::2], bands[1::2]),
|
| 1051 |
+
... zip(desired[::2], desired[1::2])):
|
| 1052 |
+
... ax.semilogy(band, np.maximum(gains, 1e-7), 'k--', linewidth=2)
|
| 1053 |
+
... if bi == 0:
|
| 1054 |
+
... ax.legend(hs, ('firls', 'remez', 'firwin2'),
|
| 1055 |
+
... loc='lower center', frameon=False)
|
| 1056 |
+
... else:
|
| 1057 |
+
... ax.set_xlabel('Frequency (Hz)')
|
| 1058 |
+
... ax.grid(True)
|
| 1059 |
+
... ax.set(title='Band-pass %d-%d Hz' % bands[2:4], ylabel='Magnitude')
|
| 1060 |
+
...
|
| 1061 |
+
>>> fig.tight_layout()
|
| 1062 |
+
>>> plt.show()
|
| 1063 |
+
|
| 1064 |
+
"""
|
| 1065 |
+
xp = array_namespace(bands, desired)
|
| 1066 |
+
bands = np.asarray(bands)
|
| 1067 |
+
desired = np.asarray(desired)
|
| 1068 |
+
|
| 1069 |
+
fs = _validate_fs(fs, allow_none=True)
|
| 1070 |
+
fs = 2 if fs is None else fs
|
| 1071 |
+
nyq = 0.5 * fs
|
| 1072 |
+
|
| 1073 |
+
numtaps = int(numtaps)
|
| 1074 |
+
if numtaps % 2 == 0 or numtaps < 1:
|
| 1075 |
+
raise ValueError("numtaps must be odd and >= 1")
|
| 1076 |
+
M = (numtaps-1) // 2
|
| 1077 |
+
|
| 1078 |
+
# normalize bands 0->1 and make it 2 columns
|
| 1079 |
+
nyq = float(nyq)
|
| 1080 |
+
if nyq <= 0:
|
| 1081 |
+
raise ValueError(f'nyq must be positive, got {nyq} <= 0.')
|
| 1082 |
+
bands = np.asarray(bands).flatten() / nyq
|
| 1083 |
+
if len(bands) % 2 != 0:
|
| 1084 |
+
raise ValueError("bands must contain frequency pairs.")
|
| 1085 |
+
if (bands < 0).any() or (bands > 1).any():
|
| 1086 |
+
raise ValueError("bands must be between 0 and 1 relative to Nyquist")
|
| 1087 |
+
bands = bands.reshape((-1, 2))
|
| 1088 |
+
|
| 1089 |
+
# check remaining params
|
| 1090 |
+
desired = np.asarray(desired).flatten()
|
| 1091 |
+
if bands.size != desired.size:
|
| 1092 |
+
raise ValueError(
|
| 1093 |
+
f"desired must have one entry per frequency, got {desired.size} "
|
| 1094 |
+
f"gains for {bands.size} frequencies."
|
| 1095 |
+
)
|
| 1096 |
+
desired = desired.reshape((-1, 2))
|
| 1097 |
+
if (np.diff(bands) <= 0).any() or (np.diff(bands[:, 0]) < 0).any():
|
| 1098 |
+
raise ValueError("bands must be monotonically nondecreasing and have "
|
| 1099 |
+
"width > 0.")
|
| 1100 |
+
if (bands[:-1, 1] > bands[1:, 0]).any():
|
| 1101 |
+
raise ValueError("bands must not overlap.")
|
| 1102 |
+
if (desired < 0).any():
|
| 1103 |
+
raise ValueError("desired must be non-negative.")
|
| 1104 |
+
if weight is None:
|
| 1105 |
+
weight = np.ones(len(desired))
|
| 1106 |
+
weight = np.asarray(weight).flatten()
|
| 1107 |
+
if len(weight) != len(desired):
|
| 1108 |
+
raise ValueError("weight must be the same size as the number of "
|
| 1109 |
+
f"band pairs ({len(bands)}).")
|
| 1110 |
+
if (weight < 0).any():
|
| 1111 |
+
raise ValueError("weight must be non-negative.")
|
| 1112 |
+
|
| 1113 |
+
# Set up the linear matrix equation to be solved, Qa = b
|
| 1114 |
+
|
| 1115 |
+
# We can express Q(k,n) = 0.5 Q1(k,n) + 0.5 Q2(k,n)
|
| 1116 |
+
# where Q1(k,n)=q(k-n) and Q2(k,n)=q(k+n), i.e. a Toeplitz plus Hankel.
|
| 1117 |
+
|
| 1118 |
+
# We omit the factor of 0.5 above, instead adding it during coefficient
|
| 1119 |
+
# calculation.
|
| 1120 |
+
|
| 1121 |
+
# We also omit the 1/π from both Q and b equations, as they cancel
|
| 1122 |
+
# during solving.
|
| 1123 |
+
|
| 1124 |
+
# We have that:
|
| 1125 |
+
# q(n) = 1/π ∫W(ω)cos(nω)dω (over 0->π)
|
| 1126 |
+
# Using our normalization ω=πf and with a constant weight W over each
|
| 1127 |
+
# interval f1->f2 we get:
|
| 1128 |
+
# q(n) = W∫cos(πnf)df (0->1) = Wf sin(πnf)/πnf
|
| 1129 |
+
# integrated over each f1->f2 pair (i.e., value at f2 - value at f1).
|
| 1130 |
+
n = np.arange(numtaps)[:, np.newaxis, np.newaxis]
|
| 1131 |
+
q = np.dot(np.diff(np.sinc(bands * n) * bands, axis=2)[:, :, 0], weight)
|
| 1132 |
+
|
| 1133 |
+
# Now we assemble our sum of Toeplitz and Hankel
|
| 1134 |
+
Q1 = toeplitz(q[:M+1])
|
| 1135 |
+
Q2 = hankel(q[:M+1], q[M:])
|
| 1136 |
+
Q = Q1 + Q2
|
| 1137 |
+
|
| 1138 |
+
# Now for b(n) we have that:
|
| 1139 |
+
# b(n) = 1/π ∫ W(ω)D(ω)cos(nω)dω (over 0->π)
|
| 1140 |
+
# Using our normalization ω=πf and with a constant weight W over each
|
| 1141 |
+
# interval and a linear term for D(ω) we get (over each f1->f2 interval):
|
| 1142 |
+
# b(n) = W ∫ (mf+c)cos(πnf)df
|
| 1143 |
+
# = f(mf+c)sin(πnf)/πnf + mf**2 cos(nπf)/(πnf)**2
|
| 1144 |
+
# integrated over each f1->f2 pair (i.e., value at f2 - value at f1).
|
| 1145 |
+
n = n[:M + 1] # only need this many coefficients here
|
| 1146 |
+
# Choose m and c such that we are at the start and end weights
|
| 1147 |
+
m = (np.diff(desired, axis=1) / np.diff(bands, axis=1))
|
| 1148 |
+
c = desired[:, [0]] - bands[:, [0]] * m
|
| 1149 |
+
b = bands * (m*bands + c) * np.sinc(bands * n)
|
| 1150 |
+
# Use L'Hospital's rule here for cos(nπf)/(πnf)**2 @ n=0
|
| 1151 |
+
b[0] -= m * bands * bands / 2.
|
| 1152 |
+
b[1:] += m * np.cos(n[1:] * np.pi * bands) / (np.pi * n[1:]) ** 2
|
| 1153 |
+
b = np.dot(np.diff(b, axis=2)[:, :, 0], weight)
|
| 1154 |
+
|
| 1155 |
+
# Now we can solve the equation
|
| 1156 |
+
try: # try the fast way
|
| 1157 |
+
with warnings.catch_warnings(record=True) as w:
|
| 1158 |
+
warnings.simplefilter('always')
|
| 1159 |
+
a = solve(Q, b, assume_a="pos", check_finite=False)
|
| 1160 |
+
for ww in w:
|
| 1161 |
+
if (ww.category == LinAlgWarning and
|
| 1162 |
+
str(ww.message).startswith('Ill-conditioned matrix')):
|
| 1163 |
+
raise LinAlgError(str(ww.message))
|
| 1164 |
+
except LinAlgError: # in case Q is rank deficient
|
| 1165 |
+
# This is faster than pinvh, even though we don't explicitly use
|
| 1166 |
+
# the symmetry here. gelsy was faster than gelsd and gelss in
|
| 1167 |
+
# some non-exhaustive tests.
|
| 1168 |
+
a = lstsq(Q, b, lapack_driver='gelsy')[0]
|
| 1169 |
+
|
| 1170 |
+
# make coefficients symmetric (linear phase)
|
| 1171 |
+
coeffs = np.hstack((a[:0:-1], 2 * a[0], a[1:]))
|
| 1172 |
+
return xp.asarray(coeffs)
|
| 1173 |
+
|
| 1174 |
+
|
| 1175 |
+
def _dhtm(mag, xp):
|
| 1176 |
+
"""Compute the modified 1-D discrete Hilbert transform
|
| 1177 |
+
|
| 1178 |
+
Parameters
|
| 1179 |
+
----------
|
| 1180 |
+
mag : ndarray
|
| 1181 |
+
The magnitude spectrum. Should be 1-D with an even length, and
|
| 1182 |
+
preferably a fast length for FFT/IFFT.
|
| 1183 |
+
"""
|
| 1184 |
+
# Adapted based on code by Niranjan Damera-Venkata,
|
| 1185 |
+
# Brian L. Evans and Shawn R. McCaslin (see refs for `minimum_phase`)
|
| 1186 |
+
sig = xp.zeros(mag.shape[0])
|
| 1187 |
+
# Leave Nyquist and DC at 0, knowing np.abs(fftfreq(N)[midpt]) == 0.5
|
| 1188 |
+
midpt = mag.shape[0] // 2
|
| 1189 |
+
sig = xpx.at(sig)[1:midpt].set(1.0)
|
| 1190 |
+
sig = xpx.at(sig)[midpt+1:].set(-1.0)
|
| 1191 |
+
# eventually if we want to support complex filters, we will need a
|
| 1192 |
+
# np.abs() on the mag inside the log, and should remove the .real
|
| 1193 |
+
recon = xp.real(ifft(mag * xp.exp(fft(sig * ifft(xp.log(mag))))))
|
| 1194 |
+
return recon
|
| 1195 |
+
|
| 1196 |
+
|
| 1197 |
+
def minimum_phase(h,
|
| 1198 |
+
method: Literal['homomorphic', 'hilbert'] = 'homomorphic',
|
| 1199 |
+
n_fft: int | None = None, *, half: bool = True):
|
| 1200 |
+
"""Convert a linear-phase FIR filter to minimum phase.
|
| 1201 |
+
|
| 1202 |
+
Parameters
|
| 1203 |
+
----------
|
| 1204 |
+
h : array
|
| 1205 |
+
Linear-phase FIR filter coefficients.
|
| 1206 |
+
method : {'hilbert', 'homomorphic'}
|
| 1207 |
+
The provided methods are:
|
| 1208 |
+
|
| 1209 |
+
- 'homomorphic' (default):
|
| 1210 |
+
This method [4]_ [5]_ works best with filters with an
|
| 1211 |
+
odd number of taps, and the resulting minimum phase filter
|
| 1212 |
+
will have a magnitude response that approximates the square
|
| 1213 |
+
root of the original filter's magnitude response using half
|
| 1214 |
+
the number of taps when ``half=True`` (default), or the
|
| 1215 |
+
original magnitude spectrum using the same number of taps
|
| 1216 |
+
when ``half=False``.
|
| 1217 |
+
- 'hilbert'
|
| 1218 |
+
This method [1]_ is designed to be used with equiripple
|
| 1219 |
+
filters (e.g., from `remez`) with unity or zero gain
|
| 1220 |
+
regions.
|
| 1221 |
+
|
| 1222 |
+
n_fft : int
|
| 1223 |
+
The number of points to use for the FFT. Should be at least a
|
| 1224 |
+
few times larger than the signal length (see Notes).
|
| 1225 |
+
half : bool
|
| 1226 |
+
If ``True``, create a filter that is half the length of the original, with a
|
| 1227 |
+
magnitude spectrum that is the square root of the original. If ``False``,
|
| 1228 |
+
create a filter that is the same length as the original, with a magnitude
|
| 1229 |
+
spectrum that is designed to match the original (only supported when
|
| 1230 |
+
``method='homomorphic'``).
|
| 1231 |
+
|
| 1232 |
+
.. versionadded:: 1.14.0
|
| 1233 |
+
|
| 1234 |
+
Returns
|
| 1235 |
+
-------
|
| 1236 |
+
h_minimum : array
|
| 1237 |
+
The minimum-phase version of the filter, with length
|
| 1238 |
+
``(len(h) + 1) // 2`` when ``half is True`` or ``len(h)`` otherwise.
|
| 1239 |
+
|
| 1240 |
+
See Also
|
| 1241 |
+
--------
|
| 1242 |
+
firwin
|
| 1243 |
+
firwin2
|
| 1244 |
+
remez
|
| 1245 |
+
|
| 1246 |
+
Notes
|
| 1247 |
+
-----
|
| 1248 |
+
Both the Hilbert [1]_ or homomorphic [4]_ [5]_ methods require selection
|
| 1249 |
+
of an FFT length to estimate the complex cepstrum of the filter.
|
| 1250 |
+
|
| 1251 |
+
In the case of the Hilbert method, the deviation from the ideal
|
| 1252 |
+
spectrum ``epsilon`` is related to the number of stopband zeros
|
| 1253 |
+
``n_stop`` and FFT length ``n_fft`` as::
|
| 1254 |
+
|
| 1255 |
+
epsilon = 2. * n_stop / n_fft
|
| 1256 |
+
|
| 1257 |
+
For example, with 100 stopband zeros and a FFT length of 2048,
|
| 1258 |
+
``epsilon = 0.0976``. If we conservatively assume that the number of
|
| 1259 |
+
stopband zeros is one less than the filter length, we can take the FFT
|
| 1260 |
+
length to be the next power of 2 that satisfies ``epsilon=0.01`` as::
|
| 1261 |
+
|
| 1262 |
+
n_fft = 2 ** int(np.ceil(np.log2(2 * (len(h) - 1) / 0.01)))
|
| 1263 |
+
|
| 1264 |
+
This gives reasonable results for both the Hilbert and homomorphic
|
| 1265 |
+
methods, and gives the value used when ``n_fft=None``.
|
| 1266 |
+
|
| 1267 |
+
Alternative implementations exist for creating minimum-phase filters,
|
| 1268 |
+
including zero inversion [2]_ and spectral factorization [3]_ [4]_.
|
| 1269 |
+
For more information, see `this DSPGuru page
|
| 1270 |
+
<http://dspguru.com/dsp/howtos/how-to-design-minimum-phase-fir-filters>`__.
|
| 1271 |
+
|
| 1272 |
+
References
|
| 1273 |
+
----------
|
| 1274 |
+
.. [1] N. Damera-Venkata and B. L. Evans, "Optimal design of real and
|
| 1275 |
+
complex minimum phase digital FIR filters," Acoustics, Speech,
|
| 1276 |
+
and Signal Processing, 1999. Proceedings., 1999 IEEE International
|
| 1277 |
+
Conference on, Phoenix, AZ, 1999, pp. 1145-1148 vol.3.
|
| 1278 |
+
:doi:`10.1109/ICASSP.1999.756179`
|
| 1279 |
+
.. [2] X. Chen and T. W. Parks, "Design of optimal minimum phase FIR
|
| 1280 |
+
filters by direct factorization," Signal Processing,
|
| 1281 |
+
vol. 10, no. 4, pp. 369-383, Jun. 1986.
|
| 1282 |
+
.. [3] T. Saramaki, "Finite Impulse Response Filter Design," in
|
| 1283 |
+
Handbook for Digital Signal Processing, chapter 4,
|
| 1284 |
+
New York: Wiley-Interscience, 1993.
|
| 1285 |
+
.. [4] J. S. Lim, Advanced Topics in Signal Processing.
|
| 1286 |
+
Englewood Cliffs, N.J.: Prentice Hall, 1988.
|
| 1287 |
+
.. [5] A. V. Oppenheim, R. W. Schafer, and J. R. Buck,
|
| 1288 |
+
"Discrete-Time Signal Processing," 3rd edition.
|
| 1289 |
+
Upper Saddle River, N.J.: Pearson, 2009.
|
| 1290 |
+
|
| 1291 |
+
Examples
|
| 1292 |
+
--------
|
| 1293 |
+
Create an optimal linear-phase low-pass filter `h` with a transition band of
|
| 1294 |
+
[0.2, 0.3] (assuming a Nyquist frequency of 1):
|
| 1295 |
+
|
| 1296 |
+
>>> import numpy as np
|
| 1297 |
+
>>> from scipy.signal import remez, minimum_phase, freqz, group_delay
|
| 1298 |
+
>>> import matplotlib.pyplot as plt
|
| 1299 |
+
>>> freq = [0, 0.2, 0.3, 1.0]
|
| 1300 |
+
>>> desired = [1, 0]
|
| 1301 |
+
>>> h_linear = remez(151, freq, desired, fs=2)
|
| 1302 |
+
|
| 1303 |
+
Convert it to minimum phase:
|
| 1304 |
+
|
| 1305 |
+
>>> h_hil = minimum_phase(h_linear, method='hilbert')
|
| 1306 |
+
>>> h_hom = minimum_phase(h_linear, method='homomorphic')
|
| 1307 |
+
>>> h_hom_full = minimum_phase(h_linear, method='homomorphic', half=False)
|
| 1308 |
+
|
| 1309 |
+
Compare the impulse and frequency response of the four filters:
|
| 1310 |
+
|
| 1311 |
+
>>> fig0, ax0 = plt.subplots(figsize=(6, 3), tight_layout=True)
|
| 1312 |
+
>>> fig1, axs = plt.subplots(3, sharex='all', figsize=(6, 6), tight_layout=True)
|
| 1313 |
+
>>> ax0.set_title("Impulse response")
|
| 1314 |
+
>>> ax0.set(xlabel='Samples', ylabel='Amplitude', xlim=(0, len(h_linear) - 1))
|
| 1315 |
+
>>> axs[0].set_title("Frequency Response")
|
| 1316 |
+
>>> axs[0].set(xlim=(0, .65), ylabel="Magnitude / dB")
|
| 1317 |
+
>>> axs[1].set(ylabel="Phase / rad")
|
| 1318 |
+
>>> axs[2].set(ylabel="Group Delay / samples", ylim=(-31, 81),
|
| 1319 |
+
... xlabel='Normalized Frequency (Nyqist frequency: 1)')
|
| 1320 |
+
>>> for h, lb in ((h_linear, f'Linear ({len(h_linear)})'),
|
| 1321 |
+
... (h_hil, f'Min-Hilbert ({len(h_hil)})'),
|
| 1322 |
+
... (h_hom, f'Min-Homomorphic ({len(h_hom)})'),
|
| 1323 |
+
... (h_hom_full, f'Min-Homom. Full ({len(h_hom_full)})')):
|
| 1324 |
+
... w_H, H = freqz(h, fs=2)
|
| 1325 |
+
... w_gd, gd = group_delay((h, 1), fs=2)
|
| 1326 |
+
...
|
| 1327 |
+
... alpha = 1.0 if lb == 'linear' else 0.5 # full opacity for 'linear' line
|
| 1328 |
+
... ax0.plot(h, '.-', alpha=alpha, label=lb)
|
| 1329 |
+
... axs[0].plot(w_H, 20 * np.log10(np.abs(H)), alpha=alpha)
|
| 1330 |
+
... axs[1].plot(w_H, np.unwrap(np.angle(H)), alpha=alpha, label=lb)
|
| 1331 |
+
... axs[2].plot(w_gd, gd, alpha=alpha)
|
| 1332 |
+
>>> ax0.grid(True)
|
| 1333 |
+
>>> ax0.legend(title='Filter Phase (Order)')
|
| 1334 |
+
>>> axs[1].legend(title='Filter Phase (Order)', loc='lower right')
|
| 1335 |
+
>>> for ax_ in axs: # shade transition band:
|
| 1336 |
+
... ax_.axvspan(freq[1], freq[2], color='y', alpha=.25)
|
| 1337 |
+
... ax_.grid(True)
|
| 1338 |
+
>>> plt.show()
|
| 1339 |
+
|
| 1340 |
+
The impulse response and group delay plot depict the 75 sample delay of the linear
|
| 1341 |
+
phase filter `h`. The phase should also be linear in the stop band--due to the small
|
| 1342 |
+
magnitude, numeric noise dominates there. Furthermore, the plots show that the
|
| 1343 |
+
minimum phase filters clearly show a reduced (negative) phase slope in the pass and
|
| 1344 |
+
transition band. The plots also illustrate that the filter with parameters
|
| 1345 |
+
``method='homomorphic', half=False`` has same order and magnitude response as the
|
| 1346 |
+
linear filter `h` whereas the other minimum phase filters have only half the order
|
| 1347 |
+
and the square root of the magnitude response.
|
| 1348 |
+
"""
|
| 1349 |
+
xp = array_namespace(h)
|
| 1350 |
+
|
| 1351 |
+
h = xp.asarray(h)
|
| 1352 |
+
if xp.isdtype(h.dtype, "complex floating"):
|
| 1353 |
+
raise ValueError('Complex filters not supported')
|
| 1354 |
+
if h.ndim != 1 or h.shape[0] <= 2:
|
| 1355 |
+
raise ValueError('h must be 1-D and at least 2 samples long')
|
| 1356 |
+
n_half = h.shape[0] // 2
|
| 1357 |
+
|
| 1358 |
+
if not xp.any(xp.flip(h[-n_half:]) - h[:n_half] <= 1e-8 + 1e-6*abs(h[:n_half])):
|
| 1359 |
+
warnings.warn('h does not appear to by symmetric, conversion may fail',
|
| 1360 |
+
RuntimeWarning, stacklevel=2)
|
| 1361 |
+
if not isinstance(method, str) or method not in \
|
| 1362 |
+
('homomorphic', 'hilbert',):
|
| 1363 |
+
raise ValueError(f'method must be "homomorphic" or "hilbert", got {method!r}')
|
| 1364 |
+
if method == "hilbert" and not half:
|
| 1365 |
+
raise ValueError("`half=False` is only supported when `method='homomorphic'`")
|
| 1366 |
+
if n_fft is None:
|
| 1367 |
+
n_fft = 2 ** int(ceil(log2(2 * (h.shape[0] - 1) / 0.01)))
|
| 1368 |
+
n_fft = int(n_fft)
|
| 1369 |
+
if n_fft < h.shape[0]:
|
| 1370 |
+
raise ValueError(f'n_fft must be at least len(h)=={len(h)}')
|
| 1371 |
+
|
| 1372 |
+
if method == 'hilbert':
|
| 1373 |
+
w = xp.arange(n_fft, dtype=xp.float64) * (2 * xp.pi / n_fft * n_half)
|
| 1374 |
+
H = xp.real(fft(h, n_fft) * xp.exp(1j * w))
|
| 1375 |
+
dp = max(H) - 1
|
| 1376 |
+
ds = 0 - min(H)
|
| 1377 |
+
S = 4. / (xp.sqrt(1+dp+ds) + xp.sqrt(1-dp+ds)) ** 2
|
| 1378 |
+
H += ds
|
| 1379 |
+
H *= S
|
| 1380 |
+
H = xp.sqrt(H)
|
| 1381 |
+
H += 1e-10 # ensure that the log does not explode
|
| 1382 |
+
h_minimum = _dhtm(H, xp)
|
| 1383 |
+
else: # method == 'homomorphic'
|
| 1384 |
+
# zero-pad; calculate the DFT
|
| 1385 |
+
h_temp = xp.abs(fft(h, n_fft))
|
| 1386 |
+
# take 0.25*log(|H|**2) = 0.5*log(|H|)
|
| 1387 |
+
h_temp += 1e-7 * xp.min(h_temp[h_temp > 0]) # don't let log blow up
|
| 1388 |
+
h_temp = xp.log(h_temp)
|
| 1389 |
+
if half: # halving of magnitude spectrum optional
|
| 1390 |
+
h_temp *= 0.5
|
| 1391 |
+
# IDFT
|
| 1392 |
+
h_temp = xp.real(ifft(h_temp))
|
| 1393 |
+
# multiply pointwise by the homomorphic filter
|
| 1394 |
+
# lmin[n] = 2u[n] - d[n]
|
| 1395 |
+
# i.e., double the positive frequencies and zero out the negative ones;
|
| 1396 |
+
# Oppenheim+Shafer 3rd ed p991 eq13.42b and p1004 fig13.7
|
| 1397 |
+
win = xp.zeros(n_fft, dtype=h_temp.dtype)
|
| 1398 |
+
win = xpx.at(win)[0].set(1)
|
| 1399 |
+
stop = n_fft // 2
|
| 1400 |
+
win = xpx.at(win)[1:stop].set(2)
|
| 1401 |
+
# Nyquist freq: odd use 2, even use 1
|
| 1402 |
+
win = xpx.at(win)[stop].set(1 + (n_fft % 2))
|
| 1403 |
+
h_temp *= win
|
| 1404 |
+
h_temp = ifft(xp.exp(fft(h_temp)))
|
| 1405 |
+
h_minimum = xp.real(h_temp)
|
| 1406 |
+
n_out = (n_half + h.shape[0] % 2) if half else h.shape[0]
|
| 1407 |
+
return h_minimum[:n_out]
|
| 1408 |
+
|
| 1409 |
+
|
| 1410 |
+
def firwin_2d(hsize, window, *, fc=None, fs=2, circular=False,
|
| 1411 |
+
pass_zero=True, scale=True):
|
| 1412 |
+
"""
|
| 1413 |
+
2D FIR filter design using the window method.
|
| 1414 |
+
|
| 1415 |
+
This function computes the coefficients of a 2D finite impulse response
|
| 1416 |
+
filter. The filter is separable with linear phase; it will be designed
|
| 1417 |
+
as a product of two 1D filters with dimensions defined by `hsize`.
|
| 1418 |
+
Additionally, it can create approximately circularly symmetric 2-D windows.
|
| 1419 |
+
|
| 1420 |
+
Parameters
|
| 1421 |
+
----------
|
| 1422 |
+
hsize : tuple or list of length 2
|
| 1423 |
+
Lengths of the filter in each dimension. `hsize[0]` specifies the
|
| 1424 |
+
number of coefficients in the row direction and `hsize[1]` specifies
|
| 1425 |
+
the number of coefficients in the column direction.
|
| 1426 |
+
window : tuple or list of length 2 or str
|
| 1427 |
+
Desired window to use for each 1D filter or a single window type for creating
|
| 1428 |
+
circularly symmetric 2-D windows. Each element should be a string or tuple of
|
| 1429 |
+
string and parameter values. The generated windows will be symmetric, unless a
|
| 1430 |
+
suffix ``'_periodic'`` is appended to the window name (e.g.,
|
| 1431 |
+
``'hamming_perodic'``). Consult `~scipy.signal.get_window` for a list of windows
|
| 1432 |
+
and required parameters.
|
| 1433 |
+
fc : float or 1-D array_like, optional
|
| 1434 |
+
Cutoff frequency of the filter in the same units as `fs`. This defines
|
| 1435 |
+
the frequency at which the filter's gain drops to approximately -6 dB
|
| 1436 |
+
(half power) in a low-pass or high-pass filter. For multi-band filters,
|
| 1437 |
+
`fc` can be an array of cutoff frequencies (i.e., band edges) in the
|
| 1438 |
+
range [0, fs/2], with each band specified in pairs. Required if
|
| 1439 |
+
`circular` is False.
|
| 1440 |
+
fs : float, optional
|
| 1441 |
+
The sampling frequency of the signal. Default is 2.
|
| 1442 |
+
circular : bool, optional
|
| 1443 |
+
Whether to create a circularly symmetric 2-D window. Default is ``False``.
|
| 1444 |
+
pass_zero : {True, False, 'bandpass', 'lowpass', 'highpass', 'bandstop'}, optional
|
| 1445 |
+
This parameter is directly passed to `firwin` for each scalar frequency axis.
|
| 1446 |
+
Hence, if ``True``, the DC gain, i.e., the gain at frequency (0, 0), is 1.
|
| 1447 |
+
If ``False``, the DC gain is 0 at frequency (0, 0) if `circular` is ``True``.
|
| 1448 |
+
If `circular` is ``False`` the frequencies (0, f1) and (f0, 0) will
|
| 1449 |
+
have gain 0.
|
| 1450 |
+
It can also be a string argument for the desired filter type
|
| 1451 |
+
(equivalent to ``btype`` in IIR design functions).
|
| 1452 |
+
scale : bool, optional
|
| 1453 |
+
This parameter is directly passed to `firwin` for each scalar frequency axis.
|
| 1454 |
+
Set to ``True`` to scale the coefficients so that the frequency
|
| 1455 |
+
response is exactly unity at a certain frequency on one frequency axis.
|
| 1456 |
+
That frequency is either:
|
| 1457 |
+
|
| 1458 |
+
- 0 (DC) if the first passband starts at 0 (i.e. pass_zero is ``True``)
|
| 1459 |
+
- `fs`/2 (the Nyquist frequency) if the first passband ends at `fs`/2
|
| 1460 |
+
(i.e., the filter is a single band highpass filter);
|
| 1461 |
+
center of first passband otherwise
|
| 1462 |
+
|
| 1463 |
+
Returns
|
| 1464 |
+
-------
|
| 1465 |
+
filter_2d : (hsize[0], hsize[1]) ndarray
|
| 1466 |
+
Coefficients of 2D FIR filter.
|
| 1467 |
+
|
| 1468 |
+
Raises
|
| 1469 |
+
------
|
| 1470 |
+
ValueError
|
| 1471 |
+
- If `hsize` and `window` are not 2-element tuples or lists.
|
| 1472 |
+
- If `cutoff` is None when `circular` is True.
|
| 1473 |
+
- If `cutoff` is outside the range [0, `fs`/2] and `circular` is ``False``.
|
| 1474 |
+
- If any of the elements in `window` are not recognized.
|
| 1475 |
+
RuntimeError
|
| 1476 |
+
If `firwin` fails to converge when designing the filter.
|
| 1477 |
+
|
| 1478 |
+
See Also
|
| 1479 |
+
--------
|
| 1480 |
+
firwin: FIR filter design using the window method for 1d arrays.
|
| 1481 |
+
get_window: Return a window of a given length and type.
|
| 1482 |
+
|
| 1483 |
+
Examples
|
| 1484 |
+
--------
|
| 1485 |
+
Generate a 5x5 low-pass filter with cutoff frequency 0.1:
|
| 1486 |
+
|
| 1487 |
+
>>> import numpy as np
|
| 1488 |
+
>>> from scipy.signal import get_window
|
| 1489 |
+
>>> from scipy.signal import firwin_2d
|
| 1490 |
+
>>> hsize = (5, 5)
|
| 1491 |
+
>>> window = (("kaiser", 5.0), ("kaiser", 5.0))
|
| 1492 |
+
>>> fc = 0.1
|
| 1493 |
+
>>> filter_2d = firwin_2d(hsize, window, fc=fc)
|
| 1494 |
+
>>> filter_2d
|
| 1495 |
+
array([[0.00025366, 0.00401662, 0.00738617, 0.00401662, 0.00025366],
|
| 1496 |
+
[0.00401662, 0.06360159, 0.11695714, 0.06360159, 0.00401662],
|
| 1497 |
+
[0.00738617, 0.11695714, 0.21507283, 0.11695714, 0.00738617],
|
| 1498 |
+
[0.00401662, 0.06360159, 0.11695714, 0.06360159, 0.00401662],
|
| 1499 |
+
[0.00025366, 0.00401662, 0.00738617, 0.00401662, 0.00025366]])
|
| 1500 |
+
|
| 1501 |
+
Generate a circularly symmetric 5x5 low-pass filter with Hamming window:
|
| 1502 |
+
|
| 1503 |
+
>>> filter_2d = firwin_2d((5, 5), 'hamming', fc=fc, circular=True)
|
| 1504 |
+
>>> filter_2d
|
| 1505 |
+
array([[-0.00020354, -0.00020354, -0.00020354, -0.00020354, -0.00020354],
|
| 1506 |
+
[-0.00020354, 0.01506844, 0.09907658, 0.01506844, -0.00020354],
|
| 1507 |
+
[-0.00020354, 0.09907658, -0.00020354, 0.09907658, -0.00020354],
|
| 1508 |
+
[-0.00020354, 0.01506844, 0.09907658, 0.01506844, -0.00020354],
|
| 1509 |
+
[-0.00020354, -0.00020354, -0.00020354, -0.00020354, -0.00020354]])
|
| 1510 |
+
|
| 1511 |
+
Generate Plots comparing the product of two 1d filters with a circular
|
| 1512 |
+
symmetric filter:
|
| 1513 |
+
|
| 1514 |
+
>>> import matplotlib.pyplot as plt
|
| 1515 |
+
>>> hsize, fc = (50, 50), 0.05
|
| 1516 |
+
>>> window = (("kaiser", 5.0), ("kaiser", 5.0))
|
| 1517 |
+
>>> filter0_2d = firwin_2d(hsize, window, fc=fc)
|
| 1518 |
+
>>> filter1_2d = firwin_2d((50, 50), 'hamming', fc=fc, circular=True)
|
| 1519 |
+
...
|
| 1520 |
+
>>> fg, (ax0, ax1) = plt.subplots(1, 2, tight_layout=True, figsize=(6.5, 3.5))
|
| 1521 |
+
>>> ax0.set_title("Product of 2 Windows")
|
| 1522 |
+
>>> im0 = ax0.imshow(filter0_2d, cmap='viridis', origin='lower', aspect='equal')
|
| 1523 |
+
>>> fg.colorbar(im0, ax=ax0, shrink=0.7)
|
| 1524 |
+
>>> ax1.set_title("Circular Window")
|
| 1525 |
+
>>> im1 = ax1.imshow(filter1_2d, cmap='plasma', origin='lower', aspect='equal')
|
| 1526 |
+
>>> fg.colorbar(im1, ax=ax1, shrink=0.7)
|
| 1527 |
+
>>> plt.show()
|
| 1528 |
+
"""
|
| 1529 |
+
if len(hsize) != 2:
|
| 1530 |
+
raise ValueError("hsize must be a 2-element tuple or list")
|
| 1531 |
+
|
| 1532 |
+
if circular:
|
| 1533 |
+
if fc is None:
|
| 1534 |
+
raise ValueError("Cutoff frequency `fc` must be "
|
| 1535 |
+
"provided when `circular` is True")
|
| 1536 |
+
|
| 1537 |
+
n_r = max(hsize[0], hsize[1]) * 8 # oversample 1d window by factor 8
|
| 1538 |
+
|
| 1539 |
+
win_r = firwin(n_r, cutoff=fc, window=window, fs=fs)
|
| 1540 |
+
|
| 1541 |
+
f1, f2 = np.meshgrid(np.linspace(-1, 1, hsize[0]), np.linspace(-1, 1, hsize[1]))
|
| 1542 |
+
r = np.sqrt(f1**2 + f2**2)
|
| 1543 |
+
|
| 1544 |
+
win_2d = np.interp(r, np.linspace(0, 1, n_r), win_r)
|
| 1545 |
+
return win_2d
|
| 1546 |
+
|
| 1547 |
+
if len(window) != 2:
|
| 1548 |
+
raise ValueError("window must be a 2-element tuple or list")
|
| 1549 |
+
|
| 1550 |
+
row_filter = firwin(hsize[0], cutoff=fc, window=window[0], fs=fs)
|
| 1551 |
+
col_filter = firwin(hsize[1], cutoff=fc, window=window[1], fs=fs)
|
| 1552 |
+
|
| 1553 |
+
return np.outer(row_filter, col_filter)
|
venv/lib/python3.12/site-packages/scipy/signal/_lti_conversion.py
ADDED
|
@@ -0,0 +1,583 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
"""
|
| 2 |
+
ltisys -- a collection of functions to convert linear time invariant systems
|
| 3 |
+
from one representation to another.
|
| 4 |
+
"""
|
| 5 |
+
|
| 6 |
+
import numpy as np
|
| 7 |
+
from numpy import (r_, eye, atleast_2d, poly, dot,
|
| 8 |
+
asarray, zeros, array, outer)
|
| 9 |
+
from scipy import linalg
|
| 10 |
+
|
| 11 |
+
from scipy._lib._array_api import (array_namespace, xp_size, xp_promote,
|
| 12 |
+
xp_result_type)
|
| 13 |
+
import scipy._external.array_api_extra as xpx
|
| 14 |
+
from ._filter_design import tf2zpk, zpk2tf, normalize
|
| 15 |
+
|
| 16 |
+
|
| 17 |
+
__all__ = ['tf2ss', 'abcd_normalize', 'ss2tf', 'zpk2ss', 'ss2zpk',
|
| 18 |
+
'cont2discrete']
|
| 19 |
+
|
| 20 |
+
|
| 21 |
+
def tf2ss(num, den):
|
| 22 |
+
r"""Transfer function to state-space representation.
|
| 23 |
+
|
| 24 |
+
Parameters
|
| 25 |
+
----------
|
| 26 |
+
num, den : array_like
|
| 27 |
+
Sequences representing the coefficients of the numerator and
|
| 28 |
+
denominator polynomials, in order of descending degree. The
|
| 29 |
+
denominator needs to be at least as long as the numerator.
|
| 30 |
+
|
| 31 |
+
Returns
|
| 32 |
+
-------
|
| 33 |
+
A, B, C, D : ndarray
|
| 34 |
+
State space representation of the system, in controller canonical
|
| 35 |
+
form.
|
| 36 |
+
|
| 37 |
+
Examples
|
| 38 |
+
--------
|
| 39 |
+
Convert the transfer function:
|
| 40 |
+
|
| 41 |
+
.. math:: H(s) = \frac{s^2 + 3s + 3}{s^2 + 2s + 1}
|
| 42 |
+
|
| 43 |
+
>>> num = [1, 3, 3]
|
| 44 |
+
>>> den = [1, 2, 1]
|
| 45 |
+
|
| 46 |
+
to the state-space representation:
|
| 47 |
+
|
| 48 |
+
.. math::
|
| 49 |
+
|
| 50 |
+
\dot{\textbf{x}}(t) =
|
| 51 |
+
\begin{bmatrix} -2 & -1 \\ 1 & 0 \end{bmatrix} \textbf{x}(t) +
|
| 52 |
+
\begin{bmatrix} 1 \\ 0 \end{bmatrix} \textbf{u}(t) \\
|
| 53 |
+
|
| 54 |
+
\textbf{y}(t) = \begin{bmatrix} 1 & 2 \end{bmatrix} \textbf{x}(t) +
|
| 55 |
+
\begin{bmatrix} 1 \end{bmatrix} \textbf{u}(t)
|
| 56 |
+
|
| 57 |
+
>>> from scipy.signal import tf2ss
|
| 58 |
+
>>> A, B, C, D = tf2ss(num, den)
|
| 59 |
+
>>> A
|
| 60 |
+
array([[-2., -1.],
|
| 61 |
+
[ 1., 0.]])
|
| 62 |
+
>>> B
|
| 63 |
+
array([[ 1.],
|
| 64 |
+
[ 0.]])
|
| 65 |
+
>>> C
|
| 66 |
+
array([[ 1., 2.]])
|
| 67 |
+
>>> D
|
| 68 |
+
array([[ 1.]])
|
| 69 |
+
"""
|
| 70 |
+
# Controller canonical state-space representation.
|
| 71 |
+
# if M+1 = len(num) and K+1 = len(den) then we must have M <= K
|
| 72 |
+
# states are found by asserting that X(s) = U(s) / D(s)
|
| 73 |
+
# then Y(s) = N(s) * X(s)
|
| 74 |
+
#
|
| 75 |
+
# A, B, C, and D follow quite naturally.
|
| 76 |
+
#
|
| 77 |
+
num, den = normalize(num, den) # Strips zeros, checks arrays
|
| 78 |
+
nn = len(num.shape)
|
| 79 |
+
if nn == 1:
|
| 80 |
+
num = asarray([num], num.dtype)
|
| 81 |
+
M = num.shape[1]
|
| 82 |
+
K = len(den)
|
| 83 |
+
if M > K:
|
| 84 |
+
msg = "Improper transfer function. `num` is longer than `den`."
|
| 85 |
+
raise ValueError(msg)
|
| 86 |
+
if M == 0 or K == 0: # Null system
|
| 87 |
+
return (array([], float), array([], float), array([], float),
|
| 88 |
+
array([], float))
|
| 89 |
+
|
| 90 |
+
# pad numerator to have same number of columns has denominator
|
| 91 |
+
num = np.hstack((np.zeros((num.shape[0], K - M), dtype=num.dtype), num))
|
| 92 |
+
|
| 93 |
+
if num.shape[-1] > 0:
|
| 94 |
+
D = atleast_2d(num[:, 0])
|
| 95 |
+
|
| 96 |
+
else:
|
| 97 |
+
# We don't assign it an empty array because this system
|
| 98 |
+
# is not 'null'. It just doesn't have a non-zero D
|
| 99 |
+
# matrix. Thus, it should have a non-zero shape so that
|
| 100 |
+
# it can be operated on by functions like 'ss2tf'
|
| 101 |
+
D = array([[0]], float)
|
| 102 |
+
|
| 103 |
+
if K == 1:
|
| 104 |
+
D = D.reshape(num.shape)
|
| 105 |
+
|
| 106 |
+
return (zeros((1, 1)), zeros((1, D.shape[1])),
|
| 107 |
+
zeros((D.shape[0], 1)), D)
|
| 108 |
+
|
| 109 |
+
frow = -array([den[1:]])
|
| 110 |
+
A = r_[frow, eye(K - 2, K - 1)]
|
| 111 |
+
B = eye(K - 1, 1)
|
| 112 |
+
C = num[:, 1:] - outer(num[:, 0], den[1:])
|
| 113 |
+
D = D.reshape((C.shape[0], B.shape[1]))
|
| 114 |
+
|
| 115 |
+
return A, B, C, D
|
| 116 |
+
|
| 117 |
+
|
| 118 |
+
def abcd_normalize(A=None, B=None, C=None, D=None):
|
| 119 |
+
r"""Check state-space matrices compatibility and ensure they are 2d arrays.
|
| 120 |
+
|
| 121 |
+
First, the input matrices are converted into two-dimensional arrays with
|
| 122 |
+
appropriate dtype as needed. Then the dimensions n, q, p are determined by
|
| 123 |
+
investigating the array shapes. If an input is ``None``, or has size zero, it is
|
| 124 |
+
set to an array of zeros of compatible shape. Finally, it is verified that all
|
| 125 |
+
parameter shapes are compatible with each other. If that fails, a ``ValueError`` is
|
| 126 |
+
raised. Note that the dimensions n, q, p are allowed to be zero.
|
| 127 |
+
|
| 128 |
+
Parameters
|
| 129 |
+
----------
|
| 130 |
+
A : array_like, optional
|
| 131 |
+
Two-dimensional array of shape (n, n).
|
| 132 |
+
B : array_like, optional
|
| 133 |
+
Two-dimensional array of shape (n, p).
|
| 134 |
+
C : array_like, optional
|
| 135 |
+
Two-dimensional array of shape (q, n).
|
| 136 |
+
D : array_like, optional
|
| 137 |
+
Two-dimensional array of shape (q, p).
|
| 138 |
+
|
| 139 |
+
Returns
|
| 140 |
+
-------
|
| 141 |
+
A, B, C, D : array
|
| 142 |
+
State-space matrices as two-dimensional arrays with identical dtype.
|
| 143 |
+
The result dtype is determined based on the standard
|
| 144 |
+
`dtype promotion rules <https://numpy.org/doc/2.3/reference/arrays.promotion.html>`_
|
| 145 |
+
except for when the inputs are all of integer dtype, in which case the returned
|
| 146 |
+
arrays will have the default floating point dtype of ``float64``.
|
| 147 |
+
|
| 148 |
+
Raises
|
| 149 |
+
------
|
| 150 |
+
ValueError
|
| 151 |
+
If the dimensions n, q, or p could not be determined or if the shapes are
|
| 152 |
+
incompatible with each other.
|
| 153 |
+
|
| 154 |
+
Notes
|
| 155 |
+
-----
|
| 156 |
+
If a matrix is not modified, the original matrix (not a copy) is returned.
|
| 157 |
+
|
| 158 |
+
The :ref:`tutorial_signal_state_space_representation` section of the
|
| 159 |
+
:ref:`user_guide` presents the corresponding definitions of continuous-time and
|
| 160 |
+
disrcete time state space systems.
|
| 161 |
+
|
| 162 |
+
See Also
|
| 163 |
+
--------
|
| 164 |
+
StateSpace: Linear Time Invariant system in state-space form.
|
| 165 |
+
dlti: Discrete-time linear time invariant system base class.
|
| 166 |
+
tf2ss: Transfer function to state-space representation.
|
| 167 |
+
ss2tf: State-space to transfer function.
|
| 168 |
+
ss2zpk: State-space representation to zero-pole-gain representation.
|
| 169 |
+
cont2discrete: Transform a continuous to a discrete state-space system.
|
| 170 |
+
|
| 171 |
+
Examples
|
| 172 |
+
--------
|
| 173 |
+
The following example demonstrates that the passed lists are converted into
|
| 174 |
+
two-dimensional arrays:
|
| 175 |
+
|
| 176 |
+
>>> from scipy.signal import abcd_normalize
|
| 177 |
+
>>> AA, BB, CC, DD = abcd_normalize(A=[[1, 2], [3, 4]], B=[[-1], [5]],
|
| 178 |
+
... C=[[4, 5]], D=2.5)
|
| 179 |
+
>>> AA.shape, BB.shape, CC.shape, DD.shape
|
| 180 |
+
((2, 2), (2, 1), (1, 2), (1, 1))
|
| 181 |
+
|
| 182 |
+
In the following, the missing parameter C is assumed to be an array of zeros
|
| 183 |
+
with shape (1, 2):
|
| 184 |
+
|
| 185 |
+
>>> from scipy.signal import abcd_normalize
|
| 186 |
+
>>> AA, BB, CC, DD = abcd_normalize(A=[[1, 2], [3, 4]], B=[[-1], [5]], D=2.5)
|
| 187 |
+
>>> AA.shape, BB.shape, CC.shape, DD.shape
|
| 188 |
+
((2, 2), (2, 1), (1, 2), (1, 1))
|
| 189 |
+
>>> CC
|
| 190 |
+
array([[0., 0.]])
|
| 191 |
+
|
| 192 |
+
"""
|
| 193 |
+
if A is None and B is None and C is None:
|
| 194 |
+
raise ValueError("Dimension n is undefined for parameters A = B = C = None!")
|
| 195 |
+
if B is None and D is None:
|
| 196 |
+
raise ValueError("Dimension p is undefined for parameters B = D = None!")
|
| 197 |
+
if C is None and D is None:
|
| 198 |
+
raise ValueError("Dimension q is undefined for parameters C = D = None!")
|
| 199 |
+
|
| 200 |
+
xp = array_namespace(A, B, C, D)
|
| 201 |
+
A, B, C, D = xp_promote(A, B, C, D, xp=xp, force_floating=True)
|
| 202 |
+
dtype = xp_result_type(A, B, C, D, xp=xp)
|
| 203 |
+
|
| 204 |
+
# convert inputs into 2d arrays (zero-size 2d array if None):
|
| 205 |
+
A, B, C, D = (
|
| 206 |
+
xpx.atleast_nd(xp.asarray(M_), ndim=2, xp=xp)
|
| 207 |
+
if M_ is not None else xp.zeros((0, 0), dtype=dtype)
|
| 208 |
+
for M_ in (A, B, C, D)
|
| 209 |
+
)
|
| 210 |
+
|
| 211 |
+
n = A.shape[0] or B.shape[0] or C.shape[1] # try finding non-zero dimensions
|
| 212 |
+
p = B.shape[1] or D.shape[1]
|
| 213 |
+
q = C.shape[0] or D.shape[0]
|
| 214 |
+
|
| 215 |
+
# Create zero matrices as needed:
|
| 216 |
+
A = xp.zeros((n, n), dtype=dtype) if xp_size(A) == 0 else A
|
| 217 |
+
B = xp.zeros((n, p), dtype=dtype) if xp_size(B) == 0 else B
|
| 218 |
+
C = xp.zeros((q, n), dtype=dtype) if xp_size(C) == 0 else C
|
| 219 |
+
D = xp.zeros((q, p), dtype=dtype) if xp_size(D) == 0 else D
|
| 220 |
+
|
| 221 |
+
if A.shape != (n, n):
|
| 222 |
+
raise ValueError(f"Parameter A has shape {A.shape} but should be ({n}, {n})!")
|
| 223 |
+
if B.shape != (n, p):
|
| 224 |
+
raise ValueError(f"Parameter B has shape {B.shape} but should be ({n}, {p})!")
|
| 225 |
+
if C.shape != (q, n):
|
| 226 |
+
raise ValueError(f"Parameter C has shape {C.shape} but should be ({q}, {n})!")
|
| 227 |
+
if D.shape != (q, p):
|
| 228 |
+
raise ValueError(f"Parameter D has shape {D.shape} but should be ({q}, {p})!")
|
| 229 |
+
|
| 230 |
+
return A, B, C, D
|
| 231 |
+
|
| 232 |
+
|
| 233 |
+
def ss2tf(A, B, C, D, input=0):
|
| 234 |
+
r"""State-space to transfer function.
|
| 235 |
+
|
| 236 |
+
A, B, C, D defines a linear state-space system with `p` inputs,
|
| 237 |
+
`q` outputs, and `n` state variables.
|
| 238 |
+
|
| 239 |
+
Parameters
|
| 240 |
+
----------
|
| 241 |
+
A : array_like
|
| 242 |
+
State (or system) matrix of shape ``(n, n)``
|
| 243 |
+
B : array_like
|
| 244 |
+
Input matrix of shape ``(n, p)``
|
| 245 |
+
C : array_like
|
| 246 |
+
Output matrix of shape ``(q, n)``
|
| 247 |
+
D : array_like
|
| 248 |
+
Feedthrough (or feedforward) matrix of shape ``(q, p)``
|
| 249 |
+
input : int, optional
|
| 250 |
+
For multiple-input systems, the index of the input to use.
|
| 251 |
+
|
| 252 |
+
Returns
|
| 253 |
+
-------
|
| 254 |
+
num : 2-D ndarray
|
| 255 |
+
Numerator(s) of the resulting transfer function(s). `num` has one row
|
| 256 |
+
for each of the system's outputs. Each row is a sequence representation
|
| 257 |
+
of the numerator polynomial.
|
| 258 |
+
den : 1-D ndarray
|
| 259 |
+
Denominator of the resulting transfer function(s). `den` is a sequence
|
| 260 |
+
representation of the denominator polynomial.
|
| 261 |
+
|
| 262 |
+
Notes
|
| 263 |
+
-----
|
| 264 |
+
Before calculating `num` and `den`, the function `abcd_normalize` is called to
|
| 265 |
+
convert the parameters `A`, `B`, `C`, `D` into two-dimesional arrays of the
|
| 266 |
+
same dtype. The resulting dtype will be based on NumPy's dtype promotion rules,
|
| 267 |
+
except in the case where each of `A`, `B`, `C`, and `D` has integer dtype, in which
|
| 268 |
+
case the resulting dtype will be the default floating point dtype of ``float64``.
|
| 269 |
+
|
| 270 |
+
The :ref:`tutorial_signal_state_space_representation` section of the
|
| 271 |
+
:ref:`user_guide` presents the corresponding definitions of continuous-time and
|
| 272 |
+
disrcete time state space systems.
|
| 273 |
+
|
| 274 |
+
Examples
|
| 275 |
+
--------
|
| 276 |
+
Convert the state-space representation:
|
| 277 |
+
|
| 278 |
+
.. math::
|
| 279 |
+
|
| 280 |
+
\dot{\textbf{x}}(t) =
|
| 281 |
+
\begin{bmatrix} -2 & -1 \\ 1 & 0 \end{bmatrix} \textbf{x}(t) +
|
| 282 |
+
\begin{bmatrix} 1 \\ 0 \end{bmatrix} \textbf{u}(t) \\
|
| 283 |
+
|
| 284 |
+
\textbf{y}(t) = \begin{bmatrix} 1 & 2 \end{bmatrix} \textbf{x}(t) +
|
| 285 |
+
\begin{bmatrix} 1 \end{bmatrix} \textbf{u}(t)
|
| 286 |
+
|
| 287 |
+
>>> A = [[-2, -1], [1, 0]]
|
| 288 |
+
>>> B = [[1], [0]] # 2-D column vector
|
| 289 |
+
>>> C = [[1, 2]] # 2-D row vector
|
| 290 |
+
>>> D = 1
|
| 291 |
+
|
| 292 |
+
to the transfer function:
|
| 293 |
+
|
| 294 |
+
.. math:: H(s) = \frac{s^2 + 3s + 3}{s^2 + 2s + 1}
|
| 295 |
+
|
| 296 |
+
>>> from scipy.signal import ss2tf
|
| 297 |
+
>>> ss2tf(A, B, C, D)
|
| 298 |
+
(array([[1., 3., 3.]]), array([ 1., 2., 1.]))
|
| 299 |
+
"""
|
| 300 |
+
# transfer function is C (sI - A)**(-1) B + D
|
| 301 |
+
|
| 302 |
+
# Check consistency and make them all floating point 2d arrays:
|
| 303 |
+
A, B, C, D = abcd_normalize(A, B, C, D)
|
| 304 |
+
|
| 305 |
+
nout, nin = D.shape
|
| 306 |
+
if input >= nin:
|
| 307 |
+
raise ValueError("System does not have the input specified.")
|
| 308 |
+
|
| 309 |
+
# make SIMO from possibly MIMO system.
|
| 310 |
+
B = B[:, input:input + 1]
|
| 311 |
+
D = D[:, input:input + 1]
|
| 312 |
+
|
| 313 |
+
try:
|
| 314 |
+
den = poly(A)
|
| 315 |
+
except ValueError:
|
| 316 |
+
den = 1
|
| 317 |
+
|
| 318 |
+
if (B.size == 0) and (C.size == 0):
|
| 319 |
+
num = np.ravel(D)
|
| 320 |
+
if (D.size == 0) and (A.size == 0):
|
| 321 |
+
den = []
|
| 322 |
+
return num, den
|
| 323 |
+
|
| 324 |
+
num_states = A.shape[0]
|
| 325 |
+
type_test = A[:, 0] + B[:, 0] + C[0, :] + D + 0.0
|
| 326 |
+
num = np.empty((nout, num_states + 1), type_test.dtype)
|
| 327 |
+
for k in range(nout):
|
| 328 |
+
Ck = atleast_2d(C[k, :])
|
| 329 |
+
num[k] = poly(A - dot(B, Ck)) + (D[k] - 1) * den
|
| 330 |
+
|
| 331 |
+
return num, den
|
| 332 |
+
|
| 333 |
+
|
| 334 |
+
def zpk2ss(z, p, k):
|
| 335 |
+
"""Zero-pole-gain representation to state-space representation.
|
| 336 |
+
|
| 337 |
+
Parameters
|
| 338 |
+
----------
|
| 339 |
+
z, p : sequence
|
| 340 |
+
Zeros and poles.
|
| 341 |
+
k : float
|
| 342 |
+
System gain.
|
| 343 |
+
|
| 344 |
+
Returns
|
| 345 |
+
-------
|
| 346 |
+
A, B, C, D : ndarray
|
| 347 |
+
State space representation of the system, in controller canonical
|
| 348 |
+
form.
|
| 349 |
+
|
| 350 |
+
"""
|
| 351 |
+
return tf2ss(*zpk2tf(z, p, k))
|
| 352 |
+
|
| 353 |
+
|
| 354 |
+
def ss2zpk(A, B, C, D, input=0):
|
| 355 |
+
"""State-space representation to zero-pole-gain representation.
|
| 356 |
+
|
| 357 |
+
A, B, C, D defines a linear state-space system with `p` inputs,
|
| 358 |
+
`q` outputs, and `n` state variables.
|
| 359 |
+
|
| 360 |
+
Parameters
|
| 361 |
+
----------
|
| 362 |
+
A : array_like
|
| 363 |
+
State (or system) matrix of shape ``(n, n)``
|
| 364 |
+
B : array_like
|
| 365 |
+
Input matrix of shape ``(n, p)``
|
| 366 |
+
C : array_like
|
| 367 |
+
Output matrix of shape ``(q, n)``
|
| 368 |
+
D : array_like
|
| 369 |
+
Feedthrough (or feedforward) matrix of shape ``(q, p)``
|
| 370 |
+
input : int, optional
|
| 371 |
+
For multiple-input systems, the index of the input to use.
|
| 372 |
+
|
| 373 |
+
Returns
|
| 374 |
+
-------
|
| 375 |
+
z, p : sequence
|
| 376 |
+
Zeros and poles.
|
| 377 |
+
k : float
|
| 378 |
+
System gain.
|
| 379 |
+
|
| 380 |
+
"""
|
| 381 |
+
return tf2zpk(*ss2tf(A, B, C, D, input=input))
|
| 382 |
+
|
| 383 |
+
|
| 384 |
+
def cont2discrete(system, dt, method="zoh", alpha=None):
|
| 385 |
+
"""
|
| 386 |
+
Transform a continuous to a discrete state-space system.
|
| 387 |
+
|
| 388 |
+
Parameters
|
| 389 |
+
----------
|
| 390 |
+
system : a tuple describing the system or an instance of `lti`
|
| 391 |
+
The following gives the number of elements in the tuple and
|
| 392 |
+
the interpretation:
|
| 393 |
+
|
| 394 |
+
* 1: (instance of `lti`)
|
| 395 |
+
* 2: (num, den)
|
| 396 |
+
* 3: (zeros, poles, gain)
|
| 397 |
+
* 4: (A, B, C, D)
|
| 398 |
+
|
| 399 |
+
dt : float
|
| 400 |
+
The discretization time step.
|
| 401 |
+
method : str, optional
|
| 402 |
+
Which method to use:
|
| 403 |
+
|
| 404 |
+
* gbt: generalized bilinear transformation
|
| 405 |
+
* bilinear: Tustin's approximation ("gbt" with alpha=0.5)
|
| 406 |
+
* euler: Euler (or forward differencing) method ("gbt" with alpha=0)
|
| 407 |
+
* backward_diff: Backwards differencing ("gbt" with alpha=1.0)
|
| 408 |
+
* zoh: zero-order hold (default)
|
| 409 |
+
* foh: first-order hold (*versionadded: 1.3.0*)
|
| 410 |
+
* impulse: equivalent impulse response (*versionadded: 1.3.0*)
|
| 411 |
+
|
| 412 |
+
alpha : float within [0, 1], optional
|
| 413 |
+
The generalized bilinear transformation weighting parameter, which
|
| 414 |
+
should only be specified with method="gbt", and is ignored otherwise
|
| 415 |
+
|
| 416 |
+
Returns
|
| 417 |
+
-------
|
| 418 |
+
sysd : tuple containing the discrete system
|
| 419 |
+
Based on the input type, the output will be of the form
|
| 420 |
+
|
| 421 |
+
* (num, den, dt) for transfer function input
|
| 422 |
+
* (zeros, poles, gain, dt) for zeros-poles-gain input
|
| 423 |
+
* (A, B, C, D, dt) for state-space system input
|
| 424 |
+
|
| 425 |
+
Notes
|
| 426 |
+
-----
|
| 427 |
+
By default, the routine uses a Zero-Order Hold (zoh) method to perform
|
| 428 |
+
the transformation. Alternatively, a generalized bilinear transformation
|
| 429 |
+
may be used, which includes the common Tustin's bilinear approximation,
|
| 430 |
+
an Euler's method technique, or a backwards differencing technique.
|
| 431 |
+
|
| 432 |
+
The Zero-Order Hold (zoh) method is based on [1]_, the generalized bilinear
|
| 433 |
+
approximation is based on [2]_ and [3]_, the First-Order Hold (foh) method
|
| 434 |
+
is based on [4]_.
|
| 435 |
+
|
| 436 |
+
References
|
| 437 |
+
----------
|
| 438 |
+
.. [1] https://en.wikipedia.org/wiki/Discretization#Discretization_of_linear_state_space_models
|
| 439 |
+
|
| 440 |
+
.. [2] http://techteach.no/publications/discretetime_signals_systems/discrete.pdf
|
| 441 |
+
|
| 442 |
+
.. [3] G. Zhang, X. Chen, and T. Chen, Digital redesign via the generalized
|
| 443 |
+
bilinear transformation, Int. J. Control, vol. 82, no. 4, pp. 741-754,
|
| 444 |
+
2009.
|
| 445 |
+
(https://www.mypolyuweb.hk/~magzhang/Research/ZCC09_IJC.pdf)
|
| 446 |
+
|
| 447 |
+
.. [4] G. F. Franklin, J. D. Powell, and M. L. Workman, Digital control
|
| 448 |
+
of dynamic systems, 3rd ed. Menlo Park, Calif: Addison-Wesley,
|
| 449 |
+
pp. 204-206, 1998.
|
| 450 |
+
|
| 451 |
+
Examples
|
| 452 |
+
--------
|
| 453 |
+
We can transform a continuous state-space system to a discrete one:
|
| 454 |
+
|
| 455 |
+
>>> import numpy as np
|
| 456 |
+
>>> import matplotlib.pyplot as plt
|
| 457 |
+
>>> from scipy.signal import cont2discrete, lti, dlti, dstep
|
| 458 |
+
|
| 459 |
+
Define a continuous state-space system.
|
| 460 |
+
|
| 461 |
+
>>> A = np.array([[0, 1],[-10., -3]])
|
| 462 |
+
>>> B = np.array([[0],[10.]])
|
| 463 |
+
>>> C = np.array([[1., 0]])
|
| 464 |
+
>>> D = np.array([[0.]])
|
| 465 |
+
>>> l_system = lti(A, B, C, D)
|
| 466 |
+
>>> t, x = l_system.step(T=np.linspace(0, 5, 100))
|
| 467 |
+
>>> fig, ax = plt.subplots()
|
| 468 |
+
>>> ax.plot(t, x, label='Continuous', linewidth=3)
|
| 469 |
+
|
| 470 |
+
Transform it to a discrete state-space system using several methods.
|
| 471 |
+
|
| 472 |
+
>>> dt = 0.1
|
| 473 |
+
>>> for method in ['zoh', 'bilinear', 'euler', 'backward_diff', 'foh', 'impulse']:
|
| 474 |
+
... d_system = cont2discrete((A, B, C, D), dt, method=method)
|
| 475 |
+
... s, x_d = dstep(d_system)
|
| 476 |
+
... ax.step(s, np.squeeze(x_d), label=method, where='post')
|
| 477 |
+
>>> ax.axis([t[0], t[-1], x[0], 1.4])
|
| 478 |
+
>>> ax.legend(loc='best')
|
| 479 |
+
>>> fig.tight_layout()
|
| 480 |
+
>>> plt.show()
|
| 481 |
+
|
| 482 |
+
"""
|
| 483 |
+
if hasattr(system, 'to_discrete') and callable(system.to_discrete):
|
| 484 |
+
return system.to_discrete(dt=dt, method=method, alpha=alpha)
|
| 485 |
+
|
| 486 |
+
if len(system) == 2:
|
| 487 |
+
sysd = cont2discrete(tf2ss(system[0], system[1]), dt, method=method,
|
| 488 |
+
alpha=alpha)
|
| 489 |
+
return ss2tf(sysd[0], sysd[1], sysd[2], sysd[3]) + (dt,)
|
| 490 |
+
elif len(system) == 3:
|
| 491 |
+
sysd = cont2discrete(zpk2ss(system[0], system[1], system[2]), dt,
|
| 492 |
+
method=method, alpha=alpha)
|
| 493 |
+
return ss2zpk(sysd[0], sysd[1], sysd[2], sysd[3]) + (dt,)
|
| 494 |
+
elif len(system) == 4:
|
| 495 |
+
a, b, c, d = system
|
| 496 |
+
else:
|
| 497 |
+
raise ValueError("First argument must either be a tuple of 2 (tf), "
|
| 498 |
+
"3 (zpk), or 4 (ss) arrays.")
|
| 499 |
+
|
| 500 |
+
if method == 'gbt':
|
| 501 |
+
if alpha is None:
|
| 502 |
+
raise ValueError("Alpha parameter must be specified for the "
|
| 503 |
+
"generalized bilinear transform (gbt) method")
|
| 504 |
+
elif alpha < 0 or alpha > 1:
|
| 505 |
+
raise ValueError("Alpha parameter must be within the interval "
|
| 506 |
+
"[0,1] for the gbt method")
|
| 507 |
+
|
| 508 |
+
if method == 'gbt':
|
| 509 |
+
# This parameter is used repeatedly - compute once here
|
| 510 |
+
ima = np.eye(a.shape[0]) - alpha*dt*a
|
| 511 |
+
ad = linalg.solve(ima, np.eye(a.shape[0]) + (1.0-alpha)*dt*a)
|
| 512 |
+
bd = linalg.solve(ima, dt*b)
|
| 513 |
+
|
| 514 |
+
# Similarly solve for the output equation matrices
|
| 515 |
+
cd = linalg.solve(ima.transpose(), c.transpose())
|
| 516 |
+
cd = cd.transpose()
|
| 517 |
+
dd = d + alpha*np.dot(c, bd)
|
| 518 |
+
|
| 519 |
+
elif method == 'bilinear' or method == 'tustin':
|
| 520 |
+
return cont2discrete(system, dt, method="gbt", alpha=0.5)
|
| 521 |
+
|
| 522 |
+
elif method == 'euler' or method == 'forward_diff':
|
| 523 |
+
return cont2discrete(system, dt, method="gbt", alpha=0.0)
|
| 524 |
+
|
| 525 |
+
elif method == 'backward_diff':
|
| 526 |
+
return cont2discrete(system, dt, method="gbt", alpha=1.0)
|
| 527 |
+
|
| 528 |
+
elif method == 'zoh':
|
| 529 |
+
# Build an exponential matrix
|
| 530 |
+
em_upper = np.hstack((a, b))
|
| 531 |
+
|
| 532 |
+
# Need to stack zeros under the a and b matrices
|
| 533 |
+
em_lower = np.hstack((np.zeros((b.shape[1], a.shape[0])),
|
| 534 |
+
np.zeros((b.shape[1], b.shape[1]))))
|
| 535 |
+
|
| 536 |
+
em = np.vstack((em_upper, em_lower))
|
| 537 |
+
ms = linalg.expm(dt * em)
|
| 538 |
+
|
| 539 |
+
# Dispose of the lower rows
|
| 540 |
+
ms = ms[:a.shape[0], :]
|
| 541 |
+
|
| 542 |
+
ad = ms[:, 0:a.shape[1]]
|
| 543 |
+
bd = ms[:, a.shape[1]:]
|
| 544 |
+
|
| 545 |
+
cd = c
|
| 546 |
+
dd = d
|
| 547 |
+
|
| 548 |
+
elif method == 'foh':
|
| 549 |
+
# Size parameters for convenience
|
| 550 |
+
n = a.shape[0]
|
| 551 |
+
m = b.shape[1]
|
| 552 |
+
|
| 553 |
+
# Build an exponential matrix similar to 'zoh' method
|
| 554 |
+
em_upper = linalg.block_diag(np.block([a, b]) * dt, np.eye(m))
|
| 555 |
+
em_lower = zeros((m, n + 2 * m))
|
| 556 |
+
em = np.block([[em_upper], [em_lower]])
|
| 557 |
+
|
| 558 |
+
ms = linalg.expm(em)
|
| 559 |
+
|
| 560 |
+
# Get the three blocks from upper rows
|
| 561 |
+
ms11 = ms[:n, 0:n]
|
| 562 |
+
ms12 = ms[:n, n:n + m]
|
| 563 |
+
ms13 = ms[:n, n + m:]
|
| 564 |
+
|
| 565 |
+
ad = ms11
|
| 566 |
+
bd = ms12 - ms13 + ms11 @ ms13
|
| 567 |
+
cd = c
|
| 568 |
+
dd = d + c @ ms13
|
| 569 |
+
|
| 570 |
+
elif method == 'impulse':
|
| 571 |
+
if not np.allclose(d, 0):
|
| 572 |
+
raise ValueError("Impulse method is only applicable "
|
| 573 |
+
"to strictly proper systems")
|
| 574 |
+
|
| 575 |
+
ad = linalg.expm(a * dt)
|
| 576 |
+
bd = ad @ b * dt
|
| 577 |
+
cd = c
|
| 578 |
+
dd = c @ b * dt
|
| 579 |
+
|
| 580 |
+
else:
|
| 581 |
+
raise ValueError(f"Unknown transformation method '{method}'")
|
| 582 |
+
|
| 583 |
+
return ad, bd, cd, dd, dt
|
venv/lib/python3.12/site-packages/scipy/signal/_ltisys.py
ADDED
|
The diff for this file is too large to render.
See raw diff
|
|
|
venv/lib/python3.12/site-packages/scipy/signal/_max_len_seq.py
ADDED
|
@@ -0,0 +1,139 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
# Author: Eric Larson
|
| 2 |
+
# 2014
|
| 3 |
+
|
| 4 |
+
"""Tools for MLS generation"""
|
| 5 |
+
|
| 6 |
+
import numpy as np
|
| 7 |
+
|
| 8 |
+
from ._max_len_seq_inner import _max_len_seq_inner
|
| 9 |
+
|
| 10 |
+
__all__ = ['max_len_seq']
|
| 11 |
+
|
| 12 |
+
|
| 13 |
+
# These are definitions of linear shift register taps for use in max_len_seq()
|
| 14 |
+
_mls_taps = {2: [1], 3: [2], 4: [3], 5: [3], 6: [5], 7: [6], 8: [7, 6, 1],
|
| 15 |
+
9: [5], 10: [7], 11: [9], 12: [11, 10, 4], 13: [12, 11, 8],
|
| 16 |
+
14: [13, 12, 2], 15: [14], 16: [15, 13, 4], 17: [14],
|
| 17 |
+
18: [11], 19: [18, 17, 14], 20: [17], 21: [19], 22: [21],
|
| 18 |
+
23: [18], 24: [23, 22, 17], 25: [22], 26: [25, 24, 20],
|
| 19 |
+
27: [26, 25, 22], 28: [25], 29: [27], 30: [29, 28, 7],
|
| 20 |
+
31: [28], 32: [31, 30, 10]}
|
| 21 |
+
|
| 22 |
+
def max_len_seq(nbits, state=None, length=None, taps=None):
|
| 23 |
+
"""
|
| 24 |
+
Maximum length sequence (MLS) generator.
|
| 25 |
+
|
| 26 |
+
Parameters
|
| 27 |
+
----------
|
| 28 |
+
nbits : int
|
| 29 |
+
Number of bits to use. Length of the resulting sequence will
|
| 30 |
+
be ``(2**nbits) - 1``. Note that generating long sequences
|
| 31 |
+
(e.g., greater than ``nbits == 16``) can take a long time.
|
| 32 |
+
state : array_like, optional
|
| 33 |
+
If array, must be of length ``nbits``, and will be cast to binary
|
| 34 |
+
(bool) representation. If None, a seed of ones will be used,
|
| 35 |
+
producing a repeatable representation. If ``state`` is all
|
| 36 |
+
zeros, an error is raised as this is invalid. Default: None.
|
| 37 |
+
length : int, optional
|
| 38 |
+
Number of samples to compute. If None, the entire length
|
| 39 |
+
``(2**nbits) - 1`` is computed.
|
| 40 |
+
taps : array_like, optional
|
| 41 |
+
Polynomial taps to use (e.g., ``[7, 6, 1]`` for an 8-bit sequence).
|
| 42 |
+
If None, taps will be automatically selected (for up to
|
| 43 |
+
``nbits == 32``).
|
| 44 |
+
|
| 45 |
+
Returns
|
| 46 |
+
-------
|
| 47 |
+
seq : array
|
| 48 |
+
Resulting MLS sequence of 0's and 1's.
|
| 49 |
+
state : array
|
| 50 |
+
The final state of the shift register.
|
| 51 |
+
|
| 52 |
+
Notes
|
| 53 |
+
-----
|
| 54 |
+
The algorithm for MLS generation is generically described in:
|
| 55 |
+
|
| 56 |
+
https://en.wikipedia.org/wiki/Maximum_length_sequence
|
| 57 |
+
|
| 58 |
+
The default values for taps are specifically taken from the first
|
| 59 |
+
option listed for each value of ``nbits`` in:
|
| 60 |
+
|
| 61 |
+
https://web.archive.org/web/20181001062252/http://www.newwaveinstruments.com/resources/articles/m_sequence_linear_feedback_shift_register_lfsr.htm
|
| 62 |
+
|
| 63 |
+
.. versionadded:: 0.15.0
|
| 64 |
+
|
| 65 |
+
Examples
|
| 66 |
+
--------
|
| 67 |
+
MLS uses binary convention:
|
| 68 |
+
|
| 69 |
+
>>> from scipy.signal import max_len_seq
|
| 70 |
+
>>> max_len_seq(4)[0]
|
| 71 |
+
array([1, 1, 1, 1, 0, 1, 0, 1, 1, 0, 0, 1, 0, 0, 0], dtype=int8)
|
| 72 |
+
|
| 73 |
+
MLS has a white spectrum (except for DC):
|
| 74 |
+
|
| 75 |
+
>>> import numpy as np
|
| 76 |
+
>>> import matplotlib.pyplot as plt
|
| 77 |
+
>>> from numpy.fft import fft, ifft, fftshift, fftfreq
|
| 78 |
+
>>> seq = max_len_seq(6)[0]*2-1 # +1 and -1
|
| 79 |
+
>>> spec = fft(seq)
|
| 80 |
+
>>> N = len(seq)
|
| 81 |
+
>>> plt.plot(fftshift(fftfreq(N)), fftshift(np.abs(spec)), '.-')
|
| 82 |
+
>>> plt.margins(0.1, 0.1)
|
| 83 |
+
>>> plt.grid(True)
|
| 84 |
+
>>> plt.show()
|
| 85 |
+
|
| 86 |
+
Circular autocorrelation of MLS is an impulse:
|
| 87 |
+
|
| 88 |
+
>>> acorrcirc = ifft(spec * np.conj(spec)).real
|
| 89 |
+
>>> plt.figure()
|
| 90 |
+
>>> plt.plot(np.arange(-N/2+1, N/2+1), fftshift(acorrcirc), '.-')
|
| 91 |
+
>>> plt.margins(0.1, 0.1)
|
| 92 |
+
>>> plt.grid(True)
|
| 93 |
+
>>> plt.show()
|
| 94 |
+
|
| 95 |
+
Linear autocorrelation of MLS is approximately an impulse:
|
| 96 |
+
|
| 97 |
+
>>> acorr = np.correlate(seq, seq, 'full')
|
| 98 |
+
>>> plt.figure()
|
| 99 |
+
>>> plt.plot(np.arange(-N+1, N), acorr, '.-')
|
| 100 |
+
>>> plt.margins(0.1, 0.1)
|
| 101 |
+
>>> plt.grid(True)
|
| 102 |
+
>>> plt.show()
|
| 103 |
+
|
| 104 |
+
"""
|
| 105 |
+
taps_dtype = np.int32 if np.intp().itemsize == 4 else np.int64
|
| 106 |
+
if taps is None:
|
| 107 |
+
if nbits not in _mls_taps:
|
| 108 |
+
known_taps = np.array(list(_mls_taps.keys()))
|
| 109 |
+
raise ValueError(f'nbits must be between {known_taps.min()} and '
|
| 110 |
+
f'{known_taps.max()} if taps is None')
|
| 111 |
+
taps = np.array(_mls_taps[nbits], taps_dtype)
|
| 112 |
+
else:
|
| 113 |
+
taps = np.unique(np.array(taps, taps_dtype))[::-1]
|
| 114 |
+
if np.any(taps < 0) or np.any(taps > nbits) or taps.size < 1:
|
| 115 |
+
raise ValueError('taps must be non-empty with values between '
|
| 116 |
+
'zero and nbits (inclusive)')
|
| 117 |
+
taps = np.array(taps) # needed for Cython and Pythran
|
| 118 |
+
n_max = (2**nbits) - 1
|
| 119 |
+
if length is None:
|
| 120 |
+
length = n_max
|
| 121 |
+
else:
|
| 122 |
+
length = int(length)
|
| 123 |
+
if length < 0:
|
| 124 |
+
raise ValueError('length must be greater than or equal to 0')
|
| 125 |
+
# We use int8 instead of bool here because NumPy arrays of bools
|
| 126 |
+
# don't seem to work nicely with Cython
|
| 127 |
+
if state is None:
|
| 128 |
+
state = np.ones(nbits, dtype=np.int8, order='c')
|
| 129 |
+
else:
|
| 130 |
+
# makes a copy if need be, ensuring it's 0's and 1's
|
| 131 |
+
state = np.array(state, dtype=bool, order='c').astype(np.int8)
|
| 132 |
+
if state.ndim != 1 or state.size != nbits:
|
| 133 |
+
raise ValueError('state must be a 1-D array of size nbits')
|
| 134 |
+
if np.all(state == 0):
|
| 135 |
+
raise ValueError('state must not be all zeros')
|
| 136 |
+
|
| 137 |
+
seq = np.empty(length, dtype=np.int8, order='c')
|
| 138 |
+
state = _max_len_seq_inner(taps, state, nbits, length, seq)
|
| 139 |
+
return seq, state
|
venv/lib/python3.12/site-packages/scipy/signal/_max_len_seq_inner.cpython-312-x86_64-linux-gnu.so
ADDED
|
Binary file (57.3 kB). View file
|
|
|
venv/lib/python3.12/site-packages/scipy/signal/_peak_finding.py
ADDED
|
@@ -0,0 +1,1307 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
"""
|
| 2 |
+
Functions for identifying peaks in signals.
|
| 3 |
+
"""
|
| 4 |
+
import math
|
| 5 |
+
import numpy as np
|
| 6 |
+
|
| 7 |
+
from scipy.signal._wavelets import _cwt, _ricker
|
| 8 |
+
from scipy.stats import scoreatpercentile
|
| 9 |
+
|
| 10 |
+
from ._peak_finding_utils import (
|
| 11 |
+
_local_maxima_1d,
|
| 12 |
+
_select_by_peak_distance,
|
| 13 |
+
_peak_prominences,
|
| 14 |
+
_peak_widths
|
| 15 |
+
)
|
| 16 |
+
|
| 17 |
+
|
| 18 |
+
__all__ = ['argrelmin', 'argrelmax', 'argrelextrema', 'peak_prominences',
|
| 19 |
+
'peak_widths', 'find_peaks', 'find_peaks_cwt']
|
| 20 |
+
|
| 21 |
+
|
| 22 |
+
def _boolrelextrema(data, comparator, axis=0, order=1, mode='clip'):
|
| 23 |
+
"""
|
| 24 |
+
Calculate the relative extrema of `data`.
|
| 25 |
+
|
| 26 |
+
Relative extrema are calculated by finding locations where
|
| 27 |
+
``comparator(data[n], data[n+1:n+order+1])`` is True.
|
| 28 |
+
|
| 29 |
+
Parameters
|
| 30 |
+
----------
|
| 31 |
+
data : ndarray
|
| 32 |
+
Array in which to find the relative extrema.
|
| 33 |
+
comparator : callable
|
| 34 |
+
Function to use to compare two data points.
|
| 35 |
+
Should take two arrays as arguments.
|
| 36 |
+
axis : int, optional
|
| 37 |
+
Axis over which to select from `data`. Default is 0.
|
| 38 |
+
order : int, optional
|
| 39 |
+
How many points on each side to use for the comparison
|
| 40 |
+
to consider ``comparator(n,n+x)`` to be True.
|
| 41 |
+
mode : str, optional
|
| 42 |
+
How the edges of the vector are treated. 'wrap' (wrap around) or
|
| 43 |
+
'clip' (treat overflow as the same as the last (or first) element).
|
| 44 |
+
Default 'clip'. See numpy.take.
|
| 45 |
+
|
| 46 |
+
Returns
|
| 47 |
+
-------
|
| 48 |
+
extrema : ndarray
|
| 49 |
+
Boolean array of the same shape as `data` that is True at an extrema,
|
| 50 |
+
False otherwise.
|
| 51 |
+
|
| 52 |
+
See Also
|
| 53 |
+
--------
|
| 54 |
+
argrelmax, argrelmin
|
| 55 |
+
|
| 56 |
+
Examples
|
| 57 |
+
--------
|
| 58 |
+
>>> import numpy as np
|
| 59 |
+
>>> from scipy.signal._peak_finding import _boolrelextrema
|
| 60 |
+
>>> testdata = np.array([1,2,3,2,1])
|
| 61 |
+
>>> _boolrelextrema(testdata, np.greater, axis=0)
|
| 62 |
+
array([False, False, True, False, False], dtype=bool)
|
| 63 |
+
|
| 64 |
+
"""
|
| 65 |
+
if (int(order) != order) or (order < 1):
|
| 66 |
+
raise ValueError('Order must be an int >= 1')
|
| 67 |
+
|
| 68 |
+
datalen = data.shape[axis]
|
| 69 |
+
locs = np.arange(0, datalen)
|
| 70 |
+
|
| 71 |
+
results = np.ones(data.shape, dtype=bool)
|
| 72 |
+
main = data.take(locs, axis=axis, mode=mode)
|
| 73 |
+
for shift in range(1, order + 1):
|
| 74 |
+
plus = data.take(locs + shift, axis=axis, mode=mode)
|
| 75 |
+
minus = data.take(locs - shift, axis=axis, mode=mode)
|
| 76 |
+
results &= comparator(main, plus)
|
| 77 |
+
results &= comparator(main, minus)
|
| 78 |
+
if ~results.any():
|
| 79 |
+
return results
|
| 80 |
+
return results
|
| 81 |
+
|
| 82 |
+
|
| 83 |
+
def argrelmin(data, axis=0, order=1, mode='clip'):
|
| 84 |
+
"""
|
| 85 |
+
Calculate the relative minima of `data`.
|
| 86 |
+
|
| 87 |
+
Parameters
|
| 88 |
+
----------
|
| 89 |
+
data : ndarray
|
| 90 |
+
Array in which to find the relative minima.
|
| 91 |
+
axis : int, optional
|
| 92 |
+
Axis over which to select from `data`. Default is 0.
|
| 93 |
+
order : int, optional
|
| 94 |
+
How many points on each side to use for the comparison
|
| 95 |
+
to consider ``comparator(n, n+x)`` to be True.
|
| 96 |
+
mode : str, optional
|
| 97 |
+
How the edges of the vector are treated.
|
| 98 |
+
Available options are 'wrap' (wrap around) or 'clip' (treat overflow
|
| 99 |
+
as the same as the last (or first) element).
|
| 100 |
+
Default 'clip'. See numpy.take.
|
| 101 |
+
|
| 102 |
+
Returns
|
| 103 |
+
-------
|
| 104 |
+
extrema : tuple of ndarrays
|
| 105 |
+
Indices of the minima in arrays of integers. ``extrema[k]`` is
|
| 106 |
+
the array of indices of axis `k` of `data`. Note that the
|
| 107 |
+
return value is a tuple even when `data` is 1-D.
|
| 108 |
+
|
| 109 |
+
See Also
|
| 110 |
+
--------
|
| 111 |
+
argrelextrema, argrelmax, find_peaks
|
| 112 |
+
|
| 113 |
+
Notes
|
| 114 |
+
-----
|
| 115 |
+
This function uses `argrelextrema` with np.less as comparator. Therefore, it
|
| 116 |
+
requires a strict inequality on both sides of a value to consider it a
|
| 117 |
+
minimum. This means flat minima (more than one sample wide) are not detected.
|
| 118 |
+
In case of 1-D `data` `find_peaks` can be used to detect all
|
| 119 |
+
local minima, including flat ones, by calling it with negated `data`.
|
| 120 |
+
|
| 121 |
+
.. versionadded:: 0.11.0
|
| 122 |
+
|
| 123 |
+
Examples
|
| 124 |
+
--------
|
| 125 |
+
>>> import numpy as np
|
| 126 |
+
>>> from scipy.signal import argrelmin
|
| 127 |
+
>>> x = np.array([2, 1, 2, 3, 2, 0, 1, 0])
|
| 128 |
+
>>> argrelmin(x)
|
| 129 |
+
(array([1, 5]),)
|
| 130 |
+
>>> y = np.array([[1, 2, 1, 2],
|
| 131 |
+
... [2, 2, 0, 0],
|
| 132 |
+
... [5, 3, 4, 4]])
|
| 133 |
+
...
|
| 134 |
+
>>> argrelmin(y, axis=1)
|
| 135 |
+
(array([0, 2]), array([2, 1]))
|
| 136 |
+
|
| 137 |
+
"""
|
| 138 |
+
return argrelextrema(data, np.less, axis, order, mode)
|
| 139 |
+
|
| 140 |
+
|
| 141 |
+
def argrelmax(data, axis=0, order=1, mode='clip'):
|
| 142 |
+
"""
|
| 143 |
+
Calculate the relative maxima of `data`.
|
| 144 |
+
|
| 145 |
+
Parameters
|
| 146 |
+
----------
|
| 147 |
+
data : ndarray
|
| 148 |
+
Array in which to find the relative maxima.
|
| 149 |
+
axis : int, optional
|
| 150 |
+
Axis over which to select from `data`. Default is 0.
|
| 151 |
+
order : int, optional
|
| 152 |
+
How many points on each side to use for the comparison
|
| 153 |
+
to consider ``comparator(n, n+x)`` to be True.
|
| 154 |
+
mode : str, optional
|
| 155 |
+
How the edges of the vector are treated.
|
| 156 |
+
Available options are 'wrap' (wrap around) or 'clip' (treat overflow
|
| 157 |
+
as the same as the last (or first) element).
|
| 158 |
+
Default 'clip'. See `numpy.take`.
|
| 159 |
+
|
| 160 |
+
Returns
|
| 161 |
+
-------
|
| 162 |
+
extrema : tuple of ndarrays
|
| 163 |
+
Indices of the maxima in arrays of integers. ``extrema[k]`` is
|
| 164 |
+
the array of indices of axis `k` of `data`. Note that the
|
| 165 |
+
return value is a tuple even when `data` is 1-D.
|
| 166 |
+
|
| 167 |
+
See Also
|
| 168 |
+
--------
|
| 169 |
+
argrelextrema, argrelmin, find_peaks
|
| 170 |
+
|
| 171 |
+
Notes
|
| 172 |
+
-----
|
| 173 |
+
This function uses `argrelextrema` with np.greater as comparator. Therefore,
|
| 174 |
+
it requires a strict inequality on both sides of a value to consider it a
|
| 175 |
+
maximum. This means flat maxima (more than one sample wide) are not detected.
|
| 176 |
+
In case of 1-D `data` `find_peaks` can be used to detect all
|
| 177 |
+
local maxima, including flat ones.
|
| 178 |
+
|
| 179 |
+
.. versionadded:: 0.11.0
|
| 180 |
+
|
| 181 |
+
Examples
|
| 182 |
+
--------
|
| 183 |
+
>>> import numpy as np
|
| 184 |
+
>>> from scipy.signal import argrelmax
|
| 185 |
+
>>> x = np.array([2, 1, 2, 3, 2, 0, 1, 0])
|
| 186 |
+
>>> argrelmax(x)
|
| 187 |
+
(array([3, 6]),)
|
| 188 |
+
>>> y = np.array([[1, 2, 1, 2],
|
| 189 |
+
... [2, 2, 0, 0],
|
| 190 |
+
... [5, 3, 4, 4]])
|
| 191 |
+
...
|
| 192 |
+
>>> argrelmax(y, axis=1)
|
| 193 |
+
(array([0]), array([1]))
|
| 194 |
+
"""
|
| 195 |
+
return argrelextrema(data, np.greater, axis, order, mode)
|
| 196 |
+
|
| 197 |
+
|
| 198 |
+
def argrelextrema(data, comparator, axis=0, order=1, mode='clip'):
|
| 199 |
+
"""
|
| 200 |
+
Calculate the relative extrema of `data`.
|
| 201 |
+
|
| 202 |
+
Parameters
|
| 203 |
+
----------
|
| 204 |
+
data : ndarray
|
| 205 |
+
Array in which to find the relative extrema.
|
| 206 |
+
comparator : callable
|
| 207 |
+
Function to use to compare two data points.
|
| 208 |
+
Should take two arrays as arguments.
|
| 209 |
+
axis : int, optional
|
| 210 |
+
Axis over which to select from `data`. Default is 0.
|
| 211 |
+
order : int, optional
|
| 212 |
+
How many points on each side to use for the comparison
|
| 213 |
+
to consider ``comparator(n, n+x)`` to be True.
|
| 214 |
+
mode : str, optional
|
| 215 |
+
How the edges of the vector are treated. 'wrap' (wrap around) or
|
| 216 |
+
'clip' (treat overflow as the same as the last (or first) element).
|
| 217 |
+
Default is 'clip'. See `numpy.take`.
|
| 218 |
+
|
| 219 |
+
Returns
|
| 220 |
+
-------
|
| 221 |
+
extrema : tuple of ndarrays
|
| 222 |
+
Indices of the maxima in arrays of integers. ``extrema[k]`` is
|
| 223 |
+
the array of indices of axis `k` of `data`. Note that the
|
| 224 |
+
return value is a tuple even when `data` is 1-D.
|
| 225 |
+
|
| 226 |
+
See Also
|
| 227 |
+
--------
|
| 228 |
+
argrelmin, argrelmax
|
| 229 |
+
|
| 230 |
+
Notes
|
| 231 |
+
-----
|
| 232 |
+
|
| 233 |
+
.. versionadded:: 0.11.0
|
| 234 |
+
|
| 235 |
+
Examples
|
| 236 |
+
--------
|
| 237 |
+
>>> import numpy as np
|
| 238 |
+
>>> from scipy.signal import argrelextrema
|
| 239 |
+
>>> x = np.array([2, 1, 2, 3, 2, 0, 1, 0])
|
| 240 |
+
>>> argrelextrema(x, np.greater)
|
| 241 |
+
(array([3, 6]),)
|
| 242 |
+
>>> y = np.array([[1, 2, 1, 2],
|
| 243 |
+
... [2, 2, 0, 0],
|
| 244 |
+
... [5, 3, 4, 4]])
|
| 245 |
+
...
|
| 246 |
+
>>> argrelextrema(y, np.less, axis=1)
|
| 247 |
+
(array([0, 2]), array([2, 1]))
|
| 248 |
+
|
| 249 |
+
"""
|
| 250 |
+
results = _boolrelextrema(data, comparator,
|
| 251 |
+
axis, order, mode)
|
| 252 |
+
return np.nonzero(results)
|
| 253 |
+
|
| 254 |
+
|
| 255 |
+
def _arg_x_as_expected(value):
|
| 256 |
+
"""Ensure argument `x` is a 1-D C-contiguous array of dtype('float64').
|
| 257 |
+
|
| 258 |
+
Used in `find_peaks`, `peak_prominences` and `peak_widths` to make `x`
|
| 259 |
+
compatible with the signature of the wrapped Cython functions.
|
| 260 |
+
|
| 261 |
+
Returns
|
| 262 |
+
-------
|
| 263 |
+
value : ndarray
|
| 264 |
+
A 1-D C-contiguous array with dtype('float64').
|
| 265 |
+
"""
|
| 266 |
+
value = np.asarray(value, order='C', dtype=np.float64)
|
| 267 |
+
if value.ndim != 1:
|
| 268 |
+
raise ValueError('`x` must be a 1-D array')
|
| 269 |
+
return value
|
| 270 |
+
|
| 271 |
+
|
| 272 |
+
def _arg_peaks_as_expected(value):
|
| 273 |
+
"""Ensure argument `peaks` is a 1-D C-contiguous array of dtype('intp').
|
| 274 |
+
|
| 275 |
+
Used in `peak_prominences` and `peak_widths` to make `peaks` compatible
|
| 276 |
+
with the signature of the wrapped Cython functions.
|
| 277 |
+
|
| 278 |
+
Returns
|
| 279 |
+
-------
|
| 280 |
+
value : ndarray
|
| 281 |
+
A 1-D C-contiguous array with dtype('intp').
|
| 282 |
+
"""
|
| 283 |
+
value = np.asarray(value)
|
| 284 |
+
if value.size == 0:
|
| 285 |
+
# Empty arrays default to np.float64 but are valid input
|
| 286 |
+
value = np.array([], dtype=np.intp)
|
| 287 |
+
try:
|
| 288 |
+
# Safely convert to C-contiguous array of type np.intp
|
| 289 |
+
value = value.astype(np.intp, order='C', casting='safe',
|
| 290 |
+
subok=False, copy=False)
|
| 291 |
+
except TypeError as e:
|
| 292 |
+
raise TypeError("cannot safely cast `peaks` to dtype('intp')") from e
|
| 293 |
+
if value.ndim != 1:
|
| 294 |
+
raise ValueError('`peaks` must be a 1-D array')
|
| 295 |
+
return value
|
| 296 |
+
|
| 297 |
+
|
| 298 |
+
def _arg_wlen_as_expected(value):
|
| 299 |
+
"""Ensure argument `wlen` is of type `np.intp` and larger than 1.
|
| 300 |
+
|
| 301 |
+
Used in `peak_prominences` and `peak_widths`.
|
| 302 |
+
|
| 303 |
+
Returns
|
| 304 |
+
-------
|
| 305 |
+
value : np.intp
|
| 306 |
+
The original `value` rounded up to an integer or -1 if `value` was
|
| 307 |
+
None.
|
| 308 |
+
"""
|
| 309 |
+
if value is None:
|
| 310 |
+
# _peak_prominences expects an intp; -1 signals that no value was
|
| 311 |
+
# supplied by the user
|
| 312 |
+
value = -1
|
| 313 |
+
elif 1 < value:
|
| 314 |
+
# Round up to a positive integer
|
| 315 |
+
if isinstance(value, float):
|
| 316 |
+
value = math.ceil(value)
|
| 317 |
+
value = np.intp(value)
|
| 318 |
+
else:
|
| 319 |
+
raise ValueError(f'`wlen` must be larger than 1, was {value}')
|
| 320 |
+
return value
|
| 321 |
+
|
| 322 |
+
|
| 323 |
+
def peak_prominences(x, peaks, wlen=None):
|
| 324 |
+
"""
|
| 325 |
+
Calculate the prominence of each peak in a signal.
|
| 326 |
+
|
| 327 |
+
The prominence of a peak measures how much a peak stands out from the
|
| 328 |
+
surrounding baseline of the signal and is defined as the vertical distance
|
| 329 |
+
between the peak and its lowest contour line.
|
| 330 |
+
|
| 331 |
+
Parameters
|
| 332 |
+
----------
|
| 333 |
+
x : sequence
|
| 334 |
+
A signal with peaks.
|
| 335 |
+
peaks : sequence
|
| 336 |
+
Indices of peaks in `x`.
|
| 337 |
+
wlen : int, optional
|
| 338 |
+
A window length in samples that optionally limits the evaluated area for
|
| 339 |
+
each peak to a subset of `x`. The peak is always placed in the middle of
|
| 340 |
+
the window therefore the given length is rounded up to the next odd
|
| 341 |
+
integer. This parameter can speed up the calculation (see Notes).
|
| 342 |
+
|
| 343 |
+
Returns
|
| 344 |
+
-------
|
| 345 |
+
prominences : ndarray
|
| 346 |
+
The calculated prominences for each peak in `peaks`.
|
| 347 |
+
left_bases, right_bases : ndarray
|
| 348 |
+
The peaks' bases as indices in `x` to the left and right of each peak.
|
| 349 |
+
The higher base of each pair is a peak's lowest contour line.
|
| 350 |
+
|
| 351 |
+
Raises
|
| 352 |
+
------
|
| 353 |
+
ValueError
|
| 354 |
+
If a value in `peaks` is an invalid index for `x`.
|
| 355 |
+
|
| 356 |
+
Warns
|
| 357 |
+
-----
|
| 358 |
+
PeakPropertyWarning
|
| 359 |
+
For indices in `peaks` that don't point to valid local maxima in `x`,
|
| 360 |
+
the returned prominence will be 0 and this warning is raised. This
|
| 361 |
+
also happens if `wlen` is smaller than the plateau size of a peak.
|
| 362 |
+
|
| 363 |
+
Warnings
|
| 364 |
+
--------
|
| 365 |
+
This function may return unexpected results for data containing NaNs. To
|
| 366 |
+
avoid this, NaNs should either be removed or replaced.
|
| 367 |
+
|
| 368 |
+
See Also
|
| 369 |
+
--------
|
| 370 |
+
find_peaks
|
| 371 |
+
Find peaks inside a signal based on peak properties.
|
| 372 |
+
peak_widths
|
| 373 |
+
Calculate the width of peaks.
|
| 374 |
+
|
| 375 |
+
Notes
|
| 376 |
+
-----
|
| 377 |
+
Strategy to compute a peak's prominence:
|
| 378 |
+
|
| 379 |
+
1. Extend a horizontal line from the current peak to the left and right
|
| 380 |
+
until the line either reaches the window border (see `wlen`) or
|
| 381 |
+
intersects the signal again at the slope of a higher peak. An
|
| 382 |
+
intersection with a peak of the same height is ignored.
|
| 383 |
+
2. On each side find the minimal signal value within the interval defined
|
| 384 |
+
above. These points are the peak's bases.
|
| 385 |
+
3. The higher one of the two bases marks the peak's lowest contour line. The
|
| 386 |
+
prominence can then be calculated as the vertical difference between the
|
| 387 |
+
peaks height itself and its lowest contour line.
|
| 388 |
+
|
| 389 |
+
Searching for the peak's bases can be slow for large `x` with periodic
|
| 390 |
+
behavior because large chunks or even the full signal need to be evaluated
|
| 391 |
+
for the first algorithmic step. This evaluation area can be limited with the
|
| 392 |
+
parameter `wlen` which restricts the algorithm to a window around the
|
| 393 |
+
current peak and can shorten the calculation time if the window length is
|
| 394 |
+
short in relation to `x`.
|
| 395 |
+
However, this may stop the algorithm from finding the true global contour
|
| 396 |
+
line if the peak's true bases are outside this window. Instead, a higher
|
| 397 |
+
contour line is found within the restricted window leading to a smaller
|
| 398 |
+
calculated prominence. In practice, this is only relevant for the highest set
|
| 399 |
+
of peaks in `x`. This behavior may even be used intentionally to calculate
|
| 400 |
+
"local" prominences.
|
| 401 |
+
|
| 402 |
+
.. versionadded:: 1.1.0
|
| 403 |
+
|
| 404 |
+
References
|
| 405 |
+
----------
|
| 406 |
+
.. [1] Wikipedia Article for Topographic Prominence:
|
| 407 |
+
https://en.wikipedia.org/wiki/Topographic_prominence
|
| 408 |
+
|
| 409 |
+
Examples
|
| 410 |
+
--------
|
| 411 |
+
>>> import numpy as np
|
| 412 |
+
>>> from scipy.signal import find_peaks, peak_prominences
|
| 413 |
+
>>> import matplotlib.pyplot as plt
|
| 414 |
+
|
| 415 |
+
Create a test signal with two overlaid harmonics
|
| 416 |
+
|
| 417 |
+
>>> x = np.linspace(0, 6 * np.pi, 1000)
|
| 418 |
+
>>> x = np.sin(x) + 0.6 * np.sin(2.6 * x)
|
| 419 |
+
|
| 420 |
+
Find all peaks and calculate prominences
|
| 421 |
+
|
| 422 |
+
>>> peaks, _ = find_peaks(x)
|
| 423 |
+
>>> prominences = peak_prominences(x, peaks)[0]
|
| 424 |
+
>>> prominences
|
| 425 |
+
array([1.24159486, 0.47840168, 0.28470524, 3.10716793, 0.284603 ,
|
| 426 |
+
0.47822491, 2.48340261, 0.47822491])
|
| 427 |
+
|
| 428 |
+
Calculate the height of each peak's contour line and plot the results
|
| 429 |
+
|
| 430 |
+
>>> contour_heights = x[peaks] - prominences
|
| 431 |
+
>>> plt.plot(x)
|
| 432 |
+
>>> plt.plot(peaks, x[peaks], "x")
|
| 433 |
+
>>> plt.vlines(x=peaks, ymin=contour_heights, ymax=x[peaks])
|
| 434 |
+
>>> plt.show()
|
| 435 |
+
|
| 436 |
+
Let's evaluate a second example that demonstrates several edge cases for
|
| 437 |
+
one peak at index 5.
|
| 438 |
+
|
| 439 |
+
>>> x = np.array([0, 1, 0, 3, 1, 3, 0, 4, 0])
|
| 440 |
+
>>> peaks = np.array([5])
|
| 441 |
+
>>> plt.plot(x)
|
| 442 |
+
>>> plt.plot(peaks, x[peaks], "x")
|
| 443 |
+
>>> plt.show()
|
| 444 |
+
>>> peak_prominences(x, peaks) # -> (prominences, left_bases, right_bases)
|
| 445 |
+
(array([3.]), array([2]), array([6]))
|
| 446 |
+
|
| 447 |
+
Note how the peak at index 3 of the same height is not considered as a
|
| 448 |
+
border while searching for the left base. Instead, two minima at 0 and 2
|
| 449 |
+
are found in which case the one closer to the evaluated peak is always
|
| 450 |
+
chosen. On the right side, however, the base must be placed at 6 because the
|
| 451 |
+
higher peak represents the right border to the evaluated area.
|
| 452 |
+
|
| 453 |
+
>>> peak_prominences(x, peaks, wlen=3.1)
|
| 454 |
+
(array([2.]), array([4]), array([6]))
|
| 455 |
+
|
| 456 |
+
Here, we restricted the algorithm to a window from 3 to 7 (the length is 5
|
| 457 |
+
samples because `wlen` was rounded up to the next odd integer). Thus, the
|
| 458 |
+
only two candidates in the evaluated area are the two neighboring samples
|
| 459 |
+
and a smaller prominence is calculated.
|
| 460 |
+
"""
|
| 461 |
+
x = _arg_x_as_expected(x)
|
| 462 |
+
peaks = _arg_peaks_as_expected(peaks)
|
| 463 |
+
wlen = _arg_wlen_as_expected(wlen)
|
| 464 |
+
return _peak_prominences(x, peaks, wlen)
|
| 465 |
+
|
| 466 |
+
|
| 467 |
+
def peak_widths(x, peaks, rel_height=0.5, prominence_data=None, wlen=None):
|
| 468 |
+
"""
|
| 469 |
+
Calculate the width of each peak in a signal.
|
| 470 |
+
|
| 471 |
+
This function calculates the width of a peak in samples at a relative
|
| 472 |
+
distance to the peak's height and prominence.
|
| 473 |
+
|
| 474 |
+
Parameters
|
| 475 |
+
----------
|
| 476 |
+
x : sequence
|
| 477 |
+
A signal with peaks.
|
| 478 |
+
peaks : sequence
|
| 479 |
+
Indices of peaks in `x`.
|
| 480 |
+
rel_height : float, optional
|
| 481 |
+
Chooses the relative height at which the peak width is measured as a
|
| 482 |
+
percentage of its prominence. 1.0 calculates the width of the peak at
|
| 483 |
+
its lowest contour line while 0.5 evaluates at half the prominence
|
| 484 |
+
height. Must be at least 0. See notes for further explanation.
|
| 485 |
+
prominence_data : tuple, optional
|
| 486 |
+
A tuple of three arrays matching the output of `peak_prominences` when
|
| 487 |
+
called with the same arguments `x` and `peaks`. This data are calculated
|
| 488 |
+
internally if not provided.
|
| 489 |
+
wlen : int, optional
|
| 490 |
+
A window length in samples passed to `peak_prominences` as an optional
|
| 491 |
+
argument for internal calculation of `prominence_data`. This argument
|
| 492 |
+
is ignored if `prominence_data` is given.
|
| 493 |
+
|
| 494 |
+
Returns
|
| 495 |
+
-------
|
| 496 |
+
widths : ndarray
|
| 497 |
+
The widths for each peak in samples.
|
| 498 |
+
width_heights : ndarray
|
| 499 |
+
The height of the contour lines at which the `widths` where evaluated.
|
| 500 |
+
left_ips, right_ips : ndarray
|
| 501 |
+
Interpolated positions of left and right intersection points of a
|
| 502 |
+
horizontal line at the respective evaluation height.
|
| 503 |
+
|
| 504 |
+
Raises
|
| 505 |
+
------
|
| 506 |
+
ValueError
|
| 507 |
+
If `prominence_data` is supplied but doesn't satisfy the condition
|
| 508 |
+
``0 <= left_base <= peak <= right_base < x.shape[0]`` for each peak,
|
| 509 |
+
has the wrong dtype, is not C-contiguous or does not have the same
|
| 510 |
+
shape.
|
| 511 |
+
|
| 512 |
+
Warns
|
| 513 |
+
-----
|
| 514 |
+
PeakPropertyWarning
|
| 515 |
+
Raised if any calculated width is 0. This may stem from the supplied
|
| 516 |
+
`prominence_data` or if `rel_height` is set to 0.
|
| 517 |
+
|
| 518 |
+
Warnings
|
| 519 |
+
--------
|
| 520 |
+
This function may return unexpected results for data containing NaNs. To
|
| 521 |
+
avoid this, NaNs should either be removed or replaced.
|
| 522 |
+
|
| 523 |
+
See Also
|
| 524 |
+
--------
|
| 525 |
+
find_peaks
|
| 526 |
+
Find peaks inside a signal based on peak properties.
|
| 527 |
+
peak_prominences
|
| 528 |
+
Calculate the prominence of peaks.
|
| 529 |
+
|
| 530 |
+
Notes
|
| 531 |
+
-----
|
| 532 |
+
The basic algorithm to calculate a peak's width is as follows:
|
| 533 |
+
|
| 534 |
+
* Calculate the evaluation height :math:`h_{eval}` with the formula
|
| 535 |
+
:math:`h_{eval} = h_{Peak} - P \\cdot R`, where :math:`h_{Peak}` is the
|
| 536 |
+
height of the peak itself, :math:`P` is the peak's prominence and
|
| 537 |
+
:math:`R` a positive ratio specified with the argument `rel_height`.
|
| 538 |
+
* Draw a horizontal line at the evaluation height to both sides, starting at
|
| 539 |
+
the peak's current vertical position until the lines either intersect a
|
| 540 |
+
slope, the signal border or cross the vertical position of the peak's
|
| 541 |
+
base (see `peak_prominences` for a definition). For the first case,
|
| 542 |
+
intersection with the signal, the true intersection point is estimated
|
| 543 |
+
with linear interpolation.
|
| 544 |
+
* Calculate the width as the horizontal distance between the chosen
|
| 545 |
+
endpoints on both sides. As a consequence of this the maximal possible
|
| 546 |
+
width for each peak is the horizontal distance between its bases.
|
| 547 |
+
|
| 548 |
+
As shown above to calculate a peak's width its prominence and bases must be
|
| 549 |
+
known. You can supply these yourself with the argument `prominence_data`.
|
| 550 |
+
Otherwise, they are internally calculated (see `peak_prominences`).
|
| 551 |
+
|
| 552 |
+
.. versionadded:: 1.1.0
|
| 553 |
+
|
| 554 |
+
Examples
|
| 555 |
+
--------
|
| 556 |
+
>>> import numpy as np
|
| 557 |
+
>>> from scipy.signal import chirp, find_peaks, peak_widths
|
| 558 |
+
>>> import matplotlib.pyplot as plt
|
| 559 |
+
|
| 560 |
+
Create a test signal with two overlaid harmonics
|
| 561 |
+
|
| 562 |
+
>>> x = np.linspace(0, 6 * np.pi, 1000)
|
| 563 |
+
>>> x = np.sin(x) + 0.6 * np.sin(2.6 * x)
|
| 564 |
+
|
| 565 |
+
Find all peaks and calculate their widths at the relative height of 0.5
|
| 566 |
+
(contour line at half the prominence height) and 1 (at the lowest contour
|
| 567 |
+
line at full prominence height).
|
| 568 |
+
|
| 569 |
+
>>> peaks, _ = find_peaks(x)
|
| 570 |
+
>>> results_half = peak_widths(x, peaks, rel_height=0.5)
|
| 571 |
+
>>> results_half[0] # widths
|
| 572 |
+
array([ 64.25172825, 41.29465463, 35.46943289, 104.71586081,
|
| 573 |
+
35.46729324, 41.30429622, 181.93835853, 45.37078546])
|
| 574 |
+
>>> results_full = peak_widths(x, peaks, rel_height=1)
|
| 575 |
+
>>> results_full[0] # widths
|
| 576 |
+
array([181.9396084 , 72.99284945, 61.28657872, 373.84622694,
|
| 577 |
+
61.78404617, 72.48822812, 253.09161876, 79.36860878])
|
| 578 |
+
|
| 579 |
+
Plot signal, peaks and contour lines at which the widths where calculated
|
| 580 |
+
|
| 581 |
+
>>> plt.plot(x)
|
| 582 |
+
>>> plt.plot(peaks, x[peaks], "x")
|
| 583 |
+
>>> plt.hlines(*results_half[1:], color="C2")
|
| 584 |
+
>>> plt.hlines(*results_full[1:], color="C3")
|
| 585 |
+
>>> plt.show()
|
| 586 |
+
"""
|
| 587 |
+
x = _arg_x_as_expected(x)
|
| 588 |
+
peaks = _arg_peaks_as_expected(peaks)
|
| 589 |
+
if prominence_data is None:
|
| 590 |
+
# Calculate prominence if not supplied and use wlen if supplied.
|
| 591 |
+
wlen = _arg_wlen_as_expected(wlen)
|
| 592 |
+
prominence_data = _peak_prominences(x, peaks, wlen)
|
| 593 |
+
return _peak_widths(x, peaks, rel_height, *prominence_data)
|
| 594 |
+
|
| 595 |
+
|
| 596 |
+
def _unpack_condition_args(interval, x, peaks):
|
| 597 |
+
"""
|
| 598 |
+
Parse condition arguments for `find_peaks`.
|
| 599 |
+
|
| 600 |
+
Parameters
|
| 601 |
+
----------
|
| 602 |
+
interval : number or ndarray or sequence
|
| 603 |
+
Either a number or ndarray or a 2-element sequence of the former. The
|
| 604 |
+
first value is always interpreted as `imin` and the second, if supplied,
|
| 605 |
+
as `imax`.
|
| 606 |
+
x : ndarray
|
| 607 |
+
The signal with `peaks`.
|
| 608 |
+
peaks : ndarray
|
| 609 |
+
An array with indices used to reduce `imin` and / or `imax` if those are
|
| 610 |
+
arrays.
|
| 611 |
+
|
| 612 |
+
Returns
|
| 613 |
+
-------
|
| 614 |
+
imin, imax : number or ndarray or None
|
| 615 |
+
Minimal and maximal value in `argument`.
|
| 616 |
+
|
| 617 |
+
Raises
|
| 618 |
+
------
|
| 619 |
+
ValueError :
|
| 620 |
+
If interval border is given as array and its size does not match the size
|
| 621 |
+
of `x`.
|
| 622 |
+
|
| 623 |
+
Notes
|
| 624 |
+
-----
|
| 625 |
+
|
| 626 |
+
.. versionadded:: 1.1.0
|
| 627 |
+
"""
|
| 628 |
+
try:
|
| 629 |
+
imin, imax = interval
|
| 630 |
+
except (TypeError, ValueError):
|
| 631 |
+
imin, imax = (interval, None)
|
| 632 |
+
|
| 633 |
+
# Reduce arrays if arrays
|
| 634 |
+
if isinstance(imin, np.ndarray):
|
| 635 |
+
if imin.size != x.size:
|
| 636 |
+
raise ValueError('array size of lower interval border must match x')
|
| 637 |
+
imin = imin[peaks]
|
| 638 |
+
if isinstance(imax, np.ndarray):
|
| 639 |
+
if imax.size != x.size:
|
| 640 |
+
raise ValueError('array size of upper interval border must match x')
|
| 641 |
+
imax = imax[peaks]
|
| 642 |
+
|
| 643 |
+
return imin, imax
|
| 644 |
+
|
| 645 |
+
|
| 646 |
+
def _select_by_property(peak_properties, pmin, pmax):
|
| 647 |
+
"""
|
| 648 |
+
Evaluate where the generic property of peaks confirms to an interval.
|
| 649 |
+
|
| 650 |
+
Parameters
|
| 651 |
+
----------
|
| 652 |
+
peak_properties : ndarray
|
| 653 |
+
An array with properties for each peak.
|
| 654 |
+
pmin : None or number or ndarray
|
| 655 |
+
Lower interval boundary for `peak_properties`. ``None`` is interpreted as
|
| 656 |
+
an open border.
|
| 657 |
+
pmax : None or number or ndarray
|
| 658 |
+
Upper interval boundary for `peak_properties`. ``None`` is interpreted as
|
| 659 |
+
an open border.
|
| 660 |
+
|
| 661 |
+
Returns
|
| 662 |
+
-------
|
| 663 |
+
keep : bool
|
| 664 |
+
A boolean mask evaluating to true where `peak_properties` confirms to the
|
| 665 |
+
interval.
|
| 666 |
+
|
| 667 |
+
See Also
|
| 668 |
+
--------
|
| 669 |
+
find_peaks
|
| 670 |
+
|
| 671 |
+
Notes
|
| 672 |
+
-----
|
| 673 |
+
|
| 674 |
+
.. versionadded:: 1.1.0
|
| 675 |
+
"""
|
| 676 |
+
keep = np.ones(peak_properties.size, dtype=bool)
|
| 677 |
+
if pmin is not None:
|
| 678 |
+
keep &= (pmin <= peak_properties)
|
| 679 |
+
if pmax is not None:
|
| 680 |
+
keep &= (peak_properties <= pmax)
|
| 681 |
+
return keep
|
| 682 |
+
|
| 683 |
+
|
| 684 |
+
def _select_by_peak_threshold(x, peaks, tmin, tmax):
|
| 685 |
+
"""
|
| 686 |
+
Evaluate which peaks fulfill the threshold condition.
|
| 687 |
+
|
| 688 |
+
Parameters
|
| 689 |
+
----------
|
| 690 |
+
x : ndarray
|
| 691 |
+
A 1-D array which is indexable by `peaks`.
|
| 692 |
+
peaks : ndarray
|
| 693 |
+
Indices of peaks in `x`.
|
| 694 |
+
tmin, tmax : scalar or ndarray or None
|
| 695 |
+
Minimal and / or maximal required thresholds. If supplied as ndarrays
|
| 696 |
+
their size must match `peaks`. ``None`` is interpreted as an open
|
| 697 |
+
border.
|
| 698 |
+
|
| 699 |
+
Returns
|
| 700 |
+
-------
|
| 701 |
+
keep : bool
|
| 702 |
+
A boolean mask evaluating to true where `peaks` fulfill the threshold
|
| 703 |
+
condition.
|
| 704 |
+
left_thresholds, right_thresholds : ndarray
|
| 705 |
+
Array matching `peak` containing the thresholds of each peak on
|
| 706 |
+
both sides.
|
| 707 |
+
|
| 708 |
+
Notes
|
| 709 |
+
-----
|
| 710 |
+
|
| 711 |
+
.. versionadded:: 1.1.0
|
| 712 |
+
"""
|
| 713 |
+
# Stack thresholds on both sides to make min / max operations easier:
|
| 714 |
+
# tmin is compared with the smaller, and tmax with the greater threshold to
|
| 715 |
+
# each peak's side
|
| 716 |
+
stacked_thresholds = np.vstack([x[peaks] - x[peaks - 1],
|
| 717 |
+
x[peaks] - x[peaks + 1]])
|
| 718 |
+
keep = np.ones(peaks.size, dtype=bool)
|
| 719 |
+
if tmin is not None:
|
| 720 |
+
min_thresholds = np.min(stacked_thresholds, axis=0)
|
| 721 |
+
keep &= (tmin <= min_thresholds)
|
| 722 |
+
if tmax is not None:
|
| 723 |
+
max_thresholds = np.max(stacked_thresholds, axis=0)
|
| 724 |
+
keep &= (max_thresholds <= tmax)
|
| 725 |
+
|
| 726 |
+
return keep, stacked_thresholds[0], stacked_thresholds[1]
|
| 727 |
+
|
| 728 |
+
|
| 729 |
+
def find_peaks(x, height=None, threshold=None, distance=None,
|
| 730 |
+
prominence=None, width=None, wlen=None, rel_height=0.5,
|
| 731 |
+
plateau_size=None):
|
| 732 |
+
"""
|
| 733 |
+
Find peaks inside a signal based on peak properties.
|
| 734 |
+
|
| 735 |
+
This function takes a 1-D array and finds all local maxima by
|
| 736 |
+
simple comparison of neighboring values. Optionally, a subset of these
|
| 737 |
+
peaks can be selected by specifying conditions for a peak's properties.
|
| 738 |
+
|
| 739 |
+
Parameters
|
| 740 |
+
----------
|
| 741 |
+
x : sequence
|
| 742 |
+
A signal with peaks.
|
| 743 |
+
height : number or ndarray or sequence, optional
|
| 744 |
+
Required height of peaks. Either a number, ``None``, an array matching
|
| 745 |
+
`x` or a 2-element sequence of the former. The first element is
|
| 746 |
+
always interpreted as the minimal and the second, if supplied, as the
|
| 747 |
+
maximal required height.
|
| 748 |
+
threshold : number or ndarray or sequence, optional
|
| 749 |
+
Required threshold of peaks, the vertical distance to its neighboring
|
| 750 |
+
samples. Either a number, ``None``, an array matching `x` or a
|
| 751 |
+
2-element sequence of the former. The first element is always
|
| 752 |
+
interpreted as the minimal and the second, if supplied, as the maximal
|
| 753 |
+
required threshold.
|
| 754 |
+
distance : number, optional
|
| 755 |
+
Required minimal horizontal distance (>= 1) in samples between
|
| 756 |
+
neighbouring peaks. Smaller peaks are removed first until the condition
|
| 757 |
+
is fulfilled for all remaining peaks.
|
| 758 |
+
prominence : number or ndarray or sequence, optional
|
| 759 |
+
Required prominence of peaks. Either a number, ``None``, an array
|
| 760 |
+
matching `x` or a 2-element sequence of the former. The first
|
| 761 |
+
element is always interpreted as the minimal and the second, if
|
| 762 |
+
supplied, as the maximal required prominence.
|
| 763 |
+
width : number or ndarray or sequence, optional
|
| 764 |
+
Required width of peaks in samples. Either a number, ``None``, an array
|
| 765 |
+
matching `x` or a 2-element sequence of the former. The first
|
| 766 |
+
element is always interpreted as the minimal and the second, if
|
| 767 |
+
supplied, as the maximal required width.
|
| 768 |
+
wlen : int, optional
|
| 769 |
+
Used for calculation of the peaks prominences, thus it is only used if
|
| 770 |
+
one of the arguments `prominence` or `width` is given. See argument
|
| 771 |
+
`wlen` in `peak_prominences` for a full description of its effects.
|
| 772 |
+
rel_height : float, optional
|
| 773 |
+
Used for calculation of the peaks width, thus it is only used if `width`
|
| 774 |
+
is given. See argument `rel_height` in `peak_widths` for a full
|
| 775 |
+
description of its effects.
|
| 776 |
+
plateau_size : number or ndarray or sequence, optional
|
| 777 |
+
Required size of the flat top of peaks in samples. Either a number,
|
| 778 |
+
``None``, an array matching `x` or a 2-element sequence of the former.
|
| 779 |
+
The first element is always interpreted as the minimal and the second,
|
| 780 |
+
if supplied as the maximal required plateau size.
|
| 781 |
+
|
| 782 |
+
.. versionadded:: 1.2.0
|
| 783 |
+
|
| 784 |
+
Returns
|
| 785 |
+
-------
|
| 786 |
+
peaks : ndarray
|
| 787 |
+
Indices of peaks in `x` that satisfy all given conditions.
|
| 788 |
+
properties : dict
|
| 789 |
+
A dictionary containing properties of the returned peaks which were
|
| 790 |
+
calculated as intermediate results during evaluation of the specified
|
| 791 |
+
conditions:
|
| 792 |
+
|
| 793 |
+
* 'peak_heights'
|
| 794 |
+
If `height` is given, the height of each peak in `x`.
|
| 795 |
+
* 'left_thresholds', 'right_thresholds'
|
| 796 |
+
If `threshold` is given, these keys contain a peaks vertical
|
| 797 |
+
distance to its neighbouring samples.
|
| 798 |
+
* 'prominences', 'right_bases', 'left_bases'
|
| 799 |
+
If `prominence` is given, these keys are accessible. See
|
| 800 |
+
`peak_prominences` for a description of their content.
|
| 801 |
+
* 'widths', 'width_heights', 'left_ips', 'right_ips'
|
| 802 |
+
If `width` is given, these keys are accessible. See `peak_widths`
|
| 803 |
+
for a description of their content.
|
| 804 |
+
* 'plateau_sizes', left_edges', 'right_edges'
|
| 805 |
+
If `plateau_size` is given, these keys are accessible and contain
|
| 806 |
+
the indices of a peak's edges (edges are still part of the
|
| 807 |
+
plateau) and the calculated plateau sizes.
|
| 808 |
+
|
| 809 |
+
.. versionadded:: 1.2.0
|
| 810 |
+
|
| 811 |
+
To calculate and return properties without excluding peaks, provide the
|
| 812 |
+
open interval ``(None, None)`` as a value to the appropriate argument
|
| 813 |
+
(excluding `distance`).
|
| 814 |
+
|
| 815 |
+
Warns
|
| 816 |
+
-----
|
| 817 |
+
PeakPropertyWarning
|
| 818 |
+
Raised if a peak's properties have unexpected values (see
|
| 819 |
+
`peak_prominences` and `peak_widths`).
|
| 820 |
+
|
| 821 |
+
Warnings
|
| 822 |
+
--------
|
| 823 |
+
This function may return unexpected results for data containing NaNs. To
|
| 824 |
+
avoid this, NaNs should either be removed or replaced.
|
| 825 |
+
|
| 826 |
+
See Also
|
| 827 |
+
--------
|
| 828 |
+
find_peaks_cwt
|
| 829 |
+
Find peaks using the wavelet transformation.
|
| 830 |
+
peak_prominences
|
| 831 |
+
Directly calculate the prominence of peaks.
|
| 832 |
+
peak_widths
|
| 833 |
+
Directly calculate the width of peaks.
|
| 834 |
+
|
| 835 |
+
Notes
|
| 836 |
+
-----
|
| 837 |
+
In the context of this function, a peak or local maximum is defined as any
|
| 838 |
+
sample whose two direct neighbours have a smaller amplitude. For flat peaks
|
| 839 |
+
(more than one sample of equal amplitude wide) the index of the middle
|
| 840 |
+
sample is returned (rounded down in case the number of samples is even).
|
| 841 |
+
For noisy signals the peak locations can be off because the noise might
|
| 842 |
+
change the position of local maxima. In those cases consider smoothing the
|
| 843 |
+
signal before searching for peaks or use other peak finding and fitting
|
| 844 |
+
methods (like `find_peaks_cwt`).
|
| 845 |
+
|
| 846 |
+
Some additional comments on specifying conditions:
|
| 847 |
+
|
| 848 |
+
* Almost all conditions (excluding `distance`) can be given as half-open or
|
| 849 |
+
closed intervals, e.g., ``1`` or ``(1, None)`` defines the half-open
|
| 850 |
+
interval :math:`[1, \\infty]` while ``(None, 1)`` defines the interval
|
| 851 |
+
:math:`[-\\infty, 1]`. The open interval ``(None, None)`` can be specified
|
| 852 |
+
as well, which returns the matching properties without exclusion of peaks.
|
| 853 |
+
* The border is always included in the interval used to select valid peaks.
|
| 854 |
+
* For several conditions the interval borders can be specified with
|
| 855 |
+
arrays matching `x` in shape which enables dynamic constrains based on
|
| 856 |
+
the sample position.
|
| 857 |
+
* The conditions are evaluated in the following order: `plateau_size`,
|
| 858 |
+
`height`, `threshold`, `distance`, `prominence`, `width`. In most cases
|
| 859 |
+
this order is the fastest one because faster operations are applied first
|
| 860 |
+
to reduce the number of peaks that need to be evaluated later.
|
| 861 |
+
* While indices in `peaks` are guaranteed to be at least `distance` samples
|
| 862 |
+
apart, edges of flat peaks may be closer than the allowed `distance`.
|
| 863 |
+
* Use `wlen` to reduce the time it takes to evaluate the conditions for
|
| 864 |
+
`prominence` or `width` if `x` is large or has many local maxima
|
| 865 |
+
(see `peak_prominences`).
|
| 866 |
+
|
| 867 |
+
.. versionadded:: 1.1.0
|
| 868 |
+
|
| 869 |
+
Examples
|
| 870 |
+
--------
|
| 871 |
+
To demonstrate this function's usage we use a signal `x` supplied with
|
| 872 |
+
SciPy (see `scipy.datasets.electrocardiogram`). Let's find all peaks (local
|
| 873 |
+
maxima) in `x` whose amplitude lies above 0.
|
| 874 |
+
|
| 875 |
+
>>> import numpy as np
|
| 876 |
+
>>> import matplotlib.pyplot as plt
|
| 877 |
+
>>> from scipy.datasets import electrocardiogram
|
| 878 |
+
>>> from scipy.signal import find_peaks
|
| 879 |
+
>>> x = electrocardiogram()[2000:4000]
|
| 880 |
+
>>> peaks, _ = find_peaks(x, height=0)
|
| 881 |
+
>>> plt.plot(x)
|
| 882 |
+
>>> plt.plot(peaks, x[peaks], "x")
|
| 883 |
+
>>> plt.plot(np.zeros_like(x), "--", color="gray")
|
| 884 |
+
>>> plt.show()
|
| 885 |
+
|
| 886 |
+
We can select peaks below 0 with ``height=(None, 0)`` or use arrays matching
|
| 887 |
+
`x` in size to reflect a changing condition for different parts of the
|
| 888 |
+
signal.
|
| 889 |
+
|
| 890 |
+
>>> border = np.sin(np.linspace(0, 3 * np.pi, x.size))
|
| 891 |
+
>>> peaks, _ = find_peaks(x, height=(-border, border))
|
| 892 |
+
>>> plt.plot(x)
|
| 893 |
+
>>> plt.plot(-border, "--", color="gray")
|
| 894 |
+
>>> plt.plot(border, ":", color="gray")
|
| 895 |
+
>>> plt.plot(peaks, x[peaks], "x")
|
| 896 |
+
>>> plt.show()
|
| 897 |
+
|
| 898 |
+
Another useful condition for periodic signals can be given with the
|
| 899 |
+
`distance` argument. In this case, we can easily select the positions of
|
| 900 |
+
QRS complexes within the electrocardiogram (ECG) by demanding a distance of
|
| 901 |
+
at least 150 samples.
|
| 902 |
+
|
| 903 |
+
>>> peaks, _ = find_peaks(x, distance=150)
|
| 904 |
+
>>> np.diff(peaks)
|
| 905 |
+
array([186, 180, 177, 171, 177, 169, 167, 164, 158, 162, 172])
|
| 906 |
+
>>> plt.plot(x)
|
| 907 |
+
>>> plt.plot(peaks, x[peaks], "x")
|
| 908 |
+
>>> plt.show()
|
| 909 |
+
|
| 910 |
+
Especially for noisy signals peaks can be easily grouped by their
|
| 911 |
+
prominence (see `peak_prominences`). E.g., we can select all peaks except
|
| 912 |
+
for the mentioned QRS complexes by limiting the allowed prominence to 0.6.
|
| 913 |
+
|
| 914 |
+
>>> peaks, properties = find_peaks(x, prominence=(None, 0.6))
|
| 915 |
+
>>> properties["prominences"].max()
|
| 916 |
+
0.5049999999999999
|
| 917 |
+
>>> plt.plot(x)
|
| 918 |
+
>>> plt.plot(peaks, x[peaks], "x")
|
| 919 |
+
>>> plt.show()
|
| 920 |
+
|
| 921 |
+
And, finally, let's examine a different section of the ECG which contains
|
| 922 |
+
beat forms of different shape. To select only the atypical heart beats, we
|
| 923 |
+
combine two conditions: a minimal prominence of 1 and width of at least 20
|
| 924 |
+
samples.
|
| 925 |
+
|
| 926 |
+
>>> x = electrocardiogram()[17000:18000]
|
| 927 |
+
>>> peaks, properties = find_peaks(x, prominence=1, width=20)
|
| 928 |
+
>>> properties["prominences"], properties["widths"]
|
| 929 |
+
(array([1.495, 2.3 ]), array([36.93773946, 39.32723577]))
|
| 930 |
+
>>> plt.plot(x)
|
| 931 |
+
>>> plt.plot(peaks, x[peaks], "x")
|
| 932 |
+
>>> plt.vlines(x=peaks, ymin=x[peaks] - properties["prominences"],
|
| 933 |
+
... ymax = x[peaks], color = "C1")
|
| 934 |
+
>>> plt.hlines(y=properties["width_heights"], xmin=properties["left_ips"],
|
| 935 |
+
... xmax=properties["right_ips"], color = "C1")
|
| 936 |
+
>>> plt.show()
|
| 937 |
+
"""
|
| 938 |
+
# _argmaxima1d expects array of dtype 'float64'
|
| 939 |
+
x = _arg_x_as_expected(x)
|
| 940 |
+
if distance is not None and distance < 1:
|
| 941 |
+
raise ValueError('`distance` must be greater or equal to 1')
|
| 942 |
+
|
| 943 |
+
peaks, left_edges, right_edges = _local_maxima_1d(x)
|
| 944 |
+
properties = {}
|
| 945 |
+
|
| 946 |
+
if plateau_size is not None:
|
| 947 |
+
# Evaluate plateau size
|
| 948 |
+
plateau_sizes = right_edges - left_edges + 1
|
| 949 |
+
pmin, pmax = _unpack_condition_args(plateau_size, x, peaks)
|
| 950 |
+
keep = _select_by_property(plateau_sizes, pmin, pmax)
|
| 951 |
+
peaks = peaks[keep]
|
| 952 |
+
properties["plateau_sizes"] = plateau_sizes
|
| 953 |
+
properties["left_edges"] = left_edges
|
| 954 |
+
properties["right_edges"] = right_edges
|
| 955 |
+
properties = {key: array[keep] for key, array in properties.items()}
|
| 956 |
+
|
| 957 |
+
if height is not None:
|
| 958 |
+
# Evaluate height condition
|
| 959 |
+
peak_heights = x[peaks]
|
| 960 |
+
hmin, hmax = _unpack_condition_args(height, x, peaks)
|
| 961 |
+
keep = _select_by_property(peak_heights, hmin, hmax)
|
| 962 |
+
peaks = peaks[keep]
|
| 963 |
+
properties["peak_heights"] = peak_heights
|
| 964 |
+
properties = {key: array[keep] for key, array in properties.items()}
|
| 965 |
+
|
| 966 |
+
if threshold is not None:
|
| 967 |
+
# Evaluate threshold condition
|
| 968 |
+
tmin, tmax = _unpack_condition_args(threshold, x, peaks)
|
| 969 |
+
keep, left_thresholds, right_thresholds = _select_by_peak_threshold(
|
| 970 |
+
x, peaks, tmin, tmax)
|
| 971 |
+
peaks = peaks[keep]
|
| 972 |
+
properties["left_thresholds"] = left_thresholds
|
| 973 |
+
properties["right_thresholds"] = right_thresholds
|
| 974 |
+
properties = {key: array[keep] for key, array in properties.items()}
|
| 975 |
+
|
| 976 |
+
if distance is not None:
|
| 977 |
+
# Evaluate distance condition
|
| 978 |
+
keep = _select_by_peak_distance(peaks, x[peaks], distance)
|
| 979 |
+
peaks = peaks[keep]
|
| 980 |
+
properties = {key: array[keep] for key, array in properties.items()}
|
| 981 |
+
|
| 982 |
+
if prominence is not None or width is not None:
|
| 983 |
+
# Calculate prominence (required for both conditions)
|
| 984 |
+
wlen = _arg_wlen_as_expected(wlen)
|
| 985 |
+
properties.update(zip(
|
| 986 |
+
['prominences', 'left_bases', 'right_bases'],
|
| 987 |
+
_peak_prominences(x, peaks, wlen=wlen)
|
| 988 |
+
))
|
| 989 |
+
|
| 990 |
+
if prominence is not None:
|
| 991 |
+
# Evaluate prominence condition
|
| 992 |
+
pmin, pmax = _unpack_condition_args(prominence, x, peaks)
|
| 993 |
+
keep = _select_by_property(properties['prominences'], pmin, pmax)
|
| 994 |
+
peaks = peaks[keep]
|
| 995 |
+
properties = {key: array[keep] for key, array in properties.items()}
|
| 996 |
+
|
| 997 |
+
if width is not None:
|
| 998 |
+
# Calculate widths
|
| 999 |
+
properties.update(zip(
|
| 1000 |
+
['widths', 'width_heights', 'left_ips', 'right_ips'],
|
| 1001 |
+
_peak_widths(x, peaks, rel_height, properties['prominences'],
|
| 1002 |
+
properties['left_bases'], properties['right_bases'])
|
| 1003 |
+
))
|
| 1004 |
+
# Evaluate width condition
|
| 1005 |
+
wmin, wmax = _unpack_condition_args(width, x, peaks)
|
| 1006 |
+
keep = _select_by_property(properties['widths'], wmin, wmax)
|
| 1007 |
+
peaks = peaks[keep]
|
| 1008 |
+
properties = {key: array[keep] for key, array in properties.items()}
|
| 1009 |
+
|
| 1010 |
+
return peaks, properties
|
| 1011 |
+
|
| 1012 |
+
|
| 1013 |
+
def _identify_ridge_lines(matr, max_distances, gap_thresh):
|
| 1014 |
+
"""
|
| 1015 |
+
Identify ridges in the 2-D matrix.
|
| 1016 |
+
|
| 1017 |
+
Expect that the width of the wavelet feature increases with increasing row
|
| 1018 |
+
number.
|
| 1019 |
+
|
| 1020 |
+
Parameters
|
| 1021 |
+
----------
|
| 1022 |
+
matr : 2-D ndarray
|
| 1023 |
+
Matrix in which to identify ridge lines.
|
| 1024 |
+
max_distances : 1-D sequence
|
| 1025 |
+
At each row, a ridge line is only connected
|
| 1026 |
+
if the relative max at row[n] is within
|
| 1027 |
+
`max_distances`[n] from the relative max at row[n+1].
|
| 1028 |
+
gap_thresh : int
|
| 1029 |
+
If a relative maximum is not found within `max_distances`,
|
| 1030 |
+
there will be a gap. A ridge line is discontinued if
|
| 1031 |
+
there are more than `gap_thresh` points without connecting
|
| 1032 |
+
a new relative maximum.
|
| 1033 |
+
|
| 1034 |
+
Returns
|
| 1035 |
+
-------
|
| 1036 |
+
ridge_lines : tuple
|
| 1037 |
+
Tuple of 2 1-D sequences. `ridge_lines`[ii][0] are the rows of the
|
| 1038 |
+
ii-th ridge-line, `ridge_lines`[ii][1] are the columns. Empty if none
|
| 1039 |
+
found. Each ridge-line will be sorted by row (increasing), but the
|
| 1040 |
+
order of the ridge lines is not specified.
|
| 1041 |
+
|
| 1042 |
+
References
|
| 1043 |
+
----------
|
| 1044 |
+
.. [1] Bioinformatics (2006) 22 (17): 2059-2065.
|
| 1045 |
+
:doi:`10.1093/bioinformatics/btl355`
|
| 1046 |
+
|
| 1047 |
+
Examples
|
| 1048 |
+
--------
|
| 1049 |
+
>>> import numpy as np
|
| 1050 |
+
>>> from scipy.signal._peak_finding import _identify_ridge_lines
|
| 1051 |
+
>>> rng = np.random.default_rng()
|
| 1052 |
+
>>> data = rng.random((5,5))
|
| 1053 |
+
>>> max_dist = 3
|
| 1054 |
+
>>> max_distances = np.full(20, max_dist)
|
| 1055 |
+
>>> ridge_lines = _identify_ridge_lines(data, max_distances, 1)
|
| 1056 |
+
|
| 1057 |
+
Notes
|
| 1058 |
+
-----
|
| 1059 |
+
This function is intended to be used in conjunction with `cwt`
|
| 1060 |
+
as part of `find_peaks_cwt`.
|
| 1061 |
+
|
| 1062 |
+
"""
|
| 1063 |
+
if len(max_distances) < matr.shape[0]:
|
| 1064 |
+
raise ValueError('Max_distances must have at least as many rows '
|
| 1065 |
+
'as matr')
|
| 1066 |
+
|
| 1067 |
+
all_max_cols = _boolrelextrema(matr, np.greater, axis=1, order=1)
|
| 1068 |
+
# Highest row for which there are any relative maxima
|
| 1069 |
+
has_relmax = np.nonzero(all_max_cols.any(axis=1))[0]
|
| 1070 |
+
if len(has_relmax) == 0:
|
| 1071 |
+
return []
|
| 1072 |
+
start_row = has_relmax[-1]
|
| 1073 |
+
# Each ridge line is a 3-tuple:
|
| 1074 |
+
# rows, cols,Gap number
|
| 1075 |
+
ridge_lines = [[[start_row],
|
| 1076 |
+
[col],
|
| 1077 |
+
0] for col in np.nonzero(all_max_cols[start_row])[0]]
|
| 1078 |
+
final_lines = []
|
| 1079 |
+
rows = np.arange(start_row - 1, -1, -1)
|
| 1080 |
+
cols = np.arange(0, matr.shape[1])
|
| 1081 |
+
for row in rows:
|
| 1082 |
+
this_max_cols = cols[all_max_cols[row]]
|
| 1083 |
+
|
| 1084 |
+
# Increment gap number of each line,
|
| 1085 |
+
# set it to zero later if appropriate
|
| 1086 |
+
for line in ridge_lines:
|
| 1087 |
+
line[2] += 1
|
| 1088 |
+
|
| 1089 |
+
# XXX These should always be all_max_cols[row]
|
| 1090 |
+
# But the order might be different. Might be an efficiency gain
|
| 1091 |
+
# to make sure the order is the same and avoid this iteration
|
| 1092 |
+
prev_ridge_cols = np.array([line[1][-1] for line in ridge_lines])
|
| 1093 |
+
# Look through every relative maximum found at current row
|
| 1094 |
+
# Attempt to connect them with existing ridge lines.
|
| 1095 |
+
for ind, col in enumerate(this_max_cols):
|
| 1096 |
+
# If there is a previous ridge line within
|
| 1097 |
+
# the max_distance to connect to, do so.
|
| 1098 |
+
# Otherwise start a new one.
|
| 1099 |
+
line = None
|
| 1100 |
+
if len(prev_ridge_cols) > 0:
|
| 1101 |
+
diffs = np.abs(col - prev_ridge_cols)
|
| 1102 |
+
closest = np.argmin(diffs)
|
| 1103 |
+
if diffs[closest] <= max_distances[row]:
|
| 1104 |
+
line = ridge_lines[closest]
|
| 1105 |
+
if line is not None:
|
| 1106 |
+
# Found a point close enough, extend current ridge line
|
| 1107 |
+
line[1].append(col)
|
| 1108 |
+
line[0].append(row)
|
| 1109 |
+
line[2] = 0
|
| 1110 |
+
else:
|
| 1111 |
+
new_line = [[row],
|
| 1112 |
+
[col],
|
| 1113 |
+
0]
|
| 1114 |
+
ridge_lines.append(new_line)
|
| 1115 |
+
|
| 1116 |
+
# Remove the ridge lines with gap_number too high
|
| 1117 |
+
# XXX Modifying a list while iterating over it.
|
| 1118 |
+
# Should be safe, since we iterate backwards, but
|
| 1119 |
+
# still tacky.
|
| 1120 |
+
for ind in range(len(ridge_lines) - 1, -1, -1):
|
| 1121 |
+
line = ridge_lines[ind]
|
| 1122 |
+
if line[2] > gap_thresh:
|
| 1123 |
+
final_lines.append(line)
|
| 1124 |
+
del ridge_lines[ind]
|
| 1125 |
+
|
| 1126 |
+
out_lines = []
|
| 1127 |
+
for line in (final_lines + ridge_lines):
|
| 1128 |
+
sortargs = np.argsort(line[0])
|
| 1129 |
+
rows = np.array(line[0])[sortargs]
|
| 1130 |
+
cols = np.array(line[1])[sortargs]
|
| 1131 |
+
out_lines.append([rows, cols])
|
| 1132 |
+
|
| 1133 |
+
return out_lines
|
| 1134 |
+
|
| 1135 |
+
|
| 1136 |
+
def _filter_ridge_lines(cwt, ridge_lines, window_size=None, min_length=None,
|
| 1137 |
+
min_snr=1, noise_perc=10):
|
| 1138 |
+
"""
|
| 1139 |
+
Filter ridge lines according to prescribed criteria. Intended
|
| 1140 |
+
to be used for finding relative maxima.
|
| 1141 |
+
|
| 1142 |
+
Parameters
|
| 1143 |
+
----------
|
| 1144 |
+
cwt : 2-D ndarray
|
| 1145 |
+
Continuous wavelet transform from which the `ridge_lines` were defined.
|
| 1146 |
+
ridge_lines : 1-D sequence
|
| 1147 |
+
Each element should contain 2 sequences, the rows and columns
|
| 1148 |
+
of the ridge line (respectively).
|
| 1149 |
+
window_size : int, optional
|
| 1150 |
+
Size of window to use to calculate noise floor.
|
| 1151 |
+
Default is ``cwt.shape[1] / 20``.
|
| 1152 |
+
min_length : int, optional
|
| 1153 |
+
Minimum length a ridge line needs to be acceptable.
|
| 1154 |
+
Default is ``cwt.shape[0] / 4``, ie 1/4-th the number of widths.
|
| 1155 |
+
min_snr : float, optional
|
| 1156 |
+
Minimum SNR ratio. Default 1. The signal is the value of
|
| 1157 |
+
the cwt matrix at the shortest length scale (``cwt[0, loc]``), the
|
| 1158 |
+
noise is the `noise_perc`\\ th percentile of datapoints contained within a
|
| 1159 |
+
window of `window_size` around ``cwt[0, loc]``.
|
| 1160 |
+
noise_perc : float, optional
|
| 1161 |
+
When calculating the noise floor, percentile of data points
|
| 1162 |
+
examined below which to consider noise. Calculated using
|
| 1163 |
+
scipy.stats.scoreatpercentile.
|
| 1164 |
+
|
| 1165 |
+
References
|
| 1166 |
+
----------
|
| 1167 |
+
.. [1] Bioinformatics (2006) 22 (17): 2059-2065.
|
| 1168 |
+
:doi:`10.1093/bioinformatics/btl355`
|
| 1169 |
+
|
| 1170 |
+
"""
|
| 1171 |
+
num_points = cwt.shape[1]
|
| 1172 |
+
if min_length is None:
|
| 1173 |
+
min_length = np.ceil(cwt.shape[0] / 4)
|
| 1174 |
+
if window_size is None:
|
| 1175 |
+
window_size = np.ceil(num_points / 20)
|
| 1176 |
+
|
| 1177 |
+
window_size = int(window_size)
|
| 1178 |
+
hf_window, odd = divmod(window_size, 2)
|
| 1179 |
+
|
| 1180 |
+
# Filter based on SNR
|
| 1181 |
+
row_one = cwt[0, :]
|
| 1182 |
+
noises = np.empty_like(row_one)
|
| 1183 |
+
for ind, val in enumerate(row_one):
|
| 1184 |
+
window_start = max(ind - hf_window, 0)
|
| 1185 |
+
window_end = min(ind + hf_window + odd, num_points)
|
| 1186 |
+
noises[ind] = scoreatpercentile(row_one[window_start:window_end],
|
| 1187 |
+
per=noise_perc)
|
| 1188 |
+
|
| 1189 |
+
def filt_func(line):
|
| 1190 |
+
if len(line[0]) < min_length:
|
| 1191 |
+
return False
|
| 1192 |
+
snr = abs(cwt[line[0][0], line[1][0]] / noises[line[1][0]])
|
| 1193 |
+
if snr < min_snr:
|
| 1194 |
+
return False
|
| 1195 |
+
return True
|
| 1196 |
+
|
| 1197 |
+
return list(filter(filt_func, ridge_lines))
|
| 1198 |
+
|
| 1199 |
+
|
| 1200 |
+
def find_peaks_cwt(vector, widths, wavelet=None, max_distances=None,
|
| 1201 |
+
gap_thresh=None, min_length=None,
|
| 1202 |
+
min_snr=1, noise_perc=10, window_size=None):
|
| 1203 |
+
"""
|
| 1204 |
+
Find peaks in a 1-D array with wavelet transformation.
|
| 1205 |
+
|
| 1206 |
+
The general approach is to smooth `vector` by convolving it with
|
| 1207 |
+
`wavelet(width)` for each width in `widths`. Relative maxima which
|
| 1208 |
+
appear at enough length scales, and with sufficiently high SNR, are
|
| 1209 |
+
accepted.
|
| 1210 |
+
|
| 1211 |
+
Parameters
|
| 1212 |
+
----------
|
| 1213 |
+
vector : ndarray
|
| 1214 |
+
1-D array in which to find the peaks.
|
| 1215 |
+
widths : float or sequence
|
| 1216 |
+
Single width or 1-D array-like of widths to use for calculating
|
| 1217 |
+
the CWT matrix. In general,
|
| 1218 |
+
this range should cover the expected width of peaks of interest.
|
| 1219 |
+
wavelet : callable, optional
|
| 1220 |
+
Should take two parameters and return a 1-D array to convolve
|
| 1221 |
+
with `vector`. The first parameter determines the number of points
|
| 1222 |
+
of the returned wavelet array, the second parameter is the scale
|
| 1223 |
+
(`width`) of the wavelet. Should be normalized and symmetric.
|
| 1224 |
+
Default is the ricker wavelet.
|
| 1225 |
+
max_distances : ndarray, optional
|
| 1226 |
+
At each row, a ridge line is only connected if the relative max at
|
| 1227 |
+
``row[n]`` is within ``max_distances[n]`` from the relative max at
|
| 1228 |
+
``row[n+1]``. Default value is ``widths/4``.
|
| 1229 |
+
gap_thresh : float, optional
|
| 1230 |
+
If a relative maximum is not found within `max_distances`,
|
| 1231 |
+
there will be a gap. A ridge line is discontinued if there are more
|
| 1232 |
+
than `gap_thresh` points without connecting a new relative maximum.
|
| 1233 |
+
Default is the first value of the widths array i.e. ``widths[0]``.
|
| 1234 |
+
min_length : int, optional
|
| 1235 |
+
Minimum length a ridge line needs to be acceptable.
|
| 1236 |
+
Default is ``cwt.shape[0] / 4``, ie 1/4-th the number of widths.
|
| 1237 |
+
min_snr : float, optional
|
| 1238 |
+
Minimum SNR ratio. Default 1. The signal is the maximum CWT coefficient
|
| 1239 |
+
on the largest ridge line. The noise is `noise_perc` th percentile of
|
| 1240 |
+
datapoints contained within the same ridge line.
|
| 1241 |
+
noise_perc : float, optional
|
| 1242 |
+
When calculating the noise floor, percentile of data points
|
| 1243 |
+
examined below which to consider noise. Calculated using
|
| 1244 |
+
`stats.scoreatpercentile`. Default is 10.
|
| 1245 |
+
window_size : int, optional
|
| 1246 |
+
Size of window to use to calculate noise floor.
|
| 1247 |
+
Default is ``cwt.shape[1] / 20``.
|
| 1248 |
+
|
| 1249 |
+
Returns
|
| 1250 |
+
-------
|
| 1251 |
+
peaks_indices : ndarray
|
| 1252 |
+
Indices of the locations in the `vector` where peaks were found.
|
| 1253 |
+
The list is sorted.
|
| 1254 |
+
|
| 1255 |
+
See Also
|
| 1256 |
+
--------
|
| 1257 |
+
find_peaks
|
| 1258 |
+
Find peaks inside a signal based on peak properties.
|
| 1259 |
+
|
| 1260 |
+
Notes
|
| 1261 |
+
-----
|
| 1262 |
+
This approach was designed for finding sharp peaks among noisy data,
|
| 1263 |
+
however with proper parameter selection it should function well for
|
| 1264 |
+
different peak shapes.
|
| 1265 |
+
|
| 1266 |
+
The algorithm is as follows:
|
| 1267 |
+
1. Perform a continuous wavelet transform on `vector`, for the supplied
|
| 1268 |
+
`widths`. This is a convolution of `vector` with `wavelet(width)` for
|
| 1269 |
+
each width in `widths`.
|
| 1270 |
+
2. Identify "ridge lines" in the cwt matrix. These are relative maxima
|
| 1271 |
+
at each row, connected across adjacent rows. See identify_ridge_lines
|
| 1272 |
+
3. Filter the ridge_lines using filter_ridge_lines.
|
| 1273 |
+
|
| 1274 |
+
References
|
| 1275 |
+
----------
|
| 1276 |
+
.. [1] Bioinformatics (2006) 22 (17): 2059-2065.
|
| 1277 |
+
:doi:`10.1093/bioinformatics/btl355`
|
| 1278 |
+
|
| 1279 |
+
Examples
|
| 1280 |
+
--------
|
| 1281 |
+
>>> import numpy as np
|
| 1282 |
+
>>> from scipy import signal
|
| 1283 |
+
>>> xs = np.arange(0, np.pi, 0.05)
|
| 1284 |
+
>>> data = np.sin(xs)
|
| 1285 |
+
>>> peakind = signal.find_peaks_cwt(data, np.arange(1,10))
|
| 1286 |
+
>>> peakind, xs[peakind], data[peakind]
|
| 1287 |
+
([32], array([ 1.6]), array([ 0.9995736]))
|
| 1288 |
+
|
| 1289 |
+
"""
|
| 1290 |
+
widths = np.atleast_1d(np.asarray(widths))
|
| 1291 |
+
|
| 1292 |
+
if gap_thresh is None:
|
| 1293 |
+
gap_thresh = np.ceil(widths[0])
|
| 1294 |
+
if max_distances is None:
|
| 1295 |
+
max_distances = widths / 4.0
|
| 1296 |
+
if wavelet is None:
|
| 1297 |
+
wavelet = _ricker
|
| 1298 |
+
|
| 1299 |
+
cwt_dat = _cwt(vector, wavelet, widths)
|
| 1300 |
+
ridge_lines = _identify_ridge_lines(cwt_dat, max_distances, gap_thresh)
|
| 1301 |
+
filtered = _filter_ridge_lines(cwt_dat, ridge_lines, min_length=min_length,
|
| 1302 |
+
window_size=window_size, min_snr=min_snr,
|
| 1303 |
+
noise_perc=noise_perc)
|
| 1304 |
+
max_locs = np.asarray([x[1][0] for x in filtered])
|
| 1305 |
+
max_locs.sort()
|
| 1306 |
+
|
| 1307 |
+
return max_locs
|