Braindecode 1.3.0.dev168926291__tar.gz → 1.3.0.dev169361694__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 (152) hide show
  1. {braindecode-1.3.0.dev168926291/braindecode.egg-info → braindecode-1.3.0.dev169361694}/PKG-INFO +14 -33
  2. {braindecode-1.3.0.dev168926291 → braindecode-1.3.0.dev169361694}/README.rst +1 -14
  3. {braindecode-1.3.0.dev168926291 → braindecode-1.3.0.dev169361694}/braindecode/augmentation/__init__.py +0 -4
  4. {braindecode-1.3.0.dev168926291 → braindecode-1.3.0.dev169361694}/braindecode/classifier.py +8 -3
  5. {braindecode-1.3.0.dev168926291 → braindecode-1.3.0.dev169361694}/braindecode/datasets/__init__.py +0 -4
  6. {braindecode-1.3.0.dev168926291 → braindecode-1.3.0.dev169361694}/braindecode/datasets/hub.py +80 -63
  7. {braindecode-1.3.0.dev168926291 → braindecode-1.3.0.dev169361694}/braindecode/datasets/nmt.py +43 -38
  8. {braindecode-1.3.0.dev168926291 → braindecode-1.3.0.dev169361694}/braindecode/datautil/__init__.py +0 -2
  9. braindecode-1.3.0.dev169361694/braindecode/datautil/util.py +41 -0
  10. {braindecode-1.3.0.dev168926291 → braindecode-1.3.0.dev169361694}/braindecode/eegneuralnet.py +48 -20
  11. {braindecode-1.3.0.dev168926291 → braindecode-1.3.0.dev169361694}/braindecode/models/atcnet.py +11 -11
  12. {braindecode-1.3.0.dev168926291 → braindecode-1.3.0.dev169361694}/braindecode/models/attentionbasenet.py +4 -4
  13. {braindecode-1.3.0.dev168926291 → braindecode-1.3.0.dev169361694}/braindecode/models/attn_sleep.py +7 -9
  14. {braindecode-1.3.0.dev168926291 → braindecode-1.3.0.dev169361694}/braindecode/models/bendr.py +1 -1
  15. {braindecode-1.3.0.dev168926291 → braindecode-1.3.0.dev169361694}/braindecode/models/biot.py +23 -25
  16. {braindecode-1.3.0.dev168926291 → braindecode-1.3.0.dev169361694}/braindecode/models/contrawr.py +2 -2
  17. {braindecode-1.3.0.dev168926291 → braindecode-1.3.0.dev169361694}/braindecode/models/ctnet.py +33 -33
  18. {braindecode-1.3.0.dev168926291 → braindecode-1.3.0.dev169361694}/braindecode/models/deep4.py +4 -4
  19. {braindecode-1.3.0.dev168926291 → braindecode-1.3.0.dev169361694}/braindecode/models/deepsleepnet.py +4 -4
  20. {braindecode-1.3.0.dev168926291 → braindecode-1.3.0.dev169361694}/braindecode/models/eegconformer.py +22 -27
  21. {braindecode-1.3.0.dev168926291 → braindecode-1.3.0.dev169361694}/braindecode/models/eeginception_erp.py +1 -1
  22. {braindecode-1.3.0.dev168926291 → braindecode-1.3.0.dev169361694}/braindecode/models/eeginception_mi.py +3 -3
  23. {braindecode-1.3.0.dev168926291 → braindecode-1.3.0.dev169361694}/braindecode/models/eegitnet.py +3 -3
  24. {braindecode-1.3.0.dev168926291 → braindecode-1.3.0.dev169361694}/braindecode/models/eegnet.py +1 -1
  25. {braindecode-1.3.0.dev168926291 → braindecode-1.3.0.dev169361694}/braindecode/models/eegnex.py +1 -1
  26. {braindecode-1.3.0.dev168926291 → braindecode-1.3.0.dev169361694}/braindecode/models/eegsimpleconv.py +1 -1
  27. {braindecode-1.3.0.dev168926291 → braindecode-1.3.0.dev169361694}/braindecode/models/eegtcnet.py +3 -3
  28. {braindecode-1.3.0.dev168926291 → braindecode-1.3.0.dev169361694}/braindecode/models/fbcnet.py +1 -1
  29. {braindecode-1.3.0.dev168926291 → braindecode-1.3.0.dev169361694}/braindecode/models/fblightconvnet.py +1 -1
  30. {braindecode-1.3.0.dev168926291 → braindecode-1.3.0.dev169361694}/braindecode/models/fbmsnet.py +1 -1
  31. {braindecode-1.3.0.dev168926291 → braindecode-1.3.0.dev169361694}/braindecode/models/hybrid.py +1 -1
  32. {braindecode-1.3.0.dev168926291 → braindecode-1.3.0.dev169361694}/braindecode/models/ifnet.py +2 -2
  33. {braindecode-1.3.0.dev168926291 → braindecode-1.3.0.dev169361694}/braindecode/models/labram.py +39 -39
  34. {braindecode-1.3.0.dev168926291 → braindecode-1.3.0.dev169361694}/braindecode/models/medformer.py +14 -14
  35. {braindecode-1.3.0.dev168926291 → braindecode-1.3.0.dev169361694}/braindecode/models/msvtnet.py +9 -9
  36. {braindecode-1.3.0.dev168926291 → braindecode-1.3.0.dev169361694}/braindecode/models/patchedtransformer.py +46 -46
  37. {braindecode-1.3.0.dev168926291 → braindecode-1.3.0.dev169361694}/braindecode/models/sccnet.py +1 -1
  38. {braindecode-1.3.0.dev168926291 → braindecode-1.3.0.dev169361694}/braindecode/models/shallow_fbcsp.py +2 -4
  39. {braindecode-1.3.0.dev168926291 → braindecode-1.3.0.dev169361694}/braindecode/models/sinc_shallow.py +2 -1
  40. {braindecode-1.3.0.dev168926291 → braindecode-1.3.0.dev169361694}/braindecode/models/sleep_stager_blanco_2020.py +1 -1
  41. {braindecode-1.3.0.dev168926291 → braindecode-1.3.0.dev169361694}/braindecode/models/sleep_stager_chambon_2018.py +1 -1
  42. {braindecode-1.3.0.dev168926291 → braindecode-1.3.0.dev169361694}/braindecode/models/sparcnet.py +4 -4
  43. {braindecode-1.3.0.dev168926291 → braindecode-1.3.0.dev169361694}/braindecode/models/sstdpn.py +1 -1
  44. {braindecode-1.3.0.dev168926291 → braindecode-1.3.0.dev169361694}/braindecode/models/summary.csv +1 -1
  45. {braindecode-1.3.0.dev168926291 → braindecode-1.3.0.dev169361694}/braindecode/models/syncnet.py +1 -1
  46. {braindecode-1.3.0.dev168926291 → braindecode-1.3.0.dev169361694}/braindecode/models/tcn.py +3 -3
  47. {braindecode-1.3.0.dev168926291 → braindecode-1.3.0.dev169361694}/braindecode/models/tidnet.py +1 -1
  48. {braindecode-1.3.0.dev168926291 → braindecode-1.3.0.dev169361694}/braindecode/models/tsinception.py +1 -1
  49. {braindecode-1.3.0.dev168926291 → braindecode-1.3.0.dev169361694}/braindecode/models/usleep.py +3 -3
  50. {braindecode-1.3.0.dev168926291 → braindecode-1.3.0.dev169361694}/braindecode/models/util.py +14 -154
  51. {braindecode-1.3.0.dev168926291 → braindecode-1.3.0.dev169361694}/braindecode/modules/blocks.py +1 -3
  52. {braindecode-1.3.0.dev168926291 → braindecode-1.3.0.dev169361694}/braindecode/regressor.py +7 -3
  53. braindecode-1.3.0.dev169361694/braindecode/version.py +1 -0
  54. {braindecode-1.3.0.dev168926291 → braindecode-1.3.0.dev169361694/braindecode.egg-info}/PKG-INFO +14 -33
  55. {braindecode-1.3.0.dev168926291 → braindecode-1.3.0.dev169361694}/braindecode.egg-info/SOURCES.txt +0 -4
  56. {braindecode-1.3.0.dev168926291 → braindecode-1.3.0.dev169361694}/braindecode.egg-info/requires.txt +10 -16
  57. {braindecode-1.3.0.dev168926291 → braindecode-1.3.0.dev169361694}/docs/api.rst +0 -7
  58. {braindecode-1.3.0.dev168926291 → braindecode-1.3.0.dev169361694}/docs/cite.rst +2 -9
  59. {braindecode-1.3.0.dev168926291 → braindecode-1.3.0.dev169361694}/docs/conf.py +0 -11
  60. {braindecode-1.3.0.dev168926291 → braindecode-1.3.0.dev169361694}/docs/whats_new.rst +0 -15
  61. {braindecode-1.3.0.dev168926291 → braindecode-1.3.0.dev169361694}/pyproject.toml +14 -20
  62. braindecode-1.3.0.dev168926291/braindecode/datasets/chb_mit.py +0 -172
  63. braindecode-1.3.0.dev168926291/braindecode/datasets/siena.py +0 -164
  64. braindecode-1.3.0.dev168926291/braindecode/datasets/utils.py +0 -67
  65. braindecode-1.3.0.dev168926291/braindecode/datautil/util.py +0 -155
  66. braindecode-1.3.0.dev168926291/braindecode/models/config.py +0 -233
  67. braindecode-1.3.0.dev168926291/braindecode/version.py +0 -1
  68. {braindecode-1.3.0.dev168926291 → braindecode-1.3.0.dev169361694}/LICENSE.txt +0 -0
  69. {braindecode-1.3.0.dev168926291 → braindecode-1.3.0.dev169361694}/MANIFEST.in +0 -0
  70. {braindecode-1.3.0.dev168926291 → braindecode-1.3.0.dev169361694}/NOTICE.txt +0 -0
  71. {braindecode-1.3.0.dev168926291 → braindecode-1.3.0.dev169361694}/braindecode/__init__.py +0 -0
  72. {braindecode-1.3.0.dev168926291 → braindecode-1.3.0.dev169361694}/braindecode/augmentation/base.py +0 -0
  73. {braindecode-1.3.0.dev168926291 → braindecode-1.3.0.dev169361694}/braindecode/augmentation/functional.py +0 -0
  74. {braindecode-1.3.0.dev168926291 → braindecode-1.3.0.dev169361694}/braindecode/augmentation/transforms.py +0 -0
  75. {braindecode-1.3.0.dev168926291 → braindecode-1.3.0.dev169361694}/braindecode/datasets/base.py +0 -0
  76. {braindecode-1.3.0.dev168926291 → braindecode-1.3.0.dev169361694}/braindecode/datasets/bbci.py +0 -0
  77. {braindecode-1.3.0.dev168926291 → braindecode-1.3.0.dev169361694}/braindecode/datasets/bcicomp.py +0 -0
  78. {braindecode-1.3.0.dev168926291 → braindecode-1.3.0.dev169361694}/braindecode/datasets/bids.py +0 -0
  79. {braindecode-1.3.0.dev168926291 → braindecode-1.3.0.dev169361694}/braindecode/datasets/experimental.py +0 -0
  80. {braindecode-1.3.0.dev168926291 → braindecode-1.3.0.dev169361694}/braindecode/datasets/hub_validation.py +0 -0
  81. {braindecode-1.3.0.dev168926291 → braindecode-1.3.0.dev169361694}/braindecode/datasets/mne.py +0 -0
  82. {braindecode-1.3.0.dev168926291 → braindecode-1.3.0.dev169361694}/braindecode/datasets/moabb.py +0 -0
  83. {braindecode-1.3.0.dev168926291 → braindecode-1.3.0.dev169361694}/braindecode/datasets/registry.py +0 -0
  84. {braindecode-1.3.0.dev168926291 → braindecode-1.3.0.dev169361694}/braindecode/datasets/sleep_physio_challe_18.py +0 -0
  85. {braindecode-1.3.0.dev168926291 → braindecode-1.3.0.dev169361694}/braindecode/datasets/sleep_physionet.py +0 -0
  86. {braindecode-1.3.0.dev168926291 → braindecode-1.3.0.dev169361694}/braindecode/datasets/tuh.py +0 -0
  87. {braindecode-1.3.0.dev168926291 → braindecode-1.3.0.dev169361694}/braindecode/datasets/xy.py +0 -0
  88. {braindecode-1.3.0.dev168926291 → braindecode-1.3.0.dev169361694}/braindecode/datautil/channel_utils.py +0 -0
  89. {braindecode-1.3.0.dev168926291 → braindecode-1.3.0.dev169361694}/braindecode/datautil/hub_formats.py +0 -0
  90. {braindecode-1.3.0.dev168926291 → braindecode-1.3.0.dev169361694}/braindecode/datautil/serialization.py +0 -0
  91. {braindecode-1.3.0.dev168926291 → braindecode-1.3.0.dev169361694}/braindecode/functional/__init__.py +0 -0
  92. {braindecode-1.3.0.dev168926291 → braindecode-1.3.0.dev169361694}/braindecode/functional/functions.py +0 -0
  93. {braindecode-1.3.0.dev168926291 → braindecode-1.3.0.dev169361694}/braindecode/functional/initialization.py +0 -0
  94. {braindecode-1.3.0.dev168926291 → braindecode-1.3.0.dev169361694}/braindecode/models/__init__.py +0 -0
  95. {braindecode-1.3.0.dev168926291 → braindecode-1.3.0.dev169361694}/braindecode/models/base.py +0 -0
  96. {braindecode-1.3.0.dev168926291 → braindecode-1.3.0.dev169361694}/braindecode/models/eegminer.py +0 -0
  97. {braindecode-1.3.0.dev168926291 → braindecode-1.3.0.dev169361694}/braindecode/models/eegsym.py +0 -0
  98. {braindecode-1.3.0.dev168926291 → braindecode-1.3.0.dev169361694}/braindecode/models/luna.py +0 -0
  99. {braindecode-1.3.0.dev168926291 → braindecode-1.3.0.dev169361694}/braindecode/models/signal_jepa.py +0 -0
  100. {braindecode-1.3.0.dev168926291 → braindecode-1.3.0.dev169361694}/braindecode/modules/__init__.py +0 -0
  101. {braindecode-1.3.0.dev168926291 → braindecode-1.3.0.dev169361694}/braindecode/modules/activation.py +0 -0
  102. {braindecode-1.3.0.dev168926291 → braindecode-1.3.0.dev169361694}/braindecode/modules/attention.py +0 -0
  103. {braindecode-1.3.0.dev168926291 → braindecode-1.3.0.dev169361694}/braindecode/modules/convolution.py +0 -0
  104. {braindecode-1.3.0.dev168926291 → braindecode-1.3.0.dev169361694}/braindecode/modules/filter.py +0 -0
  105. {braindecode-1.3.0.dev168926291 → braindecode-1.3.0.dev169361694}/braindecode/modules/layers.py +0 -0
  106. {braindecode-1.3.0.dev168926291 → braindecode-1.3.0.dev169361694}/braindecode/modules/linear.py +0 -0
  107. {braindecode-1.3.0.dev168926291 → braindecode-1.3.0.dev169361694}/braindecode/modules/parametrization.py +0 -0
  108. {braindecode-1.3.0.dev168926291 → braindecode-1.3.0.dev169361694}/braindecode/modules/stats.py +0 -0
  109. {braindecode-1.3.0.dev168926291 → braindecode-1.3.0.dev169361694}/braindecode/modules/util.py +0 -0
  110. {braindecode-1.3.0.dev168926291 → braindecode-1.3.0.dev169361694}/braindecode/modules/wrapper.py +0 -0
  111. {braindecode-1.3.0.dev168926291 → braindecode-1.3.0.dev169361694}/braindecode/preprocessing/__init__.py +0 -0
  112. {braindecode-1.3.0.dev168926291 → braindecode-1.3.0.dev169361694}/braindecode/preprocessing/eegprep_preprocess.py +0 -0
  113. {braindecode-1.3.0.dev168926291 → braindecode-1.3.0.dev169361694}/braindecode/preprocessing/mne_preprocess.py +0 -0
  114. {braindecode-1.3.0.dev168926291 → braindecode-1.3.0.dev169361694}/braindecode/preprocessing/preprocess.py +0 -0
  115. {braindecode-1.3.0.dev168926291 → braindecode-1.3.0.dev169361694}/braindecode/preprocessing/util.py +0 -0
  116. {braindecode-1.3.0.dev168926291 → braindecode-1.3.0.dev169361694}/braindecode/preprocessing/windowers.py +0 -0
  117. {braindecode-1.3.0.dev168926291 → braindecode-1.3.0.dev169361694}/braindecode/samplers/__init__.py +0 -0
  118. {braindecode-1.3.0.dev168926291 → braindecode-1.3.0.dev169361694}/braindecode/samplers/base.py +0 -0
  119. {braindecode-1.3.0.dev168926291 → braindecode-1.3.0.dev169361694}/braindecode/samplers/ssl.py +0 -0
  120. {braindecode-1.3.0.dev168926291 → braindecode-1.3.0.dev169361694}/braindecode/training/__init__.py +0 -0
  121. {braindecode-1.3.0.dev168926291 → braindecode-1.3.0.dev169361694}/braindecode/training/callbacks.py +0 -0
  122. {braindecode-1.3.0.dev168926291 → braindecode-1.3.0.dev169361694}/braindecode/training/losses.py +0 -0
  123. {braindecode-1.3.0.dev168926291 → braindecode-1.3.0.dev169361694}/braindecode/training/scoring.py +0 -0
  124. {braindecode-1.3.0.dev168926291 → braindecode-1.3.0.dev169361694}/braindecode/util.py +0 -0
  125. {braindecode-1.3.0.dev168926291 → braindecode-1.3.0.dev169361694}/braindecode/visualization/__init__.py +0 -0
  126. {braindecode-1.3.0.dev168926291 → braindecode-1.3.0.dev169361694}/braindecode/visualization/confusion_matrices.py +0 -0
  127. {braindecode-1.3.0.dev168926291 → braindecode-1.3.0.dev169361694}/braindecode/visualization/gradients.py +0 -0
  128. {braindecode-1.3.0.dev168926291 → braindecode-1.3.0.dev169361694}/braindecode.egg-info/dependency_links.txt +0 -0
  129. {braindecode-1.3.0.dev168926291 → braindecode-1.3.0.dev169361694}/braindecode.egg-info/top_level.txt +0 -0
  130. {braindecode-1.3.0.dev168926291 → braindecode-1.3.0.dev169361694}/docs/Makefile +0 -0
  131. {braindecode-1.3.0.dev168926291 → braindecode-1.3.0.dev169361694}/docs/_templates/autosummary/class.rst +0 -0
  132. {braindecode-1.3.0.dev168926291 → braindecode-1.3.0.dev169361694}/docs/_templates/autosummary/function.rst +0 -0
  133. {braindecode-1.3.0.dev168926291 → braindecode-1.3.0.dev169361694}/docs/help.rst +0 -0
  134. {braindecode-1.3.0.dev168926291 → braindecode-1.3.0.dev169361694}/docs/index.rst +0 -0
  135. {braindecode-1.3.0.dev168926291 → braindecode-1.3.0.dev169361694}/docs/install/install.rst +0 -0
  136. {braindecode-1.3.0.dev168926291 → braindecode-1.3.0.dev169361694}/docs/install/install_pip.rst +0 -0
  137. {braindecode-1.3.0.dev168926291 → braindecode-1.3.0.dev169361694}/docs/install/install_source.rst +0 -0
  138. {braindecode-1.3.0.dev168926291 → braindecode-1.3.0.dev169361694}/docs/models/categorization/attention.rst +0 -0
  139. {braindecode-1.3.0.dev168926291 → braindecode-1.3.0.dev169361694}/docs/models/categorization/channel.rst +0 -0
  140. {braindecode-1.3.0.dev168926291 → braindecode-1.3.0.dev169361694}/docs/models/categorization/convolution.rst +0 -0
  141. {braindecode-1.3.0.dev168926291 → braindecode-1.3.0.dev169361694}/docs/models/categorization/filterbank.rst +0 -0
  142. {braindecode-1.3.0.dev168926291 → braindecode-1.3.0.dev169361694}/docs/models/categorization/gnn.rst +0 -0
  143. {braindecode-1.3.0.dev168926291 → braindecode-1.3.0.dev169361694}/docs/models/categorization/interpretable.rst +0 -0
  144. {braindecode-1.3.0.dev168926291 → braindecode-1.3.0.dev169361694}/docs/models/categorization/lbm.rst +0 -0
  145. {braindecode-1.3.0.dev168926291 → braindecode-1.3.0.dev169361694}/docs/models/categorization/recurrent.rst +0 -0
  146. {braindecode-1.3.0.dev168926291 → braindecode-1.3.0.dev169361694}/docs/models/categorization/spd.rst +0 -0
  147. {braindecode-1.3.0.dev168926291 → braindecode-1.3.0.dev169361694}/docs/models/models.rst +0 -0
  148. {braindecode-1.3.0.dev168926291 → braindecode-1.3.0.dev169361694}/docs/models/models_categorization.rst +0 -0
  149. {braindecode-1.3.0.dev168926291 → braindecode-1.3.0.dev169361694}/docs/models/models_table.rst +0 -0
  150. {braindecode-1.3.0.dev168926291 → braindecode-1.3.0.dev169361694}/docs/models/models_visualization.rst +0 -0
  151. {braindecode-1.3.0.dev168926291 → braindecode-1.3.0.dev169361694}/docs/sg_execution_times.rst +0 -0
  152. {braindecode-1.3.0.dev168926291 → braindecode-1.3.0.dev169361694}/setup.cfg +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: braindecode
3
- Version: 1.3.0.dev168926291
3
+ Version: 1.3.0.dev169361694
4
4
  Summary: Deep learning software to decode EEG, ECG or MEG signals
5
5
  Author-email: Robin Tibor Schirrmeister <robintibor@gmail.com>, Bruno Aristimunha Pinto <b.aristimunha@gmail.com>, Alexandre Gramfort <agramfort@meta.com>
6
6
  Maintainer-email: Alexandre Gramfort <agramfort@meta.com>, Bruno Aristimunha Pinto <b.aristimunha@gmail.com>, Robin Tibor Schirrmeister <robintibor@gmail.com>
@@ -14,47 +14,44 @@ Classifier: Intended Audience :: Developers
14
14
  Classifier: Intended Audience :: Science/Research
15
15
  Classifier: Topic :: Software Development :: Build Tools
16
16
  Classifier: Topic :: Scientific/Engineering :: Artificial Intelligence
17
+ Classifier: Programming Language :: Python :: 3.10
17
18
  Classifier: Programming Language :: Python :: 3.11
18
19
  Classifier: Programming Language :: Python :: 3.12
19
- Classifier: Programming Language :: Python :: 3.13
20
- Classifier: Programming Language :: Python :: 3.14
21
- Requires-Python: >=3.11
20
+ Requires-Python: >=3.10
22
21
  Description-Content-Type: text/x-rst
23
22
  License-File: LICENSE.txt
24
23
  License-File: NOTICE.txt
25
- Requires-Dist: mne>=1.11.0
24
+ Requires-Dist: mne>=1.10.0
26
25
  Requires-Dist: mne_bids>=0.16
27
26
  Requires-Dist: numpy
28
27
  Requires-Dist: pandas
29
28
  Requires-Dist: scipy
30
29
  Requires-Dist: matplotlib
31
30
  Requires-Dist: h5py
32
- Requires-Dist: skorch>=1.3.0
33
- Requires-Dist: torch>=2.0
34
- Requires-Dist: torchaudio>=2.0
31
+ Requires-Dist: skorch>=1.2.0
32
+ Requires-Dist: torch<3.0,>=2.0
33
+ Requires-Dist: torchaudio<3.0,>=2.0
35
34
  Requires-Dist: einops
36
35
  Requires-Dist: joblib
37
- Requires-Dist: torchinfo
36
+ Requires-Dist: torchinfo~=1.8
38
37
  Requires-Dist: wfdb
38
+ Requires-Dist: h5py
39
39
  Requires-Dist: linear_attention_transformer
40
40
  Requires-Dist: docstring_inheritance
41
41
  Requires-Dist: rotary_embedding_torch
42
42
  Provides-Extra: moabb
43
- Requires-Dist: moabb>=1.4.2; extra == "moabb"
43
+ Requires-Dist: moabb>=1.2.0; extra == "moabb"
44
44
  Provides-Extra: eegprep
45
- Requires-Dist: eegprep[eeglabio]>=0.2.23; extra == "eegprep"
45
+ Requires-Dist: eegprep[eeglabio]>=0.1.1; extra == "eegprep"
46
46
  Provides-Extra: hub
47
47
  Requires-Dist: huggingface_hub[torch]>=0.20.0; extra == "hub"
48
- Requires-Dist: zarr>=3.0; extra == "hub"
48
+ Requires-Dist: zarr<3.0,>=2.18; extra == "hub"
49
49
  Provides-Extra: tests
50
50
  Requires-Dist: pytest; extra == "tests"
51
51
  Requires-Dist: pytest-cov; extra == "tests"
52
52
  Requires-Dist: codecov; extra == "tests"
53
53
  Requires-Dist: pytest_cases; extra == "tests"
54
54
  Requires-Dist: mypy; extra == "tests"
55
- Provides-Extra: typing
56
- Requires-Dist: exca==0.4; extra == "typing"
57
- Requires-Dist: numpydantic>=1.7; extra == "typing"
58
55
  Provides-Extra: docs
59
56
  Requires-Dist: sphinx_gallery; extra == "docs"
60
57
  Requires-Dist: sphinx_rtd_theme; extra == "docs"
@@ -73,21 +70,14 @@ Requires-Dist: seaborn; extra == "docs"
73
70
  Requires-Dist: pre-commit; extra == "docs"
74
71
  Requires-Dist: openneuro-py; extra == "docs"
75
72
  Requires-Dist: plotly; extra == "docs"
76
- Requires-Dist: shap; extra == "docs"
77
- Requires-Dist: nbformat; extra == "docs"
78
73
  Provides-Extra: all
79
74
  Requires-Dist: braindecode[moabb]; extra == "all"
75
+ Requires-Dist: braindecode[hub]; extra == "all"
80
76
  Requires-Dist: braindecode[tests]; extra == "all"
81
77
  Requires-Dist: braindecode[docs]; extra == "all"
82
- Requires-Dist: braindecode[hub]; extra == "all"
83
78
  Requires-Dist: braindecode[eegprep]; extra == "all"
84
- Requires-Dist: braindecode[typing]; extra == "all"
85
79
  Dynamic: license-file
86
80
 
87
- .. image:: https://zenodo.org/badge/232335424.svg
88
- :target: https://doi.org/10.5281/zenodo.8214376
89
- :alt: DOI
90
-
91
81
  .. image:: https://badges.gitter.im/braindecodechat/community.svg
92
82
  :alt: Join the chat at https://gitter.im/braindecodechat/community
93
83
  :target: https://gitter.im/braindecodechat/community?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge
@@ -103,7 +93,6 @@ Dynamic: license-file
103
93
  :target: https://codecov.io/gh/braindecode/braindecode
104
94
  :alt: Code Coverage
105
95
 
106
-
107
96
  .. |Braindecode| image:: https://user-images.githubusercontent.com/42702466/177958779-b00628aa-9155-4c51-96d1-d8c345aff575.svg
108
97
  .. _braindecode: braindecode.org/
109
98
 
@@ -160,15 +149,7 @@ https://gitter.im/braindecodechat/community
160
149
  Citing
161
150
  ======
162
151
 
163
- If you use Braindecode in scientific work, please cite the software using the Zenodo DOI shown in the badge below:
164
-
165
- .. image:: https://zenodo.org/badge/232335424.svg
166
- :target: https://doi.org/10.5281/zenodo.8214376
167
- :alt: DOI
168
-
169
- Additionally, we highly encourage you to cite the article that originally introduced
170
- the Braindecode library and has served as a foundational reference for many works
171
- on deep learning with EEG recordings. Please use the following reference:
152
+ If you use this code in a scientific publication, please cite us as:
172
153
 
173
154
  .. code-block:: bibtex
174
155
 
@@ -1,7 +1,3 @@
1
- .. image:: https://zenodo.org/badge/232335424.svg
2
- :target: https://doi.org/10.5281/zenodo.8214376
3
- :alt: DOI
4
-
5
1
  .. image:: https://badges.gitter.im/braindecodechat/community.svg
6
2
  :alt: Join the chat at https://gitter.im/braindecodechat/community
7
3
  :target: https://gitter.im/braindecodechat/community?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge
@@ -17,7 +13,6 @@
17
13
  :target: https://codecov.io/gh/braindecode/braindecode
18
14
  :alt: Code Coverage
19
15
 
20
-
21
16
  .. |Braindecode| image:: https://user-images.githubusercontent.com/42702466/177958779-b00628aa-9155-4c51-96d1-d8c345aff575.svg
22
17
  .. _braindecode: braindecode.org/
23
18
 
@@ -74,15 +69,7 @@ https://gitter.im/braindecodechat/community
74
69
  Citing
75
70
  ======
76
71
 
77
- If you use Braindecode in scientific work, please cite the software using the Zenodo DOI shown in the badge below:
78
-
79
- .. image:: https://zenodo.org/badge/232335424.svg
80
- :target: https://doi.org/10.5281/zenodo.8214376
81
- :alt: DOI
82
-
83
- Additionally, we highly encourage you to cite the article that originally introduced
84
- the Braindecode library and has served as a foundational reference for many works
85
- on deep learning with EEG recordings. Please use the following reference:
72
+ If you use this code in a scientific publication, please cite us as:
86
73
 
87
74
  .. code-block:: bibtex
88
75
 
@@ -5,10 +5,8 @@ Utilities for data augmentation.
5
5
  from . import functional
6
6
  from .base import AugmentedDataLoader, Compose, IdentityTransform, Transform
7
7
  from .transforms import (
8
- AmplitudeScale,
9
8
  BandstopFilter,
10
9
  ChannelsDropout,
11
- ChannelsReref,
12
10
  ChannelsShuffle,
13
11
  ChannelsSymmetry,
14
12
  FrequencyShift,
@@ -48,7 +46,5 @@ __all__ = [
48
46
  "Mixup",
49
47
  "SegmentationReconstruction",
50
48
  "MaskEncoding",
51
- "AmplitudeScale",
52
- "ChannelsReref",
53
49
  "functional",
54
50
  ]
@@ -8,6 +8,7 @@
8
8
 
9
9
  import warnings
10
10
 
11
+ import numpy as np
11
12
  from skorch import NeuralNet
12
13
  from skorch.callbacks import EpochScoring
13
14
  from skorch.classifier import NeuralNetClassifier
@@ -236,9 +237,13 @@ class EEGClassifier(_EEGNeuralNet, NeuralNetClassifier):
236
237
  num_workers=self.get_iterator(X, training=False).loader.num_workers,
237
238
  )
238
239
 
239
- @property
240
- def mode(self):
241
- return "classification"
240
+ def _get_n_outputs(self, y, classes):
241
+ classes_y = np.unique(y)
242
+ if classes is not None:
243
+ assert set(classes_y) <= set(classes)
244
+ else:
245
+ classes = classes_y
246
+ return len(classes)
242
247
 
243
248
  # Only add the 'accuracy' callback if we are not in cropped mode.
244
249
  @property
@@ -11,11 +11,9 @@ from .base import (
11
11
  )
12
12
  from .bcicomp import BCICompetitionIVDataset4
13
13
  from .bids import BIDSDataset, BIDSEpochsDataset
14
- from .chb_mit import CHBMIT
15
14
  from .mne import create_from_mne_epochs, create_from_mne_raw
16
15
  from .moabb import BNCI2014_001, HGD, MOABBDataset
17
16
  from .nmt import NMT
18
- from .siena import SIENA
19
17
  from .sleep_physio_challe_18 import SleepPhysionetChallenge2018
20
18
  from .sleep_physionet import SleepPhysionet
21
19
  from .tuh import TUH, TUHAbnormal
@@ -36,9 +34,7 @@ __all__ = [
36
34
  "create_from_mne_epochs",
37
35
  "TUH",
38
36
  "TUHAbnormal",
39
- "SIENA",
40
37
  "NMT",
41
- "CHBMIT",
42
38
  "SleepPhysionet",
43
39
  "SleepPhysionetChallenge2018",
44
40
  "create_from_X_y",
@@ -21,9 +21,18 @@ import mne
21
21
  import numpy as np
22
22
  import pandas as pd
23
23
  import scipy
24
- from mne._fiff.meas_info import Info
25
24
  from mne.utils import _soft_import
26
25
 
26
+ # TODO: Simplify this logic in the future with zarr v3+ only
27
+ # Optional imports for Hub functionality
28
+ try:
29
+ from numcodecs import Blosc, GZip, Zstd
30
+
31
+ NUMCODECS_AVAILABLE = True
32
+ except ImportError:
33
+ NUMCODECS_AVAILABLE = False
34
+ Blosc = GZip = Zstd = None
35
+
27
36
  if TYPE_CHECKING:
28
37
  from .base import BaseDataset
29
38
 
@@ -388,8 +397,9 @@ class HubDatasetMixin:
388
397
  f"{output_path} already exists. Set overwrite=True to replace it."
389
398
  )
390
399
 
391
- # Create zarr store (zarr v3 API)
392
- root = zarr.open(str(output_path), mode="w")
400
+ # Create zarr store (zarr v2 API)
401
+ store = zarr.DirectoryStore(str(output_path))
402
+ root = zarr.group(store=store, overwrite=False)
393
403
 
394
404
  # Validate uniformity across all datasets using shared validation
395
405
  dataset_type, _, _ = hub_validation.validate_dataset_uniformity(self.datasets)
@@ -434,7 +444,7 @@ class HubDatasetMixin:
434
444
  data = ds.windows.get_data()
435
445
  metadata = ds.windows.metadata
436
446
  description = ds.description
437
- info_dict = ds.windows.info.to_json_dict()
447
+ info_dict = _mne_info_to_dict(ds.windows.info)
438
448
  target_name = ds.target_name if hasattr(ds, "target_name") else None
439
449
 
440
450
  # Save using inlined function
@@ -447,7 +457,7 @@ class HubDatasetMixin:
447
457
  raw = ds.raw
448
458
  metadata = ds.metadata
449
459
  description = ds.description
450
- info_dict = ds.raw.info.to_json_dict()
460
+ info_dict = _mne_info_to_dict(ds.raw.info)
451
461
  targets_from = ds.targets_from
452
462
  last_target_only = ds.last_target_only
453
463
 
@@ -467,7 +477,7 @@ class HubDatasetMixin:
467
477
  # Get continuous raw data from RawDataset
468
478
  raw = ds.raw
469
479
  description = ds.description
470
- info_dict = ds.raw.info.to_json_dict()
480
+ info_dict = _mne_info_to_dict(ds.raw.info)
471
481
  target_name = ds.target_name if hasattr(ds, "target_name") else None
472
482
 
473
483
  # Save using inlined function
@@ -520,8 +530,9 @@ class HubDatasetMixin:
520
530
  if not input_path.exists():
521
531
  raise FileNotFoundError(f"{input_path} does not exist.")
522
532
 
523
- # Open zarr store (zarr v3 API)
524
- root = zarr.open(str(input_path), mode="r")
533
+ # Open zarr store (zarr v2 API)
534
+ store = zarr.DirectoryStore(str(input_path))
535
+ root = zarr.group(store=store)
525
536
 
526
537
  n_datasets = root.attrs["n_datasets"]
527
538
  dataset_type = root.attrs["dataset_type"]
@@ -543,7 +554,7 @@ class HubDatasetMixin:
543
554
  )
544
555
 
545
556
  # Convert to MNE objects and create dataset
546
- info = Info.from_json_dict(info_dict)
557
+ info = _dict_to_mne_info(info_dict)
547
558
  events = np.column_stack(
548
559
  [
549
560
  metadata["i_start_in_trial"].values,
@@ -569,7 +580,7 @@ class HubDatasetMixin:
569
580
 
570
581
  # Convert to MNE objects and create dataset
571
582
  # Data is already in continuous format [n_channels, n_timepoints]
572
- info = Info.from_json_dict(info_dict)
583
+ info = _dict_to_mne_info(info_dict)
573
584
  raw = mne.io.RawArray(data, info)
574
585
  ds = EEGWindowsDataset(
575
586
  raw=raw,
@@ -587,7 +598,7 @@ class HubDatasetMixin:
587
598
 
588
599
  # Convert to MNE objects and create dataset
589
600
  # Data is in continuous format [n_channels, n_timepoints]
590
- info = Info.from_json_dict(info_dict)
601
+ info = _dict_to_mne_info(info_dict)
591
602
  raw = mne.io.RawArray(data, info)
592
603
  ds = RawDataset(raw, description)
593
604
  if target_name is not None:
@@ -621,22 +632,48 @@ class HubDatasetMixin:
621
632
  # =============================================================================
622
633
 
623
634
 
635
+ # TODO: remove when this MNE is solved https://github.com/mne-tools/mne-python/issues/13487
636
+ def _mne_info_to_dict(info):
637
+ """Convert MNE Info object to dictionary for JSON serialization."""
638
+ return {
639
+ "ch_names": info["ch_names"],
640
+ "sfreq": float(info["sfreq"]),
641
+ "ch_types": [str(ch_type) for ch_type in info.get_channel_types()],
642
+ "lowpass": float(info["lowpass"]) if info["lowpass"] is not None else None,
643
+ "highpass": float(info["highpass"]) if info["highpass"] is not None else None,
644
+ }
645
+
646
+
647
+ def _dict_to_mne_info(info_dict):
648
+ """Convert dictionary back to MNE Info object."""
649
+ info = mne.create_info(
650
+ ch_names=info_dict["ch_names"],
651
+ sfreq=info_dict["sfreq"],
652
+ ch_types=info_dict["ch_types"],
653
+ )
654
+
655
+ # Use _unlock() to set filter info when reconstructing from saved metadata
656
+ # This is necessary because MNE protects these fields to prevent users from
657
+ # setting filter parameters without actually filtering the data
658
+ with info._unlock():
659
+ if info_dict.get("lowpass") is not None:
660
+ info["lowpass"] = info_dict["lowpass"]
661
+ if info_dict.get("highpass") is not None:
662
+ info["highpass"] = info_dict["highpass"]
663
+
664
+ return info
665
+
666
+
624
667
  def _save_windows_to_zarr(
625
668
  grp, data, metadata, description, info, compressor, target_name
626
669
  ):
627
670
  """Save windowed data to Zarr group (low-level function)."""
628
671
  # Save data with chunking for random access
629
- # In Zarr v3, use create_array with compressors parameter
630
- data_array = data.astype(np.float32)
631
-
632
- # Zarr v3 expects compressors as a list
633
- compressors_list = [compressor] if compressor is not None else None
634
-
635
- grp.create_array(
672
+ grp.create_dataset(
636
673
  "data",
637
- data=data_array,
638
- chunks=(1, data_array.shape[1], data_array.shape[2]),
639
- compressors=compressors_list,
674
+ data=data.astype(np.float32),
675
+ chunks=(1, data.shape[1], data.shape[2]),
676
+ compressor=compressor,
640
677
  )
641
678
 
642
679
  # Save metadata
@@ -667,17 +704,11 @@ def _save_eegwindows_to_zarr(
667
704
 
668
705
  # Save continuous data with chunking optimized for window extraction
669
706
  # Chunk size: all channels, 10000 timepoints for efficient random access
670
- # In Zarr v3, use create_array with compressors parameter
671
- continuous_float = continuous_data.astype(np.float32)
672
-
673
- # Zarr v3 expects compressors as a list
674
- compressors_list = [compressor] if compressor is not None else None
675
-
676
- grp.create_array(
707
+ grp.create_dataset(
677
708
  "data",
678
- data=continuous_float,
679
- chunks=(continuous_float.shape[0], min(10000, continuous_float.shape[1])),
680
- compressors=compressors_list,
709
+ data=continuous_data.astype(np.float32),
710
+ chunks=(continuous_data.shape[0], min(10000, continuous_data.shape[1])),
711
+ compressor=compressor,
681
712
  )
682
713
 
683
714
  # Save metadata
@@ -772,17 +803,11 @@ def _save_raw_to_zarr(grp, raw, description, info, target_name, compressor):
772
803
 
773
804
  # Save continuous data with chunking optimized for efficient access
774
805
  # Chunk size: all channels, 10000 timepoints for efficient random access
775
- # In Zarr v3, use create_array with compressors parameter
776
- continuous_float = continuous_data.astype(np.float32)
777
-
778
- # Zarr v3 expects compressors as a list
779
- compressors_list = [compressor] if compressor is not None else None
780
-
781
- grp.create_array(
806
+ grp.create_dataset(
782
807
  "data",
783
- data=continuous_float,
784
- chunks=(continuous_float.shape[0], min(10000, continuous_float.shape[1])),
785
- compressors=compressors_list,
808
+ data=continuous_data.astype(np.float32),
809
+ chunks=(continuous_data.shape[0], min(10000, continuous_data.shape[1])),
810
+ compressor=compressor,
786
811
  )
787
812
 
788
813
  # Save description
@@ -824,34 +849,26 @@ def _load_raw_from_zarr(grp, preload):
824
849
 
825
850
 
826
851
  def _create_compressor(compression, compression_level):
827
- """Create a Zarr v3 compressor codec.
828
-
829
- Returns compressor dict compatible with Zarr v3 create_array API.
830
-
831
- Parameters
832
- ----------
833
- compression : str or None
834
- Compression algorithm: "blosc", "zstd", "gzip", or None.
835
- compression_level : int
836
- Compression level (0-9).
837
-
838
- Returns
839
- -------
840
- dict or None
841
- Compressor configuration dict or None if no compression.
842
- """
852
+ """Create a Zarr compressor object (zarr v2 API)."""
843
853
  if zarr is False:
844
854
  raise ImportError(
845
855
  "Zarr is not installed. Install with: pip install braindecode[hub]"
846
856
  )
847
857
 
848
- if compression is None or compression not in ("blosc", "zstd", "gzip"):
849
- return None
850
-
851
- # Map blosc to zstd (Zarr v3 uses zstd as the primary implementation)
852
- name = "zstd" if compression == "blosc" else compression
858
+ if not NUMCODECS_AVAILABLE:
859
+ raise ImportError(
860
+ "numcodecs is not installed. Install with: pip install braindecode[hub]"
861
+ )
853
862
 
854
- return {"name": name, "configuration": {"level": compression_level}}
863
+ # Zarr v2 uses numcodecs compressors
864
+ if compression == "blosc":
865
+ return Blosc(cname="zstd", clevel=compression_level)
866
+ elif compression == "zstd":
867
+ return Zstd(level=compression_level)
868
+ elif compression == "gzip":
869
+ return GZip(level=compression_level)
870
+ else:
871
+ return None
855
872
 
856
873
 
857
874
  # TODO: improve content
@@ -32,7 +32,6 @@ from joblib import Parallel, delayed
32
32
  from mne.datasets import fetch_dataset
33
33
 
34
34
  from braindecode.datasets.base import BaseConcatDataset, RawDataset
35
- from braindecode.datasets.utils import _correct_dataset_path
36
35
 
37
36
  NMT_URL = "https://zenodo.org/record/10909103/files/NMT.zip"
38
37
  NMT_archive_name = "NMT.zip"
@@ -97,34 +96,22 @@ class NMT(BaseConcatDataset):
97
96
  preload=False,
98
97
  n_jobs=1,
99
98
  ):
100
- # Convert empty string to None for consistency
101
- if path == "":
102
- path = None
99
+ # correct the path if needed
100
+ if path is not None:
101
+ list_csv = glob.glob(f"{path}/**/Labels.csv", recursive=True)
102
+ if isinstance(list_csv, list) and len(list_csv) > 0:
103
+ path = Path(list_csv[0]).parent
103
104
 
104
- # Download dataset if not present
105
- if path is None:
105
+ if path is None or len(list_csv) == 0:
106
106
  path = fetch_dataset(
107
107
  dataset_params=NMT_dataset_params,
108
- path=None,
108
+ path=Path(path) if path is not None else None,
109
109
  processor="unzip",
110
110
  force_update=False,
111
111
  )
112
112
  # First time we fetch the dataset, we need to move the files to the
113
113
  # correct directory.
114
- path = _correct_dataset_path(
115
- path, NMT_archive_name, "nmt_scalp_eeg_dataset"
116
- )
117
- else:
118
- # Validate that the provided path is a valid NMT dataset
119
- if not Path(f"{path}/Labels.csv").exists():
120
- raise ValueError(
121
- f"The provided path {path} does not contain a valid "
122
- "NMT dataset (missing Labels.csv). Please ensure the "
123
- "path points directly to the NMT dataset directory."
124
- )
125
- path = _correct_dataset_path(
126
- path, NMT_archive_name, "nmt_scalp_eeg_dataset"
127
- )
114
+ path = _correct_path(path)
128
115
 
129
116
  # Get all file paths
130
117
  file_paths = glob.glob(
@@ -189,6 +176,39 @@ class NMT(BaseConcatDataset):
189
176
  return base_dataset
190
177
 
191
178
 
179
+ def _correct_path(path: str):
180
+ """
181
+ Check if the path is correct and rename the file if needed.
182
+
183
+ Parameters
184
+ ----------
185
+ path: basestring
186
+ Path to the file.
187
+
188
+ Returns
189
+ -------
190
+ path: basestring
191
+ Corrected path.
192
+ """
193
+ if not Path(path).exists():
194
+ unzip_file_name = f"{NMT_archive_name}.unzip"
195
+ if (Path(path).parent / unzip_file_name).exists():
196
+ try:
197
+ os.rename(
198
+ src=Path(path).parent / unzip_file_name,
199
+ dst=Path(path),
200
+ )
201
+
202
+ except PermissionError:
203
+ raise PermissionError(
204
+ f"Please rename {Path(path).parent / unzip_file_name}"
205
+ + f"manually to {path} and try again."
206
+ )
207
+ path = os.path.join(path, "nmt_scalp_eeg_dataset")
208
+
209
+ return path
210
+
211
+
192
212
  def _get_header(*args):
193
213
  all_paths = {**_NMT_PATHS}
194
214
  return all_paths[args[0]]
@@ -268,33 +288,18 @@ _NMT_PATHS = {
268
288
  class _NMTMock(NMT):
269
289
  """Mocked class for testing and examples."""
270
290
 
271
- @mock.patch("pathlib.Path.exists", return_value=True)
272
- @mock.patch("braindecode.datasets.nmt._correct_dataset_path")
273
- @mock.patch("mne.datasets.fetch_dataset")
274
- @mock.patch("pandas.read_csv", new=_fake_pd_read_csv)
275
- @mock.patch("mne.io.read_raw_edf", new=_fake_raw)
276
291
  @mock.patch("glob.glob", return_value=_NMT_PATHS.keys())
292
+ @mock.patch("mne.io.read_raw_edf", new=_fake_raw)
293
+ @mock.patch("pandas.read_csv", new=_fake_pd_read_csv)
277
294
  def __init__(
278
295
  self,
279
296
  mock_glob,
280
- mock_fetch,
281
- mock_correct_path,
282
- mock_path_exists,
283
297
  path,
284
298
  recording_ids=None,
285
299
  target_name="pathological",
286
300
  preload=False,
287
301
  n_jobs=1,
288
302
  ):
289
- # Prevent download by providing a dummy path if empty/None
290
- if not path:
291
- path = "mocked_nmt_path"
292
-
293
- # Mock fetch_dataset to return a valid path without downloading
294
- mock_fetch.return_value = path
295
- # Mock _correct_dataset_path to return the path as-is
296
- mock_correct_path.side_effect = lambda p, *args, **kwargs: p
297
-
298
303
  with warnings.catch_warnings():
299
304
  warnings.filterwarnings("ignore", message="Cannot save date file")
300
305
  super().__init__(
@@ -11,7 +11,6 @@ from .serialization import (
11
11
  load_concat_dataset,
12
12
  save_concat_dataset,
13
13
  )
14
- from .util import infer_signal_properties
15
14
 
16
15
 
17
16
  def __getattr__(name):
@@ -60,5 +59,4 @@ __all__ = [
60
59
  "_check_save_dir_empty",
61
60
  "match_hemisphere_chans",
62
61
  "division_channels_idx",
63
- "infer_signal_properties",
64
62
  ]
@@ -0,0 +1,41 @@
1
+ # Authors: Robin Schirrmeister <robintibor@gmail.com>
2
+ #
3
+ # License: BSD (3-clause)
4
+
5
+
6
+ def ms_to_samples(ms, fs):
7
+ """
8
+ Compute milliseconds to number of samples.
9
+
10
+ Parameters
11
+ ----------
12
+ ms: number
13
+ Milliseconds
14
+ fs: number
15
+ Sampling rate
16
+
17
+ Returns
18
+ -------
19
+ n_samples: int
20
+ Number of samples
21
+
22
+ """
23
+ return ms * fs / 1000.0
24
+
25
+
26
+ def samples_to_ms(n_samples, fs):
27
+ """
28
+ Compute milliseconds to number of samples.
29
+
30
+ Parameters
31
+ ----------
32
+ n_samples: number
33
+ Number of samples
34
+ fs: number
35
+ Sampling rate
36
+
37
+ Returns
38
+ -------
39
+ milliseconds: int
40
+ """
41
+ return n_samples * 1000.0 / fs