rapidtide 2.9.5__py3-none-any.whl → 3.1.3__py3-none-any.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 (405) hide show
  1. cloud/gmscalc-HCPYA +1 -1
  2. cloud/mount-and-run +2 -0
  3. cloud/rapidtide-HCPYA +3 -3
  4. rapidtide/Colortables.py +538 -38
  5. rapidtide/OrthoImageItem.py +1094 -51
  6. rapidtide/RapidtideDataset.py +1709 -114
  7. rapidtide/__init__.py +0 -8
  8. rapidtide/_version.py +4 -4
  9. rapidtide/calccoherence.py +242 -97
  10. rapidtide/calcnullsimfunc.py +240 -140
  11. rapidtide/calcsimfunc.py +314 -129
  12. rapidtide/correlate.py +1211 -389
  13. rapidtide/data/examples/src/testLD +56 -0
  14. rapidtide/data/examples/src/test_findmaxlag.py +2 -2
  15. rapidtide/data/examples/src/test_mlregressallt.py +32 -17
  16. rapidtide/data/examples/src/testalign +1 -1
  17. rapidtide/data/examples/src/testatlasaverage +35 -7
  18. rapidtide/data/examples/src/testboth +21 -0
  19. rapidtide/data/examples/src/testcifti +11 -0
  20. rapidtide/data/examples/src/testdelayvar +13 -0
  21. rapidtide/data/examples/src/testdlfilt +25 -0
  22. rapidtide/data/examples/src/testfft +35 -0
  23. rapidtide/data/examples/src/testfileorfloat +37 -0
  24. rapidtide/data/examples/src/testfmri +94 -27
  25. rapidtide/data/examples/src/testfuncs +3 -3
  26. rapidtide/data/examples/src/testglmfilt +8 -6
  27. rapidtide/data/examples/src/testhappy +84 -51
  28. rapidtide/data/examples/src/testinitdelay +19 -0
  29. rapidtide/data/examples/src/testmodels +33 -0
  30. rapidtide/data/examples/src/testnewrefine +26 -0
  31. rapidtide/data/examples/src/testnoiseamp +21 -0
  32. rapidtide/data/examples/src/testppgproc +17 -0
  33. rapidtide/data/examples/src/testrefineonly +22 -0
  34. rapidtide/data/examples/src/testretro +26 -13
  35. rapidtide/data/examples/src/testretrolagtcs +16 -0
  36. rapidtide/data/examples/src/testrolloff +11 -0
  37. rapidtide/data/examples/src/testsimdata +45 -28
  38. rapidtide/data/models/model_cnn_pytorch/loss.png +0 -0
  39. rapidtide/data/models/model_cnn_pytorch/loss.txt +1 -0
  40. rapidtide/data/models/model_cnn_pytorch/model.pth +0 -0
  41. rapidtide/data/models/model_cnn_pytorch/model_meta.json +68 -0
  42. rapidtide/data/models/model_cnn_pytorch_fulldata/loss.png +0 -0
  43. rapidtide/data/models/model_cnn_pytorch_fulldata/loss.txt +1 -0
  44. rapidtide/data/models/model_cnn_pytorch_fulldata/model.pth +0 -0
  45. rapidtide/data/models/model_cnn_pytorch_fulldata/model_meta.json +80 -0
  46. rapidtide/data/models/model_cnnbp_pytorch_fullldata/loss.png +0 -0
  47. rapidtide/data/models/model_cnnbp_pytorch_fullldata/loss.txt +1 -0
  48. rapidtide/data/models/model_cnnbp_pytorch_fullldata/model.pth +0 -0
  49. rapidtide/data/models/model_cnnbp_pytorch_fullldata/model_meta.json +138 -0
  50. rapidtide/data/models/model_cnnfft_pytorch_fulldata/loss.png +0 -0
  51. rapidtide/data/models/model_cnnfft_pytorch_fulldata/loss.txt +1 -0
  52. rapidtide/data/models/model_cnnfft_pytorch_fulldata/model.pth +0 -0
  53. rapidtide/data/models/model_cnnfft_pytorch_fulldata/model_meta.json +128 -0
  54. rapidtide/data/models/model_ppgattention_pytorch_w128_fulldata/loss.png +0 -0
  55. rapidtide/data/models/model_ppgattention_pytorch_w128_fulldata/loss.txt +1 -0
  56. rapidtide/data/models/model_ppgattention_pytorch_w128_fulldata/model.pth +0 -0
  57. rapidtide/data/models/model_ppgattention_pytorch_w128_fulldata/model_meta.json +49 -0
  58. rapidtide/data/models/model_revised_tf2/model.keras +0 -0
  59. rapidtide/data/models/{model_serdar → model_revised_tf2}/model_meta.json +1 -1
  60. rapidtide/data/models/model_serdar2_tf2/model.keras +0 -0
  61. rapidtide/data/models/{model_serdar2 → model_serdar2_tf2}/model_meta.json +1 -1
  62. rapidtide/data/models/model_serdar_tf2/model.keras +0 -0
  63. rapidtide/data/models/{model_revised → model_serdar_tf2}/model_meta.json +1 -1
  64. rapidtide/data/reference/HCP1200v2_MTT_2mm.nii.gz +0 -0
  65. rapidtide/data/reference/HCP1200v2_binmask_2mm.nii.gz +0 -0
  66. rapidtide/data/reference/HCP1200v2_csf_2mm.nii.gz +0 -0
  67. rapidtide/data/reference/HCP1200v2_gray_2mm.nii.gz +0 -0
  68. rapidtide/data/reference/HCP1200v2_graylaghist.json +7 -0
  69. rapidtide/data/reference/HCP1200v2_graylaghist.tsv.gz +0 -0
  70. rapidtide/data/reference/HCP1200v2_laghist.json +7 -0
  71. rapidtide/data/reference/HCP1200v2_laghist.tsv.gz +0 -0
  72. rapidtide/data/reference/HCP1200v2_mask_2mm.nii.gz +0 -0
  73. rapidtide/data/reference/HCP1200v2_maxcorr_2mm.nii.gz +0 -0
  74. rapidtide/data/reference/HCP1200v2_maxtime_2mm.nii.gz +0 -0
  75. rapidtide/data/reference/HCP1200v2_maxwidth_2mm.nii.gz +0 -0
  76. rapidtide/data/reference/HCP1200v2_negmask_2mm.nii.gz +0 -0
  77. rapidtide/data/reference/HCP1200v2_timepercentile_2mm.nii.gz +0 -0
  78. rapidtide/data/reference/HCP1200v2_white_2mm.nii.gz +0 -0
  79. rapidtide/data/reference/HCP1200v2_whitelaghist.json +7 -0
  80. rapidtide/data/reference/HCP1200v2_whitelaghist.tsv.gz +0 -0
  81. rapidtide/data/reference/JHU-ArterialTerritoriesNoVent-LVL1-seg2.xml +131 -0
  82. rapidtide/data/reference/JHU-ArterialTerritoriesNoVent-LVL1-seg2_regions.txt +60 -0
  83. rapidtide/data/reference/JHU-ArterialTerritoriesNoVent-LVL1-seg2_space-MNI152NLin6Asym_2mm.nii.gz +0 -0
  84. rapidtide/data/reference/JHU-ArterialTerritoriesNoVent-LVL1_space-MNI152NLin2009cAsym_2mm.nii.gz +0 -0
  85. rapidtide/data/reference/JHU-ArterialTerritoriesNoVent-LVL1_space-MNI152NLin2009cAsym_2mm_mask.nii.gz +0 -0
  86. rapidtide/data/reference/JHU-ArterialTerritoriesNoVent-LVL1_space-MNI152NLin6Asym_2mm_mask.nii.gz +0 -0
  87. rapidtide/data/reference/JHU-ArterialTerritoriesNoVent-LVL2_space-MNI152NLin6Asym_2mm_mask.nii.gz +0 -0
  88. rapidtide/data/reference/MNI152_T1_1mm_Brain_FAST_seg.nii.gz +0 -0
  89. rapidtide/data/reference/MNI152_T1_1mm_Brain_Mask.nii.gz +0 -0
  90. rapidtide/data/reference/MNI152_T1_2mm_Brain_FAST_seg.nii.gz +0 -0
  91. rapidtide/data/reference/MNI152_T1_2mm_Brain_Mask.nii.gz +0 -0
  92. rapidtide/decorators.py +91 -0
  93. rapidtide/dlfilter.py +2553 -414
  94. rapidtide/dlfiltertorch.py +5201 -0
  95. rapidtide/externaltools.py +328 -13
  96. rapidtide/fMRIData_class.py +178 -0
  97. rapidtide/ffttools.py +168 -0
  98. rapidtide/filter.py +2704 -1462
  99. rapidtide/fit.py +2361 -579
  100. rapidtide/genericmultiproc.py +197 -0
  101. rapidtide/happy_supportfuncs.py +3255 -548
  102. rapidtide/helper_classes.py +590 -1181
  103. rapidtide/io.py +2569 -468
  104. rapidtide/linfitfiltpass.py +784 -0
  105. rapidtide/makelaggedtcs.py +267 -97
  106. rapidtide/maskutil.py +555 -25
  107. rapidtide/miscmath.py +867 -137
  108. rapidtide/multiproc.py +217 -44
  109. rapidtide/patchmatch.py +752 -0
  110. rapidtide/peakeval.py +32 -32
  111. rapidtide/ppgproc.py +2205 -0
  112. rapidtide/qualitycheck.py +353 -40
  113. rapidtide/refinedelay.py +854 -0
  114. rapidtide/refineregressor.py +939 -0
  115. rapidtide/resample.py +725 -204
  116. rapidtide/scripts/__init__.py +1 -0
  117. rapidtide/scripts/{adjustoffset → adjustoffset.py} +7 -2
  118. rapidtide/scripts/{aligntcs → aligntcs.py} +7 -2
  119. rapidtide/scripts/{applydlfilter → applydlfilter.py} +7 -2
  120. rapidtide/scripts/applyppgproc.py +28 -0
  121. rapidtide/scripts/{atlasaverage → atlasaverage.py} +7 -2
  122. rapidtide/scripts/{atlastool → atlastool.py} +7 -2
  123. rapidtide/scripts/{calcicc → calcicc.py} +7 -2
  124. rapidtide/scripts/{calctexticc → calctexticc.py} +7 -2
  125. rapidtide/scripts/{calcttest → calcttest.py} +7 -2
  126. rapidtide/scripts/{ccorrica → ccorrica.py} +7 -2
  127. rapidtide/scripts/delayvar.py +28 -0
  128. rapidtide/scripts/{diffrois → diffrois.py} +7 -2
  129. rapidtide/scripts/{endtidalproc → endtidalproc.py} +7 -2
  130. rapidtide/scripts/{fdica → fdica.py} +7 -2
  131. rapidtide/scripts/{filtnifti → filtnifti.py} +7 -2
  132. rapidtide/scripts/{filttc → filttc.py} +7 -2
  133. rapidtide/scripts/{fingerprint → fingerprint.py} +20 -16
  134. rapidtide/scripts/{fixtr → fixtr.py} +7 -2
  135. rapidtide/scripts/{gmscalc → gmscalc.py} +7 -2
  136. rapidtide/scripts/{happy → happy.py} +7 -2
  137. rapidtide/scripts/{happy2std → happy2std.py} +7 -2
  138. rapidtide/scripts/{happywarp → happywarp.py} +8 -4
  139. rapidtide/scripts/{histnifti → histnifti.py} +7 -2
  140. rapidtide/scripts/{histtc → histtc.py} +7 -2
  141. rapidtide/scripts/{glmfilt → linfitfilt.py} +7 -4
  142. rapidtide/scripts/{localflow → localflow.py} +7 -2
  143. rapidtide/scripts/{mergequality → mergequality.py} +7 -2
  144. rapidtide/scripts/{pairproc → pairproc.py} +7 -2
  145. rapidtide/scripts/{pairwisemergenifti → pairwisemergenifti.py} +7 -2
  146. rapidtide/scripts/{physiofreq → physiofreq.py} +7 -2
  147. rapidtide/scripts/{pixelcomp → pixelcomp.py} +7 -2
  148. rapidtide/scripts/{plethquality → plethquality.py} +7 -2
  149. rapidtide/scripts/{polyfitim → polyfitim.py} +7 -2
  150. rapidtide/scripts/{proj2flow → proj2flow.py} +7 -2
  151. rapidtide/scripts/{rankimage → rankimage.py} +7 -2
  152. rapidtide/scripts/{rapidtide → rapidtide.py} +7 -2
  153. rapidtide/scripts/{rapidtide2std → rapidtide2std.py} +7 -2
  154. rapidtide/scripts/{resamplenifti → resamplenifti.py} +7 -2
  155. rapidtide/scripts/{resampletc → resampletc.py} +7 -2
  156. rapidtide/scripts/retrolagtcs.py +28 -0
  157. rapidtide/scripts/retroregress.py +28 -0
  158. rapidtide/scripts/{roisummarize → roisummarize.py} +7 -2
  159. rapidtide/scripts/{runqualitycheck → runqualitycheck.py} +7 -2
  160. rapidtide/scripts/{showarbcorr → showarbcorr.py} +7 -2
  161. rapidtide/scripts/{showhist → showhist.py} +7 -2
  162. rapidtide/scripts/{showstxcorr → showstxcorr.py} +7 -2
  163. rapidtide/scripts/{showtc → showtc.py} +7 -2
  164. rapidtide/scripts/{showxcorr_legacy → showxcorr_legacy.py} +8 -8
  165. rapidtide/scripts/{showxcorrx → showxcorrx.py} +7 -2
  166. rapidtide/scripts/{showxy → showxy.py} +7 -2
  167. rapidtide/scripts/{simdata → simdata.py} +7 -2
  168. rapidtide/scripts/{spatialdecomp → spatialdecomp.py} +7 -2
  169. rapidtide/scripts/{spatialfit → spatialfit.py} +7 -2
  170. rapidtide/scripts/{spatialmi → spatialmi.py} +7 -2
  171. rapidtide/scripts/{spectrogram → spectrogram.py} +7 -2
  172. rapidtide/scripts/stupidramtricks.py +238 -0
  173. rapidtide/scripts/{synthASL → synthASL.py} +7 -2
  174. rapidtide/scripts/{tcfrom2col → tcfrom2col.py} +7 -2
  175. rapidtide/scripts/{tcfrom3col → tcfrom3col.py} +7 -2
  176. rapidtide/scripts/{temporaldecomp → temporaldecomp.py} +7 -2
  177. rapidtide/scripts/{testhrv → testhrv.py} +1 -1
  178. rapidtide/scripts/{threeD → threeD.py} +7 -2
  179. rapidtide/scripts/{tidepool → tidepool.py} +7 -2
  180. rapidtide/scripts/{variabilityizer → variabilityizer.py} +7 -2
  181. rapidtide/simFuncClasses.py +2113 -0
  182. rapidtide/simfuncfit.py +312 -108
  183. rapidtide/stats.py +579 -247
  184. rapidtide/tests/.coveragerc +27 -6
  185. rapidtide-2.9.5.data/scripts/fdica → rapidtide/tests/cleanposttest +4 -6
  186. rapidtide/tests/happycomp +9 -0
  187. rapidtide/tests/resethappytargets +1 -1
  188. rapidtide/tests/resetrapidtidetargets +1 -1
  189. rapidtide/tests/resettargets +1 -1
  190. rapidtide/tests/runlocaltest +3 -3
  191. rapidtide/tests/showkernels +1 -1
  192. rapidtide/tests/test_aliasedcorrelate.py +4 -4
  193. rapidtide/tests/test_aligntcs.py +1 -1
  194. rapidtide/tests/test_calcicc.py +1 -1
  195. rapidtide/tests/test_cleanregressor.py +184 -0
  196. rapidtide/tests/test_congrid.py +70 -81
  197. rapidtide/tests/test_correlate.py +1 -1
  198. rapidtide/tests/test_corrpass.py +4 -4
  199. rapidtide/tests/test_delayestimation.py +54 -59
  200. rapidtide/tests/test_dlfiltertorch.py +437 -0
  201. rapidtide/tests/test_doresample.py +2 -2
  202. rapidtide/tests/test_externaltools.py +69 -0
  203. rapidtide/tests/test_fastresampler.py +9 -5
  204. rapidtide/tests/test_filter.py +96 -57
  205. rapidtide/tests/test_findmaxlag.py +50 -19
  206. rapidtide/tests/test_fullrunhappy_v1.py +15 -10
  207. rapidtide/tests/test_fullrunhappy_v2.py +19 -13
  208. rapidtide/tests/test_fullrunhappy_v3.py +28 -13
  209. rapidtide/tests/test_fullrunhappy_v4.py +30 -11
  210. rapidtide/tests/test_fullrunhappy_v5.py +62 -0
  211. rapidtide/tests/test_fullrunrapidtide_v1.py +61 -7
  212. rapidtide/tests/test_fullrunrapidtide_v2.py +27 -15
  213. rapidtide/tests/test_fullrunrapidtide_v3.py +28 -8
  214. rapidtide/tests/test_fullrunrapidtide_v4.py +16 -8
  215. rapidtide/tests/test_fullrunrapidtide_v5.py +15 -6
  216. rapidtide/tests/test_fullrunrapidtide_v6.py +142 -0
  217. rapidtide/tests/test_fullrunrapidtide_v7.py +114 -0
  218. rapidtide/tests/test_fullrunrapidtide_v8.py +66 -0
  219. rapidtide/tests/test_getparsers.py +158 -0
  220. rapidtide/tests/test_io.py +59 -18
  221. rapidtide/tests/{test_glmpass.py → test_linfitfiltpass.py} +10 -10
  222. rapidtide/tests/test_mi.py +1 -1
  223. rapidtide/tests/test_miscmath.py +1 -1
  224. rapidtide/tests/test_motionregress.py +5 -5
  225. rapidtide/tests/test_nullcorr.py +6 -9
  226. rapidtide/tests/test_padvec.py +216 -0
  227. rapidtide/tests/test_parserfuncs.py +101 -0
  228. rapidtide/tests/test_phaseanalysis.py +1 -1
  229. rapidtide/tests/test_rapidtideparser.py +59 -53
  230. rapidtide/tests/test_refinedelay.py +296 -0
  231. rapidtide/tests/test_runmisc.py +5 -5
  232. rapidtide/tests/test_sharedmem.py +60 -0
  233. rapidtide/tests/test_simroundtrip.py +132 -0
  234. rapidtide/tests/test_simulate.py +1 -1
  235. rapidtide/tests/test_stcorrelate.py +4 -2
  236. rapidtide/tests/test_timeshift.py +2 -2
  237. rapidtide/tests/test_valtoindex.py +1 -1
  238. rapidtide/tests/test_zRapidtideDataset.py +5 -3
  239. rapidtide/tests/utils.py +10 -9
  240. rapidtide/tidepoolTemplate.py +88 -70
  241. rapidtide/tidepoolTemplate.ui +60 -46
  242. rapidtide/tidepoolTemplate_alt.py +88 -53
  243. rapidtide/tidepoolTemplate_alt.ui +62 -52
  244. rapidtide/tidepoolTemplate_alt_qt6.py +921 -0
  245. rapidtide/tidepoolTemplate_big.py +1125 -0
  246. rapidtide/tidepoolTemplate_big.ui +2386 -0
  247. rapidtide/tidepoolTemplate_big_qt6.py +1129 -0
  248. rapidtide/tidepoolTemplate_qt6.py +793 -0
  249. rapidtide/util.py +1389 -148
  250. rapidtide/voxelData.py +1048 -0
  251. rapidtide/wiener.py +138 -25
  252. rapidtide/wiener2.py +114 -8
  253. rapidtide/workflows/adjustoffset.py +107 -5
  254. rapidtide/workflows/aligntcs.py +86 -3
  255. rapidtide/workflows/applydlfilter.py +231 -89
  256. rapidtide/workflows/applyppgproc.py +540 -0
  257. rapidtide/workflows/atlasaverage.py +309 -48
  258. rapidtide/workflows/atlastool.py +130 -9
  259. rapidtide/workflows/calcSimFuncMap.py +490 -0
  260. rapidtide/workflows/calctexticc.py +202 -10
  261. rapidtide/workflows/ccorrica.py +123 -15
  262. rapidtide/workflows/cleanregressor.py +415 -0
  263. rapidtide/workflows/delayvar.py +1268 -0
  264. rapidtide/workflows/diffrois.py +84 -6
  265. rapidtide/workflows/endtidalproc.py +149 -9
  266. rapidtide/workflows/fdica.py +197 -17
  267. rapidtide/workflows/filtnifti.py +71 -4
  268. rapidtide/workflows/filttc.py +76 -5
  269. rapidtide/workflows/fitSimFuncMap.py +578 -0
  270. rapidtide/workflows/fixtr.py +74 -4
  271. rapidtide/workflows/gmscalc.py +116 -6
  272. rapidtide/workflows/happy.py +1242 -480
  273. rapidtide/workflows/happy2std.py +145 -13
  274. rapidtide/workflows/happy_parser.py +277 -59
  275. rapidtide/workflows/histnifti.py +120 -4
  276. rapidtide/workflows/histtc.py +85 -4
  277. rapidtide/workflows/{glmfilt.py → linfitfilt.py} +128 -14
  278. rapidtide/workflows/localflow.py +329 -29
  279. rapidtide/workflows/mergequality.py +80 -4
  280. rapidtide/workflows/niftidecomp.py +323 -19
  281. rapidtide/workflows/niftistats.py +178 -8
  282. rapidtide/workflows/pairproc.py +99 -5
  283. rapidtide/workflows/pairwisemergenifti.py +86 -3
  284. rapidtide/workflows/parser_funcs.py +1488 -56
  285. rapidtide/workflows/physiofreq.py +139 -12
  286. rapidtide/workflows/pixelcomp.py +211 -9
  287. rapidtide/workflows/plethquality.py +105 -23
  288. rapidtide/workflows/polyfitim.py +159 -19
  289. rapidtide/workflows/proj2flow.py +76 -3
  290. rapidtide/workflows/rankimage.py +115 -8
  291. rapidtide/workflows/rapidtide.py +1833 -1919
  292. rapidtide/workflows/rapidtide2std.py +101 -3
  293. rapidtide/workflows/rapidtide_parser.py +607 -372
  294. rapidtide/workflows/refineDelayMap.py +249 -0
  295. rapidtide/workflows/refineRegressor.py +1215 -0
  296. rapidtide/workflows/regressfrommaps.py +308 -0
  297. rapidtide/workflows/resamplenifti.py +86 -4
  298. rapidtide/workflows/resampletc.py +92 -4
  299. rapidtide/workflows/retrolagtcs.py +442 -0
  300. rapidtide/workflows/retroregress.py +1501 -0
  301. rapidtide/workflows/roisummarize.py +176 -7
  302. rapidtide/workflows/runqualitycheck.py +72 -7
  303. rapidtide/workflows/showarbcorr.py +172 -16
  304. rapidtide/workflows/showhist.py +87 -3
  305. rapidtide/workflows/showstxcorr.py +161 -4
  306. rapidtide/workflows/showtc.py +172 -10
  307. rapidtide/workflows/showxcorrx.py +250 -62
  308. rapidtide/workflows/showxy.py +186 -16
  309. rapidtide/workflows/simdata.py +418 -112
  310. rapidtide/workflows/spatialfit.py +83 -8
  311. rapidtide/workflows/spatialmi.py +252 -29
  312. rapidtide/workflows/spectrogram.py +306 -33
  313. rapidtide/workflows/synthASL.py +157 -6
  314. rapidtide/workflows/tcfrom2col.py +77 -3
  315. rapidtide/workflows/tcfrom3col.py +75 -3
  316. rapidtide/workflows/tidepool.py +3829 -666
  317. rapidtide/workflows/utils.py +45 -19
  318. rapidtide/workflows/utils_doc.py +293 -0
  319. rapidtide/workflows/variabilityizer.py +118 -5
  320. {rapidtide-2.9.5.dist-info → rapidtide-3.1.3.dist-info}/METADATA +30 -223
  321. rapidtide-3.1.3.dist-info/RECORD +393 -0
  322. {rapidtide-2.9.5.dist-info → rapidtide-3.1.3.dist-info}/WHEEL +1 -1
  323. rapidtide-3.1.3.dist-info/entry_points.txt +65 -0
  324. rapidtide-3.1.3.dist-info/top_level.txt +2 -0
  325. rapidtide/calcandfitcorrpairs.py +0 -262
  326. rapidtide/data/examples/src/testoutputsize +0 -45
  327. rapidtide/data/models/model_revised/model.h5 +0 -0
  328. rapidtide/data/models/model_serdar/model.h5 +0 -0
  329. rapidtide/data/models/model_serdar2/model.h5 +0 -0
  330. rapidtide/data/reference/ASPECTS_nlin_asym_09c_2mm.nii.gz +0 -0
  331. rapidtide/data/reference/ASPECTS_nlin_asym_09c_2mm_mask.nii.gz +0 -0
  332. rapidtide/data/reference/ATTbasedFlowTerritories_split_nlin_asym_09c_2mm.nii.gz +0 -0
  333. rapidtide/data/reference/ATTbasedFlowTerritories_split_nlin_asym_09c_2mm_mask.nii.gz +0 -0
  334. rapidtide/data/reference/HCP1200_binmask_2mm_2009c_asym.nii.gz +0 -0
  335. rapidtide/data/reference/HCP1200_lag_2mm_2009c_asym.nii.gz +0 -0
  336. rapidtide/data/reference/HCP1200_mask_2mm_2009c_asym.nii.gz +0 -0
  337. rapidtide/data/reference/HCP1200_negmask_2mm_2009c_asym.nii.gz +0 -0
  338. rapidtide/data/reference/HCP1200_sigma_2mm_2009c_asym.nii.gz +0 -0
  339. rapidtide/data/reference/HCP1200_strength_2mm_2009c_asym.nii.gz +0 -0
  340. rapidtide/glmpass.py +0 -434
  341. rapidtide/refine_factored.py +0 -641
  342. rapidtide/scripts/retroglm +0 -23
  343. rapidtide/workflows/glmfrommaps.py +0 -202
  344. rapidtide/workflows/retroglm.py +0 -643
  345. rapidtide-2.9.5.data/scripts/adjustoffset +0 -23
  346. rapidtide-2.9.5.data/scripts/aligntcs +0 -23
  347. rapidtide-2.9.5.data/scripts/applydlfilter +0 -23
  348. rapidtide-2.9.5.data/scripts/atlasaverage +0 -23
  349. rapidtide-2.9.5.data/scripts/atlastool +0 -23
  350. rapidtide-2.9.5.data/scripts/calcicc +0 -22
  351. rapidtide-2.9.5.data/scripts/calctexticc +0 -23
  352. rapidtide-2.9.5.data/scripts/calcttest +0 -22
  353. rapidtide-2.9.5.data/scripts/ccorrica +0 -23
  354. rapidtide-2.9.5.data/scripts/diffrois +0 -23
  355. rapidtide-2.9.5.data/scripts/endtidalproc +0 -23
  356. rapidtide-2.9.5.data/scripts/filtnifti +0 -23
  357. rapidtide-2.9.5.data/scripts/filttc +0 -23
  358. rapidtide-2.9.5.data/scripts/fingerprint +0 -593
  359. rapidtide-2.9.5.data/scripts/fixtr +0 -23
  360. rapidtide-2.9.5.data/scripts/glmfilt +0 -24
  361. rapidtide-2.9.5.data/scripts/gmscalc +0 -22
  362. rapidtide-2.9.5.data/scripts/happy +0 -25
  363. rapidtide-2.9.5.data/scripts/happy2std +0 -23
  364. rapidtide-2.9.5.data/scripts/happywarp +0 -350
  365. rapidtide-2.9.5.data/scripts/histnifti +0 -23
  366. rapidtide-2.9.5.data/scripts/histtc +0 -23
  367. rapidtide-2.9.5.data/scripts/localflow +0 -23
  368. rapidtide-2.9.5.data/scripts/mergequality +0 -23
  369. rapidtide-2.9.5.data/scripts/pairproc +0 -23
  370. rapidtide-2.9.5.data/scripts/pairwisemergenifti +0 -23
  371. rapidtide-2.9.5.data/scripts/physiofreq +0 -23
  372. rapidtide-2.9.5.data/scripts/pixelcomp +0 -23
  373. rapidtide-2.9.5.data/scripts/plethquality +0 -23
  374. rapidtide-2.9.5.data/scripts/polyfitim +0 -23
  375. rapidtide-2.9.5.data/scripts/proj2flow +0 -23
  376. rapidtide-2.9.5.data/scripts/rankimage +0 -23
  377. rapidtide-2.9.5.data/scripts/rapidtide +0 -23
  378. rapidtide-2.9.5.data/scripts/rapidtide2std +0 -23
  379. rapidtide-2.9.5.data/scripts/resamplenifti +0 -23
  380. rapidtide-2.9.5.data/scripts/resampletc +0 -23
  381. rapidtide-2.9.5.data/scripts/retroglm +0 -23
  382. rapidtide-2.9.5.data/scripts/roisummarize +0 -23
  383. rapidtide-2.9.5.data/scripts/runqualitycheck +0 -23
  384. rapidtide-2.9.5.data/scripts/showarbcorr +0 -23
  385. rapidtide-2.9.5.data/scripts/showhist +0 -23
  386. rapidtide-2.9.5.data/scripts/showstxcorr +0 -23
  387. rapidtide-2.9.5.data/scripts/showtc +0 -23
  388. rapidtide-2.9.5.data/scripts/showxcorr_legacy +0 -536
  389. rapidtide-2.9.5.data/scripts/showxcorrx +0 -23
  390. rapidtide-2.9.5.data/scripts/showxy +0 -23
  391. rapidtide-2.9.5.data/scripts/simdata +0 -23
  392. rapidtide-2.9.5.data/scripts/spatialdecomp +0 -23
  393. rapidtide-2.9.5.data/scripts/spatialfit +0 -23
  394. rapidtide-2.9.5.data/scripts/spatialmi +0 -23
  395. rapidtide-2.9.5.data/scripts/spectrogram +0 -23
  396. rapidtide-2.9.5.data/scripts/synthASL +0 -23
  397. rapidtide-2.9.5.data/scripts/tcfrom2col +0 -23
  398. rapidtide-2.9.5.data/scripts/tcfrom3col +0 -23
  399. rapidtide-2.9.5.data/scripts/temporaldecomp +0 -23
  400. rapidtide-2.9.5.data/scripts/threeD +0 -236
  401. rapidtide-2.9.5.data/scripts/tidepool +0 -23
  402. rapidtide-2.9.5.data/scripts/variabilityizer +0 -23
  403. rapidtide-2.9.5.dist-info/RECORD +0 -357
  404. rapidtide-2.9.5.dist-info/top_level.txt +0 -86
  405. {rapidtide-2.9.5.dist-info → rapidtide-3.1.3.dist-info/licenses}/LICENSE +0 -0
@@ -1,7 +1,7 @@
1
1
  #!/usr/bin/env python
2
2
  # -*- coding: utf-8 -*-
3
3
  #
4
- # Copyright 2016-2024 Blaise Frederick
4
+ # Copyright 2016-2025 Blaise Frederick
5
5
  #
6
6
  # Licensed under the Apache License, Version 2.0 (the "License");
7
7
  # you may not use this file except in compliance with the License.
@@ -17,18 +17,13 @@
17
17
  #
18
18
  #
19
19
  import sys
20
- import warnings
20
+ from typing import Any
21
21
 
22
22
  import matplotlib.pyplot as plt
23
23
  import numpy as np
24
24
  import scipy as sp
25
- from numpy.polynomial import Polynomial
26
- from scipy.optimize import curve_fit
27
- from statsmodels.robust import mad
25
+ from numpy.typing import NDArray
28
26
 
29
- import rapidtide.correlate as tide_corr
30
- import rapidtide.filter as tide_filt
31
- import rapidtide.fit as tide_fit
32
27
  import rapidtide.miscmath as tide_math
33
28
  import rapidtide.util as tide_util
34
29
 
@@ -44,10 +39,48 @@ class fMRIDataset:
44
39
  slicesize = None
45
40
  numvox = None
46
41
  numskip = 0
42
+ validvoxels = None
43
+
44
+ def __init__(
45
+ self, thedata: NDArray, zerodata: bool = False, copydata: bool = False, numskip: int = 0
46
+ ) -> None:
47
+ """
48
+ Initialize the fMRIDataset with data and configuration parameters.
47
49
 
48
- def __init__(self, thedata, zerodata=False, copydata=False, numskip=0):
50
+ Parameters
51
+ ----------
52
+ thedata : NDArray
53
+ The input data array to be stored in the object.
54
+ zerodata : bool, optional
55
+ If True, initializes the data with zeros instead of copying the input data.
56
+ Default is False.
57
+ copydata : bool, optional
58
+ If True and zerodata is False, creates a copy of the input data.
59
+ If False and zerodata is False, uses the input data directly.
60
+ Default is False.
61
+ numskip : int, optional
62
+ Number of elements to skip during processing. Default is 0.
63
+
64
+ Returns
65
+ -------
66
+ None
67
+ This method does not return any value.
68
+
69
+ Notes
70
+ -----
71
+ The initialization process involves:
72
+ 1. Setting the data based on the zerodata and copydata parameters
73
+ 2. Calling getsizes() to determine data dimensions
74
+ 3. Calling setnumskip() to configure the skip parameter
75
+
76
+ Examples
77
+ --------
78
+ >>> obj = MyClass(data_array)
79
+ >>> obj = MyClass(data_array, zerodata=True)
80
+ >>> obj = MyClass(data_array, copydata=True, numskip=5)
81
+ """
49
82
  if zerodata:
50
- self.thedata = thedata * 0.0
83
+ self.thedata = np.zeros_like(thedata)
51
84
  else:
52
85
  if copydata:
53
86
  self.thedata = thedata + 0.0
@@ -56,7 +89,56 @@ class fMRIDataset:
56
89
  self.getsizes()
57
90
  self.setnumskip(numskip)
58
91
 
59
- def getsizes(self):
92
+ def getsizes(self) -> None:
93
+ """
94
+ Calculate and store various size parameters from data shape.
95
+
96
+ This method extracts dimensional information from the data shape and computes
97
+ derived quantities such as slice size and total number of voxels. It handles
98
+ both 3D and 4D data arrays by checking for the presence of a fourth dimension.
99
+
100
+ Parameters
101
+ ----------
102
+ self : object
103
+ The instance containing the data array in `thedata` attribute.
104
+ The `thedata` attribute should be a numpy array with shape (xsize, ysize, numslices, [realtimepoints])
105
+
106
+ Returns
107
+ -------
108
+ None
109
+ This method does not return any value but modifies the instance attributes.
110
+
111
+ Notes
112
+ -----
113
+ The method assumes `thedata` is a numpy array with at least 2 dimensions.
114
+ If the fourth dimension is not present, `realtimepoints` is set to 1.
115
+
116
+ Attributes Modified
117
+ -------------------
118
+ theshape : tuple
119
+ The shape of the data array
120
+ xsize : int
121
+ Size of the first dimension (x-axis)
122
+ ysize : int
123
+ Size of the second dimension (y-axis)
124
+ numslices : int
125
+ Number of slices (third dimension)
126
+ realtimepoints : int
127
+ Number of real-time points (fourth dimension, default 1)
128
+ slicesize : int
129
+ Product of xsize and ysize (number of pixels per slice)
130
+ numvox : int
131
+ Total number of voxels (slicesize * numslices)
132
+
133
+ Examples
134
+ --------
135
+ >>> # Assuming self.thedata has shape (64, 64, 30, 100)
136
+ >>> getsizes(self)
137
+ >>> print(self.xsize, self.ysize, self.numslices, self.realtimepoints)
138
+ 64 64 30 100
139
+ >>> print(self.slicesize, self.numvox)
140
+ 4096 122880
141
+ """
60
142
  self.theshape = self.thedata.shape
61
143
  self.xsize = self.theshape[0]
62
144
  self.ysize = self.theshape[1]
@@ -68,19 +150,157 @@ class fMRIDataset:
68
150
  self.slicesize = self.xsize * self.ysize
69
151
  self.numvox = self.slicesize * self.numslices
70
152
 
71
- def setnumskip(self, numskip):
153
+ def setnumskip(self, numskip: int) -> None:
154
+ """
155
+ Set the number of timepoints to skip and update the timepoints accordingly.
156
+
157
+ This method updates the internal `numskip` attribute and recalculates the
158
+ `timepoints` by subtracting the number of skipped points from the real timepoints.
159
+
160
+ Parameters
161
+ ----------
162
+ numskip : int
163
+ The number of timepoints to skip. This value is stored in the `numskip`
164
+ attribute and used to compute the effective timepoints.
165
+
166
+ Returns
167
+ -------
168
+ None
169
+ This method modifies the object's attributes in-place and does not return
170
+ any value.
171
+
172
+ Notes
173
+ -----
174
+ The `timepoints` attribute is automatically updated to reflect the difference
175
+ between `realtimepoints` and `numskip`. This is typically used in time-series
176
+ analysis where certain initial timepoints are excluded from calculations.
177
+
178
+ Examples
179
+ --------
180
+ >>> obj.setnumskip(5)
181
+ >>> print(obj.numskip)
182
+ 5
183
+ >>> print(obj.timepoints)
184
+ # Will show the difference between realtimepoints and 5
185
+ """
72
186
  self.numskip = numskip
73
187
  self.timepoints = self.realtimepoints - self.numskip
74
188
 
75
- def byslice(self):
189
+ def setvalid(self, validvoxels: NDArray) -> None:
190
+ """
191
+ Set the valid voxels for the object.
192
+
193
+ Parameters
194
+ ----------
195
+ validvoxels : NDArray
196
+ Array containing the valid voxel indices or flags indicating
197
+ which voxels are considered valid in the dataset.
198
+
199
+ Returns
200
+ -------
201
+ None
202
+ This method does not return any value.
203
+
204
+ Notes
205
+ -----
206
+ This method assigns the provided array to the internal `validvoxels` attribute
207
+ of the object, which is typically used to filter or validate voxel data
208
+ during processing operations.
209
+
210
+ Examples
211
+ --------
212
+ >>> obj = MyClass()
213
+ >>> valid_voxels = np.array([1, 2, 3, 5, 8])
214
+ >>> obj.setvalid(valid_voxels)
215
+ >>> print(obj.validvoxels)
216
+ [1 2 3 5 8]
217
+ """
218
+ self.validvoxels = validvoxels
219
+
220
+ def byslice(self) -> NDArray:
221
+ """
222
+ Return data sliced along the time dimension with specified skip.
223
+
224
+ This method extracts data from the internal `thedata` array, skipping
225
+ the first `numskip` time points and reshaping the result into a
226
+ standardized 3D array format.
227
+
228
+ Returns
229
+ -------
230
+ NDArray
231
+ 3D array with shape (slicesize, numslices, timepoints) containing
232
+ the sliced data with skipped time points removed.
233
+
234
+ Notes
235
+ -----
236
+ The returned array is reshaped from the original data structure to
237
+ facilitate further processing and analysis. The slicing operation
238
+ removes the first `numskip` time points from the original data.
239
+
240
+ Examples
241
+ --------
242
+ >>> result = obj.byslice()
243
+ >>> print(result.shape)
244
+ (100, 50, 200)
245
+ """
76
246
  return self.thedata[:, :, :, self.numskip :].reshape(
77
247
  (self.slicesize, self.numslices, self.timepoints)
78
248
  )
79
249
 
80
- def byvol(self):
250
+ def byvol(self) -> NDArray:
251
+ """
252
+ Reshape data to volume-time format.
253
+
254
+ This method extracts a subset of data along the fourth dimension and reshapes
255
+ it into a 2D array where rows represent voxels and columns represent timepoints.
256
+
257
+ Returns
258
+ -------
259
+ NDArray
260
+ 2D array of shape (numvox, timepoints) containing the reshaped data.
261
+ Each row corresponds to a voxel and each column to a timepoint.
262
+
263
+ Notes
264
+ -----
265
+ The method slices the data array starting from index `numskip` along the
266
+ fourth dimension and reshapes the remaining data into a 2D structure.
267
+
268
+ Examples
269
+ --------
270
+ >>> result = obj.byvol()
271
+ >>> print(result.shape)
272
+ (numvox, timepoints)
273
+ """
81
274
  return self.thedata[:, :, :, self.numskip :].reshape((self.numvox, self.timepoints))
82
275
 
83
- def byvox(self):
276
+ def byvox(self) -> NDArray:
277
+ """
278
+ Return voxel data with skip dimension sliced.
279
+
280
+ This method extracts a subset of the fourth dimension from the internal
281
+ data array, starting from the index specified by `numskip` to the end.
282
+
283
+ Returns
284
+ -------
285
+ NDArray
286
+ A numpy array containing the voxel data with the fourth dimension
287
+ sliced from `numskip` index to the end. The shape will be
288
+ (self.thedata.shape[0], self.thedata.shape[1], self.thedata.shape[2],
289
+ self.thedata.shape[3] - self.numskip)
290
+
291
+ Notes
292
+ -----
293
+ The function assumes that `self.thedata` is a 4-dimensional numpy array
294
+ and `self.numskip` is a non-negative integer less than the size of the
295
+ fourth dimension.
296
+
297
+ Examples
298
+ --------
299
+ >>> # Assuming self.thedata has shape (10, 10, 10, 20) and self.numskip = 5
300
+ >>> result = self.byvox()
301
+ >>> result.shape
302
+ (10, 10, 10, 15)
303
+ """
84
304
  return self.thedata[:, :, :, self.numskip :]
85
305
 
86
306
 
@@ -98,17 +318,58 @@ class ProbeRegressor:
98
318
 
99
319
  def __init__(
100
320
  self,
101
- inputvec,
102
- inputfreq,
103
- targetperiod,
104
- targetpoints,
105
- targetstartpoint,
106
- targetoversample=1,
107
- inputstart=0.0,
108
- inputoffset=0.0,
109
- targetstart=0.0,
110
- targetoffset=0.0,
111
- ):
321
+ inputvec: NDArray,
322
+ inputfreq: float,
323
+ targetperiod: float,
324
+ targetpoints: int,
325
+ targetstartpoint: int,
326
+ targetoversample: int = 1,
327
+ inputstart: float = 0.0,
328
+ inputoffset: float = 0.0,
329
+ targetstart: float = 0.0,
330
+ targetoffset: float = 0.0,
331
+ ) -> None:
332
+ """
333
+ Initialize the object with input and target parameters.
334
+
335
+ Parameters
336
+ ----------
337
+ inputvec : NDArray
338
+ Input vector data array
339
+ inputfreq : float
340
+ Input frequency in Hz
341
+ targetperiod : float
342
+ Target period in seconds
343
+ targetpoints : int
344
+ Number of target points
345
+ targetstartpoint : int
346
+ Starting point index for target
347
+ targetoversample : int, optional
348
+ Oversampling factor for target (default is 1)
349
+ inputstart : float, optional
350
+ Starting time for input (default is 0.0)
351
+ inputoffset : float, optional
352
+ Input offset value (default is 0.0)
353
+ targetstart : float, optional
354
+ Starting time for target (default is 0.0)
355
+ targetoffset : float, optional
356
+ Target offset value (default is 0.0)
357
+
358
+ Returns
359
+ -------
360
+ None
361
+ This method initializes the object attributes and does not return any value.
362
+
363
+ Notes
364
+ -----
365
+ This constructor sets up the input vector with specified frequency and start time,
366
+ and initializes target parameters for subsequent processing.
367
+
368
+ Examples
369
+ --------
370
+ >>> obj = MyClass(inputvec=np.array([1, 2, 3]), inputfreq=100.0,
371
+ ... targetperiod=0.1, targetpoints=100, targetstartpoint=0)
372
+ """
112
373
  self.inputoffset = inputoffset
113
374
  self.setinputvec(inputvec, inputfreq, inputstart=inputstart)
114
375
  self.targetperiod = targetperiod
@@ -117,17 +378,111 @@ class ProbeRegressor:
117
378
  self.targetpoints = targetpoints
118
379
  self.targetstartpoint = targetstartpoint
119
380
 
120
- def setinputvec(self, inputvec, inputfreq, inputstart=0.0):
381
+ def setinputvec(self, inputvec: NDArray, inputfreq: float, inputstart: float = 0.0) -> None:
382
+ """
383
+ Set the input vector and associated parameters for the object.
384
+
385
+ Parameters
386
+ ----------
387
+ inputvec : NDArray
388
+ The input vector to be set. This is typically a numpy array containing
389
+ the input signal or data values.
390
+ inputfreq : float
391
+ The input frequency value. This represents the sampling frequency or
392
+ frequency parameter associated with the input vector.
393
+ inputstart : float, optional
394
+ The starting time or phase value for the input. Default is 0.0.
395
+
396
+ Returns
397
+ -------
398
+ None
399
+ This method does not return any value.
400
+
401
+ Notes
402
+ -----
403
+ This method assigns the provided input vector and its associated parameters
404
+ to instance variables. The input vector is stored as ``self.inputvec``,
405
+ the frequency as ``self.inputfreq``, and the start value as ``self.inputstart``.
406
+
407
+ Examples
408
+ --------
409
+ >>> import numpy as np
410
+ >>> obj = MyClass()
411
+ >>> input_data = np.array([1, 2, 3, 4, 5])
412
+ >>> obj.setinputvec(input_data, inputfreq=10.0, inputstart=0.5)
413
+ >>> print(obj.inputvec)
414
+ [1 2 3 4 5]
415
+ >>> print(obj.inputfreq)
416
+ 10.0
417
+ >>> print(obj.inputstart)
418
+ 0.5
419
+ """
121
420
  self.inputvec = inputvec
122
421
  self.inputfreq = inputfreq
123
422
  self.inputstart = inputstart
124
423
 
125
- def makeinputtimeaxis(self):
424
+ def makeinputtimeaxis(self) -> None:
425
+ """
426
+ Create input time axis based on input vector properties.
427
+
428
+ This method generates a time axis for input data by linearly spacing
429
+ from 0 to the length of the input vector, normalized by the input frequency,
430
+ and adjusted by the input start time and offset.
431
+
432
+ Parameters
433
+ ----------
434
+ None
435
+
436
+ Returns
437
+ -------
438
+ None
439
+ This method modifies the instance in-place by setting the `inputtimeaxis` attribute.
440
+
441
+ Notes
442
+ -----
443
+ The time axis is calculated as:
444
+ ``inputtimeaxis = np.linspace(0.0, len(inputvec)) / inputfreq - (inputstarttime + inputoffset)``
445
+
446
+ Examples
447
+ --------
448
+ >>> obj.makeinputtimeaxis()
449
+ >>> print(obj.inputtimeaxis)
450
+ [ 0. 0.001 0.002 ... 0.998 0.999 ]
451
+ """
126
452
  self.inputtimeaxis = np.linspace(0.0, len(self.inputvec)) / self.inputfreq - (
127
453
  self.inputstarttime + self.inputoffset
128
454
  )
129
455
 
130
- def maketargettimeaxis(self):
456
+ def maketargettimeaxis(self) -> None:
457
+ """
458
+ Create a target time axis for signal processing.
459
+
460
+ This method generates a linearly spaced time axis based on the target period,
461
+ start point, and number of points specified in the object's attributes.
462
+
463
+ Parameters
464
+ ----------
465
+ None
466
+
467
+ Returns
468
+ -------
469
+ None
470
+ This method modifies the object's `targettimeaxis` attribute in-place.
471
+
472
+ Notes
473
+ -----
474
+ The time axis is generated using `numpy.linspace` with the following parameters:
475
+ - Start point: `targetperiod * targetstartpoint`
476
+ - End point: `targetperiod * targetstartpoint + targetperiod * targetpoints`
477
+ - Number of points: `targetpoints`
478
+ - Endpoint: True
479
+
480
+ Examples
481
+ --------
482
+ >>> obj.maketargettimeaxis()
483
+ >>> print(obj.targettimeaxis)
484
+ [0. 0.1 0.2 0.3 0.4]
485
+ """
131
486
  self.targettimeaxis = np.linspace(
132
487
  self.targetperiod * self.targetstartpoint,
133
488
  self.targetperiod * self.targetstartpoint + self.targetperiod * self.targetpoints,
@@ -136,322 +491,6 @@ class ProbeRegressor:
136
491
  )
137
492
 
138
493
 
139
- class SimilarityFunctionator:
140
- reftc = None
141
- prepreftc = None
142
- testtc = None
143
- preptesttc = None
144
- timeaxis = None
145
- similarityfunclen = 0
146
- datavalid = False
147
- timeaxisvalid = False
148
- similarityfuncorigin = 0
149
-
150
- def __init__(
151
- self,
152
- Fs=0.0,
153
- similarityfuncorigin=0,
154
- lagmininpts=0,
155
- lagmaxinpts=0,
156
- ncprefilter=None,
157
- negativegradient=False,
158
- reftc=None,
159
- reftcstart=0.0,
160
- detrendorder=1,
161
- debug=False,
162
- ):
163
- self.Fs = Fs
164
- self.similarityfuncorigin = similarityfuncorigin
165
- self.lagmininpts = lagmininpts
166
- self.lagmaxinpts = lagmaxinpts
167
- self.ncprefilter = ncprefilter
168
- self.negativegradient = negativegradient
169
- self.reftc = reftc
170
- self.detrendorder = detrendorder
171
- self.debug = debug
172
- if self.reftc is not None:
173
- self.setreftc(self.reftc)
174
- self.reftcstart = reftcstart
175
-
176
- def preptc(self, thetc, isreftc=False):
177
- # prepare timecourse by filtering, normalizing, detrending, and applying a window function
178
- if isreftc or (not self.negativegradient):
179
- thenormtc = tide_math.corrnormalize(
180
- self.ncprefilter.apply(self.Fs, thetc),
181
- detrendorder=self.detrendorder,
182
- windowfunc=self.windowfunc,
183
- )
184
- else:
185
- thenormtc = tide_math.corrnormalize(
186
- -np.gradient(self.ncprefilter.apply(self.Fs, thetc)),
187
- detrendorder=self.detrendorder,
188
- windowfunc=self.windowfunc,
189
- )
190
- return thenormtc
191
-
192
- def trim(self, vector):
193
- return vector[
194
- self.similarityfuncorigin
195
- - self.lagmininpts : self.similarityfuncorigin
196
- + self.lagmaxinpts
197
- ]
198
-
199
- def getfunction(self, trim=True):
200
- if self.datavalid:
201
- if trim:
202
- return (
203
- self.trim(self.thesimfunc),
204
- self.trim(self.timeaxis),
205
- self.theglobalmax,
206
- )
207
- else:
208
- return self.thesimfunc, self.timeaxis, self.theglobalmax
209
- else:
210
- if self.timeaxisvalid:
211
- if trim:
212
- return None, self.trim(self.timeaxis), None
213
- else:
214
- return None, self.timeaxis, None
215
- else:
216
- print("must calculate similarity function before fetching data")
217
- return None, None, None
218
-
219
-
220
- class MutualInformationator(SimilarityFunctionator):
221
- def __init__(
222
- self,
223
- windowfunc="hamming",
224
- norm=True,
225
- madnorm=False,
226
- smoothingtime=-1.0,
227
- bins=20,
228
- sigma=0.25,
229
- *args,
230
- **kwargs,
231
- ):
232
- self.windowfunc = windowfunc
233
- self.norm = norm
234
- self.madnorm = madnorm
235
- self.bins = bins
236
- self.sigma = sigma
237
- self.smoothingtime = smoothingtime
238
- self.smoothingfilter = tide_filt.NoncausalFilter(filtertype="arb")
239
- self.mi_norm = 1.0
240
- if self.smoothingtime > 0.0:
241
- self.smoothingfilter.setfreqs(
242
- 0.0, 0.0, 1.0 / self.smoothingtime, 1.0 / self.smoothingtime
243
- )
244
- super(MutualInformationator, self).__init__(*args, **kwargs)
245
-
246
- def setlimits(self, lagmininpts, lagmaxinpts):
247
- self.lagmininpts = lagmininpts
248
- self.lagmaxinpts = lagmaxinpts
249
- origpadtime = self.smoothingfilter.getpadtime()
250
- timespan = self.timeaxis[-1] - self.timeaxis[0]
251
- newpadtime = np.min([origpadtime, timespan])
252
- if newpadtime < origpadtime:
253
- print("lowering smoothing filter pad time to", newpadtime)
254
- self.smoothingfilter.setpadtime(newpadtime)
255
-
256
- def setbins(self, bins):
257
- self.bins = bins
258
-
259
- def setreftc(self, reftc, offset=0.0):
260
- self.reftc = reftc + 0.0
261
- self.prepreftc = self.preptc(self.reftc, isreftc=True)
262
-
263
- self.timeaxis, self.automi, self.similarityfuncorigin = tide_corr.cross_mutual_info(
264
- self.prepreftc,
265
- self.prepreftc,
266
- Fs=self.Fs,
267
- fast=True,
268
- negsteps=self.lagmininpts,
269
- possteps=self.lagmaxinpts,
270
- returnaxis=True,
271
- )
272
-
273
- self.timeaxis -= offset
274
- self.similarityfunclen = len(self.timeaxis)
275
- self.timeaxisvalid = True
276
- self.datavalid = False
277
- self.mi_norm = np.nan_to_num(1.0 / np.max(self.automi))
278
- if self.debug:
279
- print(f"MutualInformationator setreftc: {len(self.timeaxis)=}")
280
- print(f"MutualInformationator setreftc: {self.timeaxis}")
281
- print(f"MutualInformationator setreftc: {self.mi_norm=}")
282
-
283
- def getnormfac(self):
284
- return self.mi_norm
285
-
286
- def run(self, thetc, locs=None, trim=True, gettimeaxis=True):
287
- if len(thetc) != len(self.reftc):
288
- print(
289
- "timecourses are of different sizes:",
290
- len(thetc),
291
- "!=",
292
- len(self.reftc),
293
- "- exiting",
294
- )
295
- sys.exit()
296
-
297
- self.testtc = thetc
298
- self.preptesttc = self.preptc(self.testtc)
299
-
300
- if locs is not None:
301
- gettimeaxis = True
302
-
303
- # now calculate the similarity function
304
- if trim:
305
- retvals = tide_corr.cross_mutual_info(
306
- self.preptesttc,
307
- self.prepreftc,
308
- norm=self.norm,
309
- negsteps=self.lagmininpts,
310
- possteps=self.lagmaxinpts,
311
- locs=locs,
312
- madnorm=self.madnorm,
313
- returnaxis=gettimeaxis,
314
- fast=True,
315
- Fs=self.Fs,
316
- sigma=self.sigma,
317
- bins=self.bins,
318
- )
319
- else:
320
- retvals = tide_corr.cross_mutual_info(
321
- self.preptesttc,
322
- self.prepreftc,
323
- norm=self.norm,
324
- negsteps=-1,
325
- possteps=-1,
326
- locs=locs,
327
- madnorm=self.madnorm,
328
- returnaxis=gettimeaxis,
329
- fast=True,
330
- Fs=self.Fs,
331
- sigma=self.sigma,
332
- bins=self.bins,
333
- )
334
- if gettimeaxis:
335
- self.timeaxis, self.thesimfunc, self.similarityfuncorigin = (
336
- retvals[0],
337
- retvals[1],
338
- retvals[2],
339
- )
340
- self.timeaxisvalid = True
341
- else:
342
- self.thesimfunc = retvals[0]
343
-
344
- # normalize
345
- self.thesimfunc *= self.mi_norm
346
-
347
- if locs is not None:
348
- return self.thesimfunc
349
-
350
- if self.smoothingtime > 0.0:
351
- self.thesimfunc = self.smoothingfilter.apply(self.Fs, self.thesimfunc)
352
-
353
- self.similarityfunclen = len(self.thesimfunc)
354
- if trim:
355
- self.similarityfuncorigin = self.lagmininpts + 1
356
- else:
357
- self.similarityfuncorigin = self.similarityfunclen // 2 + 1
358
-
359
- # find the global maximum value
360
- self.theglobalmax = np.argmax(self.thesimfunc)
361
- self.datavalid = True
362
-
363
- # make a dummy filtered baseline
364
- self.filteredbaseline = self.thesimfunc * 0.0
365
-
366
- if trim:
367
- return (
368
- self.trim(self.thesimfunc),
369
- self.trim(self.timeaxis),
370
- self.theglobalmax,
371
- )
372
- else:
373
- return self.thesimfunc, self.timeaxis, self.theglobalmax
374
-
375
-
376
- class Correlator(SimilarityFunctionator):
377
- def __init__(
378
- self,
379
- windowfunc="hamming",
380
- corrweighting="None",
381
- corrpadding=0,
382
- baselinefilter=None,
383
- *args,
384
- **kwargs,
385
- ):
386
- self.windowfunc = windowfunc
387
- self.corrweighting = corrweighting
388
- self.corrpadding = corrpadding
389
- self.baselinefilter = baselinefilter
390
- super(Correlator, self).__init__(*args, **kwargs)
391
-
392
- def setlimits(self, lagmininpts, lagmaxinpts):
393
- self.lagmininpts = lagmininpts
394
- self.lagmaxinpts = lagmaxinpts
395
-
396
- def setreftc(self, reftc, offset=0.0):
397
- self.reftc = reftc + 0.0
398
- self.prepreftc = self.preptc(self.reftc, isreftc=True)
399
- self.similarityfunclen = len(self.reftc) * 2 - 1
400
- self.similarityfuncorigin = self.similarityfunclen // 2 + 1
401
-
402
- # make the reference time axis
403
- self.timeaxis = (
404
- np.arange(0.0, self.similarityfunclen) * (1.0 / self.Fs)
405
- - ((self.similarityfunclen - 1) * (1.0 / self.Fs)) / 2.0
406
- ) - offset
407
- self.timeaxisvalid = True
408
- self.datavalid = False
409
-
410
- def run(self, thetc, trim=True):
411
- if len(thetc) != len(self.reftc):
412
- print(
413
- "timecourses are of different sizes:",
414
- len(thetc),
415
- "!=",
416
- len(self.reftc),
417
- "- exiting",
418
- )
419
- sys.exit()
420
-
421
- self.testtc = thetc
422
- self.preptesttc = self.preptc(self.testtc)
423
-
424
- # now actually do the correlation
425
- self.thesimfunc = tide_corr.fastcorrelate(
426
- self.preptesttc,
427
- self.prepreftc,
428
- usefft=True,
429
- weighting=self.corrweighting,
430
- zeropadding=self.corrpadding,
431
- debug=self.debug,
432
- )
433
- self.similarityfunclen = len(self.thesimfunc)
434
- self.similarityfuncorigin = self.similarityfunclen // 2 + 1
435
-
436
- if self.baselinefilter is not None:
437
- self.filteredbaseline = self.baselinefilter.apply(self.Fs, self.thesimfunc)
438
- else:
439
- self.filteredbaseline = self.thesimfunc * 0.0
440
-
441
- # find the global maximum value
442
- self.theglobalmax = np.argmax(self.thesimfunc)
443
- self.datavalid = True
444
-
445
- if trim:
446
- return (
447
- self.trim(self.thesimfunc),
448
- self.trim(self.timeaxis),
449
- self.theglobalmax,
450
- )
451
- else:
452
- return self.thesimfunc, self.timeaxis, self.theglobalmax
453
-
454
-
455
494
  class Coherer:
456
495
  reftc = None
457
496
  prepreftc = None
@@ -467,15 +506,58 @@ class Coherer:
467
506
 
468
507
  def __init__(
469
508
  self,
470
- Fs=0.0,
471
- freqmin=None,
472
- freqmax=None,
473
- ncprefilter=None,
474
- reftc=None,
475
- detrendorder=1,
476
- windowfunc="hamming",
477
- debug=False,
478
- ):
509
+ Fs: float = 0.0,
510
+ freqmin: float | None = None,
511
+ freqmax: float | None = None,
512
+ ncprefilter: Any | None = None,
513
+ reftc: NDArray | None = None,
514
+ detrendorder: int = 1,
515
+ windowfunc: str = "hamming",
516
+ debug: bool = False,
517
+ ) -> None:
518
+ """
519
+ Initialize the Coherer object with configuration parameters.
520
+
521
+ Parameters
522
+ ----------
523
+ Fs : float, default=0.0
524
+ Sampling frequency in Hz.
525
+ freqmin : float, optional
526
+ Minimum frequency for filtering. If None, no minimum frequency filtering is applied.
527
+ freqmax : float, optional
528
+ Maximum frequency for filtering. If None, no maximum frequency filtering is applied.
529
+ ncprefilter : Any, optional
530
+ Pre-filtering configuration for non-coherent filtering.
531
+ reftc : NDArray, optional
532
+ Reference time course for coherence calculations.
533
+ detrendorder : int, default=1
534
+ Order of detrending to apply to the data. 0 for no detrending, 1 for linear detrending.
535
+ windowfunc : str, default="hamming"
536
+ Window function to apply during spectral analysis. Options include 'hamming', 'hanning', 'blackman', etc.
537
+ debug : bool, default=False
538
+ If True, print initialization debug information.
539
+
540
+ Returns
541
+ -------
542
+ None
543
+ This method initializes the object's attributes and performs setup operations.
544
+
545
+ Notes
546
+ -----
547
+ The initialization process sets up all internal parameters and performs optional
548
+ debug printing if requested. The freqmin and freqmax parameters are only stored
549
+ if they are not None. The reftc parameter, if provided, triggers the setreftc method.
550
+
551
+ Examples
552
+ --------
553
+ >>> coherer = Coherer(Fs=100.0, freqmin=1.0, freqmax=50.0, debug=True)
554
+ Coherer init:
555
+ Fs: 100.0
556
+ windowfunc: hamming
557
+ detrendorder: 1
558
+ freqmin: 1.0
559
+ freqmax: 50.0
560
+ """
479
561
  self.Fs = Fs
480
562
  self.ncprefilter = ncprefilter
481
563
  self.reftc = reftc
@@ -496,7 +578,37 @@ class Coherer:
496
578
  print("\tfreqmin:", self.freqmin)
497
579
  print("\tfreqmax:", self.freqmax)
498
580
 
499
- def preptc(self, thetc):
581
+ def preptc(self, thetc: NDArray) -> NDArray:
582
+ """
583
+ Prepare timecourse by filtering, normalizing, detrending, and applying a window function.
584
+
585
+ This function applies a series of preprocessing steps to a timecourse signal including
586
+ noise filtering, normalization, and detrending to prepare it for further analysis.
587
+
588
+ Parameters
589
+ ----------
590
+ thetc : ndarray
591
+ Input timecourse data to be prepared, typically a 1D array of signal values.
592
+
593
+ Returns
594
+ -------
595
+ ndarray
596
+ Preprocessed timecourse data after filtering, normalization, and detrending.
597
+
598
+ Notes
599
+ -----
600
+ The preprocessing pipeline includes:
601
+ 1. Noise filtering using the class's ncprefilter
602
+ 2. Correlation-based normalization
603
+ 3. Detrending with specified order
604
+
605
+ Examples
606
+ --------
607
+ >>> # Assuming 'obj' is an instance of the class containing this method
608
+ >>> processed_tc = obj.preptc(timecourse_data)
609
+ >>> print(processed_tc.shape)
610
+ (n_timepoints,)
611
+ """
500
612
  # prepare timecourse by filtering, normalizing, detrending, and applying a window function
501
613
  return tide_math.corrnormalize(
502
614
  self.ncprefilter.apply(self.Fs, thetc),
@@ -504,7 +616,37 @@ class Coherer:
504
616
  windowfunc="None",
505
617
  )
506
618
 
507
- def setlimits(self, freqmin, freqmax):
619
+ def setlimits(self, freqmin: float, freqmax: float) -> None:
620
+ """
621
+ Set frequency limits for the object and calculate corresponding indices.
622
+
623
+ This method sets the minimum and maximum frequency values and calculates the
624
+ corresponding indices in the frequency axis if the frequency axis is valid.
625
+
626
+ Parameters
627
+ ----------
628
+ freqmin : float
629
+ The minimum frequency value to set.
630
+ freqmax : float
631
+ The maximum frequency value to set.
632
+
633
+ Returns
634
+ -------
635
+ None
636
+ This method modifies the object's attributes in-place and does not return a value.
637
+
638
+ Notes
639
+ -----
640
+ If `self.freqaxisvalid` is True, the method calculates `freqmininpts` and `freqmaxinpts`
641
+ which represent the indices corresponding to the frequency limits in `self.freqaxis`.
642
+ The calculation ensures that indices stay within valid bounds (0 to len(freqaxis)-1).
643
+
644
+ Examples
645
+ --------
646
+ >>> obj.setlimits(0.1, 1.0)
647
+ >>> print(obj.freqmin, obj.freqmax)
648
+ 0.1 1.0
649
+ """
508
650
  self.freqmin = freqmin
509
651
  self.freqmax = freqmax
510
652
  if self.freqaxisvalid:
@@ -520,7 +662,32 @@ class Coherer:
520
662
  print("\tfreqmin,freqmax:", self.freqmin, self.freqmax)
521
663
  print("\tfreqmininpts,freqmaxinpts:", self.freqmininpts, self.freqmaxinpts)
522
664
 
523
- def getaxisinfo(self):
665
+ def getaxisinfo(self) -> tuple[float, float, float, int]:
666
+ """
667
+ Get frequency axis information for the object.
668
+
669
+ Returns
670
+ -------
671
+ tuple[float, float, float, int]
672
+ A tuple containing:
673
+ - Minimum frequency value (float)
674
+ - Maximum frequency value (float)
675
+ - Frequency step size (float)
676
+ - Number of frequency points (int)
677
+
678
+ Notes
679
+ -----
680
+ This method extracts key frequency axis parameters from the object's frequency array.
681
+ The frequency axis is assumed to be linearly spaced, and the returned values represent
682
+ the range and spacing of the frequency data.
683
+
684
+ Examples
685
+ --------
686
+ >>> info = obj.getaxisinfo()
687
+ >>> print(f"Frequency range: {info[0]} to {info[1]} Hz")
688
+ >>> print(f"Frequency step: {info[2]} Hz")
689
+ >>> print(f"Number of points: {info[3]}")
690
+ """
524
691
  return (
525
692
  self.freqaxis[self.freqmininpts],
526
693
  self.freqaxis[self.freqmaxinpts],
@@ -528,7 +695,43 @@ class Coherer:
528
695
  self.freqmaxinpts - self.freqmininpts,
529
696
  )
530
697
 
531
- def setreftc(self, reftc):
698
+ def setreftc(self, reftc: NDArray) -> None:
699
+ """
700
+ Set reference time series and compute coherence statistics.
701
+
702
+ This method assigns the reference time series, processes it through the preprocessing
703
+ pipeline, and computes coherence statistics between the reference signal and itself.
704
+ The method also sets up frequency axis parameters and validates the data.
705
+
706
+ Parameters
707
+ ----------
708
+ reftc : NDArray
709
+ Reference time series data to be processed. The array will be copied and converted
710
+ to float type to ensure proper numerical operations.
711
+
712
+ Returns
713
+ -------
714
+ None
715
+ This method modifies the instance attributes in-place and does not return any value.
716
+
717
+ Notes
718
+ -----
719
+ The method performs the following operations:
720
+ 1. Assigns the input array to `self.reftc` with explicit float conversion
721
+ 2. Preprocesses the reference time series using `self.preptc()` method
722
+ 3. Computes coherence between the preprocessed reference signal and itself
723
+ 4. Sets up frequency axis and coherence data attributes
724
+ 5. Validates frequency limits and converts them to array indices
725
+ 6. Updates data validity flags
726
+
727
+ Examples
728
+ --------
729
+ >>> # Assuming 'obj' is an instance of the class containing this method
730
+ >>> reference_data = np.array([1.0, 2.0, 3.0, 4.0])
731
+ >>> obj.setreftc(reference_data)
732
+ >>> print(obj.freqaxis)
733
+ >>> print(obj.thecoherence)
734
+ """
532
735
  self.reftc = reftc + 0.0
533
736
  self.prepreftc = self.preptc(self.reftc)
534
737
 
@@ -550,13 +753,39 @@ class Coherer:
550
753
  self.freqaxis, self.freqmax, discretization="ceiling", debug=self.debug
551
754
  )
552
755
 
553
- def trim(self, vector):
756
+ def trim(self, vector: NDArray) -> NDArray:
554
757
  return vector[self.freqmininpts : self.freqmaxinpts]
555
758
 
556
- def run(self, thetc, trim=True, alt=False):
759
+ def run(
760
+ self, thetc: NDArray, trim: bool = True, alt: bool = False
761
+ ) -> tuple[NDArray, NDArray, int] | tuple[NDArray, NDArray, int, NDArray, NDArray, NDArray]:
762
+ """
763
+ Trim vector to specified frequency range indices.
764
+
765
+ Parameters
766
+ ----------
767
+ vector : NDArray
768
+ Input vector to be trimmed.
769
+
770
+ Returns
771
+ -------
772
+ NDArray
773
+ Trimmed vector containing elements from `self.freqmininpts` to `self.freqmaxinpts`.
774
+
775
+ Notes
776
+ -----
777
+ This function uses array slicing to extract a portion of the input vector based on
778
+ the frequency range boundaries defined by `self.freqmininpts` and `self.freqmaxinpts`.
779
+
780
+ Examples
781
+ --------
782
+ >>> trimmed_data = obj.trim(data_vector)
783
+ >>> print(trimmed_data.shape)
784
+ (freqmaxinpts - freqmininpts,)
785
+ """
557
786
  if len(thetc) != len(self.reftc):
558
787
  print(
559
- "timecourses are of different sizes:",
788
+ "Coherer: timecourses are of different sizes:",
560
789
  len(thetc),
561
790
  "!=",
562
791
  len(self.reftc),
@@ -640,823 +869,3 @@ class Coherer:
640
869
  else:
641
870
  self.themax = np.argmax(self.thecoherence)
642
871
  return self.thecoherence, self.freqaxis, self.themax
643
-
644
-
645
- class SimilarityFunctionFitter:
646
- corrtimeaxis = None
647
- FML_NOERROR = np.uint32(0x0000)
648
-
649
- FML_INITAMPLOW = np.uint32(0x0001)
650
- FML_INITAMPHIGH = np.uint32(0x0002)
651
- FML_INITWIDTHLOW = np.uint32(0x0004)
652
- FML_INITWIDTHHIGH = np.uint32(0x0008)
653
- FML_INITLAGLOW = np.uint32(0x0010)
654
- FML_INITLAGHIGH = np.uint32(0x0020)
655
- FML_INITFAIL = (
656
- FML_INITAMPLOW
657
- | FML_INITAMPHIGH
658
- | FML_INITWIDTHLOW
659
- | FML_INITWIDTHHIGH
660
- | FML_INITLAGLOW
661
- | FML_INITLAGHIGH
662
- )
663
-
664
- FML_FITAMPLOW = np.uint32(0x0100)
665
- FML_FITAMPHIGH = np.uint32(0x0200)
666
- FML_FITWIDTHLOW = np.uint32(0x0400)
667
- FML_FITWIDTHHIGH = np.uint32(0x0800)
668
- FML_FITLAGLOW = np.uint32(0x1000)
669
- FML_FITLAGHIGH = np.uint32(0x2000)
670
- FML_FITFAIL = (
671
- FML_FITAMPLOW
672
- | FML_FITAMPHIGH
673
- | FML_FITWIDTHLOW
674
- | FML_FITWIDTHHIGH
675
- | FML_FITLAGLOW
676
- | FML_FITLAGHIGH
677
- )
678
-
679
- def __init__(
680
- self,
681
- corrtimeaxis=None,
682
- lagmin=-30.0,
683
- lagmax=30.0,
684
- absmaxsigma=1000.0,
685
- absminsigma=0.25,
686
- hardlimit=True,
687
- bipolar=False,
688
- lthreshval=0.0,
689
- uthreshval=1.0,
690
- debug=False,
691
- zerooutbadfit=True,
692
- maxguess=0.0,
693
- useguess=False,
694
- searchfrac=0.5,
695
- lagmod=1000.0,
696
- enforcethresh=True,
697
- allowhighfitamps=False,
698
- displayplots=False,
699
- functype="correlation",
700
- peakfittype="gauss",
701
- ):
702
- r"""
703
-
704
- Parameters
705
- ----------
706
- corrtimeaxis: 1D float array
707
- The time axis of the correlation function
708
- lagmin: float
709
- The minimum allowed lag time in seconds
710
- lagmax: float
711
- The maximum allowed lag time in seconds
712
- absmaxsigma: float
713
- The maximum allowed peak halfwidth in seconds
714
- hardlimit
715
- bipolar: boolean
716
- If true find the correlation peak with the maximum absolute value, regardless of sign
717
- threshval
718
- uthreshval
719
- debug
720
- zerooutbadfit
721
- maxguess
722
- useguess
723
- searchfrac
724
- lagmod
725
- enforcethresh
726
- displayplots
727
-
728
- Returns
729
- -------
730
-
731
-
732
- Methods
733
- -------
734
- fit(corrfunc):
735
- Fit the correlation function given in corrfunc and return the location of the peak in seconds, the maximum
736
- correlation value, the peak width
737
- setrange(lagmin, lagmax):
738
- Specify the search range for lag peaks, in seconds
739
- """
740
- self.setcorrtimeaxis(corrtimeaxis)
741
- self.lagmin = lagmin
742
- self.lagmax = lagmax
743
- self.absmaxsigma = absmaxsigma
744
- self.absminsigma = absminsigma
745
- self.hardlimit = hardlimit
746
- self.bipolar = bipolar
747
- self.lthreshval = lthreshval
748
- self.uthreshval = uthreshval
749
- self.debug = debug
750
- if functype == "correlation" or functype == "mutualinfo":
751
- self.functype = functype
752
- else:
753
- print("illegal functype")
754
- sys.exit()
755
- self.peakfittype = peakfittype
756
- self.zerooutbadfit = zerooutbadfit
757
- self.maxguess = maxguess
758
- self.useguess = useguess
759
- self.searchfrac = searchfrac
760
- self.lagmod = lagmod
761
- self.enforcethresh = enforcethresh
762
- self.allowhighfitamps = allowhighfitamps
763
- self.displayplots = displayplots
764
-
765
- def _maxindex_noedge(self, corrfunc):
766
- """
767
-
768
- Parameters
769
- ----------
770
- corrfunc
771
-
772
- Returns
773
- -------
774
-
775
- """
776
- lowerlim = 0
777
- upperlim = len(self.corrtimeaxis) - 1
778
- done = False
779
- while not done:
780
- flipfac = 1.0
781
- done = True
782
- maxindex = (np.argmax(corrfunc[lowerlim:upperlim]) + lowerlim).astype("int32")
783
- if self.bipolar:
784
- minindex = (np.argmax(-corrfunc[lowerlim:upperlim]) + lowerlim).astype("int32")
785
- if np.fabs(corrfunc[minindex]) > np.fabs(corrfunc[maxindex]):
786
- maxindex = minindex
787
- flipfac = -1.0
788
- if upperlim == lowerlim:
789
- done = True
790
- if maxindex == 0:
791
- lowerlim += 1
792
- done = False
793
- if maxindex == upperlim:
794
- upperlim -= 1
795
- done = False
796
- return maxindex, flipfac
797
-
798
- def setfunctype(self, functype):
799
- self.functype = functype
800
-
801
- def setpeakfittype(self, peakfittype):
802
- self.peakfittype = peakfittype
803
-
804
- def setrange(self, lagmin, lagmax):
805
- self.lagmin = lagmin
806
- self.lagmax = lagmax
807
-
808
- def setcorrtimeaxis(self, corrtimeaxis):
809
- if corrtimeaxis is not None:
810
- self.corrtimeaxis = corrtimeaxis + 0.0
811
- else:
812
- self.corrtimeaxis = corrtimeaxis
813
-
814
- def setguess(self, useguess, maxguess=0.0):
815
- self.useguess = useguess
816
- self.maxguess = maxguess
817
-
818
- def setlthresh(self, lthreshval):
819
- self.lthreshval = lthreshval
820
-
821
- def setuthresh(self, uthreshval):
822
- self.uthreshval = uthreshval
823
-
824
- def diagnosefail(self, failreason):
825
- # define error values
826
- reasons = []
827
- if failreason.astype(np.uint32) & self.FML_INITAMPLOW:
828
- reasons.append("Initial amplitude too low")
829
- if failreason.astype(np.uint32) & self.FML_INITAMPHIGH:
830
- reasons.append("Initial amplitude too high")
831
- if failreason.astype(np.uint32) & self.FML_INITWIDTHLOW:
832
- reasons.append("Initial width too low")
833
- if failreason.astype(np.uint32) & self.FML_INITWIDTHHIGH:
834
- reasons.append("Initial width too high")
835
- if failreason.astype(np.uint32) & self.FML_INITLAGLOW:
836
- reasons.append("Initial Lag too low")
837
- if failreason.astype(np.uint32) & self.FML_INITLAGHIGH:
838
- reasons.append("Initial Lag too high")
839
-
840
- if failreason.astype(np.uint32) & self.FML_FITAMPLOW:
841
- reasons.append("Fit amplitude too low")
842
- if failreason.astype(np.uint32) & self.FML_FITAMPHIGH:
843
- reasons.append("Fit amplitude too high")
844
- if failreason.astype(np.uint32) & self.FML_FITWIDTHLOW:
845
- reasons.append("Fit width too low")
846
- if failreason.astype(np.uint32) & self.FML_FITWIDTHHIGH:
847
- reasons.append("Fit width too high")
848
- if failreason.astype(np.uint32) & self.FML_FITLAGLOW:
849
- reasons.append("Fit Lag too low")
850
- if failreason.astype(np.uint32) & self.FML_FITLAGHIGH:
851
- reasons.append("Fit Lag too high")
852
-
853
- if len(reasons) > 0:
854
- return ", ".join(reasons)
855
- else:
856
- return "No error"
857
-
858
- def fit(self, incorrfunc):
859
- # check to make sure xcorr_x and xcorr_y match
860
- if self.corrtimeaxis is None:
861
- print("Correlation time axis is not defined - exiting")
862
- sys.exit()
863
- if len(self.corrtimeaxis) != len(incorrfunc):
864
- print(
865
- "Correlation time axis and values do not match in length (",
866
- len(self.corrtimeaxis),
867
- "!=",
868
- len(incorrfunc),
869
- "- exiting",
870
- )
871
- sys.exit()
872
- # set initial parameters
873
- # absmaxsigma is in seconds
874
- # maxsigma is in Hz
875
- # maxlag is in seconds
876
- warnings.filterwarnings("ignore", "Number*")
877
- failreason = self.FML_NOERROR
878
- maskval = np.uint16(1) # start out assuming the fit will succeed
879
- binwidth = self.corrtimeaxis[1] - self.corrtimeaxis[0]
880
-
881
- # set the search range
882
- lowerlim = 0
883
- upperlim = len(self.corrtimeaxis) - 1
884
- if self.debug:
885
- print(
886
- "initial search indices are",
887
- lowerlim,
888
- "to",
889
- upperlim,
890
- "(",
891
- self.corrtimeaxis[lowerlim],
892
- self.corrtimeaxis[upperlim],
893
- ")",
894
- )
895
-
896
- # make an initial guess at the fit parameters for the gaussian
897
- # start with finding the maximum value and its location
898
- flipfac = 1.0
899
- corrfunc = incorrfunc + 0.0
900
- if self.useguess:
901
- maxindex = tide_util.valtoindex(self.corrtimeaxis, self.maxguess)
902
- if (corrfunc[maxindex] < 0.0) and self.bipolar:
903
- flipfac = -1.0
904
- else:
905
- maxindex, flipfac = self._maxindex_noedge(corrfunc)
906
- corrfunc *= flipfac
907
- maxlag_init = (1.0 * self.corrtimeaxis[maxindex]).astype("float64")
908
- maxval_init = corrfunc[maxindex].astype("float64")
909
- if self.debug:
910
- print(
911
- "maxindex, maxlag_init, maxval_init:",
912
- maxindex,
913
- maxlag_init,
914
- maxval_init,
915
- )
916
-
917
- # set the baseline and baselinedev levels
918
- if (self.functype == "correlation") or (self.functype == "hybrid"):
919
- baseline = 0.0
920
- baselinedev = 0.0
921
- else:
922
- # for mutual information, there is a nonzero baseline, so we want the difference from that.
923
- baseline = np.median(corrfunc)
924
- baselinedev = mad(corrfunc)
925
- if self.debug:
926
- print("baseline, baselinedev:", baseline, baselinedev)
927
-
928
- # then calculate the width of the peak
929
- if self.peakfittype == "fastquad" or self.peakfittype == "COM":
930
- peakstart = np.max([1, maxindex - 2])
931
- peakend = np.min([len(self.corrtimeaxis) - 2, maxindex + 2])
932
- else:
933
- # come here for peakfittype of None, quad, gauss, fastgauss
934
- thegrad = np.gradient(corrfunc).astype(
935
- "float64"
936
- ) # the gradient of the correlation function
937
- if (self.functype == "correlation") or (self.functype == "hybrid"):
938
- if self.peakfittype == "quad":
939
- peakpoints = np.where(
940
- corrfunc > maxval_init - 0.05, 1, 0
941
- ) # mask for places where correlation exceeds searchfrac*maxval_init
942
- else:
943
- peakpoints = np.where(
944
- corrfunc > (baseline + self.searchfrac * (maxval_init - baseline)), 1, 0
945
- ) # mask for places where correlation exceeds searchfrac*maxval_init
946
- else:
947
- # for mutual information, there is a flattish, nonzero baseline, so we want the difference from that.
948
- peakpoints = np.where(
949
- corrfunc > (baseline + self.searchfrac * (maxval_init - baseline)),
950
- 1,
951
- 0,
952
- )
953
-
954
- peakpoints[0] = 0
955
- peakpoints[-1] = 0
956
- peakstart = np.max([1, maxindex - 1])
957
- peakend = np.min([len(self.corrtimeaxis) - 2, maxindex + 1])
958
- if self.debug:
959
- print("initial peakstart, peakend:", peakstart, peakend)
960
- if self.functype == "mutualinfo":
961
- while peakpoints[peakend + 1] == 1:
962
- peakend += 1
963
- while peakpoints[peakstart - 1] == 1:
964
- peakstart -= 1
965
- else:
966
- while thegrad[peakend + 1] <= 0.0 and peakpoints[peakend + 1] == 1:
967
- peakend += 1
968
- while thegrad[peakstart - 1] >= 0.0 and peakpoints[peakstart - 1] == 1:
969
- peakstart -= 1
970
- if self.debug:
971
- print("final peakstart, peakend:", peakstart, peakend)
972
-
973
- # deal with flat peak top
974
- while (
975
- peakend < (len(self.corrtimeaxis) - 3)
976
- and corrfunc[peakend] == corrfunc[peakend - 1]
977
- ):
978
- peakend += 1
979
- while peakstart > 2 and corrfunc[peakstart] == corrfunc[peakstart + 1]:
980
- peakstart -= 1
981
- if self.debug:
982
- print("peakstart, peakend after flattop correction:", peakstart, peakend)
983
- print("\n")
984
- for i in range(peakstart, peakend + 1):
985
- print(self.corrtimeaxis[i], corrfunc[i])
986
- print("\n")
987
- fig = plt.figure()
988
- ax = fig.add_subplot(111)
989
- ax.set_title("Peak sent to fitting routine")
990
- plt.plot(
991
- self.corrtimeaxis[peakstart : peakend + 1],
992
- corrfunc[peakstart : peakend + 1],
993
- "r",
994
- )
995
- plt.show()
996
-
997
- # This is calculated from first principles, but it's always big by a factor or ~1.4.
998
- # Which makes me think I dropped a factor if sqrt(2). So fix that with a final division
999
- maxsigma_init = np.float64(
1000
- ((peakend - peakstart + 1) * binwidth / (2.0 * np.sqrt(-np.log(self.searchfrac))))
1001
- / np.sqrt(2.0)
1002
- )
1003
- if self.debug:
1004
- print("maxsigma_init:", maxsigma_init)
1005
-
1006
- # now check the values for errors
1007
- if self.hardlimit:
1008
- rangeextension = 0.0
1009
- else:
1010
- rangeextension = (self.lagmax - self.lagmin) * 0.75
1011
- if not (
1012
- (self.lagmin - rangeextension - binwidth)
1013
- <= maxlag_init
1014
- <= (self.lagmax + rangeextension + binwidth)
1015
- ):
1016
- if maxlag_init <= (self.lagmin - rangeextension - binwidth):
1017
- failreason |= self.FML_INITLAGLOW
1018
- maxlag_init = self.lagmin - rangeextension - binwidth
1019
- else:
1020
- failreason |= self.FML_INITLAGHIGH
1021
- maxlag_init = self.lagmax + rangeextension + binwidth
1022
- if self.debug:
1023
- print("bad initial")
1024
- if maxsigma_init > self.absmaxsigma:
1025
- failreason |= self.FML_INITWIDTHHIGH
1026
- maxsigma_init = self.absmaxsigma
1027
- if self.debug:
1028
- print("bad initial width - too high")
1029
- if peakend - peakstart < 2:
1030
- failreason |= self.FML_INITWIDTHLOW
1031
- maxsigma_init = np.float64(
1032
- ((2 + 1) * binwidth / (2.0 * np.sqrt(-np.log(self.searchfrac)))) / np.sqrt(2.0)
1033
- )
1034
- if self.debug:
1035
- print("bad initial width - too low")
1036
- if (self.functype == "correlation") or (self.functype == "hybrid"):
1037
- if not (self.lthreshval <= maxval_init <= self.uthreshval) and self.enforcethresh:
1038
- failreason |= self.FML_INITAMPLOW
1039
- if self.debug:
1040
- print(
1041
- "bad initial amp:",
1042
- maxval_init,
1043
- "is less than",
1044
- self.lthreshval,
1045
- )
1046
- if maxval_init < 0.0:
1047
- failreason |= self.FML_INITAMPLOW
1048
- maxval_init = 0.0
1049
- if self.debug:
1050
- print("bad initial amp:", maxval_init, "is less than 0.0")
1051
- if maxval_init > 1.0:
1052
- failreason |= self.FML_INITAMPHIGH
1053
- maxval_init = 1.0
1054
- if self.debug:
1055
- print("bad initial amp:", maxval_init, "is greater than 1.0")
1056
- else:
1057
- # somewhat different rules for mutual information peaks
1058
- if ((maxval_init - baseline) < self.lthreshval * baselinedev) or (
1059
- maxval_init < baseline
1060
- ):
1061
- failreason |= self.FML_INITAMPLOW
1062
- maxval_init = 0.0
1063
- if self.debug:
1064
- print("bad initial amp:", maxval_init, "is less than 0.0")
1065
- if (failreason != self.FML_NOERROR) and self.zerooutbadfit:
1066
- maxval = np.float64(0.0)
1067
- maxlag = np.float64(0.0)
1068
- maxsigma = np.float64(0.0)
1069
- else:
1070
- maxval = np.float64(maxval_init)
1071
- maxlag = np.float64(maxlag_init)
1072
- maxsigma = np.float64(maxsigma_init)
1073
-
1074
- # refine if necessary
1075
- if self.peakfittype != "None":
1076
- if self.peakfittype == "COM":
1077
- X = self.corrtimeaxis[peakstart : peakend + 1] - baseline
1078
- data = corrfunc[peakstart : peakend + 1]
1079
- maxval = maxval_init
1080
- maxlag = np.sum(X * data) / np.sum(data)
1081
- maxsigma = 10.0
1082
- elif self.peakfittype == "gauss":
1083
- X = self.corrtimeaxis[peakstart : peakend + 1] - baseline
1084
- data = corrfunc[peakstart : peakend + 1]
1085
- # do a least squares fit over the top of the peak
1086
- # p0 = np.array([maxval_init, np.fmod(maxlag_init, lagmod), maxsigma_init], dtype='float64')
1087
- p0 = np.array([maxval_init, maxlag_init, maxsigma_init], dtype="float64")
1088
- if self.debug:
1089
- print("fit input array:", p0)
1090
- try:
1091
- plsq, dummy = sp.optimize.leastsq(
1092
- tide_fit.gaussresiduals, p0, args=(data, X), maxfev=5000
1093
- )
1094
- maxval = plsq[0] + baseline
1095
- maxlag = np.fmod((1.0 * plsq[1]), self.lagmod)
1096
- maxsigma = plsq[2]
1097
- except:
1098
- maxval = np.float64(0.0)
1099
- maxlag = np.float64(0.0)
1100
- maxsigma = np.float64(0.0)
1101
- if self.debug:
1102
- print("fit output array:", [maxval, maxlag, maxsigma])
1103
- elif self.peakfittype == "gausscf":
1104
- X = self.corrtimeaxis[peakstart : peakend + 1] - baseline
1105
- data = corrfunc[peakstart : peakend + 1]
1106
- # do a least squares fit over the top of the peak
1107
- try:
1108
- plsq, pcov = curve_fit(
1109
- tide_fit.gaussfunc,
1110
- X,
1111
- data,
1112
- p0=[maxval_init, maxlag_init, maxsigma_init],
1113
- )
1114
- maxval = plsq[0] + baseline
1115
- maxlag = np.fmod((1.0 * plsq[1]), self.lagmod)
1116
- maxsigma = plsq[2]
1117
- except:
1118
- maxval = np.float64(0.0)
1119
- maxlag = np.float64(0.0)
1120
- maxsigma = np.float64(0.0)
1121
- if self.debug:
1122
- print("fit output array:", [maxval, maxlag, maxsigma])
1123
- elif self.peakfittype == "fastgauss":
1124
- X = self.corrtimeaxis[peakstart : peakend + 1] - baseline
1125
- data = corrfunc[peakstart : peakend + 1]
1126
- # do a non-iterative fit over the top of the peak
1127
- # 6/12/2015 This is just broken. Gives quantized maxima
1128
- maxlag = np.float64(1.0 * np.sum(X * data) / np.sum(data))
1129
- maxsigma = np.float64(
1130
- np.sqrt(np.abs(np.sum((X - maxlag) ** 2 * data) / np.sum(data)))
1131
- )
1132
- maxval = np.float64(data.max()) + baseline
1133
- elif self.peakfittype == "fastquad":
1134
- maxlag, maxval, maxsigma, ismax, badfit = tide_fit.refinepeak_quad(
1135
- self.corrtimeaxis, corrfunc, maxindex
1136
- )
1137
- elif self.peakfittype == "quad":
1138
- X = self.corrtimeaxis[peakstart : peakend + 1]
1139
- data = corrfunc[peakstart : peakend + 1]
1140
- try:
1141
- thecoffs = Polynomial.fit(X, data, 2).convert().coef[::-1]
1142
- a = thecoffs[0]
1143
- b = thecoffs[1]
1144
- c = thecoffs[2]
1145
- maxlag = -b / (2.0 * a)
1146
- maxval = a * maxlag * maxlag + b * maxlag + c
1147
- maxsigma = 1.0 / np.fabs(a)
1148
- if self.debug:
1149
- print("poly coffs:", a, b, c)
1150
- print("maxlag, maxval, maxsigma:", maxlag, maxval, maxsigma)
1151
- except np.lib.polynomial.RankWarning:
1152
- maxlag = 0.0
1153
- maxval = 0.0
1154
- maxsigma = 0.0
1155
- if self.debug:
1156
- print("\n")
1157
- for i in range(len(X)):
1158
- print(X[i], data[i])
1159
- print("\n")
1160
- fig = plt.figure()
1161
- ax = fig.add_subplot(111)
1162
- ax.set_title("Peak and fit")
1163
- plt.plot(X, data, "r")
1164
- plt.plot(X, c + b * X + a * X * X, "b")
1165
- plt.show()
1166
-
1167
- else:
1168
- print("illegal peak refinement type")
1169
-
1170
- # check for errors in fit
1171
- fitfail = False
1172
- if self.bipolar:
1173
- lowestcorrcoeff = -1.0
1174
- else:
1175
- lowestcorrcoeff = 0.0
1176
- if (self.functype == "correlation") or (self.functype == "hybrid"):
1177
- if maxval < lowestcorrcoeff:
1178
- failreason |= self.FML_FITAMPLOW
1179
- maxval = lowestcorrcoeff
1180
- if self.debug:
1181
- print("bad fit amp: maxval is lower than lower limit")
1182
- fitfail = True
1183
- if np.abs(maxval) > 1.0:
1184
- if not self.allowhighfitamps:
1185
- failreason |= self.FML_FITAMPHIGH
1186
- if self.debug:
1187
- print(
1188
- "bad fit amp: magnitude of",
1189
- maxval,
1190
- "is greater than 1.0",
1191
- )
1192
- fitfail = True
1193
- maxval = 1.0 * np.sign(maxval)
1194
- else:
1195
- # different rules for mutual information peaks
1196
- if ((maxval - baseline) < self.lthreshval * baselinedev) or (maxval < baseline):
1197
- failreason |= self.FML_FITAMPLOW
1198
- if self.debug:
1199
- if (maxval - baseline) < self.lthreshval * baselinedev:
1200
- print(
1201
- "FITAMPLOW: maxval - baseline:",
1202
- maxval - baseline,
1203
- " < lthreshval * baselinedev:",
1204
- self.lthreshval * baselinedev,
1205
- )
1206
- if maxval < baseline:
1207
- print("FITAMPLOW: maxval < baseline:", maxval, baseline)
1208
- maxval_init = 0.0
1209
- if self.debug:
1210
- print("bad fit amp: maxval is lower than lower limit")
1211
- if (self.lagmin > maxlag) or (maxlag > self.lagmax):
1212
- if self.debug:
1213
- print("bad lag after refinement")
1214
- if self.lagmin > maxlag:
1215
- failreason |= self.FML_FITLAGLOW
1216
- maxlag = self.lagmin
1217
- else:
1218
- failreason |= self.FML_FITLAGHIGH
1219
- maxlag = self.lagmax
1220
- fitfail = True
1221
- if maxsigma > self.absmaxsigma:
1222
- failreason |= self.FML_FITWIDTHHIGH
1223
- if self.debug:
1224
- print("bad width after refinement:", maxsigma, ">", self.absmaxsigma)
1225
- maxsigma = self.absmaxsigma
1226
- fitfail = True
1227
- if maxsigma < self.absminsigma:
1228
- failreason |= self.FML_FITWIDTHLOW
1229
- if self.debug:
1230
- print("bad width after refinement:", maxsigma, "<", self.absminsigma)
1231
- maxsigma = self.absminsigma
1232
- fitfail = True
1233
- if fitfail:
1234
- if self.debug:
1235
- print("fit fail")
1236
- if self.zerooutbadfit:
1237
- maxval = np.float64(0.0)
1238
- maxlag = np.float64(0.0)
1239
- maxsigma = np.float64(0.0)
1240
- maskval = np.uint16(0)
1241
- # print(maxlag_init, maxlag, maxval_init, maxval, maxsigma_init, maxsigma, maskval, failreason, fitfail)
1242
- else:
1243
- maxval = np.float64(maxval_init)
1244
- maxlag = np.float64(np.fmod(maxlag_init, self.lagmod))
1245
- maxsigma = np.float64(maxsigma_init)
1246
- if failreason != self.FML_NOERROR:
1247
- maskval = np.uint16(0)
1248
-
1249
- if self.debug or self.displayplots:
1250
- print(
1251
- "init to final: maxval",
1252
- maxval_init,
1253
- maxval,
1254
- ", maxlag:",
1255
- maxlag_init,
1256
- maxlag,
1257
- ", width:",
1258
- maxsigma_init,
1259
- maxsigma,
1260
- )
1261
- if self.displayplots and (self.peakfittype != "None") and (maskval != 0.0):
1262
- fig = plt.figure()
1263
- ax = fig.add_subplot(111)
1264
- ax.set_title("Data and fit")
1265
- hiresx = np.arange(X[0], X[-1], (X[1] - X[0]) / 10.0)
1266
- plt.plot(
1267
- X,
1268
- data,
1269
- "ro",
1270
- hiresx,
1271
- tide_fit.gauss_eval(hiresx, np.array([maxval, maxlag, maxsigma])),
1272
- "b-",
1273
- )
1274
- plt.show()
1275
- return (
1276
- maxindex,
1277
- maxlag,
1278
- flipfac * maxval,
1279
- maxsigma,
1280
- maskval,
1281
- failreason,
1282
- peakstart,
1283
- peakend,
1284
- )
1285
-
1286
-
1287
- class FrequencyTracker:
1288
- freqs = None
1289
- times = None
1290
-
1291
- def __init__(self, lowerlim=0.1, upperlim=0.6, nperseg=32, Q=10.0, debug=False):
1292
- self.lowerlim = lowerlim
1293
- self.upperlim = upperlim
1294
- self.nperseg = nperseg
1295
- self.Q = Q
1296
- self.debug = debug
1297
- self.nfft = self.nperseg
1298
-
1299
- def track(self, x, fs):
1300
- self.freqs, self.times, thespectrogram = sp.signal.spectrogram(
1301
- np.concatenate(
1302
- [np.zeros(int(self.nperseg // 2)), x, np.zeros(int(self.nperseg // 2))],
1303
- axis=0,
1304
- ),
1305
- fs=fs,
1306
- detrend="constant",
1307
- scaling="spectrum",
1308
- nfft=None,
1309
- window=np.hamming(self.nfft),
1310
- noverlap=(self.nperseg - 1),
1311
- )
1312
- lowerliminpts = tide_util.valtoindex(self.freqs, self.lowerlim)
1313
- upperliminpts = tide_util.valtoindex(self.freqs, self.upperlim)
1314
-
1315
- if self.debug:
1316
- print(self.times.shape, self.freqs.shape, thespectrogram.shape)
1317
- print(self.times)
1318
-
1319
- # intitialize the peak fitter
1320
- thefitter = SimilarityFunctionFitter(
1321
- corrtimeaxis=self.freqs,
1322
- lagmin=self.lowerlim,
1323
- lagmax=self.upperlim,
1324
- absmaxsigma=10.0,
1325
- absminsigma=0.1,
1326
- debug=self.debug,
1327
- peakfittype="fastquad",
1328
- zerooutbadfit=False,
1329
- useguess=False,
1330
- )
1331
-
1332
- peakfreqs = np.zeros((thespectrogram.shape[1] - 1), dtype=float)
1333
- for i in range(0, thespectrogram.shape[1] - 1):
1334
- (
1335
- maxindex,
1336
- peakfreqs[i],
1337
- maxval,
1338
- maxsigma,
1339
- maskval,
1340
- failreason,
1341
- peakstart,
1342
- peakend,
1343
- ) = thefitter.fit(thespectrogram[:, i])
1344
- if not (lowerliminpts <= maxindex <= upperliminpts):
1345
- peakfreqs[i] = -1.0
1346
-
1347
- return self.times[:-1], peakfreqs
1348
-
1349
- def clean(self, x, fs, times, peakfreqs, numharmonics=2):
1350
- nyquistfreq = 0.5 * fs
1351
- y = x * 0.0
1352
- halfwidth = int(self.nperseg // 2)
1353
- padx = np.concatenate([np.zeros(halfwidth), x, np.zeros(halfwidth)], axis=0)
1354
- pady = np.concatenate([np.zeros(halfwidth), y, np.zeros(halfwidth)], axis=0)
1355
- padweight = padx * 0.0
1356
- if self.debug:
1357
- print(fs, len(times), len(peakfreqs))
1358
- for i in range(0, len(times)):
1359
- centerindex = int(times[i] * fs)
1360
- xstart = centerindex - halfwidth
1361
- xend = centerindex + halfwidth
1362
- if peakfreqs[i] > 0.0:
1363
- filtsignal = padx[xstart:xend]
1364
- numharmonics = np.min([numharmonics, int((nyquistfreq // peakfreqs[i]) - 1)])
1365
- if self.debug:
1366
- print("numharmonics:", numharmonics, nyquistfreq // peakfreqs[i])
1367
- for j in range(numharmonics + 1):
1368
- workingfreq = (j + 1) * peakfreqs[i]
1369
- if self.debug:
1370
- print("workingfreq:", workingfreq)
1371
- ws = [workingfreq * 0.95, workingfreq * 1.05]
1372
- wp = [workingfreq * 0.9, workingfreq * 1.1]
1373
- gpass = 1.0
1374
- gstop = 40.0
1375
- b, a = sp.signal.iirdesign(wp, ws, gpass, gstop, ftype="cheby2", fs=fs)
1376
- if self.debug:
1377
- print(
1378
- i,
1379
- j,
1380
- times[i],
1381
- centerindex,
1382
- halfwidth,
1383
- xstart,
1384
- xend,
1385
- xend - xstart,
1386
- wp,
1387
- ws,
1388
- len(a),
1389
- len(b),
1390
- )
1391
- filtsignal = sp.signal.filtfilt(b, a, sp.signal.filtfilt(b, a, filtsignal))
1392
- pady[xstart:xend] += filtsignal
1393
- else:
1394
- pady[xstart:xend] += padx[xstart:xend]
1395
- padweight[xstart:xend] += 1.0
1396
- return (pady / padweight)[halfwidth:-halfwidth]
1397
-
1398
-
1399
- class fMRIData:
1400
- header = None
1401
- data = None
1402
- data_byvoxel = None
1403
- data_valid = None
1404
- mask = None
1405
- validvoxels = None
1406
-
1407
- def __init__(
1408
- self,
1409
- header=None,
1410
- data=None,
1411
- mask=None,
1412
- validvoxels=None,
1413
- dims=None,
1414
- sizes=None,
1415
- description=None,
1416
- ):
1417
- r"""
1418
-
1419
- Parameters
1420
- ----------
1421
- corrtimeaxis: 1D float array
1422
- The time axis of the correlation function
1423
- lagmin: float
1424
- The minimum allowed lag time in seconds
1425
- lagmax: float
1426
- The maximum allowed lag time in seconds
1427
- absmaxsigma: float
1428
- The maximum allowed peak halfwidth in seconds
1429
- hardlimit
1430
- bipolar: boolean
1431
- If true find the correlation peak with the maximum absolute value, regardless of sign
1432
- threshval
1433
- uthreshval
1434
- debug
1435
- zerooutbadfit
1436
- maxguess
1437
- useguess
1438
- searchfrac
1439
- lagmod
1440
- enforcethresh
1441
- displayplots
1442
-
1443
- Returns
1444
- -------
1445
-
1446
-
1447
- Methods
1448
- -------
1449
- fit(corrfunc):
1450
- Fit the correlation function given in corrfunc and return the location of the peak in seconds, the maximum
1451
- correlation value, the peak width
1452
- setrange(lagmin, lagmax):
1453
- Specify the search range for lag peaks, in seconds
1454
- """
1455
-
1456
- self.header = header
1457
- self.data = data
1458
- self.mask = mask
1459
- self.validvoxels = validvoxels
1460
- self.dims = dims
1461
- self.sizes = sizes
1462
- self.description = description