PySDKit 0.4.48__tar.gz → 0.4.49__tar.gz

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 (196) hide show
  1. {pysdkit-0.4.48 → pysdkit-0.4.49}/PKG-INFO +2 -2
  2. {pysdkit-0.4.48 → pysdkit-0.4.49}/PySDKit.egg-info/PKG-INFO +2 -2
  3. {pysdkit-0.4.48 → pysdkit-0.4.49}/PySDKit.egg-info/SOURCES.txt +2 -0
  4. {pysdkit-0.4.48 → pysdkit-0.4.49}/README.md +1 -1
  5. {pysdkit-0.4.48 → pysdkit-0.4.49}/pysdkit/__init__.py +5 -1
  6. {pysdkit-0.4.48 → pysdkit-0.4.49}/pysdkit/_acmd/__init__.py +4 -1
  7. pysdkit-0.4.49/pysdkit/_acmd/dd_acmd.py +509 -0
  8. {pysdkit-0.4.48 → pysdkit-0.4.49}/pysdkit/tests/test_acmd.py +37 -1
  9. {pysdkit-0.4.48 → pysdkit-0.4.49}/pysdkit/tests/test_baacmd.py +38 -0
  10. pysdkit-0.4.49/pysdkit/tests/test_ddacmd.py +246 -0
  11. {pysdkit-0.4.48 → pysdkit-0.4.49}/LICENSE +0 -0
  12. {pysdkit-0.4.48 → pysdkit-0.4.49}/PySDKit.egg-info/dependency_links.txt +0 -0
  13. {pysdkit-0.4.48 → pysdkit-0.4.49}/PySDKit.egg-info/requires.txt +0 -0
  14. {pysdkit-0.4.48 → pysdkit-0.4.49}/PySDKit.egg-info/top_level.txt +0 -0
  15. {pysdkit-0.4.48 → pysdkit-0.4.49}/pyproject.toml +0 -0
  16. {pysdkit-0.4.48 → pysdkit-0.4.49}/pysdkit/_acmd/acmd.py +0 -0
  17. {pysdkit-0.4.48 → pysdkit-0.4.49}/pysdkit/_acmd/ba_acmd.py +0 -0
  18. {pysdkit-0.4.48 → pysdkit-0.4.49}/pysdkit/_emd/__init__.py +0 -0
  19. {pysdkit-0.4.48 → pysdkit-0.4.49}/pysdkit/_emd/_find_extrema.py +0 -0
  20. {pysdkit-0.4.48 → pysdkit-0.4.49}/pysdkit/_emd/_prepare_points.py +0 -0
  21. {pysdkit-0.4.48 → pysdkit-0.4.49}/pysdkit/_emd/_splines.py +0 -0
  22. {pysdkit-0.4.48 → pysdkit-0.4.49}/pysdkit/_emd/ceemdan.py +0 -0
  23. {pysdkit-0.4.48 → pysdkit-0.4.49}/pysdkit/_emd/eemd.py +0 -0
  24. {pysdkit-0.4.48 → pysdkit-0.4.49}/pysdkit/_emd/efd.py +0 -0
  25. {pysdkit-0.4.48 → pysdkit-0.4.49}/pysdkit/_emd/emd.py +0 -0
  26. {pysdkit-0.4.48 → pysdkit-0.4.49}/pysdkit/_emd/esmd.py +0 -0
  27. {pysdkit-0.4.48 → pysdkit-0.4.49}/pysdkit/_emd/hht/__init__.py +0 -0
  28. {pysdkit-0.4.48 → pysdkit-0.4.49}/pysdkit/_emd/hht/frequency.py +0 -0
  29. {pysdkit-0.4.48 → pysdkit-0.4.49}/pysdkit/_emd/hht/hht.py +0 -0
  30. {pysdkit-0.4.48 → pysdkit-0.4.49}/pysdkit/_emd/memd.py +0 -0
  31. {pysdkit-0.4.48 → pysdkit-0.4.49}/pysdkit/_emd/remd.py +0 -0
  32. {pysdkit-0.4.48 → pysdkit-0.4.49}/pysdkit/_emd/semd.py +0 -0
  33. {pysdkit-0.4.48 → pysdkit-0.4.49}/pysdkit/_emd/tvf_emd.py +0 -0
  34. {pysdkit-0.4.48 → pysdkit-0.4.49}/pysdkit/_emd2d/__init__.py +0 -0
  35. {pysdkit-0.4.48 → pysdkit-0.4.49}/pysdkit/_emd2d/bemd.py +0 -0
  36. {pysdkit-0.4.48 → pysdkit-0.4.49}/pysdkit/_emd2d/bmemd.py +0 -0
  37. {pysdkit-0.4.48 → pysdkit-0.4.49}/pysdkit/_emd2d/emd2d.py +0 -0
  38. {pysdkit-0.4.48 → pysdkit-0.4.49}/pysdkit/_ewt/__init__.py +0 -0
  39. {pysdkit-0.4.48 → pysdkit-0.4.49}/pysdkit/_ewt/ewt.py +0 -0
  40. {pysdkit-0.4.48 → pysdkit-0.4.49}/pysdkit/_ewt/ewt2d.py +0 -0
  41. {pysdkit-0.4.48 → pysdkit-0.4.49}/pysdkit/_faemd/__init__.py +0 -0
  42. {pysdkit-0.4.48 → pysdkit-0.4.49}/pysdkit/_faemd/extrema.py +0 -0
  43. {pysdkit-0.4.48 → pysdkit-0.4.49}/pysdkit/_faemd/faemd.py +0 -0
  44. {pysdkit-0.4.48 → pysdkit-0.4.49}/pysdkit/_faemd/faemd2d.py +0 -0
  45. {pysdkit-0.4.48 → pysdkit-0.4.49}/pysdkit/_faemd/faemd3d.py +0 -0
  46. {pysdkit-0.4.48 → pysdkit-0.4.49}/pysdkit/_faemd/filter.py +0 -0
  47. {pysdkit-0.4.48 → pysdkit-0.4.49}/pysdkit/_gdmd/__init__.py +0 -0
  48. {pysdkit-0.4.48 → pysdkit-0.4.49}/pysdkit/_gdmd/agncmd.py +0 -0
  49. {pysdkit-0.4.48 → pysdkit-0.4.49}/pysdkit/_gdmd/gdmd.py +0 -0
  50. {pysdkit-0.4.48 → pysdkit-0.4.49}/pysdkit/_gdmd/ivgnmd.py +0 -0
  51. {pysdkit-0.4.48 → pysdkit-0.4.49}/pysdkit/_gdmd/vgnmd.py +0 -0
  52. {pysdkit-0.4.48 → pysdkit-0.4.49}/pysdkit/_imd/__init__.py +0 -0
  53. {pysdkit-0.4.48 → pysdkit-0.4.49}/pysdkit/_imd/apmd.py +0 -0
  54. {pysdkit-0.4.48 → pysdkit-0.4.49}/pysdkit/_imd/data/gearbox_fault_snippet.npy +0 -0
  55. {pysdkit-0.4.48 → pysdkit-0.4.49}/pysdkit/_imd/data/input_sig.npy +0 -0
  56. {pysdkit-0.4.48 → pysdkit-0.4.49}/pysdkit/_imd/imd.py +0 -0
  57. {pysdkit-0.4.48 → pysdkit-0.4.49}/pysdkit/_jmd/__init__.py +0 -0
  58. {pysdkit-0.4.48 → pysdkit-0.4.49}/pysdkit/_jmd/jmd.py +0 -0
  59. {pysdkit-0.4.48 → pysdkit-0.4.49}/pysdkit/_jmd/mjmd.py +0 -0
  60. {pysdkit-0.4.48 → pysdkit-0.4.49}/pysdkit/_jmd/sjmd.py +0 -0
  61. {pysdkit-0.4.48 → pysdkit-0.4.49}/pysdkit/_lmd/__init__.py +0 -0
  62. {pysdkit-0.4.48 → pysdkit-0.4.49}/pysdkit/_lmd/lmd.py +0 -0
  63. {pysdkit-0.4.48 → pysdkit-0.4.49}/pysdkit/_lmd/rlmd.py +0 -0
  64. {pysdkit-0.4.48 → pysdkit-0.4.49}/pysdkit/_osd/__init__.py +0 -0
  65. {pysdkit-0.4.48 → pysdkit-0.4.49}/pysdkit/_osd/components.py +0 -0
  66. {pysdkit-0.4.48 → pysdkit-0.4.49}/pysdkit/_osd/osd.py +0 -0
  67. {pysdkit-0.4.48 → pysdkit-0.4.49}/pysdkit/_osd/swd.py +0 -0
  68. {pysdkit-0.4.48 → pysdkit-0.4.49}/pysdkit/_tfa/__init__.py +0 -0
  69. {pysdkit-0.4.48 → pysdkit-0.4.49}/pysdkit/_tfa/data/__init__.py +0 -0
  70. {pysdkit-0.4.48 → pysdkit-0.4.49}/pysdkit/_tfa/data/dual_signal_noise.npy +0 -0
  71. {pysdkit-0.4.48 → pysdkit-0.4.49}/pysdkit/_tfa/data/map2.npy +0 -0
  72. {pysdkit-0.4.48 → pysdkit-0.4.49}/pysdkit/_tfa/data/single_nsignal.npy +0 -0
  73. {pysdkit-0.4.48 → pysdkit-0.4.49}/pysdkit/_tfa/vtfmtd.py +0 -0
  74. {pysdkit-0.4.48 → pysdkit-0.4.49}/pysdkit/_tid/__init__.py +0 -0
  75. {pysdkit-0.4.48 → pysdkit-0.4.49}/pysdkit/_tid/alif.py +0 -0
  76. {pysdkit-0.4.48 → pysdkit-0.4.49}/pysdkit/_tid/data/__init__.py +0 -0
  77. {pysdkit-0.4.48 → pysdkit-0.4.49}/pysdkit/_tid/data/prefixed_double_filter.npy +0 -0
  78. {pysdkit-0.4.48 → pysdkit-0.4.49}/pysdkit/_tid/fmd.py +0 -0
  79. {pysdkit-0.4.48 → pysdkit-0.4.49}/pysdkit/_tid/hvd.py +0 -0
  80. {pysdkit-0.4.48 → pysdkit-0.4.49}/pysdkit/_tid/itd.py +0 -0
  81. {pysdkit-0.4.48 → pysdkit-0.4.49}/pysdkit/_tid/iterative_filtering.py +0 -0
  82. {pysdkit-0.4.48 → pysdkit-0.4.49}/pysdkit/_tid/ssa.py +0 -0
  83. {pysdkit-0.4.48 → pysdkit-0.4.49}/pysdkit/_vmd/__init__.py +0 -0
  84. {pysdkit-0.4.48 → pysdkit-0.4.49}/pysdkit/_vmd/avmd.py +0 -0
  85. {pysdkit-0.4.48 → pysdkit-0.4.49}/pysdkit/_vmd/base.py +0 -0
  86. {pysdkit-0.4.48 → pysdkit-0.4.49}/pysdkit/_vmd/mvmd.py +0 -0
  87. /pysdkit-0.4.48/pysdkit/_acmd/dd_acmd.py → /pysdkit-0.4.49/pysdkit/_vmd/namvmd.py +0 -0
  88. {pysdkit-0.4.48 → pysdkit-0.4.49}/pysdkit/_vmd/ovmd.py +0 -0
  89. {pysdkit-0.4.48 → pysdkit-0.4.49}/pysdkit/_vmd/stvmd.py +0 -0
  90. {pysdkit-0.4.48 → pysdkit-0.4.49}/pysdkit/_vmd/svmd.py +0 -0
  91. {pysdkit-0.4.48 → pysdkit-0.4.49}/pysdkit/_vmd/vmd_c.py +0 -0
  92. {pysdkit-0.4.48 → pysdkit-0.4.49}/pysdkit/_vmd/vmd_f.py +0 -0
  93. {pysdkit-0.4.48 → pysdkit-0.4.49}/pysdkit/_vmd/vme.py +0 -0
  94. {pysdkit-0.4.48 → pysdkit-0.4.49}/pysdkit/_vmd2d/__init__.py +0 -0
  95. {pysdkit-0.4.48 → pysdkit-0.4.49}/pysdkit/_vmd2d/cvmd2d.py +0 -0
  96. {pysdkit-0.4.48 → pysdkit-0.4.49}/pysdkit/_vmd2d/vmd2d.py +0 -0
  97. {pysdkit-0.4.48 → pysdkit-0.4.49}/pysdkit/_vncmd/__init__.py +0 -0
  98. {pysdkit-0.4.48 → pysdkit-0.4.49}/pysdkit/_vncmd/avncmd.py +0 -0
  99. {pysdkit-0.4.48 → pysdkit-0.4.49}/pysdkit/_vncmd/incmd.py +0 -0
  100. {pysdkit-0.4.48 → pysdkit-0.4.49}/pysdkit/_vncmd/stnbmd.py +0 -0
  101. {pysdkit-0.4.48 → pysdkit-0.4.49}/pysdkit/_vncmd/vncmd.py +0 -0
  102. {pysdkit-0.4.48 → pysdkit-0.4.49}/pysdkit/data/__init__.py +0 -0
  103. {pysdkit-0.4.48 → pysdkit-0.4.49}/pysdkit/data/_add_noise.py +0 -0
  104. {pysdkit-0.4.48 → pysdkit-0.4.49}/pysdkit/data/_cube.py +0 -0
  105. {pysdkit-0.4.48 → pysdkit-0.4.49}/pysdkit/data/_generator.py +0 -0
  106. {pysdkit-0.4.48 → pysdkit-0.4.49}/pysdkit/data/_image.py +0 -0
  107. {pysdkit-0.4.48 → pysdkit-0.4.49}/pysdkit/data/_models.py +0 -0
  108. {pysdkit-0.4.48 → pysdkit-0.4.49}/pysdkit/data/_test_univariate.py +0 -0
  109. {pysdkit-0.4.48 → pysdkit-0.4.49}/pysdkit/data/_time_series.py +0 -0
  110. {pysdkit-0.4.48 → pysdkit-0.4.49}/pysdkit/data/fmd_demo.npy +0 -0
  111. {pysdkit-0.4.48 → pysdkit-0.4.49}/pysdkit/data/texture.txt +0 -0
  112. {pysdkit-0.4.48 → pysdkit-0.4.49}/pysdkit/data/vmd_example.npy +0 -0
  113. {pysdkit-0.4.48 → pysdkit-0.4.49}/pysdkit/entropy/__init__.py +0 -0
  114. {pysdkit-0.4.48 → pysdkit-0.4.49}/pysdkit/entropy/_approxiamte_entropy.py +0 -0
  115. {pysdkit-0.4.48 → pysdkit-0.4.49}/pysdkit/entropy/_permutation_entropy.py +0 -0
  116. {pysdkit-0.4.48 → pysdkit-0.4.49}/pysdkit/entropy/_sample_entropy.py +0 -0
  117. {pysdkit-0.4.48 → pysdkit-0.4.49}/pysdkit/models/__init__.py +0 -0
  118. {pysdkit-0.4.48 → pysdkit-0.4.49}/pysdkit/models/_base.py +0 -0
  119. {pysdkit-0.4.48 → pysdkit-0.4.49}/pysdkit/models/_kmeans.py +0 -0
  120. {pysdkit-0.4.48 → pysdkit-0.4.49}/pysdkit/models/_knn.py +0 -0
  121. {pysdkit-0.4.48 → pysdkit-0.4.49}/pysdkit/models/_pca.py +0 -0
  122. {pysdkit-0.4.48 → pysdkit-0.4.49}/pysdkit/plot/__init__.py +0 -0
  123. {pysdkit-0.4.48 → pysdkit-0.4.49}/pysdkit/plot/_fourier_spectra.py +0 -0
  124. {pysdkit-0.4.48 → pysdkit-0.4.49}/pysdkit/plot/_functions.py +0 -0
  125. {pysdkit-0.4.48 → pysdkit-0.4.49}/pysdkit/plot/_plot_images.py +0 -0
  126. {pysdkit-0.4.48 → pysdkit-0.4.49}/pysdkit/plot/_plot_imfs.py +0 -0
  127. {pysdkit-0.4.48 → pysdkit-0.4.49}/pysdkit/plot/_plot_signal.py +0 -0
  128. {pysdkit-0.4.48 → pysdkit-0.4.49}/pysdkit/tests/__init__.py +0 -0
  129. {pysdkit-0.4.48 → pysdkit-0.4.49}/pysdkit/tests/data/__init__.py +0 -0
  130. {pysdkit-0.4.48 → pysdkit-0.4.49}/pysdkit/tests/data/test_generator_cube.py +0 -0
  131. {pysdkit-0.4.48 → pysdkit-0.4.49}/pysdkit/tests/data/test_generator_image.py +0 -0
  132. {pysdkit-0.4.48 → pysdkit-0.4.49}/pysdkit/tests/data/test_generator_signal.py +0 -0
  133. {pysdkit-0.4.48 → pysdkit-0.4.49}/pysdkit/tests/data/test_generator_univariate_signal.py +0 -0
  134. {pysdkit-0.4.48 → pysdkit-0.4.49}/pysdkit/tests/models/__init__.py +0 -0
  135. {pysdkit-0.4.48 → pysdkit-0.4.49}/pysdkit/tests/models/test_knn.py +0 -0
  136. {pysdkit-0.4.48 → pysdkit-0.4.49}/pysdkit/tests/models/test_pca.py +0 -0
  137. {pysdkit-0.4.48 → pysdkit-0.4.49}/pysdkit/tests/run_all.py +0 -0
  138. {pysdkit-0.4.48 → pysdkit-0.4.49}/pysdkit/tests/test_agncmd.py +0 -0
  139. {pysdkit-0.4.48 → pysdkit-0.4.49}/pysdkit/tests/test_alif.py +0 -0
  140. {pysdkit-0.4.48 → pysdkit-0.4.49}/pysdkit/tests/test_apmd.py +0 -0
  141. {pysdkit-0.4.48 → pysdkit-0.4.49}/pysdkit/tests/test_avncmd.py +0 -0
  142. {pysdkit-0.4.48 → pysdkit-0.4.49}/pysdkit/tests/test_bmemd.py +0 -0
  143. {pysdkit-0.4.48 → pysdkit-0.4.49}/pysdkit/tests/test_ceemdan.py +0 -0
  144. {pysdkit-0.4.48 → pysdkit-0.4.49}/pysdkit/tests/test_cvmd2d.py +0 -0
  145. {pysdkit-0.4.48 → pysdkit-0.4.49}/pysdkit/tests/test_eemd.py +0 -0
  146. {pysdkit-0.4.48 → pysdkit-0.4.49}/pysdkit/tests/test_emd.py +0 -0
  147. {pysdkit-0.4.48 → pysdkit-0.4.49}/pysdkit/tests/test_esmd.py +0 -0
  148. {pysdkit-0.4.48 → pysdkit-0.4.49}/pysdkit/tests/test_ewt.py +0 -0
  149. {pysdkit-0.4.48 → pysdkit-0.4.49}/pysdkit/tests/test_ewt2d.py +0 -0
  150. {pysdkit-0.4.48 → pysdkit-0.4.49}/pysdkit/tests/test_faemd.py +0 -0
  151. {pysdkit-0.4.48 → pysdkit-0.4.49}/pysdkit/tests/test_faemd2d.py +0 -0
  152. {pysdkit-0.4.48 → pysdkit-0.4.49}/pysdkit/tests/test_faemd3d.py +0 -0
  153. {pysdkit-0.4.48 → pysdkit-0.4.49}/pysdkit/tests/test_fmd.py +0 -0
  154. {pysdkit-0.4.48 → pysdkit-0.4.49}/pysdkit/tests/test_gdmd.py +0 -0
  155. {pysdkit-0.4.48 → pysdkit-0.4.49}/pysdkit/tests/test_hvd.py +0 -0
  156. {pysdkit-0.4.48 → pysdkit-0.4.49}/pysdkit/tests/test_imd.py +0 -0
  157. {pysdkit-0.4.48 → pysdkit-0.4.49}/pysdkit/tests/test_itd.py +0 -0
  158. {pysdkit-0.4.48 → pysdkit-0.4.49}/pysdkit/tests/test_ivgnmd.py +0 -0
  159. {pysdkit-0.4.48 → pysdkit-0.4.49}/pysdkit/tests/test_jmd.py +0 -0
  160. {pysdkit-0.4.48 → pysdkit-0.4.49}/pysdkit/tests/test_lmd.py +0 -0
  161. {pysdkit-0.4.48 → pysdkit-0.4.49}/pysdkit/tests/test_moving_decomp.py +0 -0
  162. {pysdkit-0.4.48 → pysdkit-0.4.49}/pysdkit/tests/test_mstl.py +0 -0
  163. {pysdkit-0.4.48 → pysdkit-0.4.49}/pysdkit/tests/test_osd.py +0 -0
  164. {pysdkit-0.4.48 → pysdkit-0.4.49}/pysdkit/tests/test_ovmd.py +0 -0
  165. {pysdkit-0.4.48 → pysdkit-0.4.49}/pysdkit/tests/test_rlmd.py +0 -0
  166. {pysdkit-0.4.48 → pysdkit-0.4.49}/pysdkit/tests/test_semd.py +0 -0
  167. {pysdkit-0.4.48 → pysdkit-0.4.49}/pysdkit/tests/test_sjmd.py +0 -0
  168. {pysdkit-0.4.48 → pysdkit-0.4.49}/pysdkit/tests/test_ssa.py +0 -0
  169. {pysdkit-0.4.48 → pysdkit-0.4.49}/pysdkit/tests/test_stl.py +0 -0
  170. {pysdkit-0.4.48 → pysdkit-0.4.49}/pysdkit/tests/test_stnbmd.py +0 -0
  171. {pysdkit-0.4.48 → pysdkit-0.4.49}/pysdkit/tests/test_stvmd.py +0 -0
  172. {pysdkit-0.4.48 → pysdkit-0.4.49}/pysdkit/tests/test_svmd.py +0 -0
  173. {pysdkit-0.4.48 → pysdkit-0.4.49}/pysdkit/tests/test_swd.py +0 -0
  174. {pysdkit-0.4.48 → pysdkit-0.4.49}/pysdkit/tests/test_vgnmd.py +0 -0
  175. {pysdkit-0.4.48 → pysdkit-0.4.49}/pysdkit/tests/test_vmd.py +0 -0
  176. {pysdkit-0.4.48 → pysdkit-0.4.49}/pysdkit/tests/test_vmd2d.py +0 -0
  177. {pysdkit-0.4.48 → pysdkit-0.4.49}/pysdkit/tests/test_vncmd.py +0 -0
  178. {pysdkit-0.4.48 → pysdkit-0.4.49}/pysdkit/tests/test_vtfmtd.py +0 -0
  179. {pysdkit-0.4.48 → pysdkit-0.4.49}/pysdkit/tsa/__init__.py +0 -0
  180. {pysdkit-0.4.48 → pysdkit-0.4.49}/pysdkit/tsa/_dtw.py +0 -0
  181. {pysdkit-0.4.48 → pysdkit-0.4.49}/pysdkit/tsa/_moving_decomp.py +0 -0
  182. {pysdkit-0.4.48 → pysdkit-0.4.49}/pysdkit/tsa/_mstl.py +0 -0
  183. {pysdkit-0.4.48 → pysdkit-0.4.49}/pysdkit/tsa/_stl.py +0 -0
  184. {pysdkit-0.4.48 → pysdkit-0.4.49}/pysdkit/utils/__init__.py +0 -0
  185. {pysdkit-0.4.48 → pysdkit-0.4.49}/pysdkit/utils/_correlation.py +0 -0
  186. {pysdkit-0.4.48 → pysdkit-0.4.49}/pysdkit/utils/_diagnalization.py +0 -0
  187. {pysdkit-0.4.48 → pysdkit-0.4.49}/pysdkit/utils/_differ.py +0 -0
  188. {pysdkit-0.4.48 → pysdkit-0.4.49}/pysdkit/utils/_fft.py +0 -0
  189. {pysdkit-0.4.48 → pysdkit-0.4.49}/pysdkit/utils/_function.py +0 -0
  190. {pysdkit-0.4.48 → pysdkit-0.4.49}/pysdkit/utils/_hilbert.py +0 -0
  191. {pysdkit-0.4.48 → pysdkit-0.4.49}/pysdkit/utils/_instantaneous.py +0 -0
  192. {pysdkit-0.4.48 → pysdkit-0.4.49}/pysdkit/utils/_kernel_matrix.py +0 -0
  193. {pysdkit-0.4.48 → pysdkit-0.4.49}/pysdkit/utils/_mirror.py +0 -0
  194. {pysdkit-0.4.48 → pysdkit-0.4.49}/pysdkit/utils/_process.py +0 -0
  195. {pysdkit-0.4.48 → pysdkit-0.4.49}/pysdkit/utils/_smooth1d.py +0 -0
  196. {pysdkit-0.4.48 → pysdkit-0.4.49}/setup.cfg +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: PySDKit
3
- Version: 0.4.48
3
+ Version: 0.4.49
4
4
  Summary: A Python library for signal decomposition algorithms with a unified interface.
5
5
  Author: Whenxuan Wang, RuiZhe Wang, Rongkun Zhu, Kai Wu, Lei Wang, josefinez, Deeksha Manjunath, Yuan Feng, WenTong Zhao, JacktheFowler
6
6
  Maintainer-email: Whenxuan Wang <wwhenxuan@gmail.com>, RuiZhe Wang <3133986068@qq.com>
@@ -189,7 +189,7 @@ plot_IMFs(signal, IMFs) # per-channel panels
189
189
  | [`AVNCMD`](https://github.com/wwhenxuan/PySDKit/blob/main/pysdkit/_vncmd/avncmd.py) (Adaptive Variational Nonlinear Chirp Mode Decomposition) | [[paper]](https://ieeexplore.ieee.org/abstract/document/9746147) | [[code]](https://github.com/HauLiang/AVNCMD) | ✔️ |
190
190
  | [`ACMD`](https://github.com/wwhenxuan/PySDKit/blob/main/pysdkit/_acmd/acmd.py) (Adaptive Chirp Mode Decomposition) | [[paper]]() | [[code]](https://www.mathworks.com/matlabcentral/fileexchange/121373-data-driven-adaptive-chirp-mode-decomposition?s_tid=srchtitle) | ✔️ |
191
191
  | [`BA-ACMD`](https://github.com/wwhenxuan/PySDKit/blob/main/pysdkit/_acmd/ba_acmd.py) (Bandwidth-aware Adaptive Chirp Mode Decomposition) | [[paper]](https://journals.sagepub.com/doi/abs/10.1177/14759217231174699) | [[code]](https://www.mathworks.com/matlabcentral/fileexchange/132792-bandwidth-aware-adaptive-chirp-mode-decomposition-ba-acmd?s_tid=srchtitle) | ✔️ |
192
- | [`DD-ACMD`](https://github.com/wwhenxuan/PySDKit/blob/main/pysdkit/_acmd/dd_acmd.py) (Data-driven Adaptive Chirp Mode Decomposition) | [[paper]](https://www.sciencedirect.com/science/article/abs/pii/S0888327022010652) | [[code]](https://ww2.mathworks.cn/matlabcentral/fileexchange/121373-data-driven-adaptive-chirp-mode-decomposition) | ✖️ |
192
+ | [`DD-ACMD`](https://github.com/wwhenxuan/PySDKit/blob/main/pysdkit/_acmd/dd_acmd.py) (Data-driven Adaptive Chirp Mode Decomposition) | [[paper]](https://www.sciencedirect.com/science/article/abs/pii/S0888327022010652) | [[code]](https://ww2.mathworks.cn/matlabcentral/fileexchange/121373-data-driven-adaptive-chirp-mode-decomposition) | ✔️ |
193
193
  | [`GDMD`](https://github.com/wwhenxuan/PySDKit/blob/main/pysdkit/_gdmd/gdmd.py) (Generalized Dispersion Mode Decomposition) | [[paper]](https://www.sciencedirect.com/science/article/pii/S0022460X20306295) | [[code]](https://www.sciencedirect.com/science/article/pii/S0022460X20306295) | ✔️ |
194
194
  | [`VGNMD`](https://github.com/wwhenxuan/PySDKit/blob/main/pysdkit/_gdmd/vgnmd.py) (Variational Generalized Nonlinear Mode Decomposition) | [[paper]](https://www.sciencedirect.com/science/article/pii/S088832702300821X) | [[code]](https://www.mathworks.com/matlabcentral/fileexchange/154792-variational-generalized-nonlinear-mode-decomposition-vgmnd) | ✔️ |
195
195
  | [`IVGNMD`](https://github.com/wwhenxuan/PySDKit/blob/main/pysdkit/_gdmd/ivgnmd.py) (Improved Variational Generalized Nonlinear Mode Decomposition) | [[paper]](https://www.sciencedirect.com/science/article/pii/S0888327025001086) | [[code]](https://www.mathworks.com/matlabcentral/fileexchange/180043-improved-vgnmd) | ✔️ |
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: PySDKit
3
- Version: 0.4.48
3
+ Version: 0.4.49
4
4
  Summary: A Python library for signal decomposition algorithms with a unified interface.
5
5
  Author: Whenxuan Wang, RuiZhe Wang, Rongkun Zhu, Kai Wu, Lei Wang, josefinez, Deeksha Manjunath, Yuan Feng, WenTong Zhao, JacktheFowler
6
6
  Maintainer-email: Whenxuan Wang <wwhenxuan@gmail.com>, RuiZhe Wang <3133986068@qq.com>
@@ -189,7 +189,7 @@ plot_IMFs(signal, IMFs) # per-channel panels
189
189
  | [`AVNCMD`](https://github.com/wwhenxuan/PySDKit/blob/main/pysdkit/_vncmd/avncmd.py) (Adaptive Variational Nonlinear Chirp Mode Decomposition) | [[paper]](https://ieeexplore.ieee.org/abstract/document/9746147) | [[code]](https://github.com/HauLiang/AVNCMD) | ✔️ |
190
190
  | [`ACMD`](https://github.com/wwhenxuan/PySDKit/blob/main/pysdkit/_acmd/acmd.py) (Adaptive Chirp Mode Decomposition) | [[paper]]() | [[code]](https://www.mathworks.com/matlabcentral/fileexchange/121373-data-driven-adaptive-chirp-mode-decomposition?s_tid=srchtitle) | ✔️ |
191
191
  | [`BA-ACMD`](https://github.com/wwhenxuan/PySDKit/blob/main/pysdkit/_acmd/ba_acmd.py) (Bandwidth-aware Adaptive Chirp Mode Decomposition) | [[paper]](https://journals.sagepub.com/doi/abs/10.1177/14759217231174699) | [[code]](https://www.mathworks.com/matlabcentral/fileexchange/132792-bandwidth-aware-adaptive-chirp-mode-decomposition-ba-acmd?s_tid=srchtitle) | ✔️ |
192
- | [`DD-ACMD`](https://github.com/wwhenxuan/PySDKit/blob/main/pysdkit/_acmd/dd_acmd.py) (Data-driven Adaptive Chirp Mode Decomposition) | [[paper]](https://www.sciencedirect.com/science/article/abs/pii/S0888327022010652) | [[code]](https://ww2.mathworks.cn/matlabcentral/fileexchange/121373-data-driven-adaptive-chirp-mode-decomposition) | ✖️ |
192
+ | [`DD-ACMD`](https://github.com/wwhenxuan/PySDKit/blob/main/pysdkit/_acmd/dd_acmd.py) (Data-driven Adaptive Chirp Mode Decomposition) | [[paper]](https://www.sciencedirect.com/science/article/abs/pii/S0888327022010652) | [[code]](https://ww2.mathworks.cn/matlabcentral/fileexchange/121373-data-driven-adaptive-chirp-mode-decomposition) | ✔️ |
193
193
  | [`GDMD`](https://github.com/wwhenxuan/PySDKit/blob/main/pysdkit/_gdmd/gdmd.py) (Generalized Dispersion Mode Decomposition) | [[paper]](https://www.sciencedirect.com/science/article/pii/S0022460X20306295) | [[code]](https://www.sciencedirect.com/science/article/pii/S0022460X20306295) | ✔️ |
194
194
  | [`VGNMD`](https://github.com/wwhenxuan/PySDKit/blob/main/pysdkit/_gdmd/vgnmd.py) (Variational Generalized Nonlinear Mode Decomposition) | [[paper]](https://www.sciencedirect.com/science/article/pii/S088832702300821X) | [[code]](https://www.mathworks.com/matlabcentral/fileexchange/154792-variational-generalized-nonlinear-mode-decomposition-vgmnd) | ✔️ |
195
195
  | [`IVGNMD`](https://github.com/wwhenxuan/PySDKit/blob/main/pysdkit/_gdmd/ivgnmd.py) (Improved Variational Generalized Nonlinear Mode Decomposition) | [[paper]](https://www.sciencedirect.com/science/article/pii/S0888327025001086) | [[code]](https://www.mathworks.com/matlabcentral/fileexchange/180043-improved-vgnmd) | ✔️ |
@@ -80,6 +80,7 @@ pysdkit/_vmd/__init__.py
80
80
  pysdkit/_vmd/avmd.py
81
81
  pysdkit/_vmd/base.py
82
82
  pysdkit/_vmd/mvmd.py
83
+ pysdkit/_vmd/namvmd.py
83
84
  pysdkit/_vmd/ovmd.py
84
85
  pysdkit/_vmd/stvmd.py
85
86
  pysdkit/_vmd/svmd.py
@@ -131,6 +132,7 @@ pysdkit/tests/test_baacmd.py
131
132
  pysdkit/tests/test_bmemd.py
132
133
  pysdkit/tests/test_ceemdan.py
133
134
  pysdkit/tests/test_cvmd2d.py
135
+ pysdkit/tests/test_ddacmd.py
134
136
  pysdkit/tests/test_eemd.py
135
137
  pysdkit/tests/test_emd.py
136
138
  pysdkit/tests/test_esmd.py
@@ -136,7 +136,7 @@ plot_IMFs(signal, IMFs) # per-channel panels
136
136
  | [`AVNCMD`](https://github.com/wwhenxuan/PySDKit/blob/main/pysdkit/_vncmd/avncmd.py) (Adaptive Variational Nonlinear Chirp Mode Decomposition) | [[paper]](https://ieeexplore.ieee.org/abstract/document/9746147) | [[code]](https://github.com/HauLiang/AVNCMD) | ✔️ |
137
137
  | [`ACMD`](https://github.com/wwhenxuan/PySDKit/blob/main/pysdkit/_acmd/acmd.py) (Adaptive Chirp Mode Decomposition) | [[paper]]() | [[code]](https://www.mathworks.com/matlabcentral/fileexchange/121373-data-driven-adaptive-chirp-mode-decomposition?s_tid=srchtitle) | ✔️ |
138
138
  | [`BA-ACMD`](https://github.com/wwhenxuan/PySDKit/blob/main/pysdkit/_acmd/ba_acmd.py) (Bandwidth-aware Adaptive Chirp Mode Decomposition) | [[paper]](https://journals.sagepub.com/doi/abs/10.1177/14759217231174699) | [[code]](https://www.mathworks.com/matlabcentral/fileexchange/132792-bandwidth-aware-adaptive-chirp-mode-decomposition-ba-acmd?s_tid=srchtitle) | ✔️ |
139
- | [`DD-ACMD`](https://github.com/wwhenxuan/PySDKit/blob/main/pysdkit/_acmd/dd_acmd.py) (Data-driven Adaptive Chirp Mode Decomposition) | [[paper]](https://www.sciencedirect.com/science/article/abs/pii/S0888327022010652) | [[code]](https://ww2.mathworks.cn/matlabcentral/fileexchange/121373-data-driven-adaptive-chirp-mode-decomposition) | ✖️ |
139
+ | [`DD-ACMD`](https://github.com/wwhenxuan/PySDKit/blob/main/pysdkit/_acmd/dd_acmd.py) (Data-driven Adaptive Chirp Mode Decomposition) | [[paper]](https://www.sciencedirect.com/science/article/abs/pii/S0888327022010652) | [[code]](https://ww2.mathworks.cn/matlabcentral/fileexchange/121373-data-driven-adaptive-chirp-mode-decomposition) | ✔️ |
140
140
  | [`GDMD`](https://github.com/wwhenxuan/PySDKit/blob/main/pysdkit/_gdmd/gdmd.py) (Generalized Dispersion Mode Decomposition) | [[paper]](https://www.sciencedirect.com/science/article/pii/S0022460X20306295) | [[code]](https://www.sciencedirect.com/science/article/pii/S0022460X20306295) | ✔️ |
141
141
  | [`VGNMD`](https://github.com/wwhenxuan/PySDKit/blob/main/pysdkit/_gdmd/vgnmd.py) (Variational Generalized Nonlinear Mode Decomposition) | [[paper]](https://www.sciencedirect.com/science/article/pii/S088832702300821X) | [[code]](https://www.mathworks.com/matlabcentral/fileexchange/154792-variational-generalized-nonlinear-mode-decomposition-vgmnd) | ✔️ |
142
142
  | [`IVGNMD`](https://github.com/wwhenxuan/PySDKit/blob/main/pysdkit/_gdmd/ivgnmd.py) (Improved Variational Generalized Nonlinear Mode Decomposition) | [[paper]](https://www.sciencedirect.com/science/article/pii/S0888327025001086) | [[code]](https://www.mathworks.com/matlabcentral/fileexchange/180043-improved-vgnmd) | ✔️ |
@@ -2,7 +2,7 @@
2
2
  A Python library for signal decomposition algorithms.
3
3
  """
4
4
 
5
- __version__ = "0.4.48"
5
+ __version__ = "0.4.49"
6
6
 
7
7
  # Empirical Mode Decomposition
8
8
  from ._emd import EMD
@@ -82,6 +82,9 @@ from ._acmd import ACMD
82
82
  # Bandwidth-Aware Adaptive Chirp Mode Decomposition
83
83
  from ._acmd import BA_ACMD
84
84
 
85
+ # Data-driven Adaptive Chirp Mode Decomposition
86
+ from ._acmd import DD_ACMD
87
+
85
88
  # Multivariate Variational Mode Decomposition
86
89
  from ._vmd import MVMD
87
90
 
@@ -272,6 +275,7 @@ __all__ = [
272
275
  "VMD",
273
276
  "ACMD",
274
277
  "BA_ACMD",
278
+ "DD_ACMD",
275
279
  "MVMD",
276
280
  "VME",
277
281
  "OVMD",
@@ -5,14 +5,17 @@ Adaptive Chirp Mode Decomposition (ACMD) and variants.
5
5
  Includes:
6
6
  - ACMD — Adaptive Chirp Mode Decomposition
7
7
  - BA_ACMD — Bandwidth-aware Adaptive Chirp Mode Decomposition
8
- - DD_ACMD — Data-driven Adaptive Chirp Mode Decomposition (stub)
8
+ - DD_ACMD — Data-driven Adaptive Chirp Mode Decomposition
9
9
  """
10
10
 
11
11
  from .acmd import ACMD
12
12
  from .ba_acmd import BA_ACMD, BAACMD
13
+ from .dd_acmd import DD_ACMD, DDACMD
13
14
 
14
15
  __all__ = [
15
16
  "ACMD",
16
17
  "BA_ACMD",
17
18
  "BAACMD",
19
+ "DD_ACMD",
20
+ "DDACMD",
18
21
  ]
@@ -0,0 +1,509 @@
1
+ # -*- coding: utf-8 -*-
2
+ """
3
+ Data-driven Adaptive Chirp Mode Decomposition (DD-ACMD).
4
+
5
+ Wang H, Chen S, Zhai W. Data-driven adaptive chirp mode decomposition with
6
+ application to machine fault diagnosis under non-stationary conditions.
7
+ Mechanical Systems and Signal Processing, 2023.
8
+
9
+ MATLAB reference (File Exchange 121373):
10
+ https://www.mathworks.com/matlabcentral/fileexchange/121373
11
+
12
+ Relationship to ``pysdkit._acmd.acmd.ACMD``
13
+ ------------------------------------------
14
+ DD-ACMD **reuses classical ACMD as the inner mode extractor**. What changes
15
+ is the *outer* recursion:
16
+
17
+ * **ACMD** needs a user-provided (or Fourier-peak / ridge) initial IF and a
18
+ fixed mode count ``K``.
19
+ * **DD-ACMD** (1) extracts a zero-IF trend first, (2) builds the next IF seed
20
+ by *derivative-normalization* (IF-DN) + iterative time-varying low-pass
21
+ (DDIFI), (3) calls ACMD with that seed, (4) filters the residual with TVLP,
22
+ and (5) stops when residual energy falls below a fraction of the original
23
+ signal — no STFT ridge or spectrum peak is required.
24
+ """
25
+
26
+ from __future__ import annotations
27
+
28
+ from typing import Optional, Tuple, Union
29
+
30
+ import numpy as np
31
+ from scipy.integrate import cumulative_trapezoid
32
+ from scipy.signal import firwin, hilbert
33
+
34
+ from pysdkit._acmd.acmd import ACMD, curve_smooth, differ
35
+ from pysdkit._vmd.base import Base
36
+
37
+
38
+ # ---------------------------------------------------------------------------
39
+ # Low-level helpers (MATLAB: findev / arccos / low_filter / IF_DN / DDIFI / TVLP)
40
+ # ---------------------------------------------------------------------------
41
+
42
+
43
+ def find_extrema(sig: np.ndarray) -> Tuple[np.ndarray, np.ndarray, np.ndarray]:
44
+ """
45
+ Local maxima, their indices, and a piecewise-constant upper envelope
46
+ (MATLAB ``findev``).
47
+
48
+ :return: ``(max_values, max_indices, upper_piecewise)``
49
+ """
50
+ sig = np.asarray(sig, dtype=float).ravel()
51
+ L = sig.size
52
+ if L < 3:
53
+ idx = np.array([0], dtype=int) if L else np.array([], dtype=int)
54
+ vals = sig[idx] if L else np.array([], dtype=float)
55
+ up = np.full(L, float(sig[0]) if L else 0.0)
56
+ return vals, idx, up
57
+
58
+ # MATLAB: MaxVec = find(diff(diff(Sig) > 0) < 0) + 1
59
+ interior = np.where(np.diff((np.diff(sig) > 0).astype(int)) < 0)[0] + 1
60
+ max_vec = interior.astype(int)
61
+
62
+ if sig[0] > sig[1]:
63
+ max_vec = np.concatenate(([0], max_vec))
64
+ if sig[-1] > sig[-2]:
65
+ max_vec = np.concatenate((max_vec, [L - 1]))
66
+
67
+ # unique sorted (endpoints may duplicate rare plateaus)
68
+ max_vec = np.unique(max_vec)
69
+ maxima = sig[max_vec]
70
+
71
+ up = np.empty(L, dtype=float)
72
+ if max_vec.size == 1:
73
+ up[:] = maxima[0]
74
+ else:
75
+ for i in range(max_vec.size - 1):
76
+ up[max_vec[i] : max_vec[i + 1] + 1] = maxima[i]
77
+ up[: max_vec[0] + 1] = maxima[0]
78
+ up[max_vec[-1] :] = maxima[-1]
79
+ return maxima, max_vec, up
80
+
81
+
82
+ def phase_arccos(g: np.ndarray) -> np.ndarray:
83
+ """
84
+ Cumulative phase via piecewise ``acos`` with slope-based folding
85
+ (MATLAB custom ``arccos`` — *not* ``np.arccos`` alone).
86
+
87
+ Returns phase in units of cycles (already scaled by ``0.5/π · acos``).
88
+ """
89
+ g = np.asarray(g, dtype=float).ravel()
90
+ s = g.size
91
+ if s == 0:
92
+ return g.copy()
93
+ g_clip = np.clip(g, -1.0, 1.0)
94
+ f1 = g_clip.copy()
95
+ theta = (0.5 / np.pi) * np.arccos(f1)
96
+ temp = 0.0
97
+ for i in range(2, s):
98
+ if np.sign(g[i] - g[i - 1]) != np.sign(g[i - 1] - g[i - 2]):
99
+ temp = float(theta[i - 1])
100
+ if g[i] - g[i - 1] > 0.0:
101
+ f1[i] = -g_clip[i]
102
+ else:
103
+ f1[i] = g_clip[i]
104
+ # keep acos domain
105
+ f1[i] = float(np.clip(f1[i], -1.0, 1.0))
106
+ theta[i] = (0.5 / np.pi) * np.arccos(f1[i]) + temp
107
+ return theta
108
+
109
+
110
+ def low_filter(
111
+ sig: np.ndarray, cut_freq: float, samp_freq: float
112
+ ) -> np.ndarray:
113
+ """
114
+ Linear-phase FIR low-pass with delay compensation (MATLAB ``low_filter``).
115
+
116
+ Works for real or complex inputs (FIR applied via ``np.convolve``).
117
+ """
118
+ sig = np.asarray(sig)
119
+ n0 = sig.size
120
+ if n0 < 4:
121
+ return sig.copy()
122
+
123
+ n = int(np.floor(n0 * 0.8))
124
+ L = n if (n % 2 == 0) else n + 1
125
+ # MATLAB fir1(L, Wn) with Wn = cut/(fs/2); L is filter *order*
126
+ nyq = 0.5 * float(samp_freq)
127
+ wn = float(cut_freq) / nyq
128
+ wn = float(np.clip(wn, 1e-6, 0.999999))
129
+ numtaps = L + 1
130
+ b = firwin(numtaps, wn, pass_zero="lowpass")
131
+ filtered = np.convolve(b, sig, mode="full")
132
+ start = L // 2
133
+ return filtered[start : start + n0]
134
+
135
+
136
+ def if_derivative_normalization(
137
+ sig: np.ndarray, samp_freq: float, beta: float = 1e-11
138
+ ) -> np.ndarray:
139
+ """
140
+ Instantaneous-frequency estimate via derivative normalization (MATLAB ``IF_DN``).
141
+
142
+ Steps: differentiate → normalize between consecutive extrema → custom
143
+ ``arccos`` phase → differentiate → Tikhonov smooth.
144
+ """
145
+ sig = np.asarray(sig, dtype=float).ravel()
146
+ ds = differ(sig, 1.0 / float(samp_freq))
147
+ _, max_vec, _ = find_extrema(ds)
148
+ _, min_vec, _ = find_extrema(-ds)
149
+ mv = np.sort(np.concatenate((max_vec, min_vec)))
150
+ mv = np.unique(mv)
151
+ g = np.zeros_like(ds)
152
+ for i in range(mv.size - 1):
153
+ i0, i1 = int(mv[i]), int(mv[i + 1])
154
+ lav = abs(ds[i0] - ds[i1]) / 2.0
155
+ lm = (ds[i0] + ds[i1]) / 2.0
156
+ if lav < np.finfo(float).eps:
157
+ g[i0 : i1 + 1] = 0.0
158
+ else:
159
+ g[i0 : i1 + 1] = (ds[i0 : i1 + 1] - lm) / lav
160
+ g = np.clip(g, -1.0, 1.0)
161
+ theta = phase_arccos(g)
162
+ inst_f = differ(theta, 1.0 / float(samp_freq))
163
+ inst_f = np.real(curve_smooth(inst_f, beta))
164
+ return inst_f
165
+
166
+
167
+ def time_varying_lowpass(
168
+ sig: np.ndarray,
169
+ samp_freq: float,
170
+ e_if: np.ndarray,
171
+ c_pass: float,
172
+ cutoff_scale: float = 1.1,
173
+ ) -> np.ndarray:
174
+ """
175
+ Time-varying low-pass filter (MATLAB ``TVLP``).
176
+
177
+ Demodulate by ``exp(-j ∫ 2π (IF − Cpass) dt)``, FIR-lowpass at
178
+ ``cutoff_scale * Cpass``, then remodulate. ``cutoff_scale=1.1`` matches
179
+ the fully open-source MATLAB package (``low_filter`` path).
180
+ """
181
+ sig = np.asarray(sig, dtype=float).ravel()
182
+ e_if = np.asarray(e_if, dtype=float).ravel()
183
+ n = sig.size
184
+ fs = float(samp_freq)
185
+ t = np.arange(n, dtype=float) / fs
186
+ phase = 2.0 * np.pi * cumulative_trapezoid(e_if - float(c_pass), t, initial=0.0)
187
+ analytic = hilbert(sig)
188
+ shifted = analytic * np.exp(-1j * phase)
189
+ cut = max(float(cutoff_scale) * float(c_pass), 1e-6)
190
+ # keep cutoff below Nyquist
191
+ cut = min(cut, 0.49 * fs)
192
+ filtered = low_filter(shifted, cut, fs)
193
+ restored = filtered * np.exp(1j * phase)
194
+ return np.real(restored)
195
+
196
+
197
+ def data_driven_if_init(
198
+ sig: np.ndarray,
199
+ samp_freq: float,
200
+ beta: float = 1e-11,
201
+ max_iter: int = 10,
202
+ tol: float = 0.01,
203
+ ) -> np.ndarray:
204
+ """
205
+ Data-driven IF initialization (MATLAB ``DDIFI``).
206
+
207
+ Iterate IF-DN → TVLP until the IF-norm change falls below ``tol``.
208
+ """
209
+ residual = np.asarray(sig, dtype=float).ravel().copy()
210
+ n = residual.size
211
+ iif = np.full(n, float(samp_freq), dtype=float)
212
+ last = iif.copy()
213
+ for _ in range(int(max_iter)):
214
+ inst_f = if_derivative_normalization(residual, samp_freq, beta=beta)
215
+ residual = time_varying_lowpass(
216
+ residual, samp_freq, inst_f, float(np.max(inst_f))
217
+ )
218
+ denom = norm_safe(iif)
219
+ delta = abs(norm_safe(inst_f) - denom) / denom
220
+ last = inst_f
221
+ if delta < tol:
222
+ break
223
+ iif = inst_f
224
+ return last
225
+
226
+
227
+ def norm_safe(x: np.ndarray) -> float:
228
+ nrm = float(np.linalg.norm(np.asarray(x, dtype=float).ravel()))
229
+ return nrm if nrm > 0.0 else np.finfo(float).eps
230
+
231
+
232
+ def add_noise(
233
+ n: int,
234
+ mean: float = 0.0,
235
+ std: float = 1.0,
236
+ rng: Optional[np.random.Generator] = None,
237
+ ) -> np.ndarray:
238
+ """Gaussian noise matching MATLAB ``addnoise``."""
239
+ rng = np.random.default_rng() if rng is None else rng
240
+ y = rng.standard_normal(int(n))
241
+ y = y / (np.std(y) + np.finfo(float).eps)
242
+ y = y - np.mean(y)
243
+ return mean + std * y
244
+
245
+
246
+ def generate_stationary_demo(
247
+ fs: float = 300.0,
248
+ duration: float = 1.0,
249
+ noise_std: float = 0.3,
250
+ rng: Optional[np.random.Generator] = None,
251
+ ) -> dict:
252
+ """MATLAB Test (stationary signal) mixture."""
253
+ t = np.arange(0.0, duration, 1.0 / fs)
254
+ sig1 = 4.0 * t**2
255
+ sig2 = 0.5 * np.cos(40.0 * np.pi * t)
256
+ sig3 = 0.5 * np.cos(50.0 * np.pi * t)
257
+ sig4 = 0.5 * np.cos(60.0 * np.pi * t)
258
+ clean = sig1 + sig2 + sig3 + sig4
259
+ noisy = clean + add_noise(clean.size, 0.0, noise_std, rng=rng)
260
+ return {
261
+ "t": t,
262
+ "fs": fs,
263
+ "clean": clean,
264
+ "signal": noisy,
265
+ "modes": np.vstack([sig1, sig2, sig3, sig4]),
266
+ "ifs": np.vstack(
267
+ [
268
+ np.zeros_like(t),
269
+ np.full_like(t, 20.0),
270
+ np.full_like(t, 25.0),
271
+ np.full_like(t, 30.0),
272
+ ]
273
+ ),
274
+ }
275
+
276
+
277
+ def generate_nonstationary_demo(
278
+ fs: float = 1500.0,
279
+ duration: float = 3.0,
280
+ noise_std: float = 0.5,
281
+ rng: Optional[np.random.Generator] = None,
282
+ ) -> dict:
283
+ """MATLAB Test (noisy non-stationary) mixture."""
284
+ t = np.arange(0.0, duration, 1.0 / fs)
285
+ a1 = 1.0 + 0.3 * np.cos(2.0 * np.pi * t)
286
+ sig1 = a1 * np.cos(2.0 * np.pi * (8 * t**3 + 16 * t**2 + 80 * t) + np.sin(10 * np.pi * t))
287
+ if1 = 24 * t**2 + 32 * t + 80 + 5 * np.cos(10 * np.pi * t)
288
+ a2 = 1.0 + 0.3 * np.cos(2.0 * np.pi * t + np.pi / 4)
289
+ sig2 = a2 * np.cos(2.0 * np.pi * (6 * t**3 + 12 * t**2 + 60 * t) + np.sin(10 * np.pi * t))
290
+ if2 = 18 * t**2 + 24 * t + 60 + 5 * np.cos(10 * np.pi * t)
291
+ a3 = 1.0 + 0.3 * np.cos(2.0 * np.pi * t + np.pi / 2)
292
+ sig3 = a3 * np.cos(2.0 * np.pi * (4 * t**3 + 8 * t**2 + 40 * t) + np.sin(10 * np.pi * t))
293
+ if3 = 12 * t**2 + 16 * t + 40 + 5 * np.cos(10 * np.pi * t)
294
+ clean = sig1 + sig2 + sig3
295
+ noisy = clean + add_noise(clean.size, 0.0, noise_std, rng=rng)
296
+ return {
297
+ "t": t,
298
+ "fs": fs,
299
+ "clean": clean,
300
+ "signal": noisy,
301
+ "modes": np.vstack([sig1, sig2, sig3]),
302
+ "ifs": np.vstack([if1, if2, if3]),
303
+ }
304
+
305
+
306
+ def generate_close_modes_demo(
307
+ fs: float = 800.0,
308
+ duration: float = 2.0,
309
+ noise_std: float = 0.0,
310
+ rng: Optional[np.random.Generator] = None,
311
+ ) -> dict:
312
+ """MATLAB Test (close chirp modes) mixture."""
313
+ t = np.arange(0.0, duration, 1.0 / fs)
314
+ sig1 = np.exp(-0.1 * t) * np.cos(2.0 * np.pi * (-60 * t**3 + 180 * t**2 + 100 * t))
315
+ if1 = -180 * t**2 + 360 * t + 100
316
+ sig2 = np.exp(-0.2 * t) * np.cos(2.0 * np.pi * (-60 * t**3 + 180 * t**2 + 90 * t))
317
+ if2 = -180 * t**2 + 360 * t + 90
318
+ sig3 = np.exp(-0.3 * t) * np.cos(2.0 * np.pi * (-60 * t**3 + 180 * t**2 + 80 * t))
319
+ if3 = -180 * t**2 + 360 * t + 80
320
+ clean = sig1 + sig2 + sig3
321
+ noisy = clean + add_noise(clean.size, 0.0, noise_std, rng=rng) if noise_std > 0 else clean.copy()
322
+ return {
323
+ "t": t,
324
+ "fs": fs,
325
+ "clean": clean,
326
+ "signal": noisy,
327
+ "modes": np.vstack([sig1, sig2, sig3]),
328
+ "ifs": np.vstack([if1, if2, if3]),
329
+ }
330
+
331
+
332
+ # ---------------------------------------------------------------------------
333
+ # DD-ACMD class
334
+ # ---------------------------------------------------------------------------
335
+
336
+
337
+ class DD_ACMD(Base):
338
+ """
339
+ Data-driven Adaptive Chirp Mode Decomposition.
340
+
341
+ Outer loop around classical :class:`~pysdkit._acmd.acmd.ACMD`:
342
+
343
+ 1. Extract a **trend** with zero initial IF.
344
+ 2. Estimate the next IF by **DDIFI** (IF-DN + TVLP).
345
+ 3. Run ACMD; subtract the mode; stop if
346
+ ``‖residual‖² / ‖signal‖² < energy_tol``.
347
+ 4. Otherwise apply TVLP to the residual and repeat.
348
+
349
+ MATLAB: ``DDACMD.m`` (File Exchange 121373).
350
+ """
351
+
352
+ def __init__(
353
+ self,
354
+ fs: float,
355
+ k_max: int = 20,
356
+ alpha0: float = 1e-7,
357
+ beta: float = 1e-10,
358
+ tol: float = 1e-30,
359
+ energy_tol: float = 0.01,
360
+ ddifi_beta: float = 1e-11,
361
+ ddifi_max_iter: int = 10,
362
+ ddifi_tol: float = 0.01,
363
+ max_iter: int = 300,
364
+ tvlp_cutoff_scale: float = 1.1,
365
+ ) -> None:
366
+ """
367
+ :param fs: sampling frequency (Hz)
368
+ :param k_max: maximum number of modes (incl. trend)
369
+ :param alpha0: ACMD bandwidth penalty (MATLAB DDACMD default ``1e-7``)
370
+ :param beta: ACMD IF-increment smoothness (MATLAB ``1e-10``)
371
+ :param tol: ACMD convergence tolerance (MATLAB ``1e-30`` → ~max_iter)
372
+ :param energy_tol: residual-energy stop ratio ``ε``
373
+ :param ddifi_beta: IF-DN smoothing penalty
374
+ :param ddifi_max_iter: max DDIFI iterations
375
+ :param ddifi_tol: DDIFI relative IF-norm stop
376
+ :param max_iter: max ACMD iterations per mode
377
+ :param tvlp_cutoff_scale: FIR cutoff = scale × max(IF)
378
+ """
379
+ super().__init__()
380
+ if float(fs) <= 0:
381
+ raise ValueError("fs must be positive")
382
+ self.fs = float(fs)
383
+ self.k_max = int(k_max)
384
+ self.alpha0 = float(alpha0)
385
+ self.beta = float(beta)
386
+ self.tol = float(tol)
387
+ self.energy_tol = float(energy_tol)
388
+ self.ddifi_beta = float(ddifi_beta)
389
+ self.ddifi_max_iter = int(ddifi_max_iter)
390
+ self.ddifi_tol = float(ddifi_tol)
391
+ self.max_iter = int(max_iter)
392
+ self.tvlp_cutoff_scale = float(tvlp_cutoff_scale)
393
+
394
+ self.imfs_: Optional[np.ndarray] = None
395
+ self.ifs_: Optional[np.ndarray] = None
396
+ self.ias_: Optional[np.ndarray] = None
397
+ self.ini_ifs_: Optional[np.ndarray] = None
398
+
399
+ def __call__(
400
+ self, signal: np.ndarray, return_all: bool = False
401
+ ) -> Union[np.ndarray, Tuple[np.ndarray, ...]]:
402
+ return self.fit_transform(signal, return_all=return_all)
403
+
404
+ def __str__(self) -> str:
405
+ return "Data-driven Adaptive Chirp Mode Decomposition (DD-ACMD)"
406
+
407
+ def _acmd_extractor(self) -> ACMD:
408
+ return ACMD(
409
+ K=1,
410
+ fs=self.fs,
411
+ alpha0=self.alpha0,
412
+ beta=self.beta,
413
+ tol=self.tol,
414
+ max_iter=self.max_iter,
415
+ )
416
+
417
+ def extract_trend(
418
+ self, signal: np.ndarray
419
+ ) -> Tuple[np.ndarray, np.ndarray, np.ndarray, np.ndarray]:
420
+ """Mode 1: ACMD with zero initial IF (MATLAB trend step)."""
421
+ signal = np.asarray(signal, dtype=float).ravel()
422
+ init_if = np.zeros(signal.size, dtype=float)
423
+ sest, if_est, ia_est = self._acmd_extractor().extract_mode(signal, init_if)
424
+ return sest, if_est, ia_est, init_if
425
+
426
+ def estimate_init_if(self, signal: np.ndarray) -> np.ndarray:
427
+ """Public wrapper for DDIFI."""
428
+ return data_driven_if_init(
429
+ signal,
430
+ self.fs,
431
+ beta=self.ddifi_beta,
432
+ max_iter=self.ddifi_max_iter,
433
+ tol=self.ddifi_tol,
434
+ )
435
+
436
+ def fit_transform(
437
+ self,
438
+ signal: np.ndarray,
439
+ return_all: bool = False,
440
+ ) -> Union[np.ndarray, Tuple[np.ndarray, np.ndarray, np.ndarray, np.ndarray]]:
441
+ """
442
+ Run DD-ACMD.
443
+
444
+ :param signal: 1-D real record
445
+ :param return_all: if True, also return ``(ini_IF, eIF, eIA)``
446
+ :return: ``IMF`` of shape ``(K, N)``, or
447
+ ``(IMF, ini_IF, eIF, eIA)`` when ``return_all``
448
+ """
449
+ sig0 = np.asarray(signal, dtype=float).ravel()
450
+ if sig0.size < 8:
451
+ raise ValueError("signal length must be >= 8")
452
+
453
+ n = sig0.size
454
+ residual = sig0.copy()
455
+ energy0 = float(np.sum(sig0**2)) + np.finfo(float).eps
456
+
457
+ ini_ifs = np.zeros((self.k_max, n), dtype=float)
458
+ e_ifs = np.zeros((self.k_max, n), dtype=float)
459
+ e_ias = np.zeros((self.k_max, n), dtype=float)
460
+ imfs = np.zeros((self.k_max, n), dtype=float)
461
+
462
+ acmd = self._acmd_extractor()
463
+ k_out = 0
464
+
465
+ for i in range(self.k_max):
466
+ if i == 0:
467
+ init_if = np.zeros(n, dtype=float)
468
+ else:
469
+ init_if = data_driven_if_init(
470
+ residual,
471
+ self.fs,
472
+ beta=self.ddifi_beta,
473
+ max_iter=self.ddifi_max_iter,
474
+ tol=self.ddifi_tol,
475
+ )
476
+
477
+ sest, if_est, ia_est = acmd.extract_mode(residual, init_if)
478
+ ini_ifs[i] = init_if
479
+ e_ifs[i] = if_est
480
+ e_ias[i] = ia_est
481
+ imfs[i] = sest
482
+ residual = residual - sest
483
+ k_out = i + 1
484
+
485
+ if i >= 1:
486
+ epsilon = float(np.sum(residual**2)) / energy0
487
+ if epsilon < self.energy_tol:
488
+ break
489
+ c_pass = float(np.max(if_est))
490
+ residual = time_varying_lowpass(
491
+ residual,
492
+ self.fs,
493
+ if_est,
494
+ c_pass,
495
+ cutoff_scale=self.tvlp_cutoff_scale,
496
+ )
497
+
498
+ self.ini_ifs_ = ini_ifs[:k_out]
499
+ self.ifs_ = e_ifs[:k_out]
500
+ self.ias_ = e_ias[:k_out]
501
+ self.imfs_ = imfs[:k_out]
502
+
503
+ if return_all:
504
+ return self.imfs_, self.ini_ifs_, self.ifs_, self.ias_
505
+ return self.imfs_
506
+
507
+
508
+ # Alias matching MATLAB naming
509
+ DDACMD = DD_ACMD