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