scipy 1.16.2__cp313-cp313-win_arm64.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (1530) hide show
  1. scipy/__config__.py +161 -0
  2. scipy/__init__.py +150 -0
  3. scipy/_cyutility.cp313-win_arm64.lib +0 -0
  4. scipy/_cyutility.cp313-win_arm64.pyd +0 -0
  5. scipy/_distributor_init.py +18 -0
  6. scipy/_lib/__init__.py +14 -0
  7. scipy/_lib/_array_api.py +931 -0
  8. scipy/_lib/_array_api_compat_vendor.py +9 -0
  9. scipy/_lib/_array_api_no_0d.py +103 -0
  10. scipy/_lib/_bunch.py +229 -0
  11. scipy/_lib/_ccallback.py +251 -0
  12. scipy/_lib/_ccallback_c.cp313-win_arm64.lib +0 -0
  13. scipy/_lib/_ccallback_c.cp313-win_arm64.pyd +0 -0
  14. scipy/_lib/_disjoint_set.py +254 -0
  15. scipy/_lib/_docscrape.py +761 -0
  16. scipy/_lib/_elementwise_iterative_method.py +346 -0
  17. scipy/_lib/_fpumode.cp313-win_arm64.lib +0 -0
  18. scipy/_lib/_fpumode.cp313-win_arm64.pyd +0 -0
  19. scipy/_lib/_gcutils.py +105 -0
  20. scipy/_lib/_pep440.py +487 -0
  21. scipy/_lib/_sparse.py +41 -0
  22. scipy/_lib/_test_ccallback.cp313-win_arm64.lib +0 -0
  23. scipy/_lib/_test_ccallback.cp313-win_arm64.pyd +0 -0
  24. scipy/_lib/_test_deprecation_call.cp313-win_arm64.lib +0 -0
  25. scipy/_lib/_test_deprecation_call.cp313-win_arm64.pyd +0 -0
  26. scipy/_lib/_test_deprecation_def.cp313-win_arm64.lib +0 -0
  27. scipy/_lib/_test_deprecation_def.cp313-win_arm64.pyd +0 -0
  28. scipy/_lib/_testutils.py +373 -0
  29. scipy/_lib/_threadsafety.py +58 -0
  30. scipy/_lib/_tmpdirs.py +86 -0
  31. scipy/_lib/_uarray/LICENSE +29 -0
  32. scipy/_lib/_uarray/__init__.py +116 -0
  33. scipy/_lib/_uarray/_backend.py +707 -0
  34. scipy/_lib/_uarray/_uarray.cp313-win_arm64.lib +0 -0
  35. scipy/_lib/_uarray/_uarray.cp313-win_arm64.pyd +0 -0
  36. scipy/_lib/_util.py +1283 -0
  37. scipy/_lib/array_api_compat/__init__.py +22 -0
  38. scipy/_lib/array_api_compat/_internal.py +59 -0
  39. scipy/_lib/array_api_compat/common/__init__.py +1 -0
  40. scipy/_lib/array_api_compat/common/_aliases.py +727 -0
  41. scipy/_lib/array_api_compat/common/_fft.py +213 -0
  42. scipy/_lib/array_api_compat/common/_helpers.py +1058 -0
  43. scipy/_lib/array_api_compat/common/_linalg.py +232 -0
  44. scipy/_lib/array_api_compat/common/_typing.py +192 -0
  45. scipy/_lib/array_api_compat/cupy/__init__.py +13 -0
  46. scipy/_lib/array_api_compat/cupy/_aliases.py +156 -0
  47. scipy/_lib/array_api_compat/cupy/_info.py +336 -0
  48. scipy/_lib/array_api_compat/cupy/_typing.py +31 -0
  49. scipy/_lib/array_api_compat/cupy/fft.py +36 -0
  50. scipy/_lib/array_api_compat/cupy/linalg.py +49 -0
  51. scipy/_lib/array_api_compat/dask/__init__.py +0 -0
  52. scipy/_lib/array_api_compat/dask/array/__init__.py +12 -0
  53. scipy/_lib/array_api_compat/dask/array/_aliases.py +376 -0
  54. scipy/_lib/array_api_compat/dask/array/_info.py +416 -0
  55. scipy/_lib/array_api_compat/dask/array/fft.py +21 -0
  56. scipy/_lib/array_api_compat/dask/array/linalg.py +72 -0
  57. scipy/_lib/array_api_compat/numpy/__init__.py +28 -0
  58. scipy/_lib/array_api_compat/numpy/_aliases.py +190 -0
  59. scipy/_lib/array_api_compat/numpy/_info.py +366 -0
  60. scipy/_lib/array_api_compat/numpy/_typing.py +30 -0
  61. scipy/_lib/array_api_compat/numpy/fft.py +35 -0
  62. scipy/_lib/array_api_compat/numpy/linalg.py +143 -0
  63. scipy/_lib/array_api_compat/torch/__init__.py +22 -0
  64. scipy/_lib/array_api_compat/torch/_aliases.py +855 -0
  65. scipy/_lib/array_api_compat/torch/_info.py +369 -0
  66. scipy/_lib/array_api_compat/torch/_typing.py +3 -0
  67. scipy/_lib/array_api_compat/torch/fft.py +85 -0
  68. scipy/_lib/array_api_compat/torch/linalg.py +121 -0
  69. scipy/_lib/array_api_extra/__init__.py +38 -0
  70. scipy/_lib/array_api_extra/_delegation.py +171 -0
  71. scipy/_lib/array_api_extra/_lib/__init__.py +1 -0
  72. scipy/_lib/array_api_extra/_lib/_at.py +463 -0
  73. scipy/_lib/array_api_extra/_lib/_backends.py +46 -0
  74. scipy/_lib/array_api_extra/_lib/_funcs.py +937 -0
  75. scipy/_lib/array_api_extra/_lib/_lazy.py +357 -0
  76. scipy/_lib/array_api_extra/_lib/_testing.py +278 -0
  77. scipy/_lib/array_api_extra/_lib/_utils/__init__.py +1 -0
  78. scipy/_lib/array_api_extra/_lib/_utils/_compat.py +74 -0
  79. scipy/_lib/array_api_extra/_lib/_utils/_compat.pyi +45 -0
  80. scipy/_lib/array_api_extra/_lib/_utils/_helpers.py +559 -0
  81. scipy/_lib/array_api_extra/_lib/_utils/_typing.py +10 -0
  82. scipy/_lib/array_api_extra/_lib/_utils/_typing.pyi +105 -0
  83. scipy/_lib/array_api_extra/testing.py +359 -0
  84. scipy/_lib/cobyqa/__init__.py +20 -0
  85. scipy/_lib/cobyqa/framework.py +1240 -0
  86. scipy/_lib/cobyqa/main.py +1506 -0
  87. scipy/_lib/cobyqa/models.py +1529 -0
  88. scipy/_lib/cobyqa/problem.py +1296 -0
  89. scipy/_lib/cobyqa/settings.py +132 -0
  90. scipy/_lib/cobyqa/subsolvers/__init__.py +14 -0
  91. scipy/_lib/cobyqa/subsolvers/geometry.py +387 -0
  92. scipy/_lib/cobyqa/subsolvers/optim.py +1203 -0
  93. scipy/_lib/cobyqa/utils/__init__.py +18 -0
  94. scipy/_lib/cobyqa/utils/exceptions.py +22 -0
  95. scipy/_lib/cobyqa/utils/math.py +77 -0
  96. scipy/_lib/cobyqa/utils/versions.py +67 -0
  97. scipy/_lib/decorator.py +399 -0
  98. scipy/_lib/deprecation.py +274 -0
  99. scipy/_lib/doccer.py +366 -0
  100. scipy/_lib/messagestream.cp313-win_arm64.lib +0 -0
  101. scipy/_lib/messagestream.cp313-win_arm64.pyd +0 -0
  102. scipy/_lib/pyprima/__init__.py +212 -0
  103. scipy/_lib/pyprima/cobyla/__init__.py +0 -0
  104. scipy/_lib/pyprima/cobyla/cobyla.py +559 -0
  105. scipy/_lib/pyprima/cobyla/cobylb.py +714 -0
  106. scipy/_lib/pyprima/cobyla/geometry.py +226 -0
  107. scipy/_lib/pyprima/cobyla/initialize.py +215 -0
  108. scipy/_lib/pyprima/cobyla/trustregion.py +492 -0
  109. scipy/_lib/pyprima/cobyla/update.py +289 -0
  110. scipy/_lib/pyprima/common/__init__.py +0 -0
  111. scipy/_lib/pyprima/common/_bounds.py +34 -0
  112. scipy/_lib/pyprima/common/_linear_constraints.py +46 -0
  113. scipy/_lib/pyprima/common/_nonlinear_constraints.py +54 -0
  114. scipy/_lib/pyprima/common/_project.py +173 -0
  115. scipy/_lib/pyprima/common/checkbreak.py +93 -0
  116. scipy/_lib/pyprima/common/consts.py +47 -0
  117. scipy/_lib/pyprima/common/evaluate.py +99 -0
  118. scipy/_lib/pyprima/common/history.py +38 -0
  119. scipy/_lib/pyprima/common/infos.py +30 -0
  120. scipy/_lib/pyprima/common/linalg.py +435 -0
  121. scipy/_lib/pyprima/common/message.py +290 -0
  122. scipy/_lib/pyprima/common/powalg.py +131 -0
  123. scipy/_lib/pyprima/common/preproc.py +277 -0
  124. scipy/_lib/pyprima/common/present.py +5 -0
  125. scipy/_lib/pyprima/common/ratio.py +54 -0
  126. scipy/_lib/pyprima/common/redrho.py +47 -0
  127. scipy/_lib/pyprima/common/selectx.py +296 -0
  128. scipy/_lib/tests/__init__.py +0 -0
  129. scipy/_lib/tests/test__gcutils.py +110 -0
  130. scipy/_lib/tests/test__pep440.py +67 -0
  131. scipy/_lib/tests/test__testutils.py +32 -0
  132. scipy/_lib/tests/test__threadsafety.py +51 -0
  133. scipy/_lib/tests/test__util.py +641 -0
  134. scipy/_lib/tests/test_array_api.py +322 -0
  135. scipy/_lib/tests/test_bunch.py +169 -0
  136. scipy/_lib/tests/test_ccallback.py +196 -0
  137. scipy/_lib/tests/test_config.py +45 -0
  138. scipy/_lib/tests/test_deprecation.py +10 -0
  139. scipy/_lib/tests/test_doccer.py +143 -0
  140. scipy/_lib/tests/test_import_cycles.py +18 -0
  141. scipy/_lib/tests/test_public_api.py +482 -0
  142. scipy/_lib/tests/test_scipy_version.py +28 -0
  143. scipy/_lib/tests/test_tmpdirs.py +48 -0
  144. scipy/_lib/tests/test_warnings.py +137 -0
  145. scipy/_lib/uarray.py +31 -0
  146. scipy/cluster/__init__.py +31 -0
  147. scipy/cluster/_hierarchy.cp313-win_arm64.lib +0 -0
  148. scipy/cluster/_hierarchy.cp313-win_arm64.pyd +0 -0
  149. scipy/cluster/_optimal_leaf_ordering.cp313-win_arm64.lib +0 -0
  150. scipy/cluster/_optimal_leaf_ordering.cp313-win_arm64.pyd +0 -0
  151. scipy/cluster/_vq.cp313-win_arm64.lib +0 -0
  152. scipy/cluster/_vq.cp313-win_arm64.pyd +0 -0
  153. scipy/cluster/hierarchy.py +4348 -0
  154. scipy/cluster/tests/__init__.py +0 -0
  155. scipy/cluster/tests/hierarchy_test_data.py +145 -0
  156. scipy/cluster/tests/test_disjoint_set.py +202 -0
  157. scipy/cluster/tests/test_hierarchy.py +1238 -0
  158. scipy/cluster/tests/test_vq.py +434 -0
  159. scipy/cluster/vq.py +832 -0
  160. scipy/conftest.py +683 -0
  161. scipy/constants/__init__.py +358 -0
  162. scipy/constants/_codata.py +2266 -0
  163. scipy/constants/_constants.py +369 -0
  164. scipy/constants/codata.py +21 -0
  165. scipy/constants/constants.py +53 -0
  166. scipy/constants/tests/__init__.py +0 -0
  167. scipy/constants/tests/test_codata.py +78 -0
  168. scipy/constants/tests/test_constants.py +83 -0
  169. scipy/datasets/__init__.py +90 -0
  170. scipy/datasets/_download_all.py +71 -0
  171. scipy/datasets/_fetchers.py +225 -0
  172. scipy/datasets/_registry.py +26 -0
  173. scipy/datasets/_utils.py +81 -0
  174. scipy/datasets/tests/__init__.py +0 -0
  175. scipy/datasets/tests/test_data.py +128 -0
  176. scipy/differentiate/__init__.py +27 -0
  177. scipy/differentiate/_differentiate.py +1129 -0
  178. scipy/differentiate/tests/__init__.py +0 -0
  179. scipy/differentiate/tests/test_differentiate.py +694 -0
  180. scipy/fft/__init__.py +114 -0
  181. scipy/fft/_backend.py +196 -0
  182. scipy/fft/_basic.py +1650 -0
  183. scipy/fft/_basic_backend.py +197 -0
  184. scipy/fft/_debug_backends.py +22 -0
  185. scipy/fft/_fftlog.py +223 -0
  186. scipy/fft/_fftlog_backend.py +200 -0
  187. scipy/fft/_helper.py +348 -0
  188. scipy/fft/_pocketfft/LICENSE.md +25 -0
  189. scipy/fft/_pocketfft/__init__.py +9 -0
  190. scipy/fft/_pocketfft/basic.py +251 -0
  191. scipy/fft/_pocketfft/helper.py +249 -0
  192. scipy/fft/_pocketfft/pypocketfft.cp313-win_arm64.lib +0 -0
  193. scipy/fft/_pocketfft/pypocketfft.cp313-win_arm64.pyd +0 -0
  194. scipy/fft/_pocketfft/realtransforms.py +109 -0
  195. scipy/fft/_pocketfft/tests/__init__.py +0 -0
  196. scipy/fft/_pocketfft/tests/test_basic.py +1011 -0
  197. scipy/fft/_pocketfft/tests/test_real_transforms.py +505 -0
  198. scipy/fft/_realtransforms.py +706 -0
  199. scipy/fft/_realtransforms_backend.py +63 -0
  200. scipy/fft/tests/__init__.py +0 -0
  201. scipy/fft/tests/mock_backend.py +96 -0
  202. scipy/fft/tests/test_backend.py +98 -0
  203. scipy/fft/tests/test_basic.py +504 -0
  204. scipy/fft/tests/test_fftlog.py +215 -0
  205. scipy/fft/tests/test_helper.py +558 -0
  206. scipy/fft/tests/test_multithreading.py +84 -0
  207. scipy/fft/tests/test_real_transforms.py +247 -0
  208. scipy/fftpack/__init__.py +103 -0
  209. scipy/fftpack/_basic.py +428 -0
  210. scipy/fftpack/_helper.py +115 -0
  211. scipy/fftpack/_pseudo_diffs.py +554 -0
  212. scipy/fftpack/_realtransforms.py +598 -0
  213. scipy/fftpack/basic.py +20 -0
  214. scipy/fftpack/convolve.cp313-win_arm64.lib +0 -0
  215. scipy/fftpack/convolve.cp313-win_arm64.pyd +0 -0
  216. scipy/fftpack/helper.py +19 -0
  217. scipy/fftpack/pseudo_diffs.py +22 -0
  218. scipy/fftpack/realtransforms.py +19 -0
  219. scipy/fftpack/tests/__init__.py +0 -0
  220. scipy/fftpack/tests/fftw_double_ref.npz +0 -0
  221. scipy/fftpack/tests/fftw_longdouble_ref.npz +0 -0
  222. scipy/fftpack/tests/fftw_single_ref.npz +0 -0
  223. scipy/fftpack/tests/test.npz +0 -0
  224. scipy/fftpack/tests/test_basic.py +877 -0
  225. scipy/fftpack/tests/test_helper.py +54 -0
  226. scipy/fftpack/tests/test_import.py +33 -0
  227. scipy/fftpack/tests/test_pseudo_diffs.py +388 -0
  228. scipy/fftpack/tests/test_real_transforms.py +836 -0
  229. scipy/integrate/__init__.py +122 -0
  230. scipy/integrate/_bvp.py +1160 -0
  231. scipy/integrate/_cubature.py +729 -0
  232. scipy/integrate/_dop.cp313-win_arm64.lib +0 -0
  233. scipy/integrate/_dop.cp313-win_arm64.pyd +0 -0
  234. scipy/integrate/_ivp/__init__.py +8 -0
  235. scipy/integrate/_ivp/base.py +290 -0
  236. scipy/integrate/_ivp/bdf.py +478 -0
  237. scipy/integrate/_ivp/common.py +451 -0
  238. scipy/integrate/_ivp/dop853_coefficients.py +193 -0
  239. scipy/integrate/_ivp/ivp.py +755 -0
  240. scipy/integrate/_ivp/lsoda.py +224 -0
  241. scipy/integrate/_ivp/radau.py +572 -0
  242. scipy/integrate/_ivp/rk.py +601 -0
  243. scipy/integrate/_ivp/tests/__init__.py +0 -0
  244. scipy/integrate/_ivp/tests/test_ivp.py +1287 -0
  245. scipy/integrate/_ivp/tests/test_rk.py +37 -0
  246. scipy/integrate/_lebedev.py +5450 -0
  247. scipy/integrate/_lsoda.cp313-win_arm64.lib +0 -0
  248. scipy/integrate/_lsoda.cp313-win_arm64.pyd +0 -0
  249. scipy/integrate/_ode.py +1395 -0
  250. scipy/integrate/_odepack.cp313-win_arm64.lib +0 -0
  251. scipy/integrate/_odepack.cp313-win_arm64.pyd +0 -0
  252. scipy/integrate/_odepack_py.py +273 -0
  253. scipy/integrate/_quad_vec.py +674 -0
  254. scipy/integrate/_quadpack.cp313-win_arm64.lib +0 -0
  255. scipy/integrate/_quadpack.cp313-win_arm64.pyd +0 -0
  256. scipy/integrate/_quadpack_py.py +1283 -0
  257. scipy/integrate/_quadrature.py +1336 -0
  258. scipy/integrate/_rules/__init__.py +12 -0
  259. scipy/integrate/_rules/_base.py +518 -0
  260. scipy/integrate/_rules/_gauss_kronrod.py +202 -0
  261. scipy/integrate/_rules/_gauss_legendre.py +62 -0
  262. scipy/integrate/_rules/_genz_malik.py +210 -0
  263. scipy/integrate/_tanhsinh.py +1385 -0
  264. scipy/integrate/_test_multivariate.cp313-win_arm64.lib +0 -0
  265. scipy/integrate/_test_multivariate.cp313-win_arm64.pyd +0 -0
  266. scipy/integrate/_test_odeint_banded.cp313-win_arm64.lib +0 -0
  267. scipy/integrate/_test_odeint_banded.cp313-win_arm64.pyd +0 -0
  268. scipy/integrate/_vode.cp313-win_arm64.lib +0 -0
  269. scipy/integrate/_vode.cp313-win_arm64.pyd +0 -0
  270. scipy/integrate/dop.py +15 -0
  271. scipy/integrate/lsoda.py +15 -0
  272. scipy/integrate/odepack.py +17 -0
  273. scipy/integrate/quadpack.py +23 -0
  274. scipy/integrate/tests/__init__.py +0 -0
  275. scipy/integrate/tests/test__quad_vec.py +211 -0
  276. scipy/integrate/tests/test_banded_ode_solvers.py +305 -0
  277. scipy/integrate/tests/test_bvp.py +714 -0
  278. scipy/integrate/tests/test_cubature.py +1375 -0
  279. scipy/integrate/tests/test_integrate.py +840 -0
  280. scipy/integrate/tests/test_odeint_jac.py +74 -0
  281. scipy/integrate/tests/test_quadpack.py +680 -0
  282. scipy/integrate/tests/test_quadrature.py +730 -0
  283. scipy/integrate/tests/test_tanhsinh.py +1171 -0
  284. scipy/integrate/vode.py +15 -0
  285. scipy/interpolate/__init__.py +228 -0
  286. scipy/interpolate/_bary_rational.py +715 -0
  287. scipy/interpolate/_bsplines.py +2469 -0
  288. scipy/interpolate/_cubic.py +973 -0
  289. scipy/interpolate/_dfitpack.cp313-win_arm64.lib +0 -0
  290. scipy/interpolate/_dfitpack.cp313-win_arm64.pyd +0 -0
  291. scipy/interpolate/_dierckx.cp313-win_arm64.lib +0 -0
  292. scipy/interpolate/_dierckx.cp313-win_arm64.pyd +0 -0
  293. scipy/interpolate/_fitpack.cp313-win_arm64.lib +0 -0
  294. scipy/interpolate/_fitpack.cp313-win_arm64.pyd +0 -0
  295. scipy/interpolate/_fitpack2.py +2397 -0
  296. scipy/interpolate/_fitpack_impl.py +811 -0
  297. scipy/interpolate/_fitpack_py.py +898 -0
  298. scipy/interpolate/_fitpack_repro.py +996 -0
  299. scipy/interpolate/_interpnd.cp313-win_arm64.lib +0 -0
  300. scipy/interpolate/_interpnd.cp313-win_arm64.pyd +0 -0
  301. scipy/interpolate/_interpolate.py +2266 -0
  302. scipy/interpolate/_ndbspline.py +415 -0
  303. scipy/interpolate/_ndgriddata.py +329 -0
  304. scipy/interpolate/_pade.py +67 -0
  305. scipy/interpolate/_polyint.py +1025 -0
  306. scipy/interpolate/_ppoly.cp313-win_arm64.lib +0 -0
  307. scipy/interpolate/_ppoly.cp313-win_arm64.pyd +0 -0
  308. scipy/interpolate/_rbf.py +290 -0
  309. scipy/interpolate/_rbfinterp.py +550 -0
  310. scipy/interpolate/_rbfinterp_pythran.cp313-win_arm64.lib +0 -0
  311. scipy/interpolate/_rbfinterp_pythran.cp313-win_arm64.pyd +0 -0
  312. scipy/interpolate/_rgi.py +764 -0
  313. scipy/interpolate/_rgi_cython.cp313-win_arm64.lib +0 -0
  314. scipy/interpolate/_rgi_cython.cp313-win_arm64.pyd +0 -0
  315. scipy/interpolate/dfitpack.py +24 -0
  316. scipy/interpolate/fitpack.py +31 -0
  317. scipy/interpolate/fitpack2.py +29 -0
  318. scipy/interpolate/interpnd.py +24 -0
  319. scipy/interpolate/interpolate.py +30 -0
  320. scipy/interpolate/ndgriddata.py +23 -0
  321. scipy/interpolate/polyint.py +24 -0
  322. scipy/interpolate/rbf.py +18 -0
  323. scipy/interpolate/tests/__init__.py +0 -0
  324. scipy/interpolate/tests/data/bug-1310.npz +0 -0
  325. scipy/interpolate/tests/data/estimate_gradients_hang.npy +0 -0
  326. scipy/interpolate/tests/data/gcvspl.npz +0 -0
  327. scipy/interpolate/tests/test_bary_rational.py +368 -0
  328. scipy/interpolate/tests/test_bsplines.py +3754 -0
  329. scipy/interpolate/tests/test_fitpack.py +519 -0
  330. scipy/interpolate/tests/test_fitpack2.py +1431 -0
  331. scipy/interpolate/tests/test_gil.py +64 -0
  332. scipy/interpolate/tests/test_interpnd.py +452 -0
  333. scipy/interpolate/tests/test_interpolate.py +2630 -0
  334. scipy/interpolate/tests/test_ndgriddata.py +308 -0
  335. scipy/interpolate/tests/test_pade.py +107 -0
  336. scipy/interpolate/tests/test_polyint.py +972 -0
  337. scipy/interpolate/tests/test_rbf.py +246 -0
  338. scipy/interpolate/tests/test_rbfinterp.py +534 -0
  339. scipy/interpolate/tests/test_rgi.py +1151 -0
  340. scipy/io/__init__.py +116 -0
  341. scipy/io/_fast_matrix_market/__init__.py +600 -0
  342. scipy/io/_fast_matrix_market/_fmm_core.cp313-win_arm64.lib +0 -0
  343. scipy/io/_fast_matrix_market/_fmm_core.cp313-win_arm64.pyd +0 -0
  344. scipy/io/_fortran.py +354 -0
  345. scipy/io/_harwell_boeing/__init__.py +7 -0
  346. scipy/io/_harwell_boeing/_fortran_format_parser.py +316 -0
  347. scipy/io/_harwell_boeing/hb.py +571 -0
  348. scipy/io/_harwell_boeing/tests/__init__.py +0 -0
  349. scipy/io/_harwell_boeing/tests/test_fortran_format.py +74 -0
  350. scipy/io/_harwell_boeing/tests/test_hb.py +70 -0
  351. scipy/io/_idl.py +917 -0
  352. scipy/io/_mmio.py +968 -0
  353. scipy/io/_netcdf.py +1104 -0
  354. scipy/io/_test_fortran.cp313-win_arm64.lib +0 -0
  355. scipy/io/_test_fortran.cp313-win_arm64.pyd +0 -0
  356. scipy/io/arff/__init__.py +28 -0
  357. scipy/io/arff/_arffread.py +873 -0
  358. scipy/io/arff/arffread.py +19 -0
  359. scipy/io/arff/tests/__init__.py +0 -0
  360. scipy/io/arff/tests/data/iris.arff +225 -0
  361. scipy/io/arff/tests/data/missing.arff +8 -0
  362. scipy/io/arff/tests/data/nodata.arff +11 -0
  363. scipy/io/arff/tests/data/quoted_nominal.arff +13 -0
  364. scipy/io/arff/tests/data/quoted_nominal_spaces.arff +13 -0
  365. scipy/io/arff/tests/data/test1.arff +10 -0
  366. scipy/io/arff/tests/data/test10.arff +8 -0
  367. scipy/io/arff/tests/data/test11.arff +11 -0
  368. scipy/io/arff/tests/data/test2.arff +15 -0
  369. scipy/io/arff/tests/data/test3.arff +6 -0
  370. scipy/io/arff/tests/data/test4.arff +11 -0
  371. scipy/io/arff/tests/data/test5.arff +26 -0
  372. scipy/io/arff/tests/data/test6.arff +12 -0
  373. scipy/io/arff/tests/data/test7.arff +15 -0
  374. scipy/io/arff/tests/data/test8.arff +12 -0
  375. scipy/io/arff/tests/data/test9.arff +14 -0
  376. scipy/io/arff/tests/test_arffread.py +421 -0
  377. scipy/io/harwell_boeing.py +17 -0
  378. scipy/io/idl.py +17 -0
  379. scipy/io/matlab/__init__.py +66 -0
  380. scipy/io/matlab/_byteordercodes.py +75 -0
  381. scipy/io/matlab/_mio.py +375 -0
  382. scipy/io/matlab/_mio4.py +632 -0
  383. scipy/io/matlab/_mio5.py +901 -0
  384. scipy/io/matlab/_mio5_params.py +281 -0
  385. scipy/io/matlab/_mio5_utils.cp313-win_arm64.lib +0 -0
  386. scipy/io/matlab/_mio5_utils.cp313-win_arm64.pyd +0 -0
  387. scipy/io/matlab/_mio_utils.cp313-win_arm64.lib +0 -0
  388. scipy/io/matlab/_mio_utils.cp313-win_arm64.pyd +0 -0
  389. scipy/io/matlab/_miobase.py +435 -0
  390. scipy/io/matlab/_streams.cp313-win_arm64.lib +0 -0
  391. scipy/io/matlab/_streams.cp313-win_arm64.pyd +0 -0
  392. scipy/io/matlab/byteordercodes.py +17 -0
  393. scipy/io/matlab/mio.py +16 -0
  394. scipy/io/matlab/mio4.py +17 -0
  395. scipy/io/matlab/mio5.py +19 -0
  396. scipy/io/matlab/mio5_params.py +18 -0
  397. scipy/io/matlab/mio5_utils.py +17 -0
  398. scipy/io/matlab/mio_utils.py +17 -0
  399. scipy/io/matlab/miobase.py +16 -0
  400. scipy/io/matlab/streams.py +16 -0
  401. scipy/io/matlab/tests/__init__.py +0 -0
  402. scipy/io/matlab/tests/data/bad_miuint32.mat +0 -0
  403. scipy/io/matlab/tests/data/bad_miutf8_array_name.mat +0 -0
  404. scipy/io/matlab/tests/data/big_endian.mat +0 -0
  405. scipy/io/matlab/tests/data/broken_utf8.mat +0 -0
  406. scipy/io/matlab/tests/data/corrupted_zlib_checksum.mat +0 -0
  407. scipy/io/matlab/tests/data/corrupted_zlib_data.mat +0 -0
  408. scipy/io/matlab/tests/data/debigged_m4.mat +0 -0
  409. scipy/io/matlab/tests/data/japanese_utf8.txt +5 -0
  410. scipy/io/matlab/tests/data/little_endian.mat +0 -0
  411. scipy/io/matlab/tests/data/logical_sparse.mat +0 -0
  412. scipy/io/matlab/tests/data/malformed1.mat +0 -0
  413. scipy/io/matlab/tests/data/miuint32_for_miint32.mat +0 -0
  414. scipy/io/matlab/tests/data/miutf8_array_name.mat +0 -0
  415. scipy/io/matlab/tests/data/nasty_duplicate_fieldnames.mat +0 -0
  416. scipy/io/matlab/tests/data/one_by_zero_char.mat +0 -0
  417. scipy/io/matlab/tests/data/parabola.mat +0 -0
  418. scipy/io/matlab/tests/data/single_empty_string.mat +0 -0
  419. scipy/io/matlab/tests/data/some_functions.mat +0 -0
  420. scipy/io/matlab/tests/data/sqr.mat +0 -0
  421. scipy/io/matlab/tests/data/test3dmatrix_6.1_SOL2.mat +0 -0
  422. scipy/io/matlab/tests/data/test3dmatrix_6.5.1_GLNX86.mat +0 -0
  423. scipy/io/matlab/tests/data/test3dmatrix_7.1_GLNX86.mat +0 -0
  424. scipy/io/matlab/tests/data/test3dmatrix_7.4_GLNX86.mat +0 -0
  425. scipy/io/matlab/tests/data/test_empty_struct.mat +0 -0
  426. scipy/io/matlab/tests/data/test_mat4_le_floats.mat +0 -0
  427. scipy/io/matlab/tests/data/test_skip_variable.mat +0 -0
  428. scipy/io/matlab/tests/data/testbool_8_WIN64.mat +0 -0
  429. scipy/io/matlab/tests/data/testcell_6.1_SOL2.mat +0 -0
  430. scipy/io/matlab/tests/data/testcell_6.5.1_GLNX86.mat +0 -0
  431. scipy/io/matlab/tests/data/testcell_7.1_GLNX86.mat +0 -0
  432. scipy/io/matlab/tests/data/testcell_7.4_GLNX86.mat +0 -0
  433. scipy/io/matlab/tests/data/testcellnest_6.1_SOL2.mat +0 -0
  434. scipy/io/matlab/tests/data/testcellnest_6.5.1_GLNX86.mat +0 -0
  435. scipy/io/matlab/tests/data/testcellnest_7.1_GLNX86.mat +0 -0
  436. scipy/io/matlab/tests/data/testcellnest_7.4_GLNX86.mat +0 -0
  437. scipy/io/matlab/tests/data/testcomplex_4.2c_SOL2.mat +0 -0
  438. scipy/io/matlab/tests/data/testcomplex_6.1_SOL2.mat +0 -0
  439. scipy/io/matlab/tests/data/testcomplex_6.5.1_GLNX86.mat +0 -0
  440. scipy/io/matlab/tests/data/testcomplex_7.1_GLNX86.mat +0 -0
  441. scipy/io/matlab/tests/data/testcomplex_7.4_GLNX86.mat +0 -0
  442. scipy/io/matlab/tests/data/testdouble_4.2c_SOL2.mat +0 -0
  443. scipy/io/matlab/tests/data/testdouble_6.1_SOL2.mat +0 -0
  444. scipy/io/matlab/tests/data/testdouble_6.5.1_GLNX86.mat +0 -0
  445. scipy/io/matlab/tests/data/testdouble_7.1_GLNX86.mat +0 -0
  446. scipy/io/matlab/tests/data/testdouble_7.4_GLNX86.mat +0 -0
  447. scipy/io/matlab/tests/data/testemptycell_5.3_SOL2.mat +0 -0
  448. scipy/io/matlab/tests/data/testemptycell_6.5.1_GLNX86.mat +0 -0
  449. scipy/io/matlab/tests/data/testemptycell_7.1_GLNX86.mat +0 -0
  450. scipy/io/matlab/tests/data/testemptycell_7.4_GLNX86.mat +0 -0
  451. scipy/io/matlab/tests/data/testfunc_7.4_GLNX86.mat +0 -0
  452. scipy/io/matlab/tests/data/testhdf5_7.4_GLNX86.mat +0 -0
  453. scipy/io/matlab/tests/data/testmatrix_4.2c_SOL2.mat +0 -0
  454. scipy/io/matlab/tests/data/testmatrix_6.1_SOL2.mat +0 -0
  455. scipy/io/matlab/tests/data/testmatrix_6.5.1_GLNX86.mat +0 -0
  456. scipy/io/matlab/tests/data/testmatrix_7.1_GLNX86.mat +0 -0
  457. scipy/io/matlab/tests/data/testmatrix_7.4_GLNX86.mat +0 -0
  458. scipy/io/matlab/tests/data/testminus_4.2c_SOL2.mat +0 -0
  459. scipy/io/matlab/tests/data/testminus_6.1_SOL2.mat +0 -0
  460. scipy/io/matlab/tests/data/testminus_6.5.1_GLNX86.mat +0 -0
  461. scipy/io/matlab/tests/data/testminus_7.1_GLNX86.mat +0 -0
  462. scipy/io/matlab/tests/data/testminus_7.4_GLNX86.mat +0 -0
  463. scipy/io/matlab/tests/data/testmulti_4.2c_SOL2.mat +0 -0
  464. scipy/io/matlab/tests/data/testmulti_7.1_GLNX86.mat +0 -0
  465. scipy/io/matlab/tests/data/testmulti_7.4_GLNX86.mat +0 -0
  466. scipy/io/matlab/tests/data/testobject_6.1_SOL2.mat +0 -0
  467. scipy/io/matlab/tests/data/testobject_6.5.1_GLNX86.mat +0 -0
  468. scipy/io/matlab/tests/data/testobject_7.1_GLNX86.mat +0 -0
  469. scipy/io/matlab/tests/data/testobject_7.4_GLNX86.mat +0 -0
  470. scipy/io/matlab/tests/data/testonechar_4.2c_SOL2.mat +0 -0
  471. scipy/io/matlab/tests/data/testonechar_6.1_SOL2.mat +0 -0
  472. scipy/io/matlab/tests/data/testonechar_6.5.1_GLNX86.mat +0 -0
  473. scipy/io/matlab/tests/data/testonechar_7.1_GLNX86.mat +0 -0
  474. scipy/io/matlab/tests/data/testonechar_7.4_GLNX86.mat +0 -0
  475. scipy/io/matlab/tests/data/testscalarcell_7.4_GLNX86.mat +0 -0
  476. scipy/io/matlab/tests/data/testsimplecell.mat +0 -0
  477. scipy/io/matlab/tests/data/testsparse_4.2c_SOL2.mat +0 -0
  478. scipy/io/matlab/tests/data/testsparse_6.1_SOL2.mat +0 -0
  479. scipy/io/matlab/tests/data/testsparse_6.5.1_GLNX86.mat +0 -0
  480. scipy/io/matlab/tests/data/testsparse_7.1_GLNX86.mat +0 -0
  481. scipy/io/matlab/tests/data/testsparse_7.4_GLNX86.mat +0 -0
  482. scipy/io/matlab/tests/data/testsparsecomplex_4.2c_SOL2.mat +0 -0
  483. scipy/io/matlab/tests/data/testsparsecomplex_6.1_SOL2.mat +0 -0
  484. scipy/io/matlab/tests/data/testsparsecomplex_6.5.1_GLNX86.mat +0 -0
  485. scipy/io/matlab/tests/data/testsparsecomplex_7.1_GLNX86.mat +0 -0
  486. scipy/io/matlab/tests/data/testsparsecomplex_7.4_GLNX86.mat +0 -0
  487. scipy/io/matlab/tests/data/testsparsefloat_7.4_GLNX86.mat +0 -0
  488. scipy/io/matlab/tests/data/teststring_4.2c_SOL2.mat +0 -0
  489. scipy/io/matlab/tests/data/teststring_6.1_SOL2.mat +0 -0
  490. scipy/io/matlab/tests/data/teststring_6.5.1_GLNX86.mat +0 -0
  491. scipy/io/matlab/tests/data/teststring_7.1_GLNX86.mat +0 -0
  492. scipy/io/matlab/tests/data/teststring_7.4_GLNX86.mat +0 -0
  493. scipy/io/matlab/tests/data/teststringarray_4.2c_SOL2.mat +0 -0
  494. scipy/io/matlab/tests/data/teststringarray_6.1_SOL2.mat +0 -0
  495. scipy/io/matlab/tests/data/teststringarray_6.5.1_GLNX86.mat +0 -0
  496. scipy/io/matlab/tests/data/teststringarray_7.1_GLNX86.mat +0 -0
  497. scipy/io/matlab/tests/data/teststringarray_7.4_GLNX86.mat +0 -0
  498. scipy/io/matlab/tests/data/teststruct_6.1_SOL2.mat +0 -0
  499. scipy/io/matlab/tests/data/teststruct_6.5.1_GLNX86.mat +0 -0
  500. scipy/io/matlab/tests/data/teststruct_7.1_GLNX86.mat +0 -0
  501. scipy/io/matlab/tests/data/teststruct_7.4_GLNX86.mat +0 -0
  502. scipy/io/matlab/tests/data/teststructarr_6.1_SOL2.mat +0 -0
  503. scipy/io/matlab/tests/data/teststructarr_6.5.1_GLNX86.mat +0 -0
  504. scipy/io/matlab/tests/data/teststructarr_7.1_GLNX86.mat +0 -0
  505. scipy/io/matlab/tests/data/teststructarr_7.4_GLNX86.mat +0 -0
  506. scipy/io/matlab/tests/data/teststructnest_6.1_SOL2.mat +0 -0
  507. scipy/io/matlab/tests/data/teststructnest_6.5.1_GLNX86.mat +0 -0
  508. scipy/io/matlab/tests/data/teststructnest_7.1_GLNX86.mat +0 -0
  509. scipy/io/matlab/tests/data/teststructnest_7.4_GLNX86.mat +0 -0
  510. scipy/io/matlab/tests/data/testunicode_7.1_GLNX86.mat +0 -0
  511. scipy/io/matlab/tests/data/testunicode_7.4_GLNX86.mat +0 -0
  512. scipy/io/matlab/tests/data/testvec_4_GLNX86.mat +0 -0
  513. scipy/io/matlab/tests/test_byteordercodes.py +29 -0
  514. scipy/io/matlab/tests/test_mio.py +1399 -0
  515. scipy/io/matlab/tests/test_mio5_utils.py +179 -0
  516. scipy/io/matlab/tests/test_mio_funcs.py +51 -0
  517. scipy/io/matlab/tests/test_mio_utils.py +45 -0
  518. scipy/io/matlab/tests/test_miobase.py +32 -0
  519. scipy/io/matlab/tests/test_pathological.py +33 -0
  520. scipy/io/matlab/tests/test_streams.py +241 -0
  521. scipy/io/mmio.py +17 -0
  522. scipy/io/netcdf.py +17 -0
  523. scipy/io/tests/__init__.py +0 -0
  524. scipy/io/tests/data/Transparent Busy.ani +0 -0
  525. scipy/io/tests/data/array_float32_1d.sav +0 -0
  526. scipy/io/tests/data/array_float32_2d.sav +0 -0
  527. scipy/io/tests/data/array_float32_3d.sav +0 -0
  528. scipy/io/tests/data/array_float32_4d.sav +0 -0
  529. scipy/io/tests/data/array_float32_5d.sav +0 -0
  530. scipy/io/tests/data/array_float32_6d.sav +0 -0
  531. scipy/io/tests/data/array_float32_7d.sav +0 -0
  532. scipy/io/tests/data/array_float32_8d.sav +0 -0
  533. scipy/io/tests/data/array_float32_pointer_1d.sav +0 -0
  534. scipy/io/tests/data/array_float32_pointer_2d.sav +0 -0
  535. scipy/io/tests/data/array_float32_pointer_3d.sav +0 -0
  536. scipy/io/tests/data/array_float32_pointer_4d.sav +0 -0
  537. scipy/io/tests/data/array_float32_pointer_5d.sav +0 -0
  538. scipy/io/tests/data/array_float32_pointer_6d.sav +0 -0
  539. scipy/io/tests/data/array_float32_pointer_7d.sav +0 -0
  540. scipy/io/tests/data/array_float32_pointer_8d.sav +0 -0
  541. scipy/io/tests/data/example_1.nc +0 -0
  542. scipy/io/tests/data/example_2.nc +0 -0
  543. scipy/io/tests/data/example_3_maskedvals.nc +0 -0
  544. scipy/io/tests/data/fortran-3x3d-2i.dat +0 -0
  545. scipy/io/tests/data/fortran-mixed.dat +0 -0
  546. scipy/io/tests/data/fortran-sf8-11x1x10.dat +0 -0
  547. scipy/io/tests/data/fortran-sf8-15x10x22.dat +0 -0
  548. scipy/io/tests/data/fortran-sf8-1x1x1.dat +0 -0
  549. scipy/io/tests/data/fortran-sf8-1x1x5.dat +0 -0
  550. scipy/io/tests/data/fortran-sf8-1x1x7.dat +0 -0
  551. scipy/io/tests/data/fortran-sf8-1x3x5.dat +0 -0
  552. scipy/io/tests/data/fortran-si4-11x1x10.dat +0 -0
  553. scipy/io/tests/data/fortran-si4-15x10x22.dat +0 -0
  554. scipy/io/tests/data/fortran-si4-1x1x1.dat +0 -0
  555. scipy/io/tests/data/fortran-si4-1x1x5.dat +0 -0
  556. scipy/io/tests/data/fortran-si4-1x1x7.dat +0 -0
  557. scipy/io/tests/data/fortran-si4-1x3x5.dat +0 -0
  558. scipy/io/tests/data/invalid_pointer.sav +0 -0
  559. scipy/io/tests/data/null_pointer.sav +0 -0
  560. scipy/io/tests/data/scalar_byte.sav +0 -0
  561. scipy/io/tests/data/scalar_byte_descr.sav +0 -0
  562. scipy/io/tests/data/scalar_complex32.sav +0 -0
  563. scipy/io/tests/data/scalar_complex64.sav +0 -0
  564. scipy/io/tests/data/scalar_float32.sav +0 -0
  565. scipy/io/tests/data/scalar_float64.sav +0 -0
  566. scipy/io/tests/data/scalar_heap_pointer.sav +0 -0
  567. scipy/io/tests/data/scalar_int16.sav +0 -0
  568. scipy/io/tests/data/scalar_int32.sav +0 -0
  569. scipy/io/tests/data/scalar_int64.sav +0 -0
  570. scipy/io/tests/data/scalar_string.sav +0 -0
  571. scipy/io/tests/data/scalar_uint16.sav +0 -0
  572. scipy/io/tests/data/scalar_uint32.sav +0 -0
  573. scipy/io/tests/data/scalar_uint64.sav +0 -0
  574. scipy/io/tests/data/struct_arrays.sav +0 -0
  575. scipy/io/tests/data/struct_arrays_byte_idl80.sav +0 -0
  576. scipy/io/tests/data/struct_arrays_replicated.sav +0 -0
  577. scipy/io/tests/data/struct_arrays_replicated_3d.sav +0 -0
  578. scipy/io/tests/data/struct_inherit.sav +0 -0
  579. scipy/io/tests/data/struct_pointer_arrays.sav +0 -0
  580. scipy/io/tests/data/struct_pointer_arrays_replicated.sav +0 -0
  581. scipy/io/tests/data/struct_pointer_arrays_replicated_3d.sav +0 -0
  582. scipy/io/tests/data/struct_pointers.sav +0 -0
  583. scipy/io/tests/data/struct_pointers_replicated.sav +0 -0
  584. scipy/io/tests/data/struct_pointers_replicated_3d.sav +0 -0
  585. scipy/io/tests/data/struct_scalars.sav +0 -0
  586. scipy/io/tests/data/struct_scalars_replicated.sav +0 -0
  587. scipy/io/tests/data/struct_scalars_replicated_3d.sav +0 -0
  588. scipy/io/tests/data/test-1234Hz-le-1ch-10S-20bit-extra.wav +0 -0
  589. scipy/io/tests/data/test-44100Hz-2ch-32bit-float-be.wav +0 -0
  590. scipy/io/tests/data/test-44100Hz-2ch-32bit-float-le.wav +0 -0
  591. scipy/io/tests/data/test-44100Hz-be-1ch-4bytes.wav +0 -0
  592. scipy/io/tests/data/test-44100Hz-le-1ch-4bytes-early-eof-no-data.wav +0 -0
  593. scipy/io/tests/data/test-44100Hz-le-1ch-4bytes-early-eof.wav +0 -0
  594. scipy/io/tests/data/test-44100Hz-le-1ch-4bytes-incomplete-chunk.wav +0 -0
  595. scipy/io/tests/data/test-44100Hz-le-1ch-4bytes-rf64.wav +0 -0
  596. scipy/io/tests/data/test-44100Hz-le-1ch-4bytes.wav +0 -0
  597. scipy/io/tests/data/test-48000Hz-2ch-64bit-float-le-wavex.wav +0 -0
  598. scipy/io/tests/data/test-8000Hz-be-3ch-5S-24bit.wav +0 -0
  599. scipy/io/tests/data/test-8000Hz-le-1ch-1byte-ulaw.wav +0 -0
  600. scipy/io/tests/data/test-8000Hz-le-2ch-1byteu.wav +0 -0
  601. scipy/io/tests/data/test-8000Hz-le-3ch-5S-24bit-inconsistent.wav +0 -0
  602. scipy/io/tests/data/test-8000Hz-le-3ch-5S-24bit-rf64.wav +0 -0
  603. scipy/io/tests/data/test-8000Hz-le-3ch-5S-24bit.wav +0 -0
  604. scipy/io/tests/data/test-8000Hz-le-3ch-5S-36bit.wav +0 -0
  605. scipy/io/tests/data/test-8000Hz-le-3ch-5S-45bit.wav +0 -0
  606. scipy/io/tests/data/test-8000Hz-le-3ch-5S-53bit.wav +0 -0
  607. scipy/io/tests/data/test-8000Hz-le-3ch-5S-64bit.wav +0 -0
  608. scipy/io/tests/data/test-8000Hz-le-4ch-9S-12bit.wav +0 -0
  609. scipy/io/tests/data/test-8000Hz-le-5ch-9S-5bit.wav +0 -0
  610. scipy/io/tests/data/various_compressed.sav +0 -0
  611. scipy/io/tests/test_fortran.py +264 -0
  612. scipy/io/tests/test_idl.py +483 -0
  613. scipy/io/tests/test_mmio.py +831 -0
  614. scipy/io/tests/test_netcdf.py +550 -0
  615. scipy/io/tests/test_paths.py +93 -0
  616. scipy/io/tests/test_wavfile.py +501 -0
  617. scipy/io/wavfile.py +938 -0
  618. scipy/linalg/__init__.pxd +1 -0
  619. scipy/linalg/__init__.py +236 -0
  620. scipy/linalg/_basic.py +2146 -0
  621. scipy/linalg/_blas_subroutines.h +164 -0
  622. scipy/linalg/_cythonized_array_utils.cp313-win_arm64.lib +0 -0
  623. scipy/linalg/_cythonized_array_utils.cp313-win_arm64.pyd +0 -0
  624. scipy/linalg/_cythonized_array_utils.pxd +40 -0
  625. scipy/linalg/_cythonized_array_utils.pyi +16 -0
  626. scipy/linalg/_decomp.py +1645 -0
  627. scipy/linalg/_decomp_cholesky.py +413 -0
  628. scipy/linalg/_decomp_cossin.py +236 -0
  629. scipy/linalg/_decomp_interpolative.cp313-win_arm64.lib +0 -0
  630. scipy/linalg/_decomp_interpolative.cp313-win_arm64.pyd +0 -0
  631. scipy/linalg/_decomp_ldl.py +356 -0
  632. scipy/linalg/_decomp_lu.py +401 -0
  633. scipy/linalg/_decomp_lu_cython.cp313-win_arm64.lib +0 -0
  634. scipy/linalg/_decomp_lu_cython.cp313-win_arm64.pyd +0 -0
  635. scipy/linalg/_decomp_lu_cython.pyi +6 -0
  636. scipy/linalg/_decomp_polar.py +113 -0
  637. scipy/linalg/_decomp_qr.py +494 -0
  638. scipy/linalg/_decomp_qz.py +452 -0
  639. scipy/linalg/_decomp_schur.py +336 -0
  640. scipy/linalg/_decomp_svd.py +545 -0
  641. scipy/linalg/_decomp_update.cp313-win_arm64.lib +0 -0
  642. scipy/linalg/_decomp_update.cp313-win_arm64.pyd +0 -0
  643. scipy/linalg/_expm_frechet.py +417 -0
  644. scipy/linalg/_fblas.cp313-win_arm64.lib +0 -0
  645. scipy/linalg/_fblas.cp313-win_arm64.pyd +0 -0
  646. scipy/linalg/_flapack.cp313-win_arm64.lib +0 -0
  647. scipy/linalg/_flapack.cp313-win_arm64.pyd +0 -0
  648. scipy/linalg/_lapack_subroutines.h +1521 -0
  649. scipy/linalg/_linalg_pythran.cp313-win_arm64.lib +0 -0
  650. scipy/linalg/_linalg_pythran.cp313-win_arm64.pyd +0 -0
  651. scipy/linalg/_matfuncs.py +1050 -0
  652. scipy/linalg/_matfuncs_expm.cp313-win_arm64.lib +0 -0
  653. scipy/linalg/_matfuncs_expm.cp313-win_arm64.pyd +0 -0
  654. scipy/linalg/_matfuncs_expm.pyi +6 -0
  655. scipy/linalg/_matfuncs_inv_ssq.py +886 -0
  656. scipy/linalg/_matfuncs_schur_sqrtm.cp313-win_arm64.lib +0 -0
  657. scipy/linalg/_matfuncs_schur_sqrtm.cp313-win_arm64.pyd +0 -0
  658. scipy/linalg/_matfuncs_sqrtm.py +107 -0
  659. scipy/linalg/_matfuncs_sqrtm_triu.cp313-win_arm64.lib +0 -0
  660. scipy/linalg/_matfuncs_sqrtm_triu.cp313-win_arm64.pyd +0 -0
  661. scipy/linalg/_misc.py +191 -0
  662. scipy/linalg/_procrustes.py +113 -0
  663. scipy/linalg/_sketches.py +189 -0
  664. scipy/linalg/_solve_toeplitz.cp313-win_arm64.lib +0 -0
  665. scipy/linalg/_solve_toeplitz.cp313-win_arm64.pyd +0 -0
  666. scipy/linalg/_solvers.py +862 -0
  667. scipy/linalg/_special_matrices.py +1322 -0
  668. scipy/linalg/_testutils.py +65 -0
  669. scipy/linalg/basic.py +23 -0
  670. scipy/linalg/blas.py +495 -0
  671. scipy/linalg/cython_blas.cp313-win_arm64.lib +0 -0
  672. scipy/linalg/cython_blas.cp313-win_arm64.pyd +0 -0
  673. scipy/linalg/cython_blas.pxd +169 -0
  674. scipy/linalg/cython_blas.pyx +1432 -0
  675. scipy/linalg/cython_lapack.cp313-win_arm64.lib +0 -0
  676. scipy/linalg/cython_lapack.cp313-win_arm64.pyd +0 -0
  677. scipy/linalg/cython_lapack.pxd +1528 -0
  678. scipy/linalg/cython_lapack.pyx +12045 -0
  679. scipy/linalg/decomp.py +23 -0
  680. scipy/linalg/decomp_cholesky.py +21 -0
  681. scipy/linalg/decomp_lu.py +21 -0
  682. scipy/linalg/decomp_qr.py +20 -0
  683. scipy/linalg/decomp_schur.py +21 -0
  684. scipy/linalg/decomp_svd.py +21 -0
  685. scipy/linalg/interpolative.py +989 -0
  686. scipy/linalg/lapack.py +1081 -0
  687. scipy/linalg/matfuncs.py +23 -0
  688. scipy/linalg/misc.py +21 -0
  689. scipy/linalg/special_matrices.py +22 -0
  690. scipy/linalg/tests/__init__.py +0 -0
  691. scipy/linalg/tests/_cython_examples/extending.pyx +23 -0
  692. scipy/linalg/tests/_cython_examples/meson.build +34 -0
  693. scipy/linalg/tests/data/carex_15_data.npz +0 -0
  694. scipy/linalg/tests/data/carex_18_data.npz +0 -0
  695. scipy/linalg/tests/data/carex_19_data.npz +0 -0
  696. scipy/linalg/tests/data/carex_20_data.npz +0 -0
  697. scipy/linalg/tests/data/carex_6_data.npz +0 -0
  698. scipy/linalg/tests/data/gendare_20170120_data.npz +0 -0
  699. scipy/linalg/tests/test_basic.py +2074 -0
  700. scipy/linalg/tests/test_batch.py +588 -0
  701. scipy/linalg/tests/test_blas.py +1127 -0
  702. scipy/linalg/tests/test_cython_blas.py +118 -0
  703. scipy/linalg/tests/test_cython_lapack.py +22 -0
  704. scipy/linalg/tests/test_cythonized_array_utils.py +130 -0
  705. scipy/linalg/tests/test_decomp.py +3189 -0
  706. scipy/linalg/tests/test_decomp_cholesky.py +268 -0
  707. scipy/linalg/tests/test_decomp_cossin.py +314 -0
  708. scipy/linalg/tests/test_decomp_ldl.py +137 -0
  709. scipy/linalg/tests/test_decomp_lu.py +308 -0
  710. scipy/linalg/tests/test_decomp_polar.py +110 -0
  711. scipy/linalg/tests/test_decomp_update.py +1701 -0
  712. scipy/linalg/tests/test_extending.py +46 -0
  713. scipy/linalg/tests/test_fblas.py +607 -0
  714. scipy/linalg/tests/test_interpolative.py +232 -0
  715. scipy/linalg/tests/test_lapack.py +3620 -0
  716. scipy/linalg/tests/test_matfuncs.py +1125 -0
  717. scipy/linalg/tests/test_matmul_toeplitz.py +136 -0
  718. scipy/linalg/tests/test_procrustes.py +214 -0
  719. scipy/linalg/tests/test_sketches.py +118 -0
  720. scipy/linalg/tests/test_solve_toeplitz.py +150 -0
  721. scipy/linalg/tests/test_solvers.py +844 -0
  722. scipy/linalg/tests/test_special_matrices.py +636 -0
  723. scipy/misc/__init__.py +6 -0
  724. scipy/misc/common.py +6 -0
  725. scipy/misc/doccer.py +6 -0
  726. scipy/ndimage/__init__.py +174 -0
  727. scipy/ndimage/_ctest.cp313-win_arm64.lib +0 -0
  728. scipy/ndimage/_ctest.cp313-win_arm64.pyd +0 -0
  729. scipy/ndimage/_cytest.cp313-win_arm64.lib +0 -0
  730. scipy/ndimage/_cytest.cp313-win_arm64.pyd +0 -0
  731. scipy/ndimage/_delegators.py +303 -0
  732. scipy/ndimage/_filters.py +2422 -0
  733. scipy/ndimage/_fourier.py +306 -0
  734. scipy/ndimage/_interpolation.py +1033 -0
  735. scipy/ndimage/_measurements.py +1689 -0
  736. scipy/ndimage/_morphology.py +2634 -0
  737. scipy/ndimage/_nd_image.cp313-win_arm64.lib +0 -0
  738. scipy/ndimage/_nd_image.cp313-win_arm64.pyd +0 -0
  739. scipy/ndimage/_ndimage_api.py +16 -0
  740. scipy/ndimage/_ni_docstrings.py +214 -0
  741. scipy/ndimage/_ni_label.cp313-win_arm64.lib +0 -0
  742. scipy/ndimage/_ni_label.cp313-win_arm64.pyd +0 -0
  743. scipy/ndimage/_ni_support.py +139 -0
  744. scipy/ndimage/_rank_filter_1d.cp313-win_arm64.lib +0 -0
  745. scipy/ndimage/_rank_filter_1d.cp313-win_arm64.pyd +0 -0
  746. scipy/ndimage/_support_alternative_backends.py +84 -0
  747. scipy/ndimage/filters.py +27 -0
  748. scipy/ndimage/fourier.py +21 -0
  749. scipy/ndimage/interpolation.py +22 -0
  750. scipy/ndimage/measurements.py +24 -0
  751. scipy/ndimage/morphology.py +27 -0
  752. scipy/ndimage/tests/__init__.py +12 -0
  753. scipy/ndimage/tests/data/label_inputs.txt +21 -0
  754. scipy/ndimage/tests/data/label_results.txt +294 -0
  755. scipy/ndimage/tests/data/label_strels.txt +42 -0
  756. scipy/ndimage/tests/dots.png +0 -0
  757. scipy/ndimage/tests/test_c_api.py +102 -0
  758. scipy/ndimage/tests/test_datatypes.py +67 -0
  759. scipy/ndimage/tests/test_filters.py +3083 -0
  760. scipy/ndimage/tests/test_fourier.py +187 -0
  761. scipy/ndimage/tests/test_interpolation.py +1491 -0
  762. scipy/ndimage/tests/test_measurements.py +1592 -0
  763. scipy/ndimage/tests/test_morphology.py +2950 -0
  764. scipy/ndimage/tests/test_ni_support.py +78 -0
  765. scipy/ndimage/tests/test_splines.py +70 -0
  766. scipy/odr/__init__.py +131 -0
  767. scipy/odr/__odrpack.cp313-win_arm64.lib +0 -0
  768. scipy/odr/__odrpack.cp313-win_arm64.pyd +0 -0
  769. scipy/odr/_add_newdocs.py +34 -0
  770. scipy/odr/_models.py +315 -0
  771. scipy/odr/_odrpack.py +1154 -0
  772. scipy/odr/models.py +20 -0
  773. scipy/odr/odrpack.py +21 -0
  774. scipy/odr/tests/__init__.py +0 -0
  775. scipy/odr/tests/test_odr.py +607 -0
  776. scipy/optimize/__init__.pxd +1 -0
  777. scipy/optimize/__init__.py +460 -0
  778. scipy/optimize/_basinhopping.py +741 -0
  779. scipy/optimize/_bglu_dense.cp313-win_arm64.lib +0 -0
  780. scipy/optimize/_bglu_dense.cp313-win_arm64.pyd +0 -0
  781. scipy/optimize/_bracket.py +706 -0
  782. scipy/optimize/_chandrupatla.py +551 -0
  783. scipy/optimize/_cobyla_py.py +297 -0
  784. scipy/optimize/_cobyqa_py.py +72 -0
  785. scipy/optimize/_constraints.py +598 -0
  786. scipy/optimize/_dcsrch.py +728 -0
  787. scipy/optimize/_differentiable_functions.py +835 -0
  788. scipy/optimize/_differentialevolution.py +1970 -0
  789. scipy/optimize/_direct.cp313-win_arm64.lib +0 -0
  790. scipy/optimize/_direct.cp313-win_arm64.pyd +0 -0
  791. scipy/optimize/_direct_py.py +280 -0
  792. scipy/optimize/_dual_annealing.py +732 -0
  793. scipy/optimize/_elementwise.py +798 -0
  794. scipy/optimize/_group_columns.cp313-win_arm64.lib +0 -0
  795. scipy/optimize/_group_columns.cp313-win_arm64.pyd +0 -0
  796. scipy/optimize/_hessian_update_strategy.py +479 -0
  797. scipy/optimize/_highspy/__init__.py +0 -0
  798. scipy/optimize/_highspy/_core.cp313-win_arm64.lib +0 -0
  799. scipy/optimize/_highspy/_core.cp313-win_arm64.pyd +0 -0
  800. scipy/optimize/_highspy/_highs_options.cp313-win_arm64.lib +0 -0
  801. scipy/optimize/_highspy/_highs_options.cp313-win_arm64.pyd +0 -0
  802. scipy/optimize/_highspy/_highs_wrapper.py +338 -0
  803. scipy/optimize/_isotonic.py +157 -0
  804. scipy/optimize/_lbfgsb.cp313-win_arm64.lib +0 -0
  805. scipy/optimize/_lbfgsb.cp313-win_arm64.pyd +0 -0
  806. scipy/optimize/_lbfgsb_py.py +634 -0
  807. scipy/optimize/_linesearch.py +896 -0
  808. scipy/optimize/_linprog.py +733 -0
  809. scipy/optimize/_linprog_doc.py +1434 -0
  810. scipy/optimize/_linprog_highs.py +422 -0
  811. scipy/optimize/_linprog_ip.py +1141 -0
  812. scipy/optimize/_linprog_rs.py +572 -0
  813. scipy/optimize/_linprog_simplex.py +663 -0
  814. scipy/optimize/_linprog_util.py +1521 -0
  815. scipy/optimize/_lsap.cp313-win_arm64.lib +0 -0
  816. scipy/optimize/_lsap.cp313-win_arm64.pyd +0 -0
  817. scipy/optimize/_lsq/__init__.py +5 -0
  818. scipy/optimize/_lsq/bvls.py +183 -0
  819. scipy/optimize/_lsq/common.py +731 -0
  820. scipy/optimize/_lsq/dogbox.py +345 -0
  821. scipy/optimize/_lsq/givens_elimination.cp313-win_arm64.lib +0 -0
  822. scipy/optimize/_lsq/givens_elimination.cp313-win_arm64.pyd +0 -0
  823. scipy/optimize/_lsq/least_squares.py +1044 -0
  824. scipy/optimize/_lsq/lsq_linear.py +361 -0
  825. scipy/optimize/_lsq/trf.py +587 -0
  826. scipy/optimize/_lsq/trf_linear.py +249 -0
  827. scipy/optimize/_milp.py +394 -0
  828. scipy/optimize/_minimize.py +1199 -0
  829. scipy/optimize/_minpack.cp313-win_arm64.lib +0 -0
  830. scipy/optimize/_minpack.cp313-win_arm64.pyd +0 -0
  831. scipy/optimize/_minpack_py.py +1178 -0
  832. scipy/optimize/_moduleTNC.cp313-win_arm64.lib +0 -0
  833. scipy/optimize/_moduleTNC.cp313-win_arm64.pyd +0 -0
  834. scipy/optimize/_nnls.py +96 -0
  835. scipy/optimize/_nonlin.py +1634 -0
  836. scipy/optimize/_numdiff.py +963 -0
  837. scipy/optimize/_optimize.py +4169 -0
  838. scipy/optimize/_pava_pybind.cp313-win_arm64.lib +0 -0
  839. scipy/optimize/_pava_pybind.cp313-win_arm64.pyd +0 -0
  840. scipy/optimize/_qap.py +760 -0
  841. scipy/optimize/_remove_redundancy.py +522 -0
  842. scipy/optimize/_root.py +732 -0
  843. scipy/optimize/_root_scalar.py +538 -0
  844. scipy/optimize/_shgo.py +1606 -0
  845. scipy/optimize/_shgo_lib/__init__.py +0 -0
  846. scipy/optimize/_shgo_lib/_complex.py +1225 -0
  847. scipy/optimize/_shgo_lib/_vertex.py +460 -0
  848. scipy/optimize/_slsqp_py.py +603 -0
  849. scipy/optimize/_slsqplib.cp313-win_arm64.lib +0 -0
  850. scipy/optimize/_slsqplib.cp313-win_arm64.pyd +0 -0
  851. scipy/optimize/_spectral.py +260 -0
  852. scipy/optimize/_tnc.py +438 -0
  853. scipy/optimize/_trlib/__init__.py +12 -0
  854. scipy/optimize/_trlib/_trlib.cp313-win_arm64.lib +0 -0
  855. scipy/optimize/_trlib/_trlib.cp313-win_arm64.pyd +0 -0
  856. scipy/optimize/_trustregion.py +318 -0
  857. scipy/optimize/_trustregion_constr/__init__.py +6 -0
  858. scipy/optimize/_trustregion_constr/canonical_constraint.py +390 -0
  859. scipy/optimize/_trustregion_constr/equality_constrained_sqp.py +231 -0
  860. scipy/optimize/_trustregion_constr/minimize_trustregion_constr.py +584 -0
  861. scipy/optimize/_trustregion_constr/projections.py +411 -0
  862. scipy/optimize/_trustregion_constr/qp_subproblem.py +637 -0
  863. scipy/optimize/_trustregion_constr/report.py +49 -0
  864. scipy/optimize/_trustregion_constr/tests/__init__.py +0 -0
  865. scipy/optimize/_trustregion_constr/tests/test_canonical_constraint.py +296 -0
  866. scipy/optimize/_trustregion_constr/tests/test_nested_minimize.py +39 -0
  867. scipy/optimize/_trustregion_constr/tests/test_projections.py +214 -0
  868. scipy/optimize/_trustregion_constr/tests/test_qp_subproblem.py +645 -0
  869. scipy/optimize/_trustregion_constr/tests/test_report.py +34 -0
  870. scipy/optimize/_trustregion_constr/tr_interior_point.py +361 -0
  871. scipy/optimize/_trustregion_dogleg.py +122 -0
  872. scipy/optimize/_trustregion_exact.py +437 -0
  873. scipy/optimize/_trustregion_krylov.py +65 -0
  874. scipy/optimize/_trustregion_ncg.py +126 -0
  875. scipy/optimize/_tstutils.py +972 -0
  876. scipy/optimize/_zeros.cp313-win_arm64.lib +0 -0
  877. scipy/optimize/_zeros.cp313-win_arm64.pyd +0 -0
  878. scipy/optimize/_zeros_py.py +1475 -0
  879. scipy/optimize/cobyla.py +19 -0
  880. scipy/optimize/cython_optimize/__init__.py +133 -0
  881. scipy/optimize/cython_optimize/_zeros.cp313-win_arm64.lib +0 -0
  882. scipy/optimize/cython_optimize/_zeros.cp313-win_arm64.pyd +0 -0
  883. scipy/optimize/cython_optimize/_zeros.pxd +33 -0
  884. scipy/optimize/cython_optimize/c_zeros.pxd +26 -0
  885. scipy/optimize/cython_optimize.pxd +11 -0
  886. scipy/optimize/elementwise.py +38 -0
  887. scipy/optimize/lbfgsb.py +23 -0
  888. scipy/optimize/linesearch.py +18 -0
  889. scipy/optimize/minpack.py +27 -0
  890. scipy/optimize/minpack2.py +17 -0
  891. scipy/optimize/moduleTNC.py +19 -0
  892. scipy/optimize/nonlin.py +29 -0
  893. scipy/optimize/optimize.py +40 -0
  894. scipy/optimize/slsqp.py +22 -0
  895. scipy/optimize/tests/__init__.py +0 -0
  896. scipy/optimize/tests/_cython_examples/extending.pyx +43 -0
  897. scipy/optimize/tests/_cython_examples/meson.build +32 -0
  898. scipy/optimize/tests/test__basinhopping.py +535 -0
  899. scipy/optimize/tests/test__differential_evolution.py +1703 -0
  900. scipy/optimize/tests/test__dual_annealing.py +416 -0
  901. scipy/optimize/tests/test__linprog_clean_inputs.py +312 -0
  902. scipy/optimize/tests/test__numdiff.py +885 -0
  903. scipy/optimize/tests/test__remove_redundancy.py +228 -0
  904. scipy/optimize/tests/test__root.py +124 -0
  905. scipy/optimize/tests/test__shgo.py +1164 -0
  906. scipy/optimize/tests/test__spectral.py +226 -0
  907. scipy/optimize/tests/test_bracket.py +896 -0
  908. scipy/optimize/tests/test_chandrupatla.py +982 -0
  909. scipy/optimize/tests/test_cobyla.py +195 -0
  910. scipy/optimize/tests/test_cobyqa.py +252 -0
  911. scipy/optimize/tests/test_constraint_conversion.py +286 -0
  912. scipy/optimize/tests/test_constraints.py +255 -0
  913. scipy/optimize/tests/test_cython_optimize.py +92 -0
  914. scipy/optimize/tests/test_differentiable_functions.py +1025 -0
  915. scipy/optimize/tests/test_direct.py +321 -0
  916. scipy/optimize/tests/test_extending.py +28 -0
  917. scipy/optimize/tests/test_hessian_update_strategy.py +300 -0
  918. scipy/optimize/tests/test_isotonic_regression.py +167 -0
  919. scipy/optimize/tests/test_lbfgsb_hessinv.py +65 -0
  920. scipy/optimize/tests/test_lbfgsb_setulb.py +122 -0
  921. scipy/optimize/tests/test_least_squares.py +986 -0
  922. scipy/optimize/tests/test_linear_assignment.py +116 -0
  923. scipy/optimize/tests/test_linesearch.py +328 -0
  924. scipy/optimize/tests/test_linprog.py +2577 -0
  925. scipy/optimize/tests/test_lsq_common.py +297 -0
  926. scipy/optimize/tests/test_lsq_linear.py +287 -0
  927. scipy/optimize/tests/test_milp.py +459 -0
  928. scipy/optimize/tests/test_minimize_constrained.py +845 -0
  929. scipy/optimize/tests/test_minpack.py +1194 -0
  930. scipy/optimize/tests/test_nnls.py +469 -0
  931. scipy/optimize/tests/test_nonlin.py +572 -0
  932. scipy/optimize/tests/test_optimize.py +3344 -0
  933. scipy/optimize/tests/test_quadratic_assignment.py +455 -0
  934. scipy/optimize/tests/test_regression.py +40 -0
  935. scipy/optimize/tests/test_slsqp.py +645 -0
  936. scipy/optimize/tests/test_tnc.py +345 -0
  937. scipy/optimize/tests/test_trustregion.py +110 -0
  938. scipy/optimize/tests/test_trustregion_exact.py +351 -0
  939. scipy/optimize/tests/test_trustregion_krylov.py +170 -0
  940. scipy/optimize/tests/test_zeros.py +998 -0
  941. scipy/optimize/tnc.py +22 -0
  942. scipy/optimize/zeros.py +26 -0
  943. scipy/signal/__init__.py +316 -0
  944. scipy/signal/_arraytools.py +264 -0
  945. scipy/signal/_czt.py +575 -0
  946. scipy/signal/_delegators.py +568 -0
  947. scipy/signal/_filter_design.py +5893 -0
  948. scipy/signal/_fir_filter_design.py +1458 -0
  949. scipy/signal/_lti_conversion.py +534 -0
  950. scipy/signal/_ltisys.py +3546 -0
  951. scipy/signal/_max_len_seq.py +139 -0
  952. scipy/signal/_max_len_seq_inner.cp313-win_arm64.lib +0 -0
  953. scipy/signal/_max_len_seq_inner.cp313-win_arm64.pyd +0 -0
  954. scipy/signal/_peak_finding.py +1310 -0
  955. scipy/signal/_peak_finding_utils.cp313-win_arm64.lib +0 -0
  956. scipy/signal/_peak_finding_utils.cp313-win_arm64.pyd +0 -0
  957. scipy/signal/_polyutils.py +172 -0
  958. scipy/signal/_savitzky_golay.py +357 -0
  959. scipy/signal/_short_time_fft.py +2228 -0
  960. scipy/signal/_signal_api.py +30 -0
  961. scipy/signal/_signaltools.py +5309 -0
  962. scipy/signal/_sigtools.cp313-win_arm64.lib +0 -0
  963. scipy/signal/_sigtools.cp313-win_arm64.pyd +0 -0
  964. scipy/signal/_sosfilt.cp313-win_arm64.lib +0 -0
  965. scipy/signal/_sosfilt.cp313-win_arm64.pyd +0 -0
  966. scipy/signal/_spectral_py.py +2471 -0
  967. scipy/signal/_spline.cp313-win_arm64.lib +0 -0
  968. scipy/signal/_spline.cp313-win_arm64.pyd +0 -0
  969. scipy/signal/_spline.pyi +34 -0
  970. scipy/signal/_spline_filters.py +848 -0
  971. scipy/signal/_support_alternative_backends.py +73 -0
  972. scipy/signal/_upfirdn.py +219 -0
  973. scipy/signal/_upfirdn_apply.cp313-win_arm64.lib +0 -0
  974. scipy/signal/_upfirdn_apply.cp313-win_arm64.pyd +0 -0
  975. scipy/signal/_waveforms.py +687 -0
  976. scipy/signal/_wavelets.py +29 -0
  977. scipy/signal/bsplines.py +21 -0
  978. scipy/signal/filter_design.py +28 -0
  979. scipy/signal/fir_filter_design.py +21 -0
  980. scipy/signal/lti_conversion.py +20 -0
  981. scipy/signal/ltisys.py +25 -0
  982. scipy/signal/signaltools.py +27 -0
  983. scipy/signal/spectral.py +21 -0
  984. scipy/signal/spline.py +18 -0
  985. scipy/signal/tests/__init__.py +0 -0
  986. scipy/signal/tests/_scipy_spectral_test_shim.py +311 -0
  987. scipy/signal/tests/mpsig.py +122 -0
  988. scipy/signal/tests/test_array_tools.py +111 -0
  989. scipy/signal/tests/test_bsplines.py +365 -0
  990. scipy/signal/tests/test_cont2discrete.py +424 -0
  991. scipy/signal/tests/test_czt.py +221 -0
  992. scipy/signal/tests/test_dltisys.py +599 -0
  993. scipy/signal/tests/test_filter_design.py +4744 -0
  994. scipy/signal/tests/test_fir_filter_design.py +851 -0
  995. scipy/signal/tests/test_ltisys.py +1225 -0
  996. scipy/signal/tests/test_max_len_seq.py +71 -0
  997. scipy/signal/tests/test_peak_finding.py +915 -0
  998. scipy/signal/tests/test_result_type.py +51 -0
  999. scipy/signal/tests/test_savitzky_golay.py +363 -0
  1000. scipy/signal/tests/test_short_time_fft.py +1107 -0
  1001. scipy/signal/tests/test_signaltools.py +4735 -0
  1002. scipy/signal/tests/test_spectral.py +2141 -0
  1003. scipy/signal/tests/test_splines.py +427 -0
  1004. scipy/signal/tests/test_upfirdn.py +322 -0
  1005. scipy/signal/tests/test_waveforms.py +400 -0
  1006. scipy/signal/tests/test_wavelets.py +59 -0
  1007. scipy/signal/tests/test_windows.py +987 -0
  1008. scipy/signal/waveforms.py +20 -0
  1009. scipy/signal/wavelets.py +17 -0
  1010. scipy/signal/windows/__init__.py +52 -0
  1011. scipy/signal/windows/_windows.py +2513 -0
  1012. scipy/signal/windows/windows.py +23 -0
  1013. scipy/sparse/__init__.py +350 -0
  1014. scipy/sparse/_base.py +1613 -0
  1015. scipy/sparse/_bsr.py +880 -0
  1016. scipy/sparse/_compressed.py +1328 -0
  1017. scipy/sparse/_construct.py +1454 -0
  1018. scipy/sparse/_coo.py +1581 -0
  1019. scipy/sparse/_csc.py +367 -0
  1020. scipy/sparse/_csparsetools.cp313-win_arm64.lib +0 -0
  1021. scipy/sparse/_csparsetools.cp313-win_arm64.pyd +0 -0
  1022. scipy/sparse/_csr.py +558 -0
  1023. scipy/sparse/_data.py +569 -0
  1024. scipy/sparse/_dia.py +677 -0
  1025. scipy/sparse/_dok.py +669 -0
  1026. scipy/sparse/_extract.py +178 -0
  1027. scipy/sparse/_index.py +444 -0
  1028. scipy/sparse/_lil.py +632 -0
  1029. scipy/sparse/_matrix.py +169 -0
  1030. scipy/sparse/_matrix_io.py +167 -0
  1031. scipy/sparse/_sparsetools.cp313-win_arm64.lib +0 -0
  1032. scipy/sparse/_sparsetools.cp313-win_arm64.pyd +0 -0
  1033. scipy/sparse/_spfuncs.py +76 -0
  1034. scipy/sparse/_sputils.py +632 -0
  1035. scipy/sparse/base.py +24 -0
  1036. scipy/sparse/bsr.py +22 -0
  1037. scipy/sparse/compressed.py +20 -0
  1038. scipy/sparse/construct.py +38 -0
  1039. scipy/sparse/coo.py +23 -0
  1040. scipy/sparse/csc.py +22 -0
  1041. scipy/sparse/csgraph/__init__.py +210 -0
  1042. scipy/sparse/csgraph/_flow.cp313-win_arm64.lib +0 -0
  1043. scipy/sparse/csgraph/_flow.cp313-win_arm64.pyd +0 -0
  1044. scipy/sparse/csgraph/_laplacian.py +563 -0
  1045. scipy/sparse/csgraph/_matching.cp313-win_arm64.lib +0 -0
  1046. scipy/sparse/csgraph/_matching.cp313-win_arm64.pyd +0 -0
  1047. scipy/sparse/csgraph/_min_spanning_tree.cp313-win_arm64.lib +0 -0
  1048. scipy/sparse/csgraph/_min_spanning_tree.cp313-win_arm64.pyd +0 -0
  1049. scipy/sparse/csgraph/_reordering.cp313-win_arm64.lib +0 -0
  1050. scipy/sparse/csgraph/_reordering.cp313-win_arm64.pyd +0 -0
  1051. scipy/sparse/csgraph/_shortest_path.cp313-win_arm64.lib +0 -0
  1052. scipy/sparse/csgraph/_shortest_path.cp313-win_arm64.pyd +0 -0
  1053. scipy/sparse/csgraph/_tools.cp313-win_arm64.lib +0 -0
  1054. scipy/sparse/csgraph/_tools.cp313-win_arm64.pyd +0 -0
  1055. scipy/sparse/csgraph/_traversal.cp313-win_arm64.lib +0 -0
  1056. scipy/sparse/csgraph/_traversal.cp313-win_arm64.pyd +0 -0
  1057. scipy/sparse/csgraph/_validation.py +66 -0
  1058. scipy/sparse/csgraph/tests/__init__.py +0 -0
  1059. scipy/sparse/csgraph/tests/test_connected_components.py +119 -0
  1060. scipy/sparse/csgraph/tests/test_conversions.py +61 -0
  1061. scipy/sparse/csgraph/tests/test_flow.py +209 -0
  1062. scipy/sparse/csgraph/tests/test_graph_laplacian.py +368 -0
  1063. scipy/sparse/csgraph/tests/test_matching.py +307 -0
  1064. scipy/sparse/csgraph/tests/test_pydata_sparse.py +197 -0
  1065. scipy/sparse/csgraph/tests/test_reordering.py +70 -0
  1066. scipy/sparse/csgraph/tests/test_shortest_path.py +540 -0
  1067. scipy/sparse/csgraph/tests/test_spanning_tree.py +66 -0
  1068. scipy/sparse/csgraph/tests/test_traversal.py +148 -0
  1069. scipy/sparse/csr.py +22 -0
  1070. scipy/sparse/data.py +18 -0
  1071. scipy/sparse/dia.py +22 -0
  1072. scipy/sparse/dok.py +22 -0
  1073. scipy/sparse/extract.py +23 -0
  1074. scipy/sparse/lil.py +22 -0
  1075. scipy/sparse/linalg/__init__.py +148 -0
  1076. scipy/sparse/linalg/_dsolve/__init__.py +71 -0
  1077. scipy/sparse/linalg/_dsolve/_add_newdocs.py +147 -0
  1078. scipy/sparse/linalg/_dsolve/_superlu.cp313-win_arm64.lib +0 -0
  1079. scipy/sparse/linalg/_dsolve/_superlu.cp313-win_arm64.pyd +0 -0
  1080. scipy/sparse/linalg/_dsolve/linsolve.py +882 -0
  1081. scipy/sparse/linalg/_dsolve/tests/__init__.py +0 -0
  1082. scipy/sparse/linalg/_dsolve/tests/test_linsolve.py +928 -0
  1083. scipy/sparse/linalg/_eigen/__init__.py +22 -0
  1084. scipy/sparse/linalg/_eigen/_svds.py +540 -0
  1085. scipy/sparse/linalg/_eigen/_svds_doc.py +382 -0
  1086. scipy/sparse/linalg/_eigen/arpack/COPYING +45 -0
  1087. scipy/sparse/linalg/_eigen/arpack/__init__.py +20 -0
  1088. scipy/sparse/linalg/_eigen/arpack/_arpack.cp313-win_arm64.lib +0 -0
  1089. scipy/sparse/linalg/_eigen/arpack/_arpack.cp313-win_arm64.pyd +0 -0
  1090. scipy/sparse/linalg/_eigen/arpack/arpack.py +1706 -0
  1091. scipy/sparse/linalg/_eigen/arpack/tests/__init__.py +0 -0
  1092. scipy/sparse/linalg/_eigen/arpack/tests/test_arpack.py +717 -0
  1093. scipy/sparse/linalg/_eigen/lobpcg/__init__.py +16 -0
  1094. scipy/sparse/linalg/_eigen/lobpcg/lobpcg.py +1110 -0
  1095. scipy/sparse/linalg/_eigen/lobpcg/tests/__init__.py +0 -0
  1096. scipy/sparse/linalg/_eigen/lobpcg/tests/test_lobpcg.py +725 -0
  1097. scipy/sparse/linalg/_eigen/tests/__init__.py +0 -0
  1098. scipy/sparse/linalg/_eigen/tests/test_svds.py +886 -0
  1099. scipy/sparse/linalg/_expm_multiply.py +816 -0
  1100. scipy/sparse/linalg/_interface.py +920 -0
  1101. scipy/sparse/linalg/_isolve/__init__.py +20 -0
  1102. scipy/sparse/linalg/_isolve/_gcrotmk.py +503 -0
  1103. scipy/sparse/linalg/_isolve/iterative.py +1051 -0
  1104. scipy/sparse/linalg/_isolve/lgmres.py +230 -0
  1105. scipy/sparse/linalg/_isolve/lsmr.py +486 -0
  1106. scipy/sparse/linalg/_isolve/lsqr.py +589 -0
  1107. scipy/sparse/linalg/_isolve/minres.py +372 -0
  1108. scipy/sparse/linalg/_isolve/tests/__init__.py +0 -0
  1109. scipy/sparse/linalg/_isolve/tests/test_gcrotmk.py +183 -0
  1110. scipy/sparse/linalg/_isolve/tests/test_iterative.py +809 -0
  1111. scipy/sparse/linalg/_isolve/tests/test_lgmres.py +225 -0
  1112. scipy/sparse/linalg/_isolve/tests/test_lsmr.py +185 -0
  1113. scipy/sparse/linalg/_isolve/tests/test_lsqr.py +120 -0
  1114. scipy/sparse/linalg/_isolve/tests/test_minres.py +97 -0
  1115. scipy/sparse/linalg/_isolve/tests/test_utils.py +9 -0
  1116. scipy/sparse/linalg/_isolve/tfqmr.py +179 -0
  1117. scipy/sparse/linalg/_isolve/utils.py +121 -0
  1118. scipy/sparse/linalg/_matfuncs.py +940 -0
  1119. scipy/sparse/linalg/_norm.py +195 -0
  1120. scipy/sparse/linalg/_onenormest.py +467 -0
  1121. scipy/sparse/linalg/_propack/_cpropack.cp313-win_arm64.lib +0 -0
  1122. scipy/sparse/linalg/_propack/_cpropack.cp313-win_arm64.pyd +0 -0
  1123. scipy/sparse/linalg/_propack/_dpropack.cp313-win_arm64.lib +0 -0
  1124. scipy/sparse/linalg/_propack/_dpropack.cp313-win_arm64.pyd +0 -0
  1125. scipy/sparse/linalg/_propack/_spropack.cp313-win_arm64.lib +0 -0
  1126. scipy/sparse/linalg/_propack/_spropack.cp313-win_arm64.pyd +0 -0
  1127. scipy/sparse/linalg/_propack/_zpropack.cp313-win_arm64.lib +0 -0
  1128. scipy/sparse/linalg/_propack/_zpropack.cp313-win_arm64.pyd +0 -0
  1129. scipy/sparse/linalg/_special_sparse_arrays.py +949 -0
  1130. scipy/sparse/linalg/_svdp.py +309 -0
  1131. scipy/sparse/linalg/dsolve.py +22 -0
  1132. scipy/sparse/linalg/eigen.py +21 -0
  1133. scipy/sparse/linalg/interface.py +20 -0
  1134. scipy/sparse/linalg/isolve.py +22 -0
  1135. scipy/sparse/linalg/matfuncs.py +18 -0
  1136. scipy/sparse/linalg/tests/__init__.py +0 -0
  1137. scipy/sparse/linalg/tests/propack_test_data.npz +0 -0
  1138. scipy/sparse/linalg/tests/test_expm_multiply.py +367 -0
  1139. scipy/sparse/linalg/tests/test_interface.py +561 -0
  1140. scipy/sparse/linalg/tests/test_matfuncs.py +592 -0
  1141. scipy/sparse/linalg/tests/test_norm.py +154 -0
  1142. scipy/sparse/linalg/tests/test_onenormest.py +252 -0
  1143. scipy/sparse/linalg/tests/test_propack.py +165 -0
  1144. scipy/sparse/linalg/tests/test_pydata_sparse.py +272 -0
  1145. scipy/sparse/linalg/tests/test_special_sparse_arrays.py +337 -0
  1146. scipy/sparse/sparsetools.py +17 -0
  1147. scipy/sparse/spfuncs.py +17 -0
  1148. scipy/sparse/sputils.py +17 -0
  1149. scipy/sparse/tests/__init__.py +0 -0
  1150. scipy/sparse/tests/data/csc_py2.npz +0 -0
  1151. scipy/sparse/tests/data/csc_py3.npz +0 -0
  1152. scipy/sparse/tests/test_arithmetic1d.py +341 -0
  1153. scipy/sparse/tests/test_array_api.py +561 -0
  1154. scipy/sparse/tests/test_base.py +5870 -0
  1155. scipy/sparse/tests/test_common1d.py +447 -0
  1156. scipy/sparse/tests/test_construct.py +872 -0
  1157. scipy/sparse/tests/test_coo.py +1119 -0
  1158. scipy/sparse/tests/test_csc.py +98 -0
  1159. scipy/sparse/tests/test_csr.py +214 -0
  1160. scipy/sparse/tests/test_dok.py +209 -0
  1161. scipy/sparse/tests/test_extract.py +51 -0
  1162. scipy/sparse/tests/test_indexing1d.py +603 -0
  1163. scipy/sparse/tests/test_matrix_io.py +109 -0
  1164. scipy/sparse/tests/test_minmax1d.py +128 -0
  1165. scipy/sparse/tests/test_sparsetools.py +344 -0
  1166. scipy/sparse/tests/test_spfuncs.py +97 -0
  1167. scipy/sparse/tests/test_sputils.py +424 -0
  1168. scipy/spatial/__init__.py +129 -0
  1169. scipy/spatial/_ckdtree.cp313-win_arm64.lib +0 -0
  1170. scipy/spatial/_ckdtree.cp313-win_arm64.pyd +0 -0
  1171. scipy/spatial/_distance_pybind.cp313-win_arm64.lib +0 -0
  1172. scipy/spatial/_distance_pybind.cp313-win_arm64.pyd +0 -0
  1173. scipy/spatial/_distance_wrap.cp313-win_arm64.lib +0 -0
  1174. scipy/spatial/_distance_wrap.cp313-win_arm64.pyd +0 -0
  1175. scipy/spatial/_geometric_slerp.py +238 -0
  1176. scipy/spatial/_hausdorff.cp313-win_arm64.lib +0 -0
  1177. scipy/spatial/_hausdorff.cp313-win_arm64.pyd +0 -0
  1178. scipy/spatial/_kdtree.py +920 -0
  1179. scipy/spatial/_plotutils.py +274 -0
  1180. scipy/spatial/_procrustes.py +132 -0
  1181. scipy/spatial/_qhull.cp313-win_arm64.lib +0 -0
  1182. scipy/spatial/_qhull.cp313-win_arm64.pyd +0 -0
  1183. scipy/spatial/_qhull.pyi +213 -0
  1184. scipy/spatial/_spherical_voronoi.py +341 -0
  1185. scipy/spatial/_voronoi.cp313-win_arm64.lib +0 -0
  1186. scipy/spatial/_voronoi.cp313-win_arm64.pyd +0 -0
  1187. scipy/spatial/_voronoi.pyi +4 -0
  1188. scipy/spatial/ckdtree.py +18 -0
  1189. scipy/spatial/distance.py +3147 -0
  1190. scipy/spatial/distance.pyi +210 -0
  1191. scipy/spatial/kdtree.py +25 -0
  1192. scipy/spatial/qhull.py +25 -0
  1193. scipy/spatial/qhull_src/COPYING_QHULL.txt +39 -0
  1194. scipy/spatial/tests/__init__.py +0 -0
  1195. scipy/spatial/tests/data/cdist-X1.txt +10 -0
  1196. scipy/spatial/tests/data/cdist-X2.txt +20 -0
  1197. scipy/spatial/tests/data/degenerate_pointset.npz +0 -0
  1198. scipy/spatial/tests/data/iris.txt +150 -0
  1199. scipy/spatial/tests/data/pdist-boolean-inp.txt +20 -0
  1200. scipy/spatial/tests/data/pdist-chebyshev-ml-iris.txt +1 -0
  1201. scipy/spatial/tests/data/pdist-chebyshev-ml.txt +1 -0
  1202. scipy/spatial/tests/data/pdist-cityblock-ml-iris.txt +1 -0
  1203. scipy/spatial/tests/data/pdist-cityblock-ml.txt +1 -0
  1204. scipy/spatial/tests/data/pdist-correlation-ml-iris.txt +1 -0
  1205. scipy/spatial/tests/data/pdist-correlation-ml.txt +1 -0
  1206. scipy/spatial/tests/data/pdist-cosine-ml-iris.txt +1 -0
  1207. scipy/spatial/tests/data/pdist-cosine-ml.txt +1 -0
  1208. scipy/spatial/tests/data/pdist-double-inp.txt +20 -0
  1209. scipy/spatial/tests/data/pdist-euclidean-ml-iris.txt +1 -0
  1210. scipy/spatial/tests/data/pdist-euclidean-ml.txt +1 -0
  1211. scipy/spatial/tests/data/pdist-hamming-ml.txt +1 -0
  1212. scipy/spatial/tests/data/pdist-jaccard-ml.txt +1 -0
  1213. scipy/spatial/tests/data/pdist-jensenshannon-ml-iris.txt +1 -0
  1214. scipy/spatial/tests/data/pdist-jensenshannon-ml.txt +1 -0
  1215. scipy/spatial/tests/data/pdist-minkowski-3.2-ml-iris.txt +1 -0
  1216. scipy/spatial/tests/data/pdist-minkowski-3.2-ml.txt +1 -0
  1217. scipy/spatial/tests/data/pdist-minkowski-5.8-ml-iris.txt +1 -0
  1218. scipy/spatial/tests/data/pdist-seuclidean-ml-iris.txt +1 -0
  1219. scipy/spatial/tests/data/pdist-seuclidean-ml.txt +1 -0
  1220. scipy/spatial/tests/data/pdist-spearman-ml.txt +1 -0
  1221. scipy/spatial/tests/data/random-bool-data.txt +100 -0
  1222. scipy/spatial/tests/data/random-double-data.txt +100 -0
  1223. scipy/spatial/tests/data/random-int-data.txt +100 -0
  1224. scipy/spatial/tests/data/random-uint-data.txt +100 -0
  1225. scipy/spatial/tests/data/selfdual-4d-polytope.txt +27 -0
  1226. scipy/spatial/tests/test__plotutils.py +91 -0
  1227. scipy/spatial/tests/test__procrustes.py +116 -0
  1228. scipy/spatial/tests/test_distance.py +2389 -0
  1229. scipy/spatial/tests/test_hausdorff.py +199 -0
  1230. scipy/spatial/tests/test_kdtree.py +1536 -0
  1231. scipy/spatial/tests/test_qhull.py +1313 -0
  1232. scipy/spatial/tests/test_slerp.py +417 -0
  1233. scipy/spatial/tests/test_spherical_voronoi.py +358 -0
  1234. scipy/spatial/transform/__init__.py +31 -0
  1235. scipy/spatial/transform/_rigid_transform.cp313-win_arm64.lib +0 -0
  1236. scipy/spatial/transform/_rigid_transform.cp313-win_arm64.pyd +0 -0
  1237. scipy/spatial/transform/_rotation.cp313-win_arm64.lib +0 -0
  1238. scipy/spatial/transform/_rotation.cp313-win_arm64.pyd +0 -0
  1239. scipy/spatial/transform/_rotation_groups.py +140 -0
  1240. scipy/spatial/transform/_rotation_spline.py +460 -0
  1241. scipy/spatial/transform/rotation.py +21 -0
  1242. scipy/spatial/transform/tests/__init__.py +0 -0
  1243. scipy/spatial/transform/tests/test_rigid_transform.py +1221 -0
  1244. scipy/spatial/transform/tests/test_rotation.py +2569 -0
  1245. scipy/spatial/transform/tests/test_rotation_groups.py +169 -0
  1246. scipy/spatial/transform/tests/test_rotation_spline.py +183 -0
  1247. scipy/special/__init__.pxd +1 -0
  1248. scipy/special/__init__.py +841 -0
  1249. scipy/special/_add_newdocs.py +9961 -0
  1250. scipy/special/_basic.py +3576 -0
  1251. scipy/special/_comb.cp313-win_arm64.lib +0 -0
  1252. scipy/special/_comb.cp313-win_arm64.pyd +0 -0
  1253. scipy/special/_ellip_harm.py +214 -0
  1254. scipy/special/_ellip_harm_2.cp313-win_arm64.lib +0 -0
  1255. scipy/special/_ellip_harm_2.cp313-win_arm64.pyd +0 -0
  1256. scipy/special/_gufuncs.cp313-win_arm64.lib +0 -0
  1257. scipy/special/_gufuncs.cp313-win_arm64.pyd +0 -0
  1258. scipy/special/_input_validation.py +17 -0
  1259. scipy/special/_lambertw.py +149 -0
  1260. scipy/special/_logsumexp.py +426 -0
  1261. scipy/special/_mptestutils.py +453 -0
  1262. scipy/special/_multiufuncs.py +610 -0
  1263. scipy/special/_orthogonal.py +2592 -0
  1264. scipy/special/_orthogonal.pyi +330 -0
  1265. scipy/special/_precompute/__init__.py +0 -0
  1266. scipy/special/_precompute/cosine_cdf.py +17 -0
  1267. scipy/special/_precompute/expn_asy.py +54 -0
  1268. scipy/special/_precompute/gammainc_asy.py +116 -0
  1269. scipy/special/_precompute/gammainc_data.py +124 -0
  1270. scipy/special/_precompute/hyp2f1_data.py +484 -0
  1271. scipy/special/_precompute/lambertw.py +68 -0
  1272. scipy/special/_precompute/loggamma.py +43 -0
  1273. scipy/special/_precompute/struve_convergence.py +131 -0
  1274. scipy/special/_precompute/utils.py +38 -0
  1275. scipy/special/_precompute/wright_bessel.py +342 -0
  1276. scipy/special/_precompute/wright_bessel_data.py +152 -0
  1277. scipy/special/_precompute/wrightomega.py +41 -0
  1278. scipy/special/_precompute/zetac.py +27 -0
  1279. scipy/special/_sf_error.py +15 -0
  1280. scipy/special/_specfun.cp313-win_arm64.lib +0 -0
  1281. scipy/special/_specfun.cp313-win_arm64.pyd +0 -0
  1282. scipy/special/_special_ufuncs.cp313-win_arm64.lib +0 -0
  1283. scipy/special/_special_ufuncs.cp313-win_arm64.pyd +0 -0
  1284. scipy/special/_spfun_stats.py +106 -0
  1285. scipy/special/_spherical_bessel.py +397 -0
  1286. scipy/special/_support_alternative_backends.py +295 -0
  1287. scipy/special/_test_internal.cp313-win_arm64.lib +0 -0
  1288. scipy/special/_test_internal.cp313-win_arm64.pyd +0 -0
  1289. scipy/special/_test_internal.pyi +9 -0
  1290. scipy/special/_testutils.py +321 -0
  1291. scipy/special/_ufuncs.cp313-win_arm64.lib +0 -0
  1292. scipy/special/_ufuncs.cp313-win_arm64.pyd +0 -0
  1293. scipy/special/_ufuncs.pyi +522 -0
  1294. scipy/special/_ufuncs.pyx +13173 -0
  1295. scipy/special/_ufuncs_cxx.cp313-win_arm64.lib +0 -0
  1296. scipy/special/_ufuncs_cxx.cp313-win_arm64.pyd +0 -0
  1297. scipy/special/_ufuncs_cxx.pxd +142 -0
  1298. scipy/special/_ufuncs_cxx.pyx +427 -0
  1299. scipy/special/_ufuncs_cxx_defs.h +147 -0
  1300. scipy/special/_ufuncs_defs.h +57 -0
  1301. scipy/special/add_newdocs.py +15 -0
  1302. scipy/special/basic.py +87 -0
  1303. scipy/special/cython_special.cp313-win_arm64.lib +0 -0
  1304. scipy/special/cython_special.cp313-win_arm64.pyd +0 -0
  1305. scipy/special/cython_special.pxd +259 -0
  1306. scipy/special/cython_special.pyi +3 -0
  1307. scipy/special/orthogonal.py +45 -0
  1308. scipy/special/sf_error.py +20 -0
  1309. scipy/special/specfun.py +24 -0
  1310. scipy/special/spfun_stats.py +17 -0
  1311. scipy/special/tests/__init__.py +0 -0
  1312. scipy/special/tests/_cython_examples/extending.pyx +12 -0
  1313. scipy/special/tests/_cython_examples/meson.build +34 -0
  1314. scipy/special/tests/data/__init__.py +0 -0
  1315. scipy/special/tests/data/boost.npz +0 -0
  1316. scipy/special/tests/data/gsl.npz +0 -0
  1317. scipy/special/tests/data/local.npz +0 -0
  1318. scipy/special/tests/test_basic.py +4815 -0
  1319. scipy/special/tests/test_bdtr.py +112 -0
  1320. scipy/special/tests/test_boost_ufuncs.py +64 -0
  1321. scipy/special/tests/test_boxcox.py +125 -0
  1322. scipy/special/tests/test_cdflib.py +712 -0
  1323. scipy/special/tests/test_cdft_asymptotic.py +49 -0
  1324. scipy/special/tests/test_cephes_intp_cast.py +29 -0
  1325. scipy/special/tests/test_cosine_distr.py +83 -0
  1326. scipy/special/tests/test_cython_special.py +363 -0
  1327. scipy/special/tests/test_data.py +719 -0
  1328. scipy/special/tests/test_dd.py +42 -0
  1329. scipy/special/tests/test_digamma.py +45 -0
  1330. scipy/special/tests/test_ellip_harm.py +278 -0
  1331. scipy/special/tests/test_erfinv.py +89 -0
  1332. scipy/special/tests/test_exponential_integrals.py +118 -0
  1333. scipy/special/tests/test_extending.py +28 -0
  1334. scipy/special/tests/test_faddeeva.py +85 -0
  1335. scipy/special/tests/test_gamma.py +12 -0
  1336. scipy/special/tests/test_gammainc.py +152 -0
  1337. scipy/special/tests/test_hyp2f1.py +2566 -0
  1338. scipy/special/tests/test_hypergeometric.py +234 -0
  1339. scipy/special/tests/test_iv_ratio.py +249 -0
  1340. scipy/special/tests/test_kolmogorov.py +491 -0
  1341. scipy/special/tests/test_lambertw.py +109 -0
  1342. scipy/special/tests/test_legendre.py +1518 -0
  1343. scipy/special/tests/test_log1mexp.py +85 -0
  1344. scipy/special/tests/test_loggamma.py +70 -0
  1345. scipy/special/tests/test_logit.py +162 -0
  1346. scipy/special/tests/test_logsumexp.py +469 -0
  1347. scipy/special/tests/test_mpmath.py +2293 -0
  1348. scipy/special/tests/test_nan_inputs.py +65 -0
  1349. scipy/special/tests/test_ndtr.py +77 -0
  1350. scipy/special/tests/test_ndtri_exp.py +94 -0
  1351. scipy/special/tests/test_orthogonal.py +821 -0
  1352. scipy/special/tests/test_orthogonal_eval.py +275 -0
  1353. scipy/special/tests/test_owens_t.py +53 -0
  1354. scipy/special/tests/test_pcf.py +24 -0
  1355. scipy/special/tests/test_pdtr.py +48 -0
  1356. scipy/special/tests/test_powm1.py +65 -0
  1357. scipy/special/tests/test_precompute_expn_asy.py +24 -0
  1358. scipy/special/tests/test_precompute_gammainc.py +108 -0
  1359. scipy/special/tests/test_precompute_utils.py +36 -0
  1360. scipy/special/tests/test_round.py +18 -0
  1361. scipy/special/tests/test_sf_error.py +146 -0
  1362. scipy/special/tests/test_sici.py +36 -0
  1363. scipy/special/tests/test_specfun.py +48 -0
  1364. scipy/special/tests/test_spence.py +32 -0
  1365. scipy/special/tests/test_spfun_stats.py +61 -0
  1366. scipy/special/tests/test_sph_harm.py +85 -0
  1367. scipy/special/tests/test_spherical_bessel.py +400 -0
  1368. scipy/special/tests/test_support_alternative_backends.py +248 -0
  1369. scipy/special/tests/test_trig.py +72 -0
  1370. scipy/special/tests/test_ufunc_signatures.py +46 -0
  1371. scipy/special/tests/test_wright_bessel.py +205 -0
  1372. scipy/special/tests/test_wrightomega.py +117 -0
  1373. scipy/special/tests/test_zeta.py +301 -0
  1374. scipy/stats/__init__.py +670 -0
  1375. scipy/stats/_ansari_swilk_statistics.cp313-win_arm64.lib +0 -0
  1376. scipy/stats/_ansari_swilk_statistics.cp313-win_arm64.pyd +0 -0
  1377. scipy/stats/_axis_nan_policy.py +692 -0
  1378. scipy/stats/_biasedurn.cp313-win_arm64.lib +0 -0
  1379. scipy/stats/_biasedurn.cp313-win_arm64.pyd +0 -0
  1380. scipy/stats/_biasedurn.pxd +27 -0
  1381. scipy/stats/_binned_statistic.py +795 -0
  1382. scipy/stats/_binomtest.py +375 -0
  1383. scipy/stats/_bws_test.py +177 -0
  1384. scipy/stats/_censored_data.py +459 -0
  1385. scipy/stats/_common.py +5 -0
  1386. scipy/stats/_constants.py +42 -0
  1387. scipy/stats/_continued_fraction.py +387 -0
  1388. scipy/stats/_continuous_distns.py +12486 -0
  1389. scipy/stats/_correlation.py +210 -0
  1390. scipy/stats/_covariance.py +636 -0
  1391. scipy/stats/_crosstab.py +204 -0
  1392. scipy/stats/_discrete_distns.py +2098 -0
  1393. scipy/stats/_distn_infrastructure.py +4201 -0
  1394. scipy/stats/_distr_params.py +299 -0
  1395. scipy/stats/_distribution_infrastructure.py +5750 -0
  1396. scipy/stats/_entropy.py +428 -0
  1397. scipy/stats/_finite_differences.py +145 -0
  1398. scipy/stats/_fit.py +1351 -0
  1399. scipy/stats/_hypotests.py +2060 -0
  1400. scipy/stats/_kde.py +732 -0
  1401. scipy/stats/_ksstats.py +600 -0
  1402. scipy/stats/_levy_stable/__init__.py +1231 -0
  1403. scipy/stats/_levy_stable/levyst.cp313-win_arm64.lib +0 -0
  1404. scipy/stats/_levy_stable/levyst.cp313-win_arm64.pyd +0 -0
  1405. scipy/stats/_mannwhitneyu.py +492 -0
  1406. scipy/stats/_mgc.py +550 -0
  1407. scipy/stats/_morestats.py +4626 -0
  1408. scipy/stats/_mstats_basic.py +3658 -0
  1409. scipy/stats/_mstats_extras.py +521 -0
  1410. scipy/stats/_multicomp.py +449 -0
  1411. scipy/stats/_multivariate.py +7281 -0
  1412. scipy/stats/_new_distributions.py +452 -0
  1413. scipy/stats/_odds_ratio.py +466 -0
  1414. scipy/stats/_page_trend_test.py +486 -0
  1415. scipy/stats/_probability_distribution.py +1964 -0
  1416. scipy/stats/_qmc.py +2956 -0
  1417. scipy/stats/_qmc_cy.cp313-win_arm64.lib +0 -0
  1418. scipy/stats/_qmc_cy.cp313-win_arm64.pyd +0 -0
  1419. scipy/stats/_qmc_cy.pyi +54 -0
  1420. scipy/stats/_qmvnt.py +454 -0
  1421. scipy/stats/_qmvnt_cy.cp313-win_arm64.lib +0 -0
  1422. scipy/stats/_qmvnt_cy.cp313-win_arm64.pyd +0 -0
  1423. scipy/stats/_quantile.py +335 -0
  1424. scipy/stats/_rcont/__init__.py +4 -0
  1425. scipy/stats/_rcont/rcont.cp313-win_arm64.lib +0 -0
  1426. scipy/stats/_rcont/rcont.cp313-win_arm64.pyd +0 -0
  1427. scipy/stats/_relative_risk.py +263 -0
  1428. scipy/stats/_resampling.py +2352 -0
  1429. scipy/stats/_result_classes.py +40 -0
  1430. scipy/stats/_sampling.py +1314 -0
  1431. scipy/stats/_sensitivity_analysis.py +713 -0
  1432. scipy/stats/_sobol.cp313-win_arm64.lib +0 -0
  1433. scipy/stats/_sobol.cp313-win_arm64.pyd +0 -0
  1434. scipy/stats/_sobol.pyi +54 -0
  1435. scipy/stats/_sobol_direction_numbers.npz +0 -0
  1436. scipy/stats/_stats.cp313-win_arm64.lib +0 -0
  1437. scipy/stats/_stats.cp313-win_arm64.pyd +0 -0
  1438. scipy/stats/_stats.pxd +10 -0
  1439. scipy/stats/_stats_mstats_common.py +322 -0
  1440. scipy/stats/_stats_py.py +11089 -0
  1441. scipy/stats/_stats_pythran.cp313-win_arm64.lib +0 -0
  1442. scipy/stats/_stats_pythran.cp313-win_arm64.pyd +0 -0
  1443. scipy/stats/_survival.py +683 -0
  1444. scipy/stats/_tukeylambda_stats.py +199 -0
  1445. scipy/stats/_unuran/__init__.py +0 -0
  1446. scipy/stats/_unuran/unuran_wrapper.cp313-win_arm64.lib +0 -0
  1447. scipy/stats/_unuran/unuran_wrapper.cp313-win_arm64.pyd +0 -0
  1448. scipy/stats/_unuran/unuran_wrapper.pyi +179 -0
  1449. scipy/stats/_variation.py +126 -0
  1450. scipy/stats/_warnings_errors.py +38 -0
  1451. scipy/stats/_wilcoxon.py +265 -0
  1452. scipy/stats/biasedurn.py +16 -0
  1453. scipy/stats/contingency.py +521 -0
  1454. scipy/stats/distributions.py +24 -0
  1455. scipy/stats/kde.py +18 -0
  1456. scipy/stats/morestats.py +27 -0
  1457. scipy/stats/mstats.py +140 -0
  1458. scipy/stats/mstats_basic.py +42 -0
  1459. scipy/stats/mstats_extras.py +25 -0
  1460. scipy/stats/mvn.py +17 -0
  1461. scipy/stats/qmc.py +236 -0
  1462. scipy/stats/sampling.py +73 -0
  1463. scipy/stats/stats.py +41 -0
  1464. scipy/stats/tests/__init__.py +0 -0
  1465. scipy/stats/tests/common_tests.py +356 -0
  1466. scipy/stats/tests/data/_mvt.py +171 -0
  1467. scipy/stats/tests/data/fisher_exact_results_from_r.py +607 -0
  1468. scipy/stats/tests/data/jf_skew_t_gamlss_pdf_data.npy +0 -0
  1469. scipy/stats/tests/data/levy_stable/stable-Z1-cdf-sample-data.npy +0 -0
  1470. scipy/stats/tests/data/levy_stable/stable-Z1-pdf-sample-data.npy +0 -0
  1471. scipy/stats/tests/data/levy_stable/stable-loc-scale-sample-data.npy +0 -0
  1472. scipy/stats/tests/data/nist_anova/AtmWtAg.dat +108 -0
  1473. scipy/stats/tests/data/nist_anova/SiRstv.dat +85 -0
  1474. scipy/stats/tests/data/nist_anova/SmLs01.dat +249 -0
  1475. scipy/stats/tests/data/nist_anova/SmLs02.dat +1869 -0
  1476. scipy/stats/tests/data/nist_anova/SmLs03.dat +18069 -0
  1477. scipy/stats/tests/data/nist_anova/SmLs04.dat +249 -0
  1478. scipy/stats/tests/data/nist_anova/SmLs05.dat +1869 -0
  1479. scipy/stats/tests/data/nist_anova/SmLs06.dat +18069 -0
  1480. scipy/stats/tests/data/nist_anova/SmLs07.dat +249 -0
  1481. scipy/stats/tests/data/nist_anova/SmLs08.dat +1869 -0
  1482. scipy/stats/tests/data/nist_anova/SmLs09.dat +18069 -0
  1483. scipy/stats/tests/data/nist_linregress/Norris.dat +97 -0
  1484. scipy/stats/tests/data/rel_breitwigner_pdf_sample_data_ROOT.npy +0 -0
  1485. scipy/stats/tests/data/studentized_range_mpmath_ref.json +1499 -0
  1486. scipy/stats/tests/test_axis_nan_policy.py +1388 -0
  1487. scipy/stats/tests/test_binned_statistic.py +568 -0
  1488. scipy/stats/tests/test_censored_data.py +152 -0
  1489. scipy/stats/tests/test_contingency.py +294 -0
  1490. scipy/stats/tests/test_continued_fraction.py +173 -0
  1491. scipy/stats/tests/test_continuous.py +2198 -0
  1492. scipy/stats/tests/test_continuous_basic.py +1053 -0
  1493. scipy/stats/tests/test_continuous_fit_censored.py +683 -0
  1494. scipy/stats/tests/test_correlation.py +80 -0
  1495. scipy/stats/tests/test_crosstab.py +115 -0
  1496. scipy/stats/tests/test_discrete_basic.py +580 -0
  1497. scipy/stats/tests/test_discrete_distns.py +700 -0
  1498. scipy/stats/tests/test_distributions.py +10413 -0
  1499. scipy/stats/tests/test_entropy.py +322 -0
  1500. scipy/stats/tests/test_fast_gen_inversion.py +435 -0
  1501. scipy/stats/tests/test_fit.py +1090 -0
  1502. scipy/stats/tests/test_hypotests.py +1991 -0
  1503. scipy/stats/tests/test_kdeoth.py +676 -0
  1504. scipy/stats/tests/test_marray.py +289 -0
  1505. scipy/stats/tests/test_mgc.py +217 -0
  1506. scipy/stats/tests/test_morestats.py +3259 -0
  1507. scipy/stats/tests/test_mstats_basic.py +2071 -0
  1508. scipy/stats/tests/test_mstats_extras.py +172 -0
  1509. scipy/stats/tests/test_multicomp.py +405 -0
  1510. scipy/stats/tests/test_multivariate.py +4381 -0
  1511. scipy/stats/tests/test_odds_ratio.py +148 -0
  1512. scipy/stats/tests/test_qmc.py +1492 -0
  1513. scipy/stats/tests/test_quantile.py +199 -0
  1514. scipy/stats/tests/test_rank.py +345 -0
  1515. scipy/stats/tests/test_relative_risk.py +95 -0
  1516. scipy/stats/tests/test_resampling.py +2000 -0
  1517. scipy/stats/tests/test_sampling.py +1450 -0
  1518. scipy/stats/tests/test_sensitivity_analysis.py +310 -0
  1519. scipy/stats/tests/test_stats.py +9707 -0
  1520. scipy/stats/tests/test_survival.py +466 -0
  1521. scipy/stats/tests/test_tukeylambda_stats.py +85 -0
  1522. scipy/stats/tests/test_variation.py +216 -0
  1523. scipy/version.py +12 -0
  1524. scipy-1.16.2.dist-info/DELVEWHEEL +2 -0
  1525. scipy-1.16.2.dist-info/LICENSE.txt +912 -0
  1526. scipy-1.16.2.dist-info/METADATA +1061 -0
  1527. scipy-1.16.2.dist-info/RECORD +1530 -0
  1528. scipy-1.16.2.dist-info/WHEEL +4 -0
  1529. scipy.libs/msvcp140-5f1c5dd31916990d94181e07bc3afb32.dll +0 -0
  1530. scipy.libs/scipy_openblas-f3ac85b1f412f7e86514c923dc4058d1.dll +0 -0
@@ -0,0 +1,3546 @@
1
+ """
2
+ ltisys -- a collection of classes and functions for modeling linear
3
+ time invariant systems.
4
+ """
5
+ #
6
+ # Author: Travis Oliphant 2001
7
+ #
8
+ # Feb 2010: Warren Weckesser
9
+ # Rewrote lsim2 and added impulse2.
10
+ # Apr 2011: Jeffrey Armstrong <jeff@approximatrix.com>
11
+ # Added dlsim, dstep, dimpulse, cont2discrete
12
+ # Aug 2013: Juan Luis Cano
13
+ # Rewrote abcd_normalize.
14
+ # Jan 2015: Irvin Probst irvin DOT probst AT ensta-bretagne DOT fr
15
+ # Added pole placement
16
+ # Mar 2015: Clancy Rowley
17
+ # Rewrote lsim
18
+ # May 2015: Felix Berkenkamp
19
+ # Split lti class into subclasses
20
+ # Merged discrete systems and added dlti
21
+
22
+ import warnings
23
+
24
+ # np.linalg.qr fails on some tests with LinAlgError: zgeqrf returns -7
25
+ # use scipy's qr until this is solved
26
+
27
+ from scipy.linalg import qr as s_qr
28
+ from scipy import linalg
29
+ from scipy.interpolate import make_interp_spline
30
+ from ._filter_design import (tf2zpk, zpk2tf, normalize, freqs, freqz, freqs_zpk,
31
+ freqz_zpk)
32
+ from ._lti_conversion import (tf2ss, abcd_normalize, ss2tf, zpk2ss, ss2zpk,
33
+ cont2discrete, _atleast_2d_or_none)
34
+
35
+ import numpy as np
36
+ from numpy import (real, atleast_1d, squeeze, asarray, zeros,
37
+ dot, transpose, ones, linspace)
38
+ import copy
39
+
40
+ __all__ = ['lti', 'dlti', 'TransferFunction', 'ZerosPolesGain', 'StateSpace',
41
+ 'lsim', 'impulse', 'step', 'bode',
42
+ 'freqresp', 'place_poles', 'dlsim', 'dstep', 'dimpulse',
43
+ 'dfreqresp', 'dbode']
44
+
45
+
46
+ class LinearTimeInvariant:
47
+ def __new__(cls, *system, **kwargs):
48
+ """Create a new object, don't allow direct instances."""
49
+ if cls is LinearTimeInvariant:
50
+ raise NotImplementedError('The LinearTimeInvariant class is not '
51
+ 'meant to be used directly, use `lti` '
52
+ 'or `dlti` instead.')
53
+ return super().__new__(cls)
54
+
55
+ def __init__(self):
56
+ """
57
+ Initialize the `lti` baseclass.
58
+
59
+ The heavy lifting is done by the subclasses.
60
+ """
61
+ super().__init__()
62
+
63
+ self.inputs = None
64
+ self.outputs = None
65
+ self._dt = None
66
+
67
+ @property
68
+ def dt(self):
69
+ """Return the sampling time of the system, `None` for `lti` systems."""
70
+ return self._dt
71
+
72
+ @property
73
+ def _dt_dict(self):
74
+ if self.dt is None:
75
+ return {}
76
+ else:
77
+ return {'dt': self.dt}
78
+
79
+ @property
80
+ def zeros(self):
81
+ """Zeros of the system."""
82
+ return self.to_zpk().zeros
83
+
84
+ @property
85
+ def poles(self):
86
+ """Poles of the system."""
87
+ return self.to_zpk().poles
88
+
89
+ def _as_ss(self):
90
+ """Convert to `StateSpace` system, without copying.
91
+
92
+ Returns
93
+ -------
94
+ sys: StateSpace
95
+ The `StateSpace` system. If the class is already an instance of
96
+ `StateSpace` then this instance is returned.
97
+ """
98
+ if isinstance(self, StateSpace):
99
+ return self
100
+ else:
101
+ return self.to_ss()
102
+
103
+ def _as_zpk(self):
104
+ """Convert to `ZerosPolesGain` system, without copying.
105
+
106
+ Returns
107
+ -------
108
+ sys: ZerosPolesGain
109
+ The `ZerosPolesGain` system. If the class is already an instance of
110
+ `ZerosPolesGain` then this instance is returned.
111
+ """
112
+ if isinstance(self, ZerosPolesGain):
113
+ return self
114
+ else:
115
+ return self.to_zpk()
116
+
117
+ def _as_tf(self):
118
+ """Convert to `TransferFunction` system, without copying.
119
+
120
+ Returns
121
+ -------
122
+ sys: ZerosPolesGain
123
+ The `TransferFunction` system. If the class is already an instance of
124
+ `TransferFunction` then this instance is returned.
125
+ """
126
+ if isinstance(self, TransferFunction):
127
+ return self
128
+ else:
129
+ return self.to_tf()
130
+
131
+
132
+ class lti(LinearTimeInvariant):
133
+ r"""
134
+ Continuous-time linear time invariant system base class.
135
+
136
+ Parameters
137
+ ----------
138
+ *system : arguments
139
+ The `lti` class can be instantiated with either 2, 3 or 4 arguments.
140
+ The following gives the number of arguments and the corresponding
141
+ continuous-time subclass that is created:
142
+
143
+ * 2: `TransferFunction`: (numerator, denominator)
144
+ * 3: `ZerosPolesGain`: (zeros, poles, gain)
145
+ * 4: `StateSpace`: (A, B, C, D)
146
+
147
+ Each argument can be an array or a sequence.
148
+
149
+ See Also
150
+ --------
151
+ ZerosPolesGain, StateSpace, TransferFunction, dlti
152
+
153
+ Notes
154
+ -----
155
+ `lti` instances do not exist directly. Instead, `lti` creates an instance
156
+ of one of its subclasses: `StateSpace`, `TransferFunction` or
157
+ `ZerosPolesGain`.
158
+
159
+ If (numerator, denominator) is passed in for ``*system``, coefficients for
160
+ both the numerator and denominator should be specified in descending
161
+ exponent order (e.g., ``s^2 + 3s + 5`` would be represented as ``[1, 3,
162
+ 5]``).
163
+
164
+ Changing the value of properties that are not directly part of the current
165
+ system representation (such as the `zeros` of a `StateSpace` system) is
166
+ very inefficient and may lead to numerical inaccuracies. It is better to
167
+ convert to the specific system representation first. For example, call
168
+ ``sys = sys.to_zpk()`` before accessing/changing the zeros, poles or gain.
169
+
170
+ Examples
171
+ --------
172
+ >>> from scipy import signal
173
+
174
+ >>> signal.lti(1, 2, 3, 4)
175
+ StateSpaceContinuous(
176
+ array([[1]]),
177
+ array([[2]]),
178
+ array([[3]]),
179
+ array([[4]]),
180
+ dt: None
181
+ )
182
+
183
+ Construct the transfer function
184
+ :math:`H(s) = \frac{5(s - 1)(s - 2)}{(s - 3)(s - 4)}`:
185
+
186
+ >>> signal.lti([1, 2], [3, 4], 5)
187
+ ZerosPolesGainContinuous(
188
+ array([1, 2]),
189
+ array([3, 4]),
190
+ 5,
191
+ dt: None
192
+ )
193
+
194
+ Construct the transfer function :math:`H(s) = \frac{3s + 4}{1s + 2}`:
195
+
196
+ >>> signal.lti([3, 4], [1, 2])
197
+ TransferFunctionContinuous(
198
+ array([3., 4.]),
199
+ array([1., 2.]),
200
+ dt: None
201
+ )
202
+
203
+ """
204
+ def __new__(cls, *system):
205
+ """Create an instance of the appropriate subclass."""
206
+ if cls is lti:
207
+ N = len(system)
208
+ if N == 2:
209
+ return TransferFunctionContinuous.__new__(
210
+ TransferFunctionContinuous, *system)
211
+ elif N == 3:
212
+ return ZerosPolesGainContinuous.__new__(
213
+ ZerosPolesGainContinuous, *system)
214
+ elif N == 4:
215
+ return StateSpaceContinuous.__new__(StateSpaceContinuous,
216
+ *system)
217
+ else:
218
+ raise ValueError("`system` needs to be an instance of `lti` "
219
+ "or have 2, 3 or 4 arguments.")
220
+ # __new__ was called from a subclass, let it call its own functions
221
+ return super().__new__(cls)
222
+
223
+ def __init__(self, *system):
224
+ """
225
+ Initialize the `lti` baseclass.
226
+
227
+ The heavy lifting is done by the subclasses.
228
+ """
229
+ super().__init__(*system)
230
+
231
+ def impulse(self, X0=None, T=None, N=None):
232
+ """
233
+ Return the impulse response of a continuous-time system.
234
+ See `impulse` for details.
235
+ """
236
+ return impulse(self, X0=X0, T=T, N=N)
237
+
238
+ def step(self, X0=None, T=None, N=None):
239
+ """
240
+ Return the step response of a continuous-time system.
241
+ See `step` for details.
242
+ """
243
+ return step(self, X0=X0, T=T, N=N)
244
+
245
+ def output(self, U, T, X0=None):
246
+ """
247
+ Return the response of a continuous-time system to input `U`.
248
+ See `lsim` for details.
249
+ """
250
+ return lsim(self, U, T, X0=X0)
251
+
252
+ def bode(self, w=None, n=100):
253
+ """
254
+ Calculate Bode magnitude and phase data of a continuous-time system.
255
+
256
+ Returns a 3-tuple containing arrays of frequencies [rad/s], magnitude
257
+ [dB] and phase [deg]. See `bode` for details.
258
+
259
+ Examples
260
+ --------
261
+ >>> from scipy import signal
262
+ >>> import matplotlib.pyplot as plt
263
+
264
+ >>> sys = signal.TransferFunction([1], [1, 1])
265
+ >>> w, mag, phase = sys.bode()
266
+
267
+ >>> plt.figure()
268
+ >>> plt.semilogx(w, mag) # Bode magnitude plot
269
+ >>> plt.figure()
270
+ >>> plt.semilogx(w, phase) # Bode phase plot
271
+ >>> plt.show()
272
+
273
+ """
274
+ return bode(self, w=w, n=n)
275
+
276
+ def freqresp(self, w=None, n=10000):
277
+ """
278
+ Calculate the frequency response of a continuous-time system.
279
+
280
+ Returns a 2-tuple containing arrays of frequencies [rad/s] and
281
+ complex magnitude.
282
+ See `freqresp` for details.
283
+ """
284
+ return freqresp(self, w=w, n=n)
285
+
286
+ def to_discrete(self, dt, method='zoh', alpha=None):
287
+ """Return a discretized version of the current system.
288
+
289
+ Parameters: See `cont2discrete` for details.
290
+
291
+ Returns
292
+ -------
293
+ sys: instance of `dlti`
294
+ """
295
+ raise NotImplementedError('to_discrete is not implemented for this '
296
+ 'system class.')
297
+
298
+
299
+ class dlti(LinearTimeInvariant):
300
+ r"""
301
+ Discrete-time linear time invariant system base class.
302
+
303
+ Parameters
304
+ ----------
305
+ *system: arguments
306
+ The `dlti` class can be instantiated with either 2, 3 or 4 arguments.
307
+ The following gives the number of arguments and the corresponding
308
+ discrete-time subclass that is created:
309
+
310
+ * 2: `TransferFunction`: (numerator, denominator)
311
+ * 3: `ZerosPolesGain`: (zeros, poles, gain)
312
+ * 4: `StateSpace`: (A, B, C, D)
313
+
314
+ Each argument can be an array or a sequence.
315
+ dt: float, optional
316
+ Sampling time [s] of the discrete-time systems. Defaults to ``True``
317
+ (unspecified sampling time). Must be specified as a keyword argument,
318
+ for example, ``dt=0.1``.
319
+
320
+ See Also
321
+ --------
322
+ ZerosPolesGain, StateSpace, TransferFunction, lti
323
+
324
+ Notes
325
+ -----
326
+ `dlti` instances do not exist directly. Instead, `dlti` creates an instance
327
+ of one of its subclasses: `StateSpace`, `TransferFunction` or
328
+ `ZerosPolesGain`.
329
+
330
+ Changing the value of properties that are not directly part of the current
331
+ system representation (such as the `zeros` of a `StateSpace` system) is
332
+ very inefficient and may lead to numerical inaccuracies. It is better to
333
+ convert to the specific system representation first. For example, call
334
+ ``sys = sys.to_zpk()`` before accessing/changing the zeros, poles or gain.
335
+
336
+ If (numerator, denominator) is passed in for ``*system``, coefficients for
337
+ both the numerator and denominator should be specified in descending
338
+ exponent order (e.g., ``z^2 + 3z + 5`` would be represented as ``[1, 3,
339
+ 5]``).
340
+
341
+ .. versionadded:: 0.18.0
342
+
343
+ Examples
344
+ --------
345
+ >>> from scipy import signal
346
+
347
+ >>> signal.dlti(1, 2, 3, 4)
348
+ StateSpaceDiscrete(
349
+ array([[1]]),
350
+ array([[2]]),
351
+ array([[3]]),
352
+ array([[4]]),
353
+ dt: True
354
+ )
355
+
356
+ >>> signal.dlti(1, 2, 3, 4, dt=0.1)
357
+ StateSpaceDiscrete(
358
+ array([[1]]),
359
+ array([[2]]),
360
+ array([[3]]),
361
+ array([[4]]),
362
+ dt: 0.1
363
+ )
364
+
365
+ Construct the transfer function
366
+ :math:`H(z) = \frac{5(z - 1)(z - 2)}{(z - 3)(z - 4)}` with a sampling time
367
+ of 0.1 seconds:
368
+
369
+ >>> signal.dlti([1, 2], [3, 4], 5, dt=0.1)
370
+ ZerosPolesGainDiscrete(
371
+ array([1, 2]),
372
+ array([3, 4]),
373
+ 5,
374
+ dt: 0.1
375
+ )
376
+
377
+ Construct the transfer function :math:`H(z) = \frac{3z + 4}{1z + 2}` with
378
+ a sampling time of 0.1 seconds:
379
+
380
+ >>> signal.dlti([3, 4], [1, 2], dt=0.1)
381
+ TransferFunctionDiscrete(
382
+ array([3., 4.]),
383
+ array([1., 2.]),
384
+ dt: 0.1
385
+ )
386
+
387
+ """
388
+ def __new__(cls, *system, **kwargs):
389
+ """Create an instance of the appropriate subclass."""
390
+ if cls is dlti:
391
+ N = len(system)
392
+ if N == 2:
393
+ return TransferFunctionDiscrete.__new__(
394
+ TransferFunctionDiscrete, *system, **kwargs)
395
+ elif N == 3:
396
+ return ZerosPolesGainDiscrete.__new__(ZerosPolesGainDiscrete,
397
+ *system, **kwargs)
398
+ elif N == 4:
399
+ return StateSpaceDiscrete.__new__(StateSpaceDiscrete, *system,
400
+ **kwargs)
401
+ else:
402
+ raise ValueError("`system` needs to be an instance of `dlti` "
403
+ "or have 2, 3 or 4 arguments.")
404
+ # __new__ was called from a subclass, let it call its own functions
405
+ return super().__new__(cls)
406
+
407
+ def __init__(self, *system, **kwargs):
408
+ """
409
+ Initialize the `lti` baseclass.
410
+
411
+ The heavy lifting is done by the subclasses.
412
+ """
413
+ dt = kwargs.pop('dt', True)
414
+ super().__init__(*system, **kwargs)
415
+
416
+ self.dt = dt
417
+
418
+ @property
419
+ def dt(self):
420
+ """Return the sampling time of the system."""
421
+ return self._dt
422
+
423
+ @dt.setter
424
+ def dt(self, dt):
425
+ self._dt = dt
426
+
427
+ def impulse(self, x0=None, t=None, n=None):
428
+ """
429
+ Return the impulse response of the discrete-time `dlti` system.
430
+ See `dimpulse` for details.
431
+ """
432
+ return dimpulse(self, x0=x0, t=t, n=n)
433
+
434
+ def step(self, x0=None, t=None, n=None):
435
+ """
436
+ Return the step response of the discrete-time `dlti` system.
437
+ See `dstep` for details.
438
+ """
439
+ return dstep(self, x0=x0, t=t, n=n)
440
+
441
+ def output(self, u, t, x0=None):
442
+ """
443
+ Return the response of the discrete-time system to input `u`.
444
+ See `dlsim` for details.
445
+ """
446
+ return dlsim(self, u, t, x0=x0)
447
+
448
+ def bode(self, w=None, n=100):
449
+ r"""
450
+ Calculate Bode magnitude and phase data of a discrete-time system.
451
+
452
+ Returns a 3-tuple containing arrays of frequencies [rad/s], magnitude
453
+ [dB] and phase [deg]. See `dbode` for details.
454
+
455
+ Examples
456
+ --------
457
+ >>> from scipy import signal
458
+ >>> import matplotlib.pyplot as plt
459
+
460
+ Construct the transfer function :math:`H(z) = \frac{1}{z^2 + 2z + 3}`
461
+ with sampling time 0.5s:
462
+
463
+ >>> sys = signal.TransferFunction([1], [1, 2, 3], dt=0.5)
464
+
465
+ Equivalent: signal.dbode(sys)
466
+
467
+ >>> w, mag, phase = sys.bode()
468
+
469
+ >>> plt.figure()
470
+ >>> plt.semilogx(w, mag) # Bode magnitude plot
471
+ >>> plt.figure()
472
+ >>> plt.semilogx(w, phase) # Bode phase plot
473
+ >>> plt.show()
474
+
475
+ """
476
+ return dbode(self, w=w, n=n)
477
+
478
+ def freqresp(self, w=None, n=10000, whole=False):
479
+ """
480
+ Calculate the frequency response of a discrete-time system.
481
+
482
+ Returns a 2-tuple containing arrays of frequencies [rad/s] and
483
+ complex magnitude.
484
+ See `dfreqresp` for details.
485
+
486
+ """
487
+ return dfreqresp(self, w=w, n=n, whole=whole)
488
+
489
+
490
+ class TransferFunction(LinearTimeInvariant):
491
+ r"""Linear Time Invariant system class in transfer function form.
492
+
493
+ Represents the system as the continuous-time transfer function
494
+ :math:`H(s)=\sum_{i=0}^N b[N-i] s^i / \sum_{j=0}^M a[M-j] s^j` or the
495
+ discrete-time transfer function
496
+ :math:`H(z)=\sum_{i=0}^N b[N-i] z^i / \sum_{j=0}^M a[M-j] z^j`, where
497
+ :math:`b` are elements of the numerator `num`, :math:`a` are elements of
498
+ the denominator `den`, and ``N == len(b) - 1``, ``M == len(a) - 1``.
499
+ `TransferFunction` systems inherit additional
500
+ functionality from the `lti`, respectively the `dlti` classes, depending on
501
+ which system representation is used.
502
+
503
+ Parameters
504
+ ----------
505
+ *system: arguments
506
+ The `TransferFunction` class can be instantiated with 1 or 2
507
+ arguments. The following gives the number of input arguments and their
508
+ interpretation:
509
+
510
+ * 1: `lti` or `dlti` system: (`StateSpace`, `TransferFunction` or
511
+ `ZerosPolesGain`)
512
+ * 2: array_like: (numerator, denominator)
513
+ dt: float, optional
514
+ Sampling time [s] of the discrete-time systems. Defaults to `None`
515
+ (continuous-time). Must be specified as a keyword argument, for
516
+ example, ``dt=0.1``.
517
+
518
+ See Also
519
+ --------
520
+ ZerosPolesGain, StateSpace, lti, dlti
521
+ tf2ss, tf2zpk, tf2sos
522
+
523
+ Notes
524
+ -----
525
+ Changing the value of properties that are not part of the
526
+ `TransferFunction` system representation (such as the `A`, `B`, `C`, `D`
527
+ state-space matrices) is very inefficient and may lead to numerical
528
+ inaccuracies. It is better to convert to the specific system
529
+ representation first. For example, call ``sys = sys.to_ss()`` before
530
+ accessing/changing the A, B, C, D system matrices.
531
+
532
+ If (numerator, denominator) is passed in for ``*system``, coefficients
533
+ for both the numerator and denominator should be specified in descending
534
+ exponent order (e.g. ``s^2 + 3s + 5`` or ``z^2 + 3z + 5`` would be
535
+ represented as ``[1, 3, 5]``)
536
+
537
+ Examples
538
+ --------
539
+ Construct the transfer function
540
+ :math:`H(s) = \frac{s^2 + 3s + 3}{s^2 + 2s + 1}`:
541
+
542
+ >>> from scipy import signal
543
+
544
+ >>> num = [1, 3, 3]
545
+ >>> den = [1, 2, 1]
546
+
547
+ >>> signal.TransferFunction(num, den)
548
+ TransferFunctionContinuous(
549
+ array([1., 3., 3.]),
550
+ array([1., 2., 1.]),
551
+ dt: None
552
+ )
553
+
554
+ Construct the transfer function
555
+ :math:`H(z) = \frac{z^2 + 3z + 3}{z^2 + 2z + 1}` with a sampling time of
556
+ 0.1 seconds:
557
+
558
+ >>> signal.TransferFunction(num, den, dt=0.1)
559
+ TransferFunctionDiscrete(
560
+ array([1., 3., 3.]),
561
+ array([1., 2., 1.]),
562
+ dt: 0.1
563
+ )
564
+
565
+ """
566
+ def __new__(cls, *system, **kwargs):
567
+ """Handle object conversion if input is an instance of lti."""
568
+ if len(system) == 1 and isinstance(system[0], LinearTimeInvariant):
569
+ return system[0].to_tf()
570
+
571
+ # Choose whether to inherit from `lti` or from `dlti`
572
+ if cls is TransferFunction:
573
+ if kwargs.get('dt') is None:
574
+ return TransferFunctionContinuous.__new__(
575
+ TransferFunctionContinuous,
576
+ *system,
577
+ **kwargs)
578
+ else:
579
+ return TransferFunctionDiscrete.__new__(
580
+ TransferFunctionDiscrete,
581
+ *system,
582
+ **kwargs)
583
+
584
+ # No special conversion needed
585
+ return super().__new__(cls)
586
+
587
+ def __init__(self, *system, **kwargs):
588
+ """Initialize the state space LTI system."""
589
+ # Conversion of lti instances is handled in __new__
590
+ if isinstance(system[0], LinearTimeInvariant):
591
+ return
592
+
593
+ # Remove system arguments, not needed by parents anymore
594
+ super().__init__(**kwargs)
595
+
596
+ self._num = None
597
+ self._den = None
598
+
599
+ self.num, self.den = normalize(*system)
600
+
601
+ def __repr__(self):
602
+ """Return representation of the system's transfer function"""
603
+ return (
604
+ f'{self.__class__.__name__}(\n'
605
+ f'{repr(self.num)},\n'
606
+ f'{repr(self.den)},\n'
607
+ f'dt: {repr(self.dt)}\n)'
608
+ )
609
+
610
+ @property
611
+ def num(self):
612
+ """Numerator of the `TransferFunction` system."""
613
+ return self._num
614
+
615
+ @num.setter
616
+ def num(self, num):
617
+ self._num = atleast_1d(num)
618
+
619
+ # Update dimensions
620
+ if len(self.num.shape) > 1:
621
+ self.outputs, self.inputs = self.num.shape
622
+ else:
623
+ self.outputs = 1
624
+ self.inputs = 1
625
+
626
+ @property
627
+ def den(self):
628
+ """Denominator of the `TransferFunction` system."""
629
+ return self._den
630
+
631
+ @den.setter
632
+ def den(self, den):
633
+ self._den = atleast_1d(den)
634
+
635
+ def _copy(self, system):
636
+ """
637
+ Copy the parameters of another `TransferFunction` object
638
+
639
+ Parameters
640
+ ----------
641
+ system : `TransferFunction`
642
+ The `StateSpace` system that is to be copied
643
+
644
+ """
645
+ self.num = system.num
646
+ self.den = system.den
647
+
648
+ def to_tf(self):
649
+ """
650
+ Return a copy of the current `TransferFunction` system.
651
+
652
+ Returns
653
+ -------
654
+ sys : instance of `TransferFunction`
655
+ The current system (copy)
656
+
657
+ """
658
+ return copy.deepcopy(self)
659
+
660
+ def to_zpk(self):
661
+ """
662
+ Convert system representation to `ZerosPolesGain`.
663
+
664
+ Returns
665
+ -------
666
+ sys : instance of `ZerosPolesGain`
667
+ Zeros, poles, gain representation of the current system
668
+
669
+ """
670
+ return ZerosPolesGain(*tf2zpk(self.num, self.den),
671
+ **self._dt_dict)
672
+
673
+ def to_ss(self):
674
+ """
675
+ Convert system representation to `StateSpace`.
676
+
677
+ Returns
678
+ -------
679
+ sys : instance of `StateSpace`
680
+ State space model of the current system
681
+
682
+ """
683
+ return StateSpace(*tf2ss(self.num, self.den),
684
+ **self._dt_dict)
685
+
686
+ @staticmethod
687
+ def _z_to_zinv(num, den):
688
+ """Change a transfer function from the variable `z` to `z**-1`.
689
+
690
+ Parameters
691
+ ----------
692
+ num, den: 1d array_like
693
+ Sequences representing the coefficients of the numerator and
694
+ denominator polynomials, in order of descending degree of 'z'.
695
+ That is, ``5z**2 + 3z + 2`` is presented as ``[5, 3, 2]``.
696
+
697
+ Returns
698
+ -------
699
+ num, den: 1d array_like
700
+ Sequences representing the coefficients of the numerator and
701
+ denominator polynomials, in order of ascending degree of 'z**-1'.
702
+ That is, ``5 + 3 z**-1 + 2 z**-2`` is presented as ``[5, 3, 2]``.
703
+ """
704
+ diff = len(num) - len(den)
705
+ if diff > 0:
706
+ den = np.hstack((np.zeros(diff), den))
707
+ elif diff < 0:
708
+ num = np.hstack((np.zeros(-diff), num))
709
+ return num, den
710
+
711
+ @staticmethod
712
+ def _zinv_to_z(num, den):
713
+ """Change a transfer function from the variable `z` to `z**-1`.
714
+
715
+ Parameters
716
+ ----------
717
+ num, den: 1d array_like
718
+ Sequences representing the coefficients of the numerator and
719
+ denominator polynomials, in order of ascending degree of 'z**-1'.
720
+ That is, ``5 + 3 z**-1 + 2 z**-2`` is presented as ``[5, 3, 2]``.
721
+
722
+ Returns
723
+ -------
724
+ num, den: 1d array_like
725
+ Sequences representing the coefficients of the numerator and
726
+ denominator polynomials, in order of descending degree of 'z'.
727
+ That is, ``5z**2 + 3z + 2`` is presented as ``[5, 3, 2]``.
728
+ """
729
+ diff = len(num) - len(den)
730
+ if diff > 0:
731
+ den = np.hstack((den, np.zeros(diff)))
732
+ elif diff < 0:
733
+ num = np.hstack((num, np.zeros(-diff)))
734
+ return num, den
735
+
736
+
737
+ class TransferFunctionContinuous(TransferFunction, lti):
738
+ r"""
739
+ Continuous-time Linear Time Invariant system in transfer function form.
740
+
741
+ Represents the system as the transfer function
742
+ :math:`H(s)=\sum_{i=0}^N b[N-i] s^i / \sum_{j=0}^M a[M-j] s^j`, where
743
+ :math:`b` are elements of the numerator `num`, :math:`a` are elements of
744
+ the denominator `den`, and ``N == len(b) - 1``, ``M == len(a) - 1``.
745
+ Continuous-time `TransferFunction` systems inherit additional
746
+ functionality from the `lti` class.
747
+
748
+ Parameters
749
+ ----------
750
+ *system: arguments
751
+ The `TransferFunction` class can be instantiated with 1 or 2
752
+ arguments. The following gives the number of input arguments and their
753
+ interpretation:
754
+
755
+ * 1: `lti` system: (`StateSpace`, `TransferFunction` or
756
+ `ZerosPolesGain`)
757
+ * 2: array_like: (numerator, denominator)
758
+
759
+ See Also
760
+ --------
761
+ ZerosPolesGain, StateSpace, lti
762
+ tf2ss, tf2zpk, tf2sos
763
+
764
+ Notes
765
+ -----
766
+ Changing the value of properties that are not part of the
767
+ `TransferFunction` system representation (such as the `A`, `B`, `C`, `D`
768
+ state-space matrices) is very inefficient and may lead to numerical
769
+ inaccuracies. It is better to convert to the specific system
770
+ representation first. For example, call ``sys = sys.to_ss()`` before
771
+ accessing/changing the A, B, C, D system matrices.
772
+
773
+ If (numerator, denominator) is passed in for ``*system``, coefficients
774
+ for both the numerator and denominator should be specified in descending
775
+ exponent order (e.g. ``s^2 + 3s + 5`` would be represented as
776
+ ``[1, 3, 5]``)
777
+
778
+ Examples
779
+ --------
780
+ Construct the transfer function
781
+ :math:`H(s) = \frac{s^2 + 3s + 3}{s^2 + 2s + 1}`:
782
+
783
+ >>> from scipy import signal
784
+
785
+ >>> num = [1, 3, 3]
786
+ >>> den = [1, 2, 1]
787
+
788
+ >>> signal.TransferFunction(num, den)
789
+ TransferFunctionContinuous(
790
+ array([ 1., 3., 3.]),
791
+ array([ 1., 2., 1.]),
792
+ dt: None
793
+ )
794
+
795
+ """
796
+
797
+ def to_discrete(self, dt, method='zoh', alpha=None):
798
+ """
799
+ Returns the discretized `TransferFunction` system.
800
+
801
+ Parameters: See `cont2discrete` for details.
802
+
803
+ Returns
804
+ -------
805
+ sys: instance of `dlti` and `StateSpace`
806
+ """
807
+ return TransferFunction(*cont2discrete((self.num, self.den),
808
+ dt,
809
+ method=method,
810
+ alpha=alpha)[:-1],
811
+ dt=dt)
812
+
813
+
814
+ class TransferFunctionDiscrete(TransferFunction, dlti):
815
+ r"""
816
+ Discrete-time Linear Time Invariant system in transfer function form.
817
+
818
+ Represents the system as the transfer function
819
+ :math:`H(z)=\sum_{i=0}^N b[N-i] z^i / \sum_{j=0}^M a[M-j] z^j`, where
820
+ :math:`b` are elements of the numerator `num`, :math:`a` are elements of
821
+ the denominator `den`, and ``N == len(b) - 1``, ``M == len(a) - 1``.
822
+ Discrete-time `TransferFunction` systems inherit additional functionality
823
+ from the `dlti` class.
824
+
825
+ Parameters
826
+ ----------
827
+ *system: arguments
828
+ The `TransferFunction` class can be instantiated with 1 or 2
829
+ arguments. The following gives the number of input arguments and their
830
+ interpretation:
831
+
832
+ * 1: `dlti` system: (`StateSpace`, `TransferFunction` or
833
+ `ZerosPolesGain`)
834
+ * 2: array_like: (numerator, denominator)
835
+ dt: float, optional
836
+ Sampling time [s] of the discrete-time systems. Defaults to `True`
837
+ (unspecified sampling time). Must be specified as a keyword argument,
838
+ for example, ``dt=0.1``.
839
+
840
+ See Also
841
+ --------
842
+ ZerosPolesGain, StateSpace, dlti
843
+ tf2ss, tf2zpk, tf2sos
844
+
845
+ Notes
846
+ -----
847
+ Changing the value of properties that are not part of the
848
+ `TransferFunction` system representation (such as the `A`, `B`, `C`, `D`
849
+ state-space matrices) is very inefficient and may lead to numerical
850
+ inaccuracies.
851
+
852
+ If (numerator, denominator) is passed in for ``*system``, coefficients
853
+ for both the numerator and denominator should be specified in descending
854
+ exponent order (e.g., ``z^2 + 3z + 5`` would be represented as
855
+ ``[1, 3, 5]``).
856
+
857
+ Examples
858
+ --------
859
+ Construct the transfer function
860
+ :math:`H(z) = \frac{z^2 + 3z + 3}{z^2 + 2z + 1}` with a sampling time of
861
+ 0.5 seconds:
862
+
863
+ >>> from scipy import signal
864
+
865
+ >>> num = [1, 3, 3]
866
+ >>> den = [1, 2, 1]
867
+
868
+ >>> signal.TransferFunction(num, den, dt=0.5)
869
+ TransferFunctionDiscrete(
870
+ array([ 1., 3., 3.]),
871
+ array([ 1., 2., 1.]),
872
+ dt: 0.5
873
+ )
874
+
875
+ """
876
+ pass
877
+
878
+
879
+ class ZerosPolesGain(LinearTimeInvariant):
880
+ r"""
881
+ Linear Time Invariant system class in zeros, poles, gain form.
882
+
883
+ Represents the system as the continuous- or discrete-time transfer function
884
+ :math:`H(s)=k \prod_i (s - z[i]) / \prod_j (s - p[j])`, where :math:`k` is
885
+ the `gain`, :math:`z` are the `zeros` and :math:`p` are the `poles`.
886
+ `ZerosPolesGain` systems inherit additional functionality from the `lti`,
887
+ respectively the `dlti` classes, depending on which system representation
888
+ is used.
889
+
890
+ Parameters
891
+ ----------
892
+ *system : arguments
893
+ The `ZerosPolesGain` class can be instantiated with 1 or 3
894
+ arguments. The following gives the number of input arguments and their
895
+ interpretation:
896
+
897
+ * 1: `lti` or `dlti` system: (`StateSpace`, `TransferFunction` or
898
+ `ZerosPolesGain`)
899
+ * 3: array_like: (zeros, poles, gain)
900
+ dt: float, optional
901
+ Sampling time [s] of the discrete-time systems. Defaults to `None`
902
+ (continuous-time). Must be specified as a keyword argument, for
903
+ example, ``dt=0.1``.
904
+
905
+
906
+ See Also
907
+ --------
908
+ TransferFunction, StateSpace, lti, dlti
909
+ zpk2ss, zpk2tf, zpk2sos
910
+
911
+ Notes
912
+ -----
913
+ Changing the value of properties that are not part of the
914
+ `ZerosPolesGain` system representation (such as the `A`, `B`, `C`, `D`
915
+ state-space matrices) is very inefficient and may lead to numerical
916
+ inaccuracies. It is better to convert to the specific system
917
+ representation first. For example, call ``sys = sys.to_ss()`` before
918
+ accessing/changing the A, B, C, D system matrices.
919
+
920
+ Examples
921
+ --------
922
+ Construct the transfer function
923
+ :math:`H(s) = \frac{5(s - 1)(s - 2)}{(s - 3)(s - 4)}`:
924
+
925
+ >>> from scipy import signal
926
+
927
+ >>> signal.ZerosPolesGain([1, 2], [3, 4], 5)
928
+ ZerosPolesGainContinuous(
929
+ array([1, 2]),
930
+ array([3, 4]),
931
+ 5,
932
+ dt: None
933
+ )
934
+
935
+ Construct the transfer function
936
+ :math:`H(z) = \frac{5(z - 1)(z - 2)}{(z - 3)(z - 4)}` with a sampling time
937
+ of 0.1 seconds:
938
+
939
+ >>> signal.ZerosPolesGain([1, 2], [3, 4], 5, dt=0.1)
940
+ ZerosPolesGainDiscrete(
941
+ array([1, 2]),
942
+ array([3, 4]),
943
+ 5,
944
+ dt: 0.1
945
+ )
946
+
947
+ """
948
+ def __new__(cls, *system, **kwargs):
949
+ """Handle object conversion if input is an instance of `lti`"""
950
+ if len(system) == 1 and isinstance(system[0], LinearTimeInvariant):
951
+ return system[0].to_zpk()
952
+
953
+ # Choose whether to inherit from `lti` or from `dlti`
954
+ if cls is ZerosPolesGain:
955
+ if kwargs.get('dt') is None:
956
+ return ZerosPolesGainContinuous.__new__(
957
+ ZerosPolesGainContinuous,
958
+ *system,
959
+ **kwargs)
960
+ else:
961
+ return ZerosPolesGainDiscrete.__new__(
962
+ ZerosPolesGainDiscrete,
963
+ *system,
964
+ **kwargs
965
+ )
966
+
967
+ # No special conversion needed
968
+ return super().__new__(cls)
969
+
970
+ def __init__(self, *system, **kwargs):
971
+ """Initialize the zeros, poles, gain system."""
972
+ # Conversion of lti instances is handled in __new__
973
+ if isinstance(system[0], LinearTimeInvariant):
974
+ return
975
+
976
+ super().__init__(**kwargs)
977
+
978
+ self._zeros = None
979
+ self._poles = None
980
+ self._gain = None
981
+
982
+ self.zeros, self.poles, self.gain = system
983
+
984
+ def __repr__(self):
985
+ """Return representation of the `ZerosPolesGain` system."""
986
+ return (
987
+ f'{self.__class__.__name__}(\n'
988
+ f'{repr(self.zeros)},\n'
989
+ f'{repr(self.poles)},\n'
990
+ f'{repr(self.gain)},\n'
991
+ f'dt: {repr(self.dt)}\n)'
992
+ )
993
+
994
+ @property
995
+ def zeros(self):
996
+ """Zeros of the `ZerosPolesGain` system."""
997
+ return self._zeros
998
+
999
+ @zeros.setter
1000
+ def zeros(self, zeros):
1001
+ self._zeros = atleast_1d(zeros)
1002
+
1003
+ # Update dimensions
1004
+ if len(self.zeros.shape) > 1:
1005
+ self.outputs, self.inputs = self.zeros.shape
1006
+ else:
1007
+ self.outputs = 1
1008
+ self.inputs = 1
1009
+
1010
+ @property
1011
+ def poles(self):
1012
+ """Poles of the `ZerosPolesGain` system."""
1013
+ return self._poles
1014
+
1015
+ @poles.setter
1016
+ def poles(self, poles):
1017
+ self._poles = atleast_1d(poles)
1018
+
1019
+ @property
1020
+ def gain(self):
1021
+ """Gain of the `ZerosPolesGain` system."""
1022
+ return self._gain
1023
+
1024
+ @gain.setter
1025
+ def gain(self, gain):
1026
+ self._gain = gain
1027
+
1028
+ def _copy(self, system):
1029
+ """
1030
+ Copy the parameters of another `ZerosPolesGain` system.
1031
+
1032
+ Parameters
1033
+ ----------
1034
+ system : instance of `ZerosPolesGain`
1035
+ The zeros, poles gain system that is to be copied
1036
+
1037
+ """
1038
+ self.poles = system.poles
1039
+ self.zeros = system.zeros
1040
+ self.gain = system.gain
1041
+
1042
+ def to_tf(self):
1043
+ """
1044
+ Convert system representation to `TransferFunction`.
1045
+
1046
+ Returns
1047
+ -------
1048
+ sys : instance of `TransferFunction`
1049
+ Transfer function of the current system
1050
+
1051
+ """
1052
+ return TransferFunction(*zpk2tf(self.zeros, self.poles, self.gain),
1053
+ **self._dt_dict)
1054
+
1055
+ def to_zpk(self):
1056
+ """
1057
+ Return a copy of the current 'ZerosPolesGain' system.
1058
+
1059
+ Returns
1060
+ -------
1061
+ sys : instance of `ZerosPolesGain`
1062
+ The current system (copy)
1063
+
1064
+ """
1065
+ return copy.deepcopy(self)
1066
+
1067
+ def to_ss(self):
1068
+ """
1069
+ Convert system representation to `StateSpace`.
1070
+
1071
+ Returns
1072
+ -------
1073
+ sys : instance of `StateSpace`
1074
+ State space model of the current system
1075
+
1076
+ """
1077
+ return StateSpace(*zpk2ss(self.zeros, self.poles, self.gain),
1078
+ **self._dt_dict)
1079
+
1080
+
1081
+ class ZerosPolesGainContinuous(ZerosPolesGain, lti):
1082
+ r"""
1083
+ Continuous-time Linear Time Invariant system in zeros, poles, gain form.
1084
+
1085
+ Represents the system as the continuous time transfer function
1086
+ :math:`H(s)=k \prod_i (s - z[i]) / \prod_j (s - p[j])`, where :math:`k` is
1087
+ the `gain`, :math:`z` are the `zeros` and :math:`p` are the `poles`.
1088
+ Continuous-time `ZerosPolesGain` systems inherit additional functionality
1089
+ from the `lti` class.
1090
+
1091
+ Parameters
1092
+ ----------
1093
+ *system : arguments
1094
+ The `ZerosPolesGain` class can be instantiated with 1 or 3
1095
+ arguments. The following gives the number of input arguments and their
1096
+ interpretation:
1097
+
1098
+ * 1: `lti` system: (`StateSpace`, `TransferFunction` or
1099
+ `ZerosPolesGain`)
1100
+ * 3: array_like: (zeros, poles, gain)
1101
+
1102
+ See Also
1103
+ --------
1104
+ TransferFunction, StateSpace, lti
1105
+ zpk2ss, zpk2tf, zpk2sos
1106
+
1107
+ Notes
1108
+ -----
1109
+ Changing the value of properties that are not part of the
1110
+ `ZerosPolesGain` system representation (such as the `A`, `B`, `C`, `D`
1111
+ state-space matrices) is very inefficient and may lead to numerical
1112
+ inaccuracies. It is better to convert to the specific system
1113
+ representation first. For example, call ``sys = sys.to_ss()`` before
1114
+ accessing/changing the A, B, C, D system matrices.
1115
+
1116
+ Examples
1117
+ --------
1118
+ Construct the transfer function
1119
+ :math:`H(s)=\frac{5(s - 1)(s - 2)}{(s - 3)(s - 4)}`:
1120
+
1121
+ >>> from scipy import signal
1122
+
1123
+ >>> signal.ZerosPolesGain([1, 2], [3, 4], 5)
1124
+ ZerosPolesGainContinuous(
1125
+ array([1, 2]),
1126
+ array([3, 4]),
1127
+ 5,
1128
+ dt: None
1129
+ )
1130
+
1131
+ """
1132
+
1133
+ def to_discrete(self, dt, method='zoh', alpha=None):
1134
+ """
1135
+ Returns the discretized `ZerosPolesGain` system.
1136
+
1137
+ Parameters: See `cont2discrete` for details.
1138
+
1139
+ Returns
1140
+ -------
1141
+ sys: instance of `dlti` and `ZerosPolesGain`
1142
+ """
1143
+ return ZerosPolesGain(
1144
+ *cont2discrete((self.zeros, self.poles, self.gain),
1145
+ dt,
1146
+ method=method,
1147
+ alpha=alpha)[:-1],
1148
+ dt=dt)
1149
+
1150
+
1151
+ class ZerosPolesGainDiscrete(ZerosPolesGain, dlti):
1152
+ r"""
1153
+ Discrete-time Linear Time Invariant system in zeros, poles, gain form.
1154
+
1155
+ Represents the system as the discrete-time transfer function
1156
+ :math:`H(z)=k \prod_i (z - q[i]) / \prod_j (z - p[j])`, where :math:`k` is
1157
+ the `gain`, :math:`q` are the `zeros` and :math:`p` are the `poles`.
1158
+ Discrete-time `ZerosPolesGain` systems inherit additional functionality
1159
+ from the `dlti` class.
1160
+
1161
+ Parameters
1162
+ ----------
1163
+ *system : arguments
1164
+ The `ZerosPolesGain` class can be instantiated with 1 or 3
1165
+ arguments. The following gives the number of input arguments and their
1166
+ interpretation:
1167
+
1168
+ * 1: `dlti` system: (`StateSpace`, `TransferFunction` or
1169
+ `ZerosPolesGain`)
1170
+ * 3: array_like: (zeros, poles, gain)
1171
+ dt: float, optional
1172
+ Sampling time [s] of the discrete-time systems. Defaults to `True`
1173
+ (unspecified sampling time). Must be specified as a keyword argument,
1174
+ for example, ``dt=0.1``.
1175
+
1176
+ See Also
1177
+ --------
1178
+ TransferFunction, StateSpace, dlti
1179
+ zpk2ss, zpk2tf, zpk2sos
1180
+
1181
+ Notes
1182
+ -----
1183
+ Changing the value of properties that are not part of the
1184
+ `ZerosPolesGain` system representation (such as the `A`, `B`, `C`, `D`
1185
+ state-space matrices) is very inefficient and may lead to numerical
1186
+ inaccuracies. It is better to convert to the specific system
1187
+ representation first. For example, call ``sys = sys.to_ss()`` before
1188
+ accessing/changing the A, B, C, D system matrices.
1189
+
1190
+ Examples
1191
+ --------
1192
+ Construct the transfer function
1193
+ :math:`H(s) = \frac{5(s - 1)(s - 2)}{(s - 3)(s - 4)}`:
1194
+
1195
+ >>> from scipy import signal
1196
+
1197
+ >>> signal.ZerosPolesGain([1, 2], [3, 4], 5)
1198
+ ZerosPolesGainContinuous(
1199
+ array([1, 2]),
1200
+ array([3, 4]),
1201
+ 5,
1202
+ dt: None
1203
+ )
1204
+
1205
+ Construct the transfer function
1206
+ :math:`H(z) = \frac{5(z - 1)(z - 2)}{(z - 3)(z - 4)}` with a sampling time
1207
+ of 0.1 seconds:
1208
+
1209
+ >>> signal.ZerosPolesGain([1, 2], [3, 4], 5, dt=0.1)
1210
+ ZerosPolesGainDiscrete(
1211
+ array([1, 2]),
1212
+ array([3, 4]),
1213
+ 5,
1214
+ dt: 0.1
1215
+ )
1216
+
1217
+ """
1218
+ pass
1219
+
1220
+
1221
+ class StateSpace(LinearTimeInvariant):
1222
+ r"""
1223
+ Linear Time Invariant system in state-space form.
1224
+
1225
+ Represents the system as the continuous-time, first order differential
1226
+ equation :math:`\dot{x} = A x + B u` or the discrete-time difference
1227
+ equation :math:`x[k+1] = A x[k] + B u[k]`. `StateSpace` systems
1228
+ inherit additional functionality from the `lti`, respectively the `dlti`
1229
+ classes, depending on which system representation is used.
1230
+
1231
+ Parameters
1232
+ ----------
1233
+ *system: arguments
1234
+ The `StateSpace` class can be instantiated with 1 or 4 arguments.
1235
+ The following gives the number of input arguments and their
1236
+ interpretation:
1237
+
1238
+ * 1: `lti` or `dlti` system: (`StateSpace`, `TransferFunction` or
1239
+ `ZerosPolesGain`)
1240
+ * 4: array_like: (A, B, C, D)
1241
+ dt: float, optional
1242
+ Sampling time [s] of the discrete-time systems. Defaults to `None`
1243
+ (continuous-time). Must be specified as a keyword argument, for
1244
+ example, ``dt=0.1``.
1245
+
1246
+ See Also
1247
+ --------
1248
+ TransferFunction, ZerosPolesGain, lti, dlti
1249
+ ss2zpk, ss2tf, zpk2sos
1250
+
1251
+ Notes
1252
+ -----
1253
+ Changing the value of properties that are not part of the
1254
+ `StateSpace` system representation (such as `zeros` or `poles`) is very
1255
+ inefficient and may lead to numerical inaccuracies. It is better to
1256
+ convert to the specific system representation first. For example, call
1257
+ ``sys = sys.to_zpk()`` before accessing/changing the zeros, poles or gain.
1258
+
1259
+ Examples
1260
+ --------
1261
+ >>> from scipy import signal
1262
+ >>> import numpy as np
1263
+ >>> a = np.array([[0, 1], [0, 0]])
1264
+ >>> b = np.array([[0], [1]])
1265
+ >>> c = np.array([[1, 0]])
1266
+ >>> d = np.array([[0]])
1267
+
1268
+ >>> sys = signal.StateSpace(a, b, c, d)
1269
+ >>> print(sys)
1270
+ StateSpaceContinuous(
1271
+ array([[0, 1],
1272
+ [0, 0]]),
1273
+ array([[0],
1274
+ [1]]),
1275
+ array([[1, 0]]),
1276
+ array([[0]]),
1277
+ dt: None
1278
+ )
1279
+
1280
+ >>> sys.to_discrete(0.1)
1281
+ StateSpaceDiscrete(
1282
+ array([[1. , 0.1],
1283
+ [0. , 1. ]]),
1284
+ array([[0.005],
1285
+ [0.1 ]]),
1286
+ array([[1, 0]]),
1287
+ array([[0]]),
1288
+ dt: 0.1
1289
+ )
1290
+
1291
+ >>> a = np.array([[1, 0.1], [0, 1]])
1292
+ >>> b = np.array([[0.005], [0.1]])
1293
+
1294
+ >>> signal.StateSpace(a, b, c, d, dt=0.1)
1295
+ StateSpaceDiscrete(
1296
+ array([[1. , 0.1],
1297
+ [0. , 1. ]]),
1298
+ array([[0.005],
1299
+ [0.1 ]]),
1300
+ array([[1, 0]]),
1301
+ array([[0]]),
1302
+ dt: 0.1
1303
+ )
1304
+
1305
+ """
1306
+
1307
+ # Override NumPy binary operations and ufuncs
1308
+ __array_priority__ = 100.0
1309
+ __array_ufunc__ = None
1310
+
1311
+ def __new__(cls, *system, **kwargs):
1312
+ """Create new StateSpace object and settle inheritance."""
1313
+ # Handle object conversion if input is an instance of `lti`
1314
+ if len(system) == 1 and isinstance(system[0], LinearTimeInvariant):
1315
+ return system[0].to_ss()
1316
+
1317
+ # Choose whether to inherit from `lti` or from `dlti`
1318
+ if cls is StateSpace:
1319
+ if kwargs.get('dt') is None:
1320
+ return StateSpaceContinuous.__new__(StateSpaceContinuous,
1321
+ *system, **kwargs)
1322
+ else:
1323
+ return StateSpaceDiscrete.__new__(StateSpaceDiscrete,
1324
+ *system, **kwargs)
1325
+
1326
+ # No special conversion needed
1327
+ return super().__new__(cls)
1328
+
1329
+ def __init__(self, *system, **kwargs):
1330
+ """Initialize the state space lti/dlti system."""
1331
+ # Conversion of lti instances is handled in __new__
1332
+ if isinstance(system[0], LinearTimeInvariant):
1333
+ return
1334
+
1335
+ # Remove system arguments, not needed by parents anymore
1336
+ super().__init__(**kwargs)
1337
+
1338
+ self._A = None
1339
+ self._B = None
1340
+ self._C = None
1341
+ self._D = None
1342
+
1343
+ self.A, self.B, self.C, self.D = abcd_normalize(*system)
1344
+
1345
+ def __repr__(self):
1346
+ """Return representation of the `StateSpace` system."""
1347
+ return (
1348
+ f'{self.__class__.__name__}(\n'
1349
+ f'{repr(self.A)},\n'
1350
+ f'{repr(self.B)},\n'
1351
+ f'{repr(self.C)},\n'
1352
+ f'{repr(self.D)},\n'
1353
+ f'dt: {repr(self.dt)}\n)'
1354
+ )
1355
+
1356
+ def _check_binop_other(self, other):
1357
+ return isinstance(other, StateSpace | np.ndarray | float | complex |
1358
+ np.number | int)
1359
+
1360
+ def __mul__(self, other):
1361
+ """
1362
+ Post-multiply another system or a scalar
1363
+
1364
+ Handles multiplication of systems in the sense of a frequency domain
1365
+ multiplication. That means, given two systems E1(s) and E2(s), their
1366
+ multiplication, H(s) = E1(s) * E2(s), means that applying H(s) to U(s)
1367
+ is equivalent to first applying E2(s), and then E1(s).
1368
+
1369
+ Notes
1370
+ -----
1371
+ For SISO systems the order of system application does not matter.
1372
+ However, for MIMO systems, where the two systems are matrices, the
1373
+ order above ensures standard Matrix multiplication rules apply.
1374
+ """
1375
+ if not self._check_binop_other(other):
1376
+ return NotImplemented
1377
+
1378
+ if isinstance(other, StateSpace):
1379
+ # Disallow mix of discrete and continuous systems.
1380
+ if type(other) is not type(self):
1381
+ return NotImplemented
1382
+
1383
+ if self.dt != other.dt:
1384
+ raise TypeError('Cannot multiply systems with different `dt`.')
1385
+
1386
+ n1 = self.A.shape[0]
1387
+ n2 = other.A.shape[0]
1388
+
1389
+ # Interconnection of systems
1390
+ # x1' = A1 x1 + B1 u1
1391
+ # y1 = C1 x1 + D1 u1
1392
+ # x2' = A2 x2 + B2 y1
1393
+ # y2 = C2 x2 + D2 y1
1394
+ #
1395
+ # Plugging in with u1 = y2 yields
1396
+ # [x1'] [A1 B1*C2 ] [x1] [B1*D2]
1397
+ # [x2'] = [0 A2 ] [x2] + [B2 ] u2
1398
+ # [x1]
1399
+ # y2 = [C1 D1*C2] [x2] + D1*D2 u2
1400
+ a = np.vstack((np.hstack((self.A, np.dot(self.B, other.C))),
1401
+ np.hstack((zeros((n2, n1)), other.A))))
1402
+ b = np.vstack((np.dot(self.B, other.D), other.B))
1403
+ c = np.hstack((self.C, np.dot(self.D, other.C)))
1404
+ d = np.dot(self.D, other.D)
1405
+ else:
1406
+ # Assume that other is a scalar / matrix
1407
+ # For post multiplication the input gets scaled
1408
+ a = self.A
1409
+ b = np.dot(self.B, other)
1410
+ c = self.C
1411
+ d = np.dot(self.D, other)
1412
+
1413
+ common_dtype = np.result_type(a.dtype, b.dtype, c.dtype, d.dtype)
1414
+ return StateSpace(np.asarray(a, dtype=common_dtype),
1415
+ np.asarray(b, dtype=common_dtype),
1416
+ np.asarray(c, dtype=common_dtype),
1417
+ np.asarray(d, dtype=common_dtype),
1418
+ **self._dt_dict)
1419
+
1420
+ def __rmul__(self, other):
1421
+ """Pre-multiply a scalar or matrix (but not StateSpace)"""
1422
+ if not self._check_binop_other(other) or isinstance(other, StateSpace):
1423
+ return NotImplemented
1424
+
1425
+ # For pre-multiplication only the output gets scaled
1426
+ a = self.A
1427
+ b = self.B
1428
+ c = np.dot(other, self.C)
1429
+ d = np.dot(other, self.D)
1430
+
1431
+ common_dtype = np.result_type(a.dtype, b.dtype, c.dtype, d.dtype)
1432
+ return StateSpace(np.asarray(a, dtype=common_dtype),
1433
+ np.asarray(b, dtype=common_dtype),
1434
+ np.asarray(c, dtype=common_dtype),
1435
+ np.asarray(d, dtype=common_dtype),
1436
+ **self._dt_dict)
1437
+
1438
+ def __neg__(self):
1439
+ """Negate the system (equivalent to pre-multiplying by -1)."""
1440
+ return StateSpace(self.A, self.B, -self.C, -self.D, **self._dt_dict)
1441
+
1442
+ def __add__(self, other):
1443
+ """
1444
+ Adds two systems in the sense of frequency domain addition.
1445
+ """
1446
+ if not self._check_binop_other(other):
1447
+ return NotImplemented
1448
+
1449
+ if isinstance(other, StateSpace):
1450
+ # Disallow mix of discrete and continuous systems.
1451
+ if type(other) is not type(self):
1452
+ raise TypeError(f'Cannot add {type(self)} and {type(other)}')
1453
+
1454
+ if self.dt != other.dt:
1455
+ raise TypeError('Cannot add systems with different `dt`.')
1456
+ # Interconnection of systems
1457
+ # x1' = A1 x1 + B1 u
1458
+ # y1 = C1 x1 + D1 u
1459
+ # x2' = A2 x2 + B2 u
1460
+ # y2 = C2 x2 + D2 u
1461
+ # y = y1 + y2
1462
+ #
1463
+ # Plugging in yields
1464
+ # [x1'] [A1 0 ] [x1] [B1]
1465
+ # [x2'] = [0 A2] [x2] + [B2] u
1466
+ # [x1]
1467
+ # y = [C1 C2] [x2] + [D1 + D2] u
1468
+ a = linalg.block_diag(self.A, other.A)
1469
+ b = np.vstack((self.B, other.B))
1470
+ c = np.hstack((self.C, other.C))
1471
+ d = self.D + other.D
1472
+ else:
1473
+ other = np.atleast_2d(other)
1474
+ if self.D.shape == other.shape:
1475
+ # A scalar/matrix is really just a static system (A=0, B=0, C=0)
1476
+ a = self.A
1477
+ b = self.B
1478
+ c = self.C
1479
+ d = self.D + other
1480
+ else:
1481
+ raise ValueError("Cannot add systems with incompatible "
1482
+ f"dimensions ({self.D.shape} and {other.shape})")
1483
+
1484
+ common_dtype = np.result_type(a.dtype, b.dtype, c.dtype, d.dtype)
1485
+ return StateSpace(np.asarray(a, dtype=common_dtype),
1486
+ np.asarray(b, dtype=common_dtype),
1487
+ np.asarray(c, dtype=common_dtype),
1488
+ np.asarray(d, dtype=common_dtype),
1489
+ **self._dt_dict)
1490
+
1491
+ def __sub__(self, other):
1492
+ if not self._check_binop_other(other):
1493
+ return NotImplemented
1494
+
1495
+ return self.__add__(-other)
1496
+
1497
+ def __radd__(self, other):
1498
+ if not self._check_binop_other(other):
1499
+ return NotImplemented
1500
+
1501
+ return self.__add__(other)
1502
+
1503
+ def __rsub__(self, other):
1504
+ if not self._check_binop_other(other):
1505
+ return NotImplemented
1506
+
1507
+ return (-self).__add__(other)
1508
+
1509
+ def __truediv__(self, other):
1510
+ """
1511
+ Divide by a scalar
1512
+ """
1513
+ # Division by non-StateSpace scalars
1514
+ if not self._check_binop_other(other) or isinstance(other, StateSpace):
1515
+ return NotImplemented
1516
+
1517
+ if isinstance(other, np.ndarray) and other.ndim > 0:
1518
+ # It's ambiguous what this means, so disallow it
1519
+ raise ValueError("Cannot divide StateSpace by non-scalar numpy arrays")
1520
+
1521
+ return self.__mul__(1/other)
1522
+
1523
+ @property
1524
+ def A(self):
1525
+ """State matrix of the `StateSpace` system."""
1526
+ return self._A
1527
+
1528
+ @A.setter
1529
+ def A(self, A):
1530
+ self._A = _atleast_2d_or_none(A)
1531
+
1532
+ @property
1533
+ def B(self):
1534
+ """Input matrix of the `StateSpace` system."""
1535
+ return self._B
1536
+
1537
+ @B.setter
1538
+ def B(self, B):
1539
+ self._B = _atleast_2d_or_none(B)
1540
+ self.inputs = self.B.shape[-1]
1541
+
1542
+ @property
1543
+ def C(self):
1544
+ """Output matrix of the `StateSpace` system."""
1545
+ return self._C
1546
+
1547
+ @C.setter
1548
+ def C(self, C):
1549
+ self._C = _atleast_2d_or_none(C)
1550
+ self.outputs = self.C.shape[0]
1551
+
1552
+ @property
1553
+ def D(self):
1554
+ """Feedthrough matrix of the `StateSpace` system."""
1555
+ return self._D
1556
+
1557
+ @D.setter
1558
+ def D(self, D):
1559
+ self._D = _atleast_2d_or_none(D)
1560
+
1561
+ def _copy(self, system):
1562
+ """
1563
+ Copy the parameters of another `StateSpace` system.
1564
+
1565
+ Parameters
1566
+ ----------
1567
+ system : instance of `StateSpace`
1568
+ The state-space system that is to be copied
1569
+
1570
+ """
1571
+ self.A = system.A
1572
+ self.B = system.B
1573
+ self.C = system.C
1574
+ self.D = system.D
1575
+
1576
+ def to_tf(self, **kwargs):
1577
+ """
1578
+ Convert system representation to `TransferFunction`.
1579
+
1580
+ Parameters
1581
+ ----------
1582
+ kwargs : dict, optional
1583
+ Additional keywords passed to `ss2zpk`
1584
+
1585
+ Returns
1586
+ -------
1587
+ sys : instance of `TransferFunction`
1588
+ Transfer function of the current system
1589
+
1590
+ """
1591
+ return TransferFunction(*ss2tf(self._A, self._B, self._C, self._D,
1592
+ **kwargs), **self._dt_dict)
1593
+
1594
+ def to_zpk(self, **kwargs):
1595
+ """
1596
+ Convert system representation to `ZerosPolesGain`.
1597
+
1598
+ Parameters
1599
+ ----------
1600
+ kwargs : dict, optional
1601
+ Additional keywords passed to `ss2zpk`
1602
+
1603
+ Returns
1604
+ -------
1605
+ sys : instance of `ZerosPolesGain`
1606
+ Zeros, poles, gain representation of the current system
1607
+
1608
+ """
1609
+ return ZerosPolesGain(*ss2zpk(self._A, self._B, self._C, self._D,
1610
+ **kwargs), **self._dt_dict)
1611
+
1612
+ def to_ss(self):
1613
+ """
1614
+ Return a copy of the current `StateSpace` system.
1615
+
1616
+ Returns
1617
+ -------
1618
+ sys : instance of `StateSpace`
1619
+ The current system (copy)
1620
+
1621
+ """
1622
+ return copy.deepcopy(self)
1623
+
1624
+
1625
+ class StateSpaceContinuous(StateSpace, lti):
1626
+ r"""
1627
+ Continuous-time Linear Time Invariant system in state-space form.
1628
+
1629
+ Represents the system as the continuous-time, first order differential
1630
+ equation :math:`\dot{x} = A x + B u`.
1631
+ Continuous-time `StateSpace` systems inherit additional functionality
1632
+ from the `lti` class.
1633
+
1634
+ Parameters
1635
+ ----------
1636
+ *system: arguments
1637
+ The `StateSpace` class can be instantiated with 1 or 3 arguments.
1638
+ The following gives the number of input arguments and their
1639
+ interpretation:
1640
+
1641
+ * 1: `lti` system: (`StateSpace`, `TransferFunction` or
1642
+ `ZerosPolesGain`)
1643
+ * 4: array_like: (A, B, C, D)
1644
+
1645
+ See Also
1646
+ --------
1647
+ TransferFunction, ZerosPolesGain, lti
1648
+ ss2zpk, ss2tf, zpk2sos
1649
+
1650
+ Notes
1651
+ -----
1652
+ Changing the value of properties that are not part of the
1653
+ `StateSpace` system representation (such as `zeros` or `poles`) is very
1654
+ inefficient and may lead to numerical inaccuracies. It is better to
1655
+ convert to the specific system representation first. For example, call
1656
+ ``sys = sys.to_zpk()`` before accessing/changing the zeros, poles or gain.
1657
+
1658
+ Examples
1659
+ --------
1660
+ >>> import numpy as np
1661
+ >>> from scipy import signal
1662
+
1663
+ >>> a = np.array([[0, 1], [0, 0]])
1664
+ >>> b = np.array([[0], [1]])
1665
+ >>> c = np.array([[1, 0]])
1666
+ >>> d = np.array([[0]])
1667
+
1668
+ >>> sys = signal.StateSpace(a, b, c, d)
1669
+ >>> print(sys)
1670
+ StateSpaceContinuous(
1671
+ array([[0, 1],
1672
+ [0, 0]]),
1673
+ array([[0],
1674
+ [1]]),
1675
+ array([[1, 0]]),
1676
+ array([[0]]),
1677
+ dt: None
1678
+ )
1679
+
1680
+ """
1681
+
1682
+ def to_discrete(self, dt, method='zoh', alpha=None):
1683
+ """
1684
+ Returns the discretized `StateSpace` system.
1685
+
1686
+ Parameters: See `cont2discrete` for details.
1687
+
1688
+ Returns
1689
+ -------
1690
+ sys: instance of `dlti` and `StateSpace`
1691
+ """
1692
+ return StateSpace(*cont2discrete((self.A, self.B, self.C, self.D),
1693
+ dt,
1694
+ method=method,
1695
+ alpha=alpha)[:-1],
1696
+ dt=dt)
1697
+
1698
+
1699
+ class StateSpaceDiscrete(StateSpace, dlti):
1700
+ r"""
1701
+ Discrete-time Linear Time Invariant system in state-space form.
1702
+
1703
+ Represents the system as the discrete-time difference equation
1704
+ :math:`x[k+1] = A x[k] + B u[k]`.
1705
+ `StateSpace` systems inherit additional functionality from the `dlti`
1706
+ class.
1707
+
1708
+ Parameters
1709
+ ----------
1710
+ *system: arguments
1711
+ The `StateSpace` class can be instantiated with 1 or 3 arguments.
1712
+ The following gives the number of input arguments and their
1713
+ interpretation:
1714
+
1715
+ * 1: `dlti` system: (`StateSpace`, `TransferFunction` or
1716
+ `ZerosPolesGain`)
1717
+ * 4: array_like: (A, B, C, D)
1718
+ dt: float, optional
1719
+ Sampling time [s] of the discrete-time systems. Defaults to `True`
1720
+ (unspecified sampling time). Must be specified as a keyword argument,
1721
+ for example, ``dt=0.1``.
1722
+
1723
+ See Also
1724
+ --------
1725
+ TransferFunction, ZerosPolesGain, dlti
1726
+ ss2zpk, ss2tf, zpk2sos
1727
+
1728
+ Notes
1729
+ -----
1730
+ Changing the value of properties that are not part of the
1731
+ `StateSpace` system representation (such as `zeros` or `poles`) is very
1732
+ inefficient and may lead to numerical inaccuracies. It is better to
1733
+ convert to the specific system representation first. For example, call
1734
+ ``sys = sys.to_zpk()`` before accessing/changing the zeros, poles or gain.
1735
+
1736
+ Examples
1737
+ --------
1738
+ >>> import numpy as np
1739
+ >>> from scipy import signal
1740
+
1741
+ >>> a = np.array([[1, 0.1], [0, 1]])
1742
+ >>> b = np.array([[0.005], [0.1]])
1743
+ >>> c = np.array([[1, 0]])
1744
+ >>> d = np.array([[0]])
1745
+
1746
+ >>> signal.StateSpace(a, b, c, d, dt=0.1)
1747
+ StateSpaceDiscrete(
1748
+ array([[ 1. , 0.1],
1749
+ [ 0. , 1. ]]),
1750
+ array([[ 0.005],
1751
+ [ 0.1 ]]),
1752
+ array([[1, 0]]),
1753
+ array([[0]]),
1754
+ dt: 0.1
1755
+ )
1756
+
1757
+ """
1758
+ pass
1759
+
1760
+
1761
+ def lsim(system, U, T, X0=None, interp=True):
1762
+ """
1763
+ Simulate output of a continuous-time linear system.
1764
+
1765
+ Parameters
1766
+ ----------
1767
+ system : an instance of the LTI class or a tuple describing the system.
1768
+ The following gives the number of elements in the tuple and
1769
+ the interpretation:
1770
+
1771
+ * 1: (instance of `lti`)
1772
+ * 2: (num, den)
1773
+ * 3: (zeros, poles, gain)
1774
+ * 4: (A, B, C, D)
1775
+
1776
+ U : array_like
1777
+ An input array describing the input at each time `T`
1778
+ (interpolation is assumed between given times). If there are
1779
+ multiple inputs, then each column of the rank-2 array
1780
+ represents an input. If U = 0 or None, a zero input is used.
1781
+ T : array_like
1782
+ The time steps at which the input is defined and at which the
1783
+ output is desired. Must be nonnegative, increasing, and equally spaced.
1784
+ X0 : array_like, optional
1785
+ The initial conditions on the state vector (zero by default).
1786
+ interp : bool, optional
1787
+ Whether to use linear (True, the default) or zero-order-hold (False)
1788
+ interpolation for the input array.
1789
+
1790
+ Returns
1791
+ -------
1792
+ T : 1D ndarray
1793
+ Time values for the output.
1794
+ yout : 1D ndarray
1795
+ System response.
1796
+ xout : ndarray
1797
+ Time evolution of the state vector.
1798
+
1799
+ Notes
1800
+ -----
1801
+ If (num, den) is passed in for ``system``, coefficients for both the
1802
+ numerator and denominator should be specified in descending exponent
1803
+ order (e.g. ``s^2 + 3s + 5`` would be represented as ``[1, 3, 5]``).
1804
+
1805
+ Examples
1806
+ --------
1807
+ We'll use `lsim` to simulate an analog Bessel filter applied to
1808
+ a signal.
1809
+
1810
+ >>> import numpy as np
1811
+ >>> from scipy.signal import bessel, lsim
1812
+ >>> import matplotlib.pyplot as plt
1813
+
1814
+ Create a low-pass Bessel filter with a cutoff of 12 Hz.
1815
+
1816
+ >>> b, a = bessel(N=5, Wn=2*np.pi*12, btype='lowpass', analog=True)
1817
+
1818
+ Generate data to which the filter is applied.
1819
+
1820
+ >>> t = np.linspace(0, 1.25, 500, endpoint=False)
1821
+
1822
+ The input signal is the sum of three sinusoidal curves, with
1823
+ frequencies 4 Hz, 40 Hz, and 80 Hz. The filter should mostly
1824
+ eliminate the 40 Hz and 80 Hz components, leaving just the 4 Hz signal.
1825
+
1826
+ >>> u = (np.cos(2*np.pi*4*t) + 0.6*np.sin(2*np.pi*40*t) +
1827
+ ... 0.5*np.cos(2*np.pi*80*t))
1828
+
1829
+ Simulate the filter with `lsim`.
1830
+
1831
+ >>> tout, yout, xout = lsim((b, a), U=u, T=t)
1832
+
1833
+ Plot the result.
1834
+
1835
+ >>> plt.plot(t, u, 'r', alpha=0.5, linewidth=1, label='input')
1836
+ >>> plt.plot(tout, yout, 'k', linewidth=1.5, label='output')
1837
+ >>> plt.legend(loc='best', shadow=True, framealpha=1)
1838
+ >>> plt.grid(alpha=0.3)
1839
+ >>> plt.xlabel('t')
1840
+ >>> plt.show()
1841
+
1842
+ In a second example, we simulate a double integrator ``y'' = u``, with
1843
+ a constant input ``u = 1``. We'll use the state space representation
1844
+ of the integrator.
1845
+
1846
+ >>> from scipy.signal import lti
1847
+ >>> A = np.array([[0.0, 1.0], [0.0, 0.0]])
1848
+ >>> B = np.array([[0.0], [1.0]])
1849
+ >>> C = np.array([[1.0, 0.0]])
1850
+ >>> D = 0.0
1851
+ >>> system = lti(A, B, C, D)
1852
+
1853
+ `t` and `u` define the time and input signal for the system to
1854
+ be simulated.
1855
+
1856
+ >>> t = np.linspace(0, 5, num=50)
1857
+ >>> u = np.ones_like(t)
1858
+
1859
+ Compute the simulation, and then plot `y`. As expected, the plot shows
1860
+ the curve ``y = 0.5*t**2``.
1861
+
1862
+ >>> tout, y, x = lsim(system, u, t)
1863
+ >>> plt.plot(t, y)
1864
+ >>> plt.grid(alpha=0.3)
1865
+ >>> plt.xlabel('t')
1866
+ >>> plt.show()
1867
+
1868
+ """
1869
+ if isinstance(system, lti):
1870
+ sys = system._as_ss()
1871
+ elif isinstance(system, dlti):
1872
+ raise AttributeError('lsim can only be used with continuous-time '
1873
+ 'systems.')
1874
+ else:
1875
+ sys = lti(*system)._as_ss()
1876
+ T = atleast_1d(T)
1877
+ if len(T.shape) != 1:
1878
+ raise ValueError("T must be a rank-1 array.")
1879
+
1880
+ A, B, C, D = map(np.asarray, (sys.A, sys.B, sys.C, sys.D))
1881
+ n_states = A.shape[0]
1882
+ n_inputs = B.shape[1]
1883
+
1884
+ n_steps = T.size
1885
+ if X0 is None:
1886
+ X0 = zeros(n_states, sys.A.dtype)
1887
+ xout = np.empty((n_steps, n_states), sys.A.dtype)
1888
+
1889
+ if T[0] == 0:
1890
+ xout[0] = X0
1891
+ elif T[0] > 0:
1892
+ # step forward to initial time, with zero input
1893
+ xout[0] = dot(X0, linalg.expm(transpose(A) * T[0]))
1894
+ else:
1895
+ raise ValueError("Initial time must be nonnegative")
1896
+
1897
+ no_input = (U is None or
1898
+ (isinstance(U, int | float) and U == 0.) or
1899
+ not np.any(U))
1900
+
1901
+ if n_steps == 1:
1902
+ yout = squeeze(xout @ C.T)
1903
+ if not no_input:
1904
+ yout += squeeze(U @ D.T)
1905
+ return T, yout, squeeze(xout)
1906
+
1907
+ dt = T[1] - T[0]
1908
+ if not np.allclose(np.diff(T), dt):
1909
+ raise ValueError("Time steps are not equally spaced.")
1910
+
1911
+ if no_input:
1912
+ # Zero input: just use matrix exponential
1913
+ # take transpose because state is a row vector
1914
+ expAT_dt = linalg.expm(A.T * dt)
1915
+ for i in range(1, n_steps):
1916
+ xout[i] = xout[i-1] @ expAT_dt
1917
+ yout = squeeze(xout @ C.T)
1918
+ return T, yout, squeeze(xout)
1919
+
1920
+ # Nonzero input
1921
+ U = atleast_1d(U)
1922
+ if U.ndim == 1:
1923
+ U = U[:, np.newaxis]
1924
+
1925
+ if U.shape[0] != n_steps:
1926
+ raise ValueError("U must have the same number of rows "
1927
+ "as elements in T.")
1928
+
1929
+ if U.shape[1] != n_inputs:
1930
+ raise ValueError("System does not define that many inputs.")
1931
+
1932
+ if not interp:
1933
+ # Zero-order hold
1934
+ # Algorithm: to integrate from time 0 to time dt, we solve
1935
+ # xdot = A x + B u, x(0) = x0
1936
+ # udot = 0, u(0) = u0.
1937
+ #
1938
+ # Solution is
1939
+ # [ x(dt) ] [ A*dt B*dt ] [ x0 ]
1940
+ # [ u(dt) ] = exp [ 0 0 ] [ u0 ]
1941
+ M = np.vstack([np.hstack([A * dt, B * dt]),
1942
+ np.zeros((n_inputs, n_states + n_inputs))])
1943
+ # transpose everything because the state and input are row vectors
1944
+ expMT = linalg.expm(M.T)
1945
+ Ad = expMT[:n_states, :n_states]
1946
+ Bd = expMT[n_states:, :n_states]
1947
+ for i in range(1, n_steps):
1948
+ xout[i] = xout[i-1] @ Ad + U[i-1] @ Bd
1949
+ else:
1950
+ # Linear interpolation between steps
1951
+ # Algorithm: to integrate from time 0 to time dt, with linear
1952
+ # interpolation between inputs u(0) = u0 and u(dt) = u1, we solve
1953
+ # xdot = A x + B u, x(0) = x0
1954
+ # udot = (u1 - u0) / dt, u(0) = u0.
1955
+ #
1956
+ # Solution is
1957
+ # [ x(dt) ] [ A*dt B*dt 0 ] [ x0 ]
1958
+ # [ u(dt) ] = exp [ 0 0 I ] [ u0 ]
1959
+ # [u1 - u0] [ 0 0 0 ] [u1 - u0]
1960
+ M = np.vstack([np.hstack([A * dt, B * dt,
1961
+ np.zeros((n_states, n_inputs))]),
1962
+ np.hstack([np.zeros((n_inputs, n_states + n_inputs)),
1963
+ np.identity(n_inputs)]),
1964
+ np.zeros((n_inputs, n_states + 2 * n_inputs))])
1965
+ expMT = linalg.expm(M.T)
1966
+ Ad = expMT[:n_states, :n_states]
1967
+ Bd1 = expMT[n_states+n_inputs:, :n_states]
1968
+ Bd0 = expMT[n_states:n_states + n_inputs, :n_states] - Bd1
1969
+ for i in range(1, n_steps):
1970
+ xout[i] = xout[i-1] @ Ad + U[i-1] @ Bd0 + U[i] @ Bd1
1971
+
1972
+ yout = squeeze(xout @ C.T) + squeeze(U @ D.T)
1973
+ return T, yout, squeeze(xout)
1974
+
1975
+
1976
+ def _default_response_times(A, n):
1977
+ """Compute a reasonable set of time samples for the response time.
1978
+
1979
+ This function is used by `impulse` and `step` to compute the response time
1980
+ when the `T` argument to the function is None.
1981
+
1982
+ Parameters
1983
+ ----------
1984
+ A : array_like
1985
+ The system matrix, which is square.
1986
+ n : int
1987
+ The number of time samples to generate.
1988
+
1989
+ Returns
1990
+ -------
1991
+ t : ndarray
1992
+ The 1-D array of length `n` of time samples at which the response
1993
+ is to be computed.
1994
+ """
1995
+ # Create a reasonable time interval.
1996
+ # TODO: This could use some more work.
1997
+ # For example, what is expected when the system is unstable?
1998
+ vals = linalg.eigvals(A)
1999
+ r = min(abs(real(vals)))
2000
+ if r == 0.0:
2001
+ r = 1.0
2002
+ tc = 1.0 / r
2003
+ t = linspace(0.0, 7 * tc, n)
2004
+ return t
2005
+
2006
+
2007
+ def impulse(system, X0=None, T=None, N=None):
2008
+ """Impulse response of continuous-time system.
2009
+
2010
+ Parameters
2011
+ ----------
2012
+ system : an instance of the LTI class or a tuple of array_like
2013
+ describing the system.
2014
+ The following gives the number of elements in the tuple and
2015
+ the interpretation:
2016
+
2017
+ * 1 (instance of `lti`)
2018
+ * 2 (num, den)
2019
+ * 3 (zeros, poles, gain)
2020
+ * 4 (A, B, C, D)
2021
+
2022
+ X0 : array_like, optional
2023
+ Initial state-vector. Defaults to zero.
2024
+ T : array_like, optional
2025
+ Time points. Computed if not given.
2026
+ N : int, optional
2027
+ The number of time points to compute (if `T` is not given).
2028
+
2029
+ Returns
2030
+ -------
2031
+ T : ndarray
2032
+ A 1-D array of time points.
2033
+ yout : ndarray
2034
+ A 1-D array containing the impulse response of the system (except for
2035
+ singularities at zero).
2036
+
2037
+ Notes
2038
+ -----
2039
+ If (num, den) is passed in for ``system``, coefficients for both the
2040
+ numerator and denominator should be specified in descending exponent
2041
+ order (e.g. ``s^2 + 3s + 5`` would be represented as ``[1, 3, 5]``).
2042
+
2043
+ Examples
2044
+ --------
2045
+ Compute the impulse response of a second order system with a repeated
2046
+ root: ``x''(t) + 2*x'(t) + x(t) = u(t)``
2047
+
2048
+ >>> from scipy import signal
2049
+ >>> system = ([1.0], [1.0, 2.0, 1.0])
2050
+ >>> t, y = signal.impulse(system)
2051
+ >>> import matplotlib.pyplot as plt
2052
+ >>> plt.plot(t, y)
2053
+
2054
+ """
2055
+ if isinstance(system, lti):
2056
+ sys = system._as_ss()
2057
+ elif isinstance(system, dlti):
2058
+ raise AttributeError('impulse can only be used with continuous-time '
2059
+ 'systems.')
2060
+ else:
2061
+ sys = lti(*system)._as_ss()
2062
+ if X0 is None:
2063
+ X = squeeze(sys.B)
2064
+ else:
2065
+ X = squeeze(sys.B + X0)
2066
+ if N is None:
2067
+ N = 100
2068
+ if T is None:
2069
+ T = _default_response_times(sys.A, N)
2070
+ else:
2071
+ T = asarray(T)
2072
+
2073
+ _, h, _ = lsim(sys, 0., T, X, interp=False)
2074
+ return T, h
2075
+
2076
+
2077
+ def step(system, X0=None, T=None, N=None):
2078
+ """Step response of continuous-time system.
2079
+
2080
+ Parameters
2081
+ ----------
2082
+ system : an instance of the LTI class or a tuple of array_like
2083
+ describing the system.
2084
+ The following gives the number of elements in the tuple and
2085
+ the interpretation:
2086
+
2087
+ * 1 (instance of `lti`)
2088
+ * 2 (num, den)
2089
+ * 3 (zeros, poles, gain)
2090
+ * 4 (A, B, C, D)
2091
+
2092
+ X0 : array_like, optional
2093
+ Initial state-vector (default is zero).
2094
+ T : array_like, optional
2095
+ Time points (computed if not given).
2096
+ N : int, optional
2097
+ Number of time points to compute if `T` is not given.
2098
+
2099
+ Returns
2100
+ -------
2101
+ T : 1D ndarray
2102
+ Output time points.
2103
+ yout : 1D ndarray
2104
+ Step response of system.
2105
+
2106
+
2107
+ Notes
2108
+ -----
2109
+ If (num, den) is passed in for ``system``, coefficients for both the
2110
+ numerator and denominator should be specified in descending exponent
2111
+ order (e.g. ``s^2 + 3s + 5`` would be represented as ``[1, 3, 5]``).
2112
+
2113
+ Examples
2114
+ --------
2115
+ >>> from scipy import signal
2116
+ >>> import matplotlib.pyplot as plt
2117
+ >>> lti = signal.lti([1.0], [1.0, 1.0])
2118
+ >>> t, y = signal.step(lti)
2119
+ >>> plt.plot(t, y)
2120
+ >>> plt.xlabel('Time [s]')
2121
+ >>> plt.ylabel('Amplitude')
2122
+ >>> plt.title('Step response for 1. Order Lowpass')
2123
+ >>> plt.grid()
2124
+
2125
+ """
2126
+ if isinstance(system, lti):
2127
+ sys = system._as_ss()
2128
+ elif isinstance(system, dlti):
2129
+ raise AttributeError('step can only be used with continuous-time '
2130
+ 'systems.')
2131
+ else:
2132
+ sys = lti(*system)._as_ss()
2133
+ if N is None:
2134
+ N = 100
2135
+ if T is None:
2136
+ T = _default_response_times(sys.A, N)
2137
+ else:
2138
+ T = asarray(T)
2139
+ U = ones(T.shape, sys.A.dtype)
2140
+ vals = lsim(sys, U, T, X0=X0, interp=False)
2141
+ return vals[0], vals[1]
2142
+
2143
+
2144
+ def bode(system, w=None, n=100):
2145
+ """
2146
+ Calculate Bode magnitude and phase data of a continuous-time system.
2147
+
2148
+ Parameters
2149
+ ----------
2150
+ system : an instance of the LTI class or a tuple describing the system.
2151
+ The following gives the number of elements in the tuple and
2152
+ the interpretation:
2153
+
2154
+ * 1 (instance of `lti`)
2155
+ * 2 (num, den)
2156
+ * 3 (zeros, poles, gain)
2157
+ * 4 (A, B, C, D)
2158
+
2159
+ w : array_like, optional
2160
+ Array of frequencies (in rad/s). Magnitude and phase data is calculated
2161
+ for every value in this array. If not given a reasonable set will be
2162
+ calculated.
2163
+ n : int, optional
2164
+ Number of frequency points to compute if `w` is not given. The `n`
2165
+ frequencies are logarithmically spaced in an interval chosen to
2166
+ include the influence of the poles and zeros of the system.
2167
+
2168
+ Returns
2169
+ -------
2170
+ w : 1D ndarray
2171
+ Frequency array [rad/s]
2172
+ mag : 1D ndarray
2173
+ Magnitude array [dB]
2174
+ phase : 1D ndarray
2175
+ Phase array [deg]
2176
+
2177
+ Notes
2178
+ -----
2179
+ If (num, den) is passed in for ``system``, coefficients for both the
2180
+ numerator and denominator should be specified in descending exponent
2181
+ order (e.g. ``s^2 + 3s + 5`` would be represented as ``[1, 3, 5]``).
2182
+
2183
+ .. versionadded:: 0.11.0
2184
+
2185
+ Examples
2186
+ --------
2187
+ >>> from scipy import signal
2188
+ >>> import matplotlib.pyplot as plt
2189
+
2190
+ >>> sys = signal.TransferFunction([1], [1, 1])
2191
+ >>> w, mag, phase = signal.bode(sys)
2192
+
2193
+ >>> plt.figure()
2194
+ >>> plt.semilogx(w, mag) # Bode magnitude plot
2195
+ >>> plt.figure()
2196
+ >>> plt.semilogx(w, phase) # Bode phase plot
2197
+ >>> plt.show()
2198
+
2199
+ """
2200
+ w, y = freqresp(system, w=w, n=n)
2201
+
2202
+ mag = 20.0 * np.log10(abs(y))
2203
+ phase = np.unwrap(np.arctan2(y.imag, y.real)) * 180.0 / np.pi
2204
+
2205
+ return w, mag, phase
2206
+
2207
+
2208
+ def freqresp(system, w=None, n=10000):
2209
+ r"""Calculate the frequency response of a continuous-time system.
2210
+
2211
+ Parameters
2212
+ ----------
2213
+ system : an instance of the `lti` class or a tuple describing the system.
2214
+ The following gives the number of elements in the tuple and
2215
+ the interpretation:
2216
+
2217
+ * 1 (instance of `lti`)
2218
+ * 2 (num, den)
2219
+ * 3 (zeros, poles, gain)
2220
+ * 4 (A, B, C, D)
2221
+
2222
+ w : array_like, optional
2223
+ Array of frequencies (in rad/s). Magnitude and phase data is
2224
+ calculated for every value in this array. If not given, a reasonable
2225
+ set will be calculated.
2226
+ n : int, optional
2227
+ Number of frequency points to compute if `w` is not given. The `n`
2228
+ frequencies are logarithmically spaced in an interval chosen to
2229
+ include the influence of the poles and zeros of the system.
2230
+
2231
+ Returns
2232
+ -------
2233
+ w : 1D ndarray
2234
+ Frequency array [rad/s]
2235
+ H : 1D ndarray
2236
+ Array of complex magnitude values
2237
+
2238
+ Notes
2239
+ -----
2240
+ If (num, den) is passed in for ``system``, coefficients for both the
2241
+ numerator and denominator should be specified in descending exponent
2242
+ order (e.g. ``s^2 + 3s + 5`` would be represented as ``[1, 3, 5]``).
2243
+
2244
+ Examples
2245
+ --------
2246
+ Generating the Nyquist plot of a transfer function
2247
+
2248
+ >>> from scipy import signal
2249
+ >>> import matplotlib.pyplot as plt
2250
+
2251
+ Construct the transfer function :math:`H(s) = \frac{5}{(s-1)^3}`:
2252
+
2253
+ >>> s1 = signal.ZerosPolesGain([], [1, 1, 1], [5])
2254
+
2255
+ >>> w, H = signal.freqresp(s1)
2256
+
2257
+ >>> plt.figure()
2258
+ >>> plt.plot(H.real, H.imag, "b")
2259
+ >>> plt.plot(H.real, -H.imag, "r")
2260
+ >>> plt.show()
2261
+ """
2262
+ if isinstance(system, lti):
2263
+ if isinstance(system, TransferFunction | ZerosPolesGain):
2264
+ sys = system
2265
+ else:
2266
+ sys = system._as_zpk()
2267
+ elif isinstance(system, dlti):
2268
+ raise AttributeError('freqresp can only be used with continuous-time '
2269
+ 'systems.')
2270
+ else:
2271
+ sys = lti(*system)._as_zpk()
2272
+
2273
+ if sys.inputs != 1 or sys.outputs != 1:
2274
+ raise ValueError("freqresp() requires a SISO (single input, single "
2275
+ "output) system.")
2276
+
2277
+ if w is not None:
2278
+ worN = w
2279
+ else:
2280
+ worN = n
2281
+
2282
+ if isinstance(sys, TransferFunction):
2283
+ # In the call to freqs(), sys.num.ravel() is used because there are
2284
+ # cases where sys.num is a 2-D array with a single row.
2285
+ w, h = freqs(sys.num.ravel(), sys.den, worN=worN)
2286
+
2287
+ elif isinstance(sys, ZerosPolesGain):
2288
+ w, h = freqs_zpk(sys.zeros, sys.poles, sys.gain, worN=worN)
2289
+
2290
+ return w, h
2291
+
2292
+
2293
+ # This class will be used by place_poles to return its results
2294
+ # see https://code.activestate.com/recipes/52308/
2295
+ class Bunch:
2296
+ def __init__(self, **kwds):
2297
+ self.__dict__.update(kwds)
2298
+
2299
+
2300
+ def _valid_inputs(A, B, poles, method, rtol, maxiter):
2301
+ """
2302
+ Check the poles come in complex conjugate pairs
2303
+ Check shapes of A, B and poles are compatible.
2304
+ Check the method chosen is compatible with provided poles
2305
+ Return update method to use and ordered poles
2306
+
2307
+ """
2308
+ poles = np.asarray(poles)
2309
+ if poles.ndim > 1:
2310
+ raise ValueError("Poles must be a 1D array like.")
2311
+ # Will raise ValueError if poles do not come in complex conjugates pairs
2312
+ poles = _order_complex_poles(poles)
2313
+ if A.ndim > 2:
2314
+ raise ValueError("A must be a 2D array/matrix.")
2315
+ if B.ndim > 2:
2316
+ raise ValueError("B must be a 2D array/matrix")
2317
+ if A.shape[0] != A.shape[1]:
2318
+ raise ValueError("A must be square")
2319
+ if len(poles) > A.shape[0]:
2320
+ raise ValueError(
2321
+ f"maximum number of poles is {A.shape[0]} but you asked for {len(poles)}"
2322
+ )
2323
+ if len(poles) < A.shape[0]:
2324
+ raise ValueError(
2325
+ f"number of poles is {len(poles)} but you should provide {A.shape[0]}"
2326
+ )
2327
+ r = np.linalg.matrix_rank(B)
2328
+ for p in poles:
2329
+ if sum(p == poles) > r:
2330
+ raise ValueError("at least one of the requested pole is repeated "
2331
+ "more than rank(B) times")
2332
+ # Choose update method
2333
+ update_loop = _YT_loop
2334
+ if method not in ('KNV0','YT'):
2335
+ raise ValueError("The method keyword must be one of 'YT' or 'KNV0'")
2336
+
2337
+ if method == "KNV0":
2338
+ update_loop = _KNV0_loop
2339
+ if not all(np.isreal(poles)):
2340
+ raise ValueError("Complex poles are not supported by KNV0")
2341
+
2342
+ if maxiter < 1:
2343
+ raise ValueError("maxiter must be at least equal to 1")
2344
+
2345
+ # We do not check rtol <= 0 as the user can use a negative rtol to
2346
+ # force maxiter iterations
2347
+ if rtol > 1:
2348
+ raise ValueError("rtol can not be greater than 1")
2349
+
2350
+ return update_loop, poles
2351
+
2352
+
2353
+ def _order_complex_poles(poles):
2354
+ """
2355
+ Check we have complex conjugates pairs and reorder P according to YT, ie
2356
+ real_poles, complex_i, conjugate complex_i, ....
2357
+ The lexicographic sort on the complex poles is added to help the user to
2358
+ compare sets of poles.
2359
+ """
2360
+ ordered_poles = np.sort(poles[np.isreal(poles)])
2361
+ im_poles = []
2362
+ for p in np.sort(poles[np.imag(poles) < 0]):
2363
+ if np.conj(p) in poles:
2364
+ im_poles.extend((p, np.conj(p)))
2365
+
2366
+ ordered_poles = np.hstack((ordered_poles, im_poles))
2367
+
2368
+ if poles.shape[0] != len(ordered_poles):
2369
+ raise ValueError("Complex poles must come with their conjugates")
2370
+ return ordered_poles
2371
+
2372
+
2373
+ def _KNV0(B, ker_pole, transfer_matrix, j, poles):
2374
+ """
2375
+ Algorithm "KNV0" Kautsky et Al. Robust pole
2376
+ assignment in linear state feedback, Int journal of Control
2377
+ 1985, vol 41 p 1129->1155
2378
+ https://la.epfl.ch/files/content/sites/la/files/
2379
+ users/105941/public/KautskyNicholsDooren
2380
+
2381
+ """
2382
+ # Remove xj form the base
2383
+ transfer_matrix_not_j = np.delete(transfer_matrix, j, axis=1)
2384
+ # If we QR this matrix in full mode Q=Q0|Q1
2385
+ # then Q1 will be a single column orthogonal to
2386
+ # Q0, that's what we are looking for !
2387
+
2388
+ # After merge of gh-4249 great speed improvements could be achieved
2389
+ # using QR updates instead of full QR in the line below
2390
+
2391
+ # To debug with numpy qr uncomment the line below
2392
+ # Q, R = np.linalg.qr(transfer_matrix_not_j, mode="complete")
2393
+ Q, R = s_qr(transfer_matrix_not_j, mode="full")
2394
+
2395
+ mat_ker_pj = np.dot(ker_pole[j], ker_pole[j].T)
2396
+ yj = np.dot(mat_ker_pj, Q[:, -1])
2397
+
2398
+ # If Q[:, -1] is "almost" orthogonal to ker_pole[j] its
2399
+ # projection into ker_pole[j] will yield a vector
2400
+ # close to 0. As we are looking for a vector in ker_pole[j]
2401
+ # simply stick with transfer_matrix[:, j] (unless someone provides me with
2402
+ # a better choice ?)
2403
+
2404
+ if not np.allclose(yj, 0):
2405
+ xj = yj/np.linalg.norm(yj)
2406
+ transfer_matrix[:, j] = xj
2407
+
2408
+ # KNV does not support complex poles, using YT technique the two lines
2409
+ # below seem to work 9 out of 10 times but it is not reliable enough:
2410
+ # transfer_matrix[:, j]=real(xj)
2411
+ # transfer_matrix[:, j+1]=imag(xj)
2412
+
2413
+ # Add this at the beginning of this function if you wish to test
2414
+ # complex support:
2415
+ # if ~np.isreal(P[j]) and (j>=B.shape[0]-1 or P[j]!=np.conj(P[j+1])):
2416
+ # return
2417
+ # Problems arise when imag(xj)=>0 I have no idea on how to fix this
2418
+
2419
+
2420
+ def _YT_real(ker_pole, Q, transfer_matrix, i, j):
2421
+ """
2422
+ Applies algorithm from YT section 6.1 page 19 related to real pairs
2423
+ """
2424
+ # step 1 page 19
2425
+ u = Q[:, -2, np.newaxis]
2426
+ v = Q[:, -1, np.newaxis]
2427
+
2428
+ # step 2 page 19
2429
+ m = np.dot(np.dot(ker_pole[i].T, np.dot(u, v.T) -
2430
+ np.dot(v, u.T)), ker_pole[j])
2431
+
2432
+ # step 3 page 19
2433
+ um, sm, vm = np.linalg.svd(m)
2434
+ # mu1, mu2 two first columns of U => 2 first lines of U.T
2435
+ mu1, mu2 = um.T[:2, :, np.newaxis]
2436
+ # VM is V.T with numpy we want the first two lines of V.T
2437
+ nu1, nu2 = vm[:2, :, np.newaxis]
2438
+
2439
+ # what follows is a rough python translation of the formulas
2440
+ # in section 6.2 page 20 (step 4)
2441
+ transfer_matrix_j_mo_transfer_matrix_j = np.vstack((
2442
+ transfer_matrix[:, i, np.newaxis],
2443
+ transfer_matrix[:, j, np.newaxis]))
2444
+
2445
+ if not np.allclose(sm[0], sm[1]):
2446
+ ker_pole_imo_mu1 = np.dot(ker_pole[i], mu1)
2447
+ ker_pole_i_nu1 = np.dot(ker_pole[j], nu1)
2448
+ ker_pole_mu_nu = np.vstack((ker_pole_imo_mu1, ker_pole_i_nu1))
2449
+ else:
2450
+ ker_pole_ij = np.vstack((
2451
+ np.hstack((ker_pole[i],
2452
+ np.zeros(ker_pole[i].shape))),
2453
+ np.hstack((np.zeros(ker_pole[j].shape),
2454
+ ker_pole[j]))
2455
+ ))
2456
+ mu_nu_matrix = np.vstack(
2457
+ (np.hstack((mu1, mu2)), np.hstack((nu1, nu2)))
2458
+ )
2459
+ ker_pole_mu_nu = np.dot(ker_pole_ij, mu_nu_matrix)
2460
+ transfer_matrix_ij = np.dot(np.dot(ker_pole_mu_nu, ker_pole_mu_nu.T),
2461
+ transfer_matrix_j_mo_transfer_matrix_j)
2462
+ if not np.allclose(transfer_matrix_ij, 0):
2463
+ transfer_matrix_ij = (np.sqrt(2)*transfer_matrix_ij /
2464
+ np.linalg.norm(transfer_matrix_ij))
2465
+ transfer_matrix[:, i] = transfer_matrix_ij[
2466
+ :transfer_matrix[:, i].shape[0], 0
2467
+ ]
2468
+ transfer_matrix[:, j] = transfer_matrix_ij[
2469
+ transfer_matrix[:, i].shape[0]:, 0
2470
+ ]
2471
+ else:
2472
+ # As in knv0 if transfer_matrix_j_mo_transfer_matrix_j is orthogonal to
2473
+ # Vect{ker_pole_mu_nu} assign transfer_matrixi/transfer_matrix_j to
2474
+ # ker_pole_mu_nu and iterate. As we are looking for a vector in
2475
+ # Vect{Matker_pole_MU_NU} (see section 6.1 page 19) this might help
2476
+ # (that's a guess, not a claim !)
2477
+ transfer_matrix[:, i] = ker_pole_mu_nu[
2478
+ :transfer_matrix[:, i].shape[0], 0
2479
+ ]
2480
+ transfer_matrix[:, j] = ker_pole_mu_nu[
2481
+ transfer_matrix[:, i].shape[0]:, 0
2482
+ ]
2483
+
2484
+
2485
+ def _YT_complex(ker_pole, Q, transfer_matrix, i, j):
2486
+ """
2487
+ Applies algorithm from YT section 6.2 page 20 related to complex pairs
2488
+ """
2489
+ # step 1 page 20
2490
+ ur = np.sqrt(2)*Q[:, -2, np.newaxis]
2491
+ ui = np.sqrt(2)*Q[:, -1, np.newaxis]
2492
+ u = ur + 1j*ui
2493
+
2494
+ # step 2 page 20
2495
+ ker_pole_ij = ker_pole[i]
2496
+ m = np.dot(np.dot(np.conj(ker_pole_ij.T), np.dot(u, np.conj(u).T) -
2497
+ np.dot(np.conj(u), u.T)), ker_pole_ij)
2498
+
2499
+ # step 3 page 20
2500
+ e_val, e_vec = np.linalg.eig(m)
2501
+ # sort eigenvalues according to their module
2502
+ e_val_idx = np.argsort(np.abs(e_val))
2503
+ mu1 = e_vec[:, e_val_idx[-1], np.newaxis]
2504
+ mu2 = e_vec[:, e_val_idx[-2], np.newaxis]
2505
+
2506
+ # what follows is a rough python translation of the formulas
2507
+ # in section 6.2 page 20 (step 4)
2508
+
2509
+ # remember transfer_matrix_i has been split as
2510
+ # transfer_matrix[i]=real(transfer_matrix_i) and
2511
+ # transfer_matrix[j]=imag(transfer_matrix_i)
2512
+ transfer_matrix_j_mo_transfer_matrix_j = (
2513
+ transfer_matrix[:, i, np.newaxis] +
2514
+ 1j*transfer_matrix[:, j, np.newaxis]
2515
+ )
2516
+ if not np.allclose(np.abs(e_val[e_val_idx[-1]]),
2517
+ np.abs(e_val[e_val_idx[-2]])):
2518
+ ker_pole_mu = np.dot(ker_pole_ij, mu1)
2519
+ else:
2520
+ mu1_mu2_matrix = np.hstack((mu1, mu2))
2521
+ ker_pole_mu = np.dot(ker_pole_ij, mu1_mu2_matrix)
2522
+ transfer_matrix_i_j = np.dot(np.dot(ker_pole_mu, np.conj(ker_pole_mu.T)),
2523
+ transfer_matrix_j_mo_transfer_matrix_j)
2524
+
2525
+ if not np.allclose(transfer_matrix_i_j, 0):
2526
+ transfer_matrix_i_j = (transfer_matrix_i_j /
2527
+ np.linalg.norm(transfer_matrix_i_j))
2528
+ transfer_matrix[:, i] = np.real(transfer_matrix_i_j[:, 0])
2529
+ transfer_matrix[:, j] = np.imag(transfer_matrix_i_j[:, 0])
2530
+ else:
2531
+ # same idea as in YT_real
2532
+ transfer_matrix[:, i] = np.real(ker_pole_mu[:, 0])
2533
+ transfer_matrix[:, j] = np.imag(ker_pole_mu[:, 0])
2534
+
2535
+
2536
+ def _YT_loop(ker_pole, transfer_matrix, poles, B, maxiter, rtol):
2537
+ """
2538
+ Algorithm "YT" Tits, Yang. Globally Convergent
2539
+ Algorithms for Robust Pole Assignment by State Feedback
2540
+ https://hdl.handle.net/1903/5598
2541
+ The poles P have to be sorted accordingly to section 6.2 page 20
2542
+
2543
+ """
2544
+ # The IEEE edition of the YT paper gives useful information on the
2545
+ # optimal update order for the real poles in order to minimize the number
2546
+ # of times we have to loop over all poles, see page 1442
2547
+ nb_real = poles[np.isreal(poles)].shape[0]
2548
+ # hnb => Half Nb Real
2549
+ hnb = nb_real // 2
2550
+
2551
+ # Stick to the indices in the paper and then remove one to get numpy array
2552
+ # index it is a bit easier to link the code to the paper this way even if it
2553
+ # is not very clean. The paper is unclear about what should be done when
2554
+ # there is only one real pole => use KNV0 on this real pole seem to work
2555
+ if nb_real > 0:
2556
+ #update the biggest real pole with the smallest one
2557
+ update_order = [[nb_real], [1]]
2558
+ else:
2559
+ update_order = [[],[]]
2560
+
2561
+ r_comp = np.arange(nb_real+1, len(poles)+1, 2)
2562
+ # step 1.a
2563
+ r_p = np.arange(1, hnb+nb_real % 2)
2564
+ update_order[0].extend(2*r_p)
2565
+ update_order[1].extend(2*r_p+1)
2566
+ # step 1.b
2567
+ update_order[0].extend(r_comp)
2568
+ update_order[1].extend(r_comp+1)
2569
+ # step 1.c
2570
+ r_p = np.arange(1, hnb+1)
2571
+ update_order[0].extend(2*r_p-1)
2572
+ update_order[1].extend(2*r_p)
2573
+ # step 1.d
2574
+ if hnb == 0 and np.isreal(poles[0]):
2575
+ update_order[0].append(1)
2576
+ update_order[1].append(1)
2577
+ update_order[0].extend(r_comp)
2578
+ update_order[1].extend(r_comp+1)
2579
+ # step 2.a
2580
+ r_j = np.arange(2, hnb+nb_real % 2)
2581
+ for j in r_j:
2582
+ for i in range(1, hnb+1):
2583
+ update_order[0].append(i)
2584
+ update_order[1].append(i+j)
2585
+ # step 2.b
2586
+ if hnb == 0 and np.isreal(poles[0]):
2587
+ update_order[0].append(1)
2588
+ update_order[1].append(1)
2589
+ update_order[0].extend(r_comp)
2590
+ update_order[1].extend(r_comp+1)
2591
+ # step 2.c
2592
+ r_j = np.arange(2, hnb+nb_real % 2)
2593
+ for j in r_j:
2594
+ for i in range(hnb+1, nb_real+1):
2595
+ idx_1 = i+j
2596
+ if idx_1 > nb_real:
2597
+ idx_1 = i+j-nb_real
2598
+ update_order[0].append(i)
2599
+ update_order[1].append(idx_1)
2600
+ # step 2.d
2601
+ if hnb == 0 and np.isreal(poles[0]):
2602
+ update_order[0].append(1)
2603
+ update_order[1].append(1)
2604
+ update_order[0].extend(r_comp)
2605
+ update_order[1].extend(r_comp+1)
2606
+ # step 3.a
2607
+ for i in range(1, hnb+1):
2608
+ update_order[0].append(i)
2609
+ update_order[1].append(i+hnb)
2610
+ # step 3.b
2611
+ if hnb == 0 and np.isreal(poles[0]):
2612
+ update_order[0].append(1)
2613
+ update_order[1].append(1)
2614
+ update_order[0].extend(r_comp)
2615
+ update_order[1].extend(r_comp+1)
2616
+
2617
+ update_order = np.array(update_order).T-1
2618
+ stop = False
2619
+ nb_try = 0
2620
+ while nb_try < maxiter and not stop:
2621
+ det_transfer_matrixb = np.abs(np.linalg.det(transfer_matrix))
2622
+ for i, j in update_order:
2623
+ if i == j:
2624
+ assert i == 0, "i!=0 for KNV call in YT"
2625
+ assert np.isreal(poles[i]), "calling KNV on a complex pole"
2626
+ _KNV0(B, ker_pole, transfer_matrix, i, poles)
2627
+ else:
2628
+ transfer_matrix_not_i_j = np.delete(transfer_matrix, (i, j),
2629
+ axis=1)
2630
+ # after merge of gh-4249 great speed improvements could be
2631
+ # achieved using QR updates instead of full QR in the line below
2632
+
2633
+ #to debug with numpy qr uncomment the line below
2634
+ #Q, _ = np.linalg.qr(transfer_matrix_not_i_j, mode="complete")
2635
+ Q, _ = s_qr(transfer_matrix_not_i_j, mode="full")
2636
+
2637
+ if np.isreal(poles[i]):
2638
+ assert np.isreal(poles[j]), "mixing real and complex " + \
2639
+ "in YT_real" + str(poles)
2640
+ _YT_real(ker_pole, Q, transfer_matrix, i, j)
2641
+ else:
2642
+ assert ~np.isreal(poles[i]), "mixing real and complex " + \
2643
+ "in YT_real" + str(poles)
2644
+ _YT_complex(ker_pole, Q, transfer_matrix, i, j)
2645
+
2646
+ det_transfer_matrix = np.max((np.sqrt(np.spacing(1)),
2647
+ np.abs(np.linalg.det(transfer_matrix))))
2648
+ cur_rtol = np.abs(
2649
+ (det_transfer_matrix -
2650
+ det_transfer_matrixb) /
2651
+ det_transfer_matrix)
2652
+ if cur_rtol < rtol and det_transfer_matrix > np.sqrt(np.spacing(1)):
2653
+ # Convergence test from YT page 21
2654
+ stop = True
2655
+ nb_try += 1
2656
+ return stop, cur_rtol, nb_try
2657
+
2658
+
2659
+ def _KNV0_loop(ker_pole, transfer_matrix, poles, B, maxiter, rtol):
2660
+ """
2661
+ Loop over all poles one by one and apply KNV method 0 algorithm
2662
+ """
2663
+ # This method is useful only because we need to be able to call
2664
+ # _KNV0 from YT without looping over all poles, otherwise it would
2665
+ # have been fine to mix _KNV0_loop and _KNV0 in a single function
2666
+ stop = False
2667
+ nb_try = 0
2668
+ while nb_try < maxiter and not stop:
2669
+ det_transfer_matrixb = np.abs(np.linalg.det(transfer_matrix))
2670
+ for j in range(B.shape[0]):
2671
+ _KNV0(B, ker_pole, transfer_matrix, j, poles)
2672
+
2673
+ det_transfer_matrix = np.max((np.sqrt(np.spacing(1)),
2674
+ np.abs(np.linalg.det(transfer_matrix))))
2675
+ cur_rtol = np.abs((det_transfer_matrix - det_transfer_matrixb) /
2676
+ det_transfer_matrix)
2677
+ if cur_rtol < rtol and det_transfer_matrix > np.sqrt(np.spacing(1)):
2678
+ # Convergence test from YT page 21
2679
+ stop = True
2680
+
2681
+ nb_try += 1
2682
+ return stop, cur_rtol, nb_try
2683
+
2684
+
2685
+ def place_poles(A, B, poles, method="YT", rtol=1e-3, maxiter=30):
2686
+ """
2687
+ Compute K such that eigenvalues (A - dot(B, K))=poles.
2688
+
2689
+ K is the gain matrix such as the plant described by the linear system
2690
+ ``AX+BU`` will have its closed-loop poles, i.e the eigenvalues ``A - B*K``,
2691
+ as close as possible to those asked for in poles.
2692
+
2693
+ SISO, MISO and MIMO systems are supported.
2694
+
2695
+ Parameters
2696
+ ----------
2697
+ A, B : ndarray
2698
+ State-space representation of linear system ``AX + BU``.
2699
+ poles : array_like
2700
+ Desired real poles and/or complex conjugates poles.
2701
+ Complex poles are only supported with ``method="YT"`` (default).
2702
+ method: {'YT', 'KNV0'}, optional
2703
+ Which method to choose to find the gain matrix K. One of:
2704
+
2705
+ - 'YT': Yang Tits
2706
+ - 'KNV0': Kautsky, Nichols, Van Dooren update method 0
2707
+
2708
+ See References and Notes for details on the algorithms.
2709
+ rtol: float, optional
2710
+ After each iteration the determinant of the eigenvectors of
2711
+ ``A - B*K`` is compared to its previous value, when the relative
2712
+ error between these two values becomes lower than `rtol` the algorithm
2713
+ stops. Default is 1e-3.
2714
+ maxiter: int, optional
2715
+ Maximum number of iterations to compute the gain matrix.
2716
+ Default is 30.
2717
+
2718
+ Returns
2719
+ -------
2720
+ full_state_feedback : Bunch object
2721
+ full_state_feedback is composed of:
2722
+ gain_matrix : 1-D ndarray
2723
+ The closed loop matrix K such as the eigenvalues of ``A-BK``
2724
+ are as close as possible to the requested poles.
2725
+ computed_poles : 1-D ndarray
2726
+ The poles corresponding to ``A-BK`` sorted as first the real
2727
+ poles in increasing order, then the complex conjugates in
2728
+ lexicographic order.
2729
+ requested_poles : 1-D ndarray
2730
+ The poles the algorithm was asked to place sorted as above,
2731
+ they may differ from what was achieved.
2732
+ X : 2-D ndarray
2733
+ The transfer matrix such as ``X * diag(poles) = (A - B*K)*X``
2734
+ (see Notes)
2735
+ rtol : float
2736
+ The relative tolerance achieved on ``det(X)`` (see Notes).
2737
+ `rtol` will be NaN if it is possible to solve the system
2738
+ ``diag(poles) = (A - B*K)``, or 0 when the optimization
2739
+ algorithms can't do anything i.e when ``B.shape[1] == 1``.
2740
+ nb_iter : int
2741
+ The number of iterations performed before converging.
2742
+ `nb_iter` will be NaN if it is possible to solve the system
2743
+ ``diag(poles) = (A - B*K)``, or 0 when the optimization
2744
+ algorithms can't do anything i.e when ``B.shape[1] == 1``.
2745
+
2746
+ Notes
2747
+ -----
2748
+ The Tits and Yang (YT), [2]_ paper is an update of the original Kautsky et
2749
+ al. (KNV) paper [1]_. KNV relies on rank-1 updates to find the transfer
2750
+ matrix X such that ``X * diag(poles) = (A - B*K)*X``, whereas YT uses
2751
+ rank-2 updates. This yields on average more robust solutions (see [2]_
2752
+ pp 21-22), furthermore the YT algorithm supports complex poles whereas KNV
2753
+ does not in its original version. Only update method 0 proposed by KNV has
2754
+ been implemented here, hence the name ``'KNV0'``.
2755
+
2756
+ KNV extended to complex poles is used in Matlab's ``place`` function, YT is
2757
+ distributed under a non-free licence by Slicot under the name ``robpole``.
2758
+ It is unclear and undocumented how KNV0 has been extended to complex poles
2759
+ (Tits and Yang claim on page 14 of their paper that their method can not be
2760
+ used to extend KNV to complex poles), therefore only YT supports them in
2761
+ this implementation.
2762
+
2763
+ As the solution to the problem of pole placement is not unique for MIMO
2764
+ systems, both methods start with a tentative transfer matrix which is
2765
+ altered in various way to increase its determinant. Both methods have been
2766
+ proven to converge to a stable solution, however depending on the way the
2767
+ initial transfer matrix is chosen they will converge to different
2768
+ solutions and therefore there is absolutely no guarantee that using
2769
+ ``'KNV0'`` will yield results similar to Matlab's or any other
2770
+ implementation of these algorithms.
2771
+
2772
+ Using the default method ``'YT'`` should be fine in most cases; ``'KNV0'``
2773
+ is only provided because it is needed by ``'YT'`` in some specific cases.
2774
+ Furthermore ``'YT'`` gives on average more robust results than ``'KNV0'``
2775
+ when ``abs(det(X))`` is used as a robustness indicator.
2776
+
2777
+ [2]_ is available as a technical report on the following URL:
2778
+ https://hdl.handle.net/1903/5598
2779
+
2780
+ References
2781
+ ----------
2782
+ .. [1] J. Kautsky, N.K. Nichols and P. van Dooren, "Robust pole assignment
2783
+ in linear state feedback", International Journal of Control, Vol. 41
2784
+ pp. 1129-1155, 1985.
2785
+ .. [2] A.L. Tits and Y. Yang, "Globally convergent algorithms for robust
2786
+ pole assignment by state feedback", IEEE Transactions on Automatic
2787
+ Control, Vol. 41, pp. 1432-1452, 1996.
2788
+
2789
+ Examples
2790
+ --------
2791
+ A simple example demonstrating real pole placement using both KNV and YT
2792
+ algorithms. This is example number 1 from section 4 of the reference KNV
2793
+ publication ([1]_):
2794
+
2795
+ >>> import numpy as np
2796
+ >>> from scipy import signal
2797
+ >>> import matplotlib.pyplot as plt
2798
+
2799
+ >>> A = np.array([[ 1.380, -0.2077, 6.715, -5.676 ],
2800
+ ... [-0.5814, -4.290, 0, 0.6750 ],
2801
+ ... [ 1.067, 4.273, -6.654, 5.893 ],
2802
+ ... [ 0.0480, 4.273, 1.343, -2.104 ]])
2803
+ >>> B = np.array([[ 0, 5.679 ],
2804
+ ... [ 1.136, 1.136 ],
2805
+ ... [ 0, 0, ],
2806
+ ... [-3.146, 0 ]])
2807
+ >>> P = np.array([-0.2, -0.5, -5.0566, -8.6659])
2808
+
2809
+ Now compute K with KNV method 0, with the default YT method and with the YT
2810
+ method while forcing 100 iterations of the algorithm and print some results
2811
+ after each call.
2812
+
2813
+ >>> fsf1 = signal.place_poles(A, B, P, method='KNV0')
2814
+ >>> fsf1.gain_matrix
2815
+ array([[ 0.20071427, -0.96665799, 0.24066128, -0.10279785],
2816
+ [ 0.50587268, 0.57779091, 0.51795763, -0.41991442]])
2817
+
2818
+ >>> fsf2 = signal.place_poles(A, B, P) # uses YT method
2819
+ >>> fsf2.computed_poles
2820
+ array([-8.6659, -5.0566, -0.5 , -0.2 ])
2821
+
2822
+ >>> fsf3 = signal.place_poles(A, B, P, rtol=-1, maxiter=100)
2823
+ >>> fsf3.X
2824
+ array([[ 0.52072442+0.j, -0.08409372+0.j, -0.56847937+0.j, 0.74823657+0.j],
2825
+ [-0.04977751+0.j, -0.80872954+0.j, 0.13566234+0.j, -0.29322906+0.j],
2826
+ [-0.82266932+0.j, -0.19168026+0.j, -0.56348322+0.j, -0.43815060+0.j],
2827
+ [ 0.22267347+0.j, 0.54967577+0.j, -0.58387806+0.j, -0.40271926+0.j]])
2828
+
2829
+ The absolute value of the determinant of X is a good indicator to check the
2830
+ robustness of the results, both ``'KNV0'`` and ``'YT'`` aim at maximizing
2831
+ it. Below a comparison of the robustness of the results above:
2832
+
2833
+ >>> abs(np.linalg.det(fsf1.X)) < abs(np.linalg.det(fsf2.X))
2834
+ True
2835
+ >>> abs(np.linalg.det(fsf2.X)) < abs(np.linalg.det(fsf3.X))
2836
+ True
2837
+
2838
+ Now a simple example for complex poles:
2839
+
2840
+ >>> A = np.array([[ 0, 7/3., 0, 0 ],
2841
+ ... [ 0, 0, 0, 7/9. ],
2842
+ ... [ 0, 0, 0, 0 ],
2843
+ ... [ 0, 0, 0, 0 ]])
2844
+ >>> B = np.array([[ 0, 0 ],
2845
+ ... [ 0, 0 ],
2846
+ ... [ 1, 0 ],
2847
+ ... [ 0, 1 ]])
2848
+ >>> P = np.array([-3, -1, -2-1j, -2+1j]) / 3.
2849
+ >>> fsf = signal.place_poles(A, B, P, method='YT')
2850
+
2851
+ We can plot the desired and computed poles in the complex plane:
2852
+
2853
+ >>> t = np.linspace(0, 2*np.pi, 401)
2854
+ >>> plt.plot(np.cos(t), np.sin(t), 'k--') # unit circle
2855
+ >>> plt.plot(fsf.requested_poles.real, fsf.requested_poles.imag,
2856
+ ... 'wo', label='Desired')
2857
+ >>> plt.plot(fsf.computed_poles.real, fsf.computed_poles.imag, 'bx',
2858
+ ... label='Placed')
2859
+ >>> plt.grid()
2860
+ >>> plt.axis('image')
2861
+ >>> plt.axis([-1.1, 1.1, -1.1, 1.1])
2862
+ >>> plt.legend(bbox_to_anchor=(1.05, 1), loc=2, numpoints=1)
2863
+
2864
+ """
2865
+ # Move away all the inputs checking, it only adds noise to the code
2866
+ update_loop, poles = _valid_inputs(A, B, poles, method, rtol, maxiter)
2867
+
2868
+ # The current value of the relative tolerance we achieved
2869
+ cur_rtol = 0
2870
+ # The number of iterations needed before converging
2871
+ nb_iter = 0
2872
+
2873
+ # Step A: QR decomposition of B page 1132 KN
2874
+ # to debug with numpy qr uncomment the line below
2875
+ # u, z = np.linalg.qr(B, mode="complete")
2876
+ u, z = s_qr(B, mode="full")
2877
+ rankB = np.linalg.matrix_rank(B)
2878
+ u0 = u[:, :rankB]
2879
+ u1 = u[:, rankB:]
2880
+ z = z[:rankB, :]
2881
+
2882
+ # If we can use the identity matrix as X the solution is obvious
2883
+ if B.shape[0] == rankB:
2884
+ # if B is square and full rank there is only one solution
2885
+ # such as (A+BK)=inv(X)*diag(P)*X with X=eye(A.shape[0])
2886
+ # i.e K=inv(B)*(diag(P)-A)
2887
+ # if B has as many lines as its rank (but not square) there are many
2888
+ # solutions and we can choose one using least squares
2889
+ # => use lstsq in both cases.
2890
+ # In both cases the transfer matrix X will be eye(A.shape[0]) and I
2891
+ # can hardly think of a better one so there is nothing to optimize
2892
+ #
2893
+ # for complex poles we use the following trick
2894
+ #
2895
+ # |a -b| has for eigenvalues a+b and a-b
2896
+ # |b a|
2897
+ #
2898
+ # |a+bi 0| has the obvious eigenvalues a+bi and a-bi
2899
+ # |0 a-bi|
2900
+ #
2901
+ # e.g solving the first one in R gives the solution
2902
+ # for the second one in C
2903
+ diag_poles = np.zeros(A.shape)
2904
+ idx = 0
2905
+ while idx < poles.shape[0]:
2906
+ p = poles[idx]
2907
+ diag_poles[idx, idx] = np.real(p)
2908
+ if ~np.isreal(p):
2909
+ diag_poles[idx, idx+1] = -np.imag(p)
2910
+ diag_poles[idx+1, idx+1] = np.real(p)
2911
+ diag_poles[idx+1, idx] = np.imag(p)
2912
+ idx += 1 # skip next one
2913
+ idx += 1
2914
+ gain_matrix = np.linalg.lstsq(B, diag_poles-A, rcond=-1)[0]
2915
+ transfer_matrix = np.eye(A.shape[0])
2916
+ cur_rtol = np.nan
2917
+ nb_iter = np.nan
2918
+ else:
2919
+ # step A (p1144 KNV) and beginning of step F: decompose
2920
+ # dot(U1.T, A-P[i]*I).T and build our set of transfer_matrix vectors
2921
+ # in the same loop
2922
+ ker_pole = []
2923
+
2924
+ # flag to skip the conjugate of a complex pole
2925
+ skip_conjugate = False
2926
+ # select orthonormal base ker_pole for each Pole and vectors for
2927
+ # transfer_matrix
2928
+ for j in range(B.shape[0]):
2929
+ if skip_conjugate:
2930
+ skip_conjugate = False
2931
+ continue
2932
+ pole_space_j = np.dot(u1.T, A-poles[j]*np.eye(B.shape[0])).T
2933
+
2934
+ # after QR Q=Q0|Q1
2935
+ # only Q0 is used to reconstruct the qr'ed (dot Q, R) matrix.
2936
+ # Q1 is orthogonal to Q0 and will be multiplied by the zeros in
2937
+ # R when using mode "complete". In default mode Q1 and the zeros
2938
+ # in R are not computed
2939
+
2940
+ # To debug with numpy qr uncomment the line below
2941
+ # Q, _ = np.linalg.qr(pole_space_j, mode="complete")
2942
+ Q, _ = s_qr(pole_space_j, mode="full")
2943
+
2944
+ ker_pole_j = Q[:, pole_space_j.shape[1]:]
2945
+
2946
+ # We want to select one vector in ker_pole_j to build the transfer
2947
+ # matrix, however qr returns sometimes vectors with zeros on the
2948
+ # same line for each pole and this yields very long convergence
2949
+ # times.
2950
+ # Or some other times a set of vectors, one with zero imaginary
2951
+ # part and one (or several) with imaginary parts. After trying
2952
+ # many ways to select the best possible one (eg ditch vectors
2953
+ # with zero imaginary part for complex poles) I ended up summing
2954
+ # all vectors in ker_pole_j, this solves 100% of the problems and
2955
+ # is a valid choice for transfer_matrix.
2956
+ # This way for complex poles we are sure to have a non zero
2957
+ # imaginary part that way, and the problem of lines full of zeros
2958
+ # in transfer_matrix is solved too as when a vector from
2959
+ # ker_pole_j has a zero the other one(s) when
2960
+ # ker_pole_j.shape[1]>1) for sure won't have a zero there.
2961
+
2962
+ transfer_matrix_j = np.sum(ker_pole_j, axis=1)[:, np.newaxis]
2963
+ transfer_matrix_j = (transfer_matrix_j /
2964
+ np.linalg.norm(transfer_matrix_j))
2965
+ if ~np.isreal(poles[j]): # complex pole
2966
+ transfer_matrix_j = np.hstack([np.real(transfer_matrix_j),
2967
+ np.imag(transfer_matrix_j)])
2968
+ ker_pole.extend([ker_pole_j, ker_pole_j])
2969
+
2970
+ # Skip next pole as it is the conjugate
2971
+ skip_conjugate = True
2972
+ else: # real pole, nothing to do
2973
+ ker_pole.append(ker_pole_j)
2974
+
2975
+ if j == 0:
2976
+ transfer_matrix = transfer_matrix_j
2977
+ else:
2978
+ transfer_matrix = np.hstack((transfer_matrix, transfer_matrix_j))
2979
+
2980
+ if rankB > 1: # otherwise there is nothing we can optimize
2981
+ stop, cur_rtol, nb_iter = update_loop(ker_pole, transfer_matrix,
2982
+ poles, B, maxiter, rtol)
2983
+ if not stop and rtol > 0:
2984
+ # if rtol<=0 the user has probably done that on purpose,
2985
+ # don't annoy them
2986
+ err_msg = (
2987
+ "Convergence was not reached after maxiter iterations.\n"
2988
+ f"You asked for a tolerance of {rtol}, we got {cur_rtol}."
2989
+ )
2990
+ warnings.warn(err_msg, stacklevel=2)
2991
+
2992
+ # reconstruct transfer_matrix to match complex conjugate pairs,
2993
+ # ie transfer_matrix_j/transfer_matrix_j+1 are
2994
+ # Re(Complex_pole), Im(Complex_pole) now and will be Re-Im/Re+Im after
2995
+ transfer_matrix = transfer_matrix.astype(complex)
2996
+ idx = 0
2997
+ while idx < poles.shape[0]-1:
2998
+ if ~np.isreal(poles[idx]):
2999
+ rel = transfer_matrix[:, idx].copy()
3000
+ img = transfer_matrix[:, idx+1]
3001
+ # rel will be an array referencing a column of transfer_matrix
3002
+ # if we don't copy() it will changer after the next line and
3003
+ # and the line after will not yield the correct value
3004
+ transfer_matrix[:, idx] = rel-1j*img
3005
+ transfer_matrix[:, idx+1] = rel+1j*img
3006
+ idx += 1 # skip next one
3007
+ idx += 1
3008
+
3009
+ try:
3010
+ m = np.linalg.solve(transfer_matrix.T, np.dot(np.diag(poles),
3011
+ transfer_matrix.T)).T
3012
+ gain_matrix = np.linalg.solve(z, np.dot(u0.T, m-A))
3013
+ except np.linalg.LinAlgError as e:
3014
+ raise ValueError("The poles you've chosen can't be placed. "
3015
+ "Check the controllability matrix and try "
3016
+ "another set of poles") from e
3017
+
3018
+ # Beware: Kautsky solves A+BK but the usual form is A-BK
3019
+ gain_matrix = -gain_matrix
3020
+ # K still contains complex with ~=0j imaginary parts, get rid of them
3021
+ gain_matrix = np.real(gain_matrix)
3022
+
3023
+ full_state_feedback = Bunch()
3024
+ full_state_feedback.gain_matrix = gain_matrix
3025
+ full_state_feedback.computed_poles = _order_complex_poles(
3026
+ np.linalg.eig(A - np.dot(B, gain_matrix))[0]
3027
+ )
3028
+ full_state_feedback.requested_poles = poles
3029
+ full_state_feedback.X = transfer_matrix
3030
+ full_state_feedback.rtol = cur_rtol
3031
+ full_state_feedback.nb_iter = nb_iter
3032
+
3033
+ return full_state_feedback
3034
+
3035
+
3036
+ def dlsim(system, u, t=None, x0=None):
3037
+ r"""Simulate output of a discrete-time linear system.
3038
+
3039
+ Parameters
3040
+ ----------
3041
+ system : dlti | tuple
3042
+ An instance of the LTI class `dlti` or a tuple describing the system.
3043
+ The number of elements in the tuple determine the interpretation. I.e.:
3044
+
3045
+ * ``system``: Instance of LTI class `dlti`. Note that derived instances, such
3046
+ as instances of `TransferFunction`, `ZerosPolesGain`, or `StateSpace`, are
3047
+ allowed as well.
3048
+ * ``(num, den, dt)``: Rational polynomial as described in `TransferFunction`.
3049
+ The coefficients of the polynomials should be specified in descending
3050
+ exponent order, e.g., z² + 3z + 5 would be represented as ``[1, 3, 5]``.
3051
+ * ``(zeros, poles, gain, dt)``: Zeros, poles, gain form as described
3052
+ in `ZerosPolesGain`.
3053
+ * ``(A, B, C, D, dt)``: State-space form as described in `StateSpace`.
3054
+
3055
+
3056
+ u : array_like
3057
+ An input array describing the input at each time `t` (interpolation is
3058
+ assumed between given times). If there are multiple inputs, then each
3059
+ column of the rank-2 array represents an input.
3060
+ t : array_like, optional
3061
+ The time steps at which the input is defined. If `t` is given, it
3062
+ must be the same length as `u`, and the final value in `t` determines
3063
+ the number of steps returned in the output.
3064
+ x0 : array_like, optional
3065
+ The initial conditions on the state vector (zero by default).
3066
+
3067
+ Returns
3068
+ -------
3069
+ tout : ndarray
3070
+ Time values for the output, as a 1-D array.
3071
+ yout : ndarray
3072
+ System response, as a 1-D array.
3073
+ xout : ndarray, optional
3074
+ Time-evolution of the state-vector. Only generated if the input is a
3075
+ `StateSpace` system.
3076
+
3077
+ See Also
3078
+ --------
3079
+ lsim, dstep, dimpulse, cont2discrete
3080
+
3081
+ Examples
3082
+ --------
3083
+ A simple integrator transfer function with a discrete time step of 1.0
3084
+ could be implemented as:
3085
+
3086
+ >>> import numpy as np
3087
+ >>> from scipy import signal
3088
+ >>> tf = ([1.0,], [1.0, -1.0], 1.0)
3089
+ >>> t_in = [0.0, 1.0, 2.0, 3.0]
3090
+ >>> u = np.asarray([0.0, 0.0, 1.0, 1.0])
3091
+ >>> t_out, y = signal.dlsim(tf, u, t=t_in)
3092
+ >>> y.T
3093
+ array([[ 0., 0., 0., 1.]])
3094
+
3095
+ """
3096
+ # Convert system to dlti-StateSpace
3097
+ if isinstance(system, lti):
3098
+ raise AttributeError('dlsim can only be used with discrete-time dlti '
3099
+ 'systems.')
3100
+ elif not isinstance(system, dlti):
3101
+ system = dlti(*system[:-1], dt=system[-1])
3102
+
3103
+ # Condition needed to ensure output remains compatible
3104
+ is_ss_input = isinstance(system, StateSpace)
3105
+ system = system._as_ss()
3106
+
3107
+ u = np.atleast_1d(u)
3108
+
3109
+ if u.ndim == 1:
3110
+ u = np.atleast_2d(u).T
3111
+
3112
+ if t is None:
3113
+ out_samples = len(u)
3114
+ stoptime = (out_samples - 1) * system.dt
3115
+ else:
3116
+ stoptime = t[-1]
3117
+ out_samples = int(np.floor(stoptime / system.dt)) + 1
3118
+
3119
+ # Pre-build output arrays
3120
+ xout = np.zeros((out_samples, system.A.shape[0]))
3121
+ yout = np.zeros((out_samples, system.C.shape[0]))
3122
+ tout = np.linspace(0.0, stoptime, num=out_samples)
3123
+
3124
+ # Check initial condition
3125
+ if x0 is None:
3126
+ xout[0, :] = np.zeros((system.A.shape[1],))
3127
+ else:
3128
+ xout[0, :] = np.asarray(x0)
3129
+
3130
+ # Pre-interpolate inputs into the desired time steps
3131
+ if t is None:
3132
+ u_dt = u
3133
+ else:
3134
+ if len(u.shape) == 1:
3135
+ u = u[:, np.newaxis]
3136
+
3137
+ u_dt = make_interp_spline(t, u, k=1)(tout)
3138
+
3139
+ # Simulate the system
3140
+ for i in range(0, out_samples - 1):
3141
+ xout[i+1, :] = (np.dot(system.A, xout[i, :]) +
3142
+ np.dot(system.B, u_dt[i, :]))
3143
+ yout[i, :] = (np.dot(system.C, xout[i, :]) +
3144
+ np.dot(system.D, u_dt[i, :]))
3145
+
3146
+ # Last point
3147
+ yout[out_samples-1, :] = (np.dot(system.C, xout[out_samples-1, :]) +
3148
+ np.dot(system.D, u_dt[out_samples-1, :]))
3149
+
3150
+ if is_ss_input:
3151
+ return tout, yout, xout
3152
+ else:
3153
+ return tout, yout
3154
+
3155
+
3156
+ def dimpulse(system, x0=None, t=None, n=None):
3157
+ r"""Impulse response of discrete-time system.
3158
+
3159
+ Parameters
3160
+ ----------
3161
+ system : dlti | tuple
3162
+ An instance of the LTI class `dlti` or a tuple describing the system.
3163
+ The number of elements in the tuple determine the interpretation. I.e.:
3164
+
3165
+ * ``system``: Instance of LTI class `dlti`. Note that derived instances, such
3166
+ as instances of `TransferFunction`, `ZerosPolesGain`, or `StateSpace`, are
3167
+ allowed as well.
3168
+ * ``(num, den, dt)``: Rational polynomial as described in `TransferFunction`.
3169
+ The coefficients of the polynomials should be specified in descending
3170
+ exponent order, e.g., z² + 3z + 5 would be represented as ``[1, 3, 5]``.
3171
+ * ``(zeros, poles, gain, dt)``: Zeros, poles, gain form as described
3172
+ in `ZerosPolesGain`.
3173
+ * ``(A, B, C, D, dt)``: State-space form as described in `StateSpace`.
3174
+
3175
+ x0 : array_like, optional
3176
+ Initial state-vector. Defaults to zero.
3177
+ t : array_like, optional
3178
+ Time points. Computed if not given.
3179
+ n : int, optional
3180
+ The number of time points to compute (if `t` is not given).
3181
+
3182
+ Returns
3183
+ -------
3184
+ tout : ndarray
3185
+ Time values for the output, as a 1-D array.
3186
+ yout : tuple of ndarray
3187
+ Impulse response of system. Each element of the tuple represents
3188
+ the output of the system based on an impulse in each input.
3189
+
3190
+ See Also
3191
+ --------
3192
+ impulse, dstep, dlsim, cont2discrete
3193
+
3194
+ Examples
3195
+ --------
3196
+ >>> import numpy as np
3197
+ >>> from scipy import signal
3198
+ >>> import matplotlib.pyplot as plt
3199
+ ...
3200
+ >>> dt = 1 # sampling interval is one => time unit is sample number
3201
+ >>> bb, aa = signal.butter(3, 0.25, fs=1/dt)
3202
+ >>> t, y = signal.dimpulse((bb, aa, dt), n=25)
3203
+ ...
3204
+ >>> fig0, ax0 = plt.subplots()
3205
+ >>> ax0.step(t, np.squeeze(y), '.-', where='post')
3206
+ >>> ax0.set_title(r"Impulse Response of a $3^\text{rd}$ Order Butterworth Filter")
3207
+ >>> ax0.set(xlabel='Sample number', ylabel='Amplitude')
3208
+ >>> ax0.grid()
3209
+ >>> plt.show()
3210
+ """
3211
+ # Convert system to dlti-StateSpace
3212
+ if isinstance(system, dlti):
3213
+ system = system._as_ss()
3214
+ elif isinstance(system, lti):
3215
+ raise AttributeError('dimpulse can only be used with discrete-time '
3216
+ 'dlti systems.')
3217
+ else:
3218
+ system = dlti(*system[:-1], dt=system[-1])._as_ss()
3219
+
3220
+ # Default to 100 samples if unspecified
3221
+ if n is None:
3222
+ n = 100
3223
+
3224
+ # If time is not specified, use the number of samples
3225
+ # and system dt
3226
+ if t is None:
3227
+ t = np.linspace(0, n * system.dt, n, endpoint=False)
3228
+ else:
3229
+ t = np.asarray(t)
3230
+
3231
+ # For each input, implement a step change
3232
+ yout = None
3233
+ for i in range(0, system.inputs):
3234
+ u = np.zeros((t.shape[0], system.inputs))
3235
+ u[0, i] = 1.0
3236
+
3237
+ one_output = dlsim(system, u, t=t, x0=x0)
3238
+
3239
+ if yout is None:
3240
+ yout = (one_output[1],)
3241
+ else:
3242
+ yout = yout + (one_output[1],)
3243
+
3244
+ tout = one_output[0]
3245
+
3246
+ return tout, yout
3247
+
3248
+
3249
+ def dstep(system, x0=None, t=None, n=None):
3250
+ r"""Step response of discrete-time system.
3251
+
3252
+ Parameters
3253
+ ----------
3254
+ system : dlti | tuple
3255
+ An instance of the LTI class `dlti` or a tuple describing the system.
3256
+ The number of elements in the tuple determine the interpretation. I.e.:
3257
+
3258
+ * ``system``: Instance of LTI class `dlti`. Note that derived instances, such
3259
+ as instances of `TransferFunction`, `ZerosPolesGain`, or `StateSpace`, are
3260
+ allowed as well.
3261
+ * ``(num, den, dt)``: Rational polynomial as described in `TransferFunction`.
3262
+ The coefficients of the polynomials should be specified in descending
3263
+ exponent order, e.g., z² + 3z + 5 would be represented as ``[1, 3, 5]``.
3264
+ * ``(zeros, poles, gain, dt)``: Zeros, poles, gain form as described
3265
+ in `ZerosPolesGain`.
3266
+ * ``(A, B, C, D, dt)``: State-space form as described in `StateSpace`.
3267
+
3268
+ x0 : array_like, optional
3269
+ Initial state-vector. Defaults to zero.
3270
+ t : array_like, optional
3271
+ Time points. Computed if not given.
3272
+ n : int, optional
3273
+ The number of time points to compute (if `t` is not given).
3274
+
3275
+ Returns
3276
+ -------
3277
+ tout : ndarray
3278
+ Output time points, as a 1-D array.
3279
+ yout : tuple of ndarray
3280
+ Step response of system. Each element of the tuple represents
3281
+ the output of the system based on a step response to each input.
3282
+
3283
+ See Also
3284
+ --------
3285
+ step, dimpulse, dlsim, cont2discrete
3286
+
3287
+ Examples
3288
+ --------
3289
+ The following example illustrates how to create a digital Butterworth filer and
3290
+ plot its step response:
3291
+
3292
+ >>> import numpy as np
3293
+ >>> from scipy import signal
3294
+ >>> import matplotlib.pyplot as plt
3295
+ ...
3296
+ >>> dt = 1 # sampling interval is one => time unit is sample number
3297
+ >>> bb, aa = signal.butter(3, 0.25, fs=1/dt)
3298
+ >>> t, y = signal.dstep((bb, aa, dt), n=25)
3299
+ ...
3300
+ >>> fig0, ax0 = plt.subplots()
3301
+ >>> ax0.step(t, np.squeeze(y), '.-', where='post')
3302
+ >>> ax0.set_title(r"Step Response of a $3^\text{rd}$ Order Butterworth Filter")
3303
+ >>> ax0.set(xlabel='Sample number', ylabel='Amplitude', ylim=(0, 1.1*np.max(y)))
3304
+ >>> ax0.grid()
3305
+ >>> plt.show()
3306
+ """
3307
+ # Convert system to dlti-StateSpace
3308
+ if isinstance(system, dlti):
3309
+ system = system._as_ss()
3310
+ elif isinstance(system, lti):
3311
+ raise AttributeError('dstep can only be used with discrete-time dlti '
3312
+ 'systems.')
3313
+ else:
3314
+ system = dlti(*system[:-1], dt=system[-1])._as_ss()
3315
+
3316
+ # Default to 100 samples if unspecified
3317
+ if n is None:
3318
+ n = 100
3319
+
3320
+ # If time is not specified, use the number of samples
3321
+ # and system dt
3322
+ if t is None:
3323
+ t = np.linspace(0, n * system.dt, n, endpoint=False)
3324
+ else:
3325
+ t = np.asarray(t)
3326
+
3327
+ # For each input, implement a step change
3328
+ yout = None
3329
+ for i in range(0, system.inputs):
3330
+ u = np.zeros((t.shape[0], system.inputs))
3331
+ u[:, i] = np.ones((t.shape[0],))
3332
+
3333
+ one_output = dlsim(system, u, t=t, x0=x0)
3334
+
3335
+ if yout is None:
3336
+ yout = (one_output[1],)
3337
+ else:
3338
+ yout = yout + (one_output[1],)
3339
+
3340
+ tout = one_output[0]
3341
+
3342
+ return tout, yout
3343
+
3344
+
3345
+ def dfreqresp(system, w=None, n=10000, whole=False):
3346
+ r"""
3347
+ Calculate the frequency response of a discrete-time system.
3348
+
3349
+ Parameters
3350
+ ----------
3351
+ system : dlti | tuple
3352
+ An instance of the LTI class `dlti` or a tuple describing the system.
3353
+ The number of elements in the tuple determine the interpretation. I.e.:
3354
+
3355
+ * ``system``: Instance of LTI class `dlti`. Note that derived instances, such
3356
+ as instances of `TransferFunction`, `ZerosPolesGain`, or `StateSpace`, are
3357
+ allowed as well.
3358
+ * ``(num, den, dt)``: Rational polynomial as described in `TransferFunction`.
3359
+ The coefficients of the polynomials should be specified in descending
3360
+ exponent order, e.g., z² + 3z + 5 would be represented as ``[1, 3, 5]``.
3361
+ * ``(zeros, poles, gain, dt)``: Zeros, poles, gain form as described
3362
+ in `ZerosPolesGain`.
3363
+ * ``(A, B, C, D, dt)``: State-space form as described in `StateSpace`.
3364
+
3365
+ w : array_like, optional
3366
+ Array of frequencies (in radians/sample). Magnitude and phase data is
3367
+ calculated for every value in this array. If not given a reasonable
3368
+ set will be calculated.
3369
+ n : int, optional
3370
+ Number of frequency points to compute if `w` is not given. The `n`
3371
+ frequencies are logarithmically spaced in an interval chosen to
3372
+ include the influence of the poles and zeros of the system.
3373
+ whole : bool, optional
3374
+ Normally, if 'w' is not given, frequencies are computed from 0 to the
3375
+ Nyquist frequency, pi radians/sample (upper-half of unit-circle). If
3376
+ `whole` is True, compute frequencies from 0 to 2*pi radians/sample.
3377
+
3378
+ Returns
3379
+ -------
3380
+ w : 1D ndarray
3381
+ Frequency array [radians/sample]
3382
+ H : 1D ndarray
3383
+ Array of complex magnitude values
3384
+
3385
+ Notes
3386
+ -----
3387
+ If (num, den) is passed in for ``system``, coefficients for both the
3388
+ numerator and denominator should be specified in descending exponent
3389
+ order (e.g. ``z^2 + 3z + 5`` would be represented as ``[1, 3, 5]``).
3390
+
3391
+ .. versionadded:: 0.18.0
3392
+
3393
+ Examples
3394
+ --------
3395
+ The following example generates the Nyquist plot of the transfer function
3396
+ :math:`H(z) = \frac{1}{z^2 + 2z + 3}` with a sampling time of 0.05 seconds:
3397
+
3398
+ >>> from scipy import signal
3399
+ >>> import matplotlib.pyplot as plt
3400
+ >>> sys = signal.TransferFunction([1], [1, 2, 3], dt=0.05) # construct H(z)
3401
+ >>> w, H = signal.dfreqresp(sys)
3402
+ ...
3403
+ >>> fig0, ax0 = plt.subplots()
3404
+ >>> ax0.plot(H.real, H.imag, label=r"$H(z=e^{+j\omega})$")
3405
+ >>> ax0.plot(H.real, -H.imag, label=r"$H(z=e^{-j\omega})$")
3406
+ >>> ax0.set_title(r"Nyquist Plot of $H(z) = 1 / (z^2 + 2z + 3)$")
3407
+ >>> ax0.set(xlabel=r"$\text{Re}\{z\}$", ylabel=r"$\text{Im}\{z\}$",
3408
+ ... xlim=(-0.2, 0.65), aspect='equal')
3409
+ >>> ax0.plot(H[0].real, H[0].imag, 'k.') # mark H(exp(1j*w[0]))
3410
+ >>> ax0.text(0.2, 0, r"$H(e^{j0})$")
3411
+ >>> ax0.grid(True)
3412
+ >>> ax0.legend()
3413
+ >>> plt.show()
3414
+ """
3415
+ if not isinstance(system, dlti):
3416
+ if isinstance(system, lti):
3417
+ raise AttributeError('dfreqresp can only be used with '
3418
+ 'discrete-time systems.')
3419
+
3420
+ system = dlti(*system[:-1], dt=system[-1])
3421
+
3422
+ if isinstance(system, StateSpace):
3423
+ # No SS->ZPK code exists right now, just SS->TF->ZPK
3424
+ system = system._as_tf()
3425
+
3426
+ if not isinstance(system, TransferFunction | ZerosPolesGain):
3427
+ raise ValueError('Unknown system type')
3428
+
3429
+ if system.inputs != 1 or system.outputs != 1:
3430
+ raise ValueError("dfreqresp requires a SISO (single input, single "
3431
+ "output) system.")
3432
+
3433
+ if w is not None:
3434
+ worN = w
3435
+ else:
3436
+ worN = n
3437
+
3438
+ if isinstance(system, TransferFunction):
3439
+ # Convert numerator and denominator from polynomials in the variable
3440
+ # 'z' to polynomials in the variable 'z^-1', as freqz expects.
3441
+ num, den = TransferFunction._z_to_zinv(system.num.ravel(), system.den)
3442
+ w, h = freqz(num, den, worN=worN, whole=whole)
3443
+
3444
+ elif isinstance(system, ZerosPolesGain):
3445
+ w, h = freqz_zpk(system.zeros, system.poles, system.gain, worN=worN,
3446
+ whole=whole)
3447
+
3448
+ return w, h
3449
+
3450
+
3451
+ def dbode(system, w=None, n=100):
3452
+ r"""Calculate Bode magnitude and phase data of a discrete-time system.
3453
+
3454
+ Parameters
3455
+ ----------
3456
+ system : dlti | tuple
3457
+ An instance of the LTI class `dlti` or a tuple describing the system.
3458
+ The number of elements in the tuple determine the interpretation. I.e.:
3459
+
3460
+ * ``system``: Instance of LTI class `dlti`. Note that derived instances, such
3461
+ as instances of `TransferFunction`, `ZerosPolesGain`, or `StateSpace`, are
3462
+ allowed as well.
3463
+ * ``(num, den, dt)``: Rational polynomial as described in `TransferFunction`.
3464
+ The coefficients of the polynomials should be specified in descending
3465
+ exponent order, e.g., z² + 3z + 5 would be represented as ``[1, 3, 5]``.
3466
+ * ``(zeros, poles, gain, dt)``: Zeros, poles, gain form as described
3467
+ in `ZerosPolesGain`.
3468
+ * ``(A, B, C, D, dt)``: State-space form as described in `StateSpace`.
3469
+
3470
+ w : array_like, optional
3471
+ Array of frequencies normalized to the Nyquist frequency being π, i.e.,
3472
+ having unit radiant / sample. Magnitude and phase data is calculated for every
3473
+ value in this array. If not given, a reasonable set will be calculated.
3474
+ n : int, optional
3475
+ Number of frequency points to compute if `w` is not given. The `n`
3476
+ frequencies are logarithmically spaced in an interval chosen to
3477
+ include the influence of the poles and zeros of the system.
3478
+
3479
+ Returns
3480
+ -------
3481
+ w : 1D ndarray
3482
+ Array of frequencies normalized to the Nyquist frequency being ``np.pi/dt``
3483
+ with ``dt`` being the sampling interval of the `system` parameter.
3484
+ The unit is rad/s assuming ``dt`` is in seconds.
3485
+ mag : 1D ndarray
3486
+ Magnitude array in dB
3487
+ phase : 1D ndarray
3488
+ Phase array in degrees
3489
+
3490
+ Notes
3491
+ -----
3492
+ This function is a convenience wrapper around `dfreqresp` for extracting
3493
+ magnitude and phase from the calculated complex-valued amplitude of the
3494
+ frequency response.
3495
+
3496
+ .. versionadded:: 0.18.0
3497
+
3498
+ See Also
3499
+ --------
3500
+ dfreqresp, dlti, TransferFunction, ZerosPolesGain, StateSpace
3501
+
3502
+
3503
+ Examples
3504
+ --------
3505
+ The following example shows how to create a Bode plot of a 5-th order
3506
+ Butterworth lowpass filter with a corner frequency of 100 Hz:
3507
+
3508
+ >>> import matplotlib.pyplot as plt
3509
+ >>> import numpy as np
3510
+ >>> from scipy import signal
3511
+ ...
3512
+ >>> T = 1e-4 # sampling interval in s
3513
+ >>> f_c, o = 1e2, 5 # corner frequency in Hz (i.e., -3 dB value) and filter order
3514
+ >>> bb, aa = signal.butter(o, f_c, 'lowpass', fs=1/T)
3515
+ ...
3516
+ >>> w, mag, phase = signal.dbode((bb, aa, T))
3517
+ >>> w /= 2*np.pi # convert unit of frequency into Hertz
3518
+ ...
3519
+ >>> fg, (ax0, ax1) = plt.subplots(2, 1, sharex='all', figsize=(5, 4),
3520
+ ... tight_layout=True)
3521
+ >>> ax0.set_title("Bode Plot of Butterworth Lowpass Filter " +
3522
+ ... rf"($f_c={f_c:g}\,$Hz, order={o})")
3523
+ >>> ax0.set_ylabel(r"Magnitude in dB")
3524
+ >>> ax1.set(ylabel=r"Phase in Degrees",
3525
+ ... xlabel="Frequency $f$ in Hertz", xlim=(w[1], w[-1]))
3526
+ >>> ax0.semilogx(w, mag, 'C0-', label=r"$20\,\log_{10}|G(f)|$") # Magnitude plot
3527
+ >>> ax1.semilogx(w, phase, 'C1-', label=r"$\angle G(f)$") # Phase plot
3528
+ ...
3529
+ >>> for ax_ in (ax0, ax1):
3530
+ ... ax_.axvline(f_c, color='m', alpha=0.25, label=rf"${f_c=:g}\,$Hz")
3531
+ ... ax_.grid(which='both', axis='x') # plot major & minor vertical grid lines
3532
+ ... ax_.grid(which='major', axis='y')
3533
+ ... ax_.legend()
3534
+ >>> plt.show()
3535
+ """
3536
+ w, y = dfreqresp(system, w=w, n=n)
3537
+
3538
+ if isinstance(system, dlti):
3539
+ dt = system.dt
3540
+ else:
3541
+ dt = system[-1]
3542
+
3543
+ mag = 20.0 * np.log10(abs(y))
3544
+ phase = np.rad2deg(np.unwrap(np.angle(y)))
3545
+
3546
+ return w / dt, mag, phase