paradigma 0.1.2__py3-none-any.whl → 0.2.0__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 (112) hide show
  1. paradigma/__init__.py +1 -3
  2. paradigma/constants.py +35 -0
  3. paradigma/feature_extraction.py +678 -0
  4. paradigma/gait_analysis.py +413 -0
  5. paradigma/gait_analysis_config.py +244 -0
  6. paradigma/heart_rate_analysis.py +127 -0
  7. paradigma/heart_rate_analysis_config.py +9 -0
  8. paradigma/heart_rate_util.py +173 -0
  9. paradigma/imu_preprocessing.py +229 -0
  10. paradigma/ppg/classifier/LR_PPG_quality.pkl +0 -0
  11. paradigma/ppg/classifier/LR_model.mat +0 -0
  12. paradigma/ppg/feat_extraction/acc_feature.m +20 -0
  13. paradigma/ppg/feat_extraction/peakdet.m +64 -0
  14. paradigma/ppg/feat_extraction/ppg_features.m +53 -0
  15. paradigma/ppg/glob_functions/extract_hr_segments.m +37 -0
  16. paradigma/ppg/glob_functions/extract_overlapping_segments.m +23 -0
  17. paradigma/ppg/glob_functions/jsonlab/AUTHORS.txt +41 -0
  18. paradigma/ppg/glob_functions/jsonlab/ChangeLog.txt +74 -0
  19. paradigma/ppg/glob_functions/jsonlab/LICENSE_BSD.txt +25 -0
  20. paradigma/ppg/glob_functions/jsonlab/LICENSE_GPLv3.txt +699 -0
  21. paradigma/ppg/glob_functions/jsonlab/README.txt +394 -0
  22. paradigma/ppg/glob_functions/jsonlab/examples/.svn/entries +368 -0
  23. paradigma/ppg/glob_functions/jsonlab/examples/.svn/text-base/demo_jsonlab_basic.m.svn-base +180 -0
  24. paradigma/ppg/glob_functions/jsonlab/examples/.svn/text-base/demo_ubjson_basic.m.svn-base +180 -0
  25. paradigma/ppg/glob_functions/jsonlab/examples/.svn/text-base/example1.json.svn-base +23 -0
  26. paradigma/ppg/glob_functions/jsonlab/examples/.svn/text-base/example2.json.svn-base +22 -0
  27. paradigma/ppg/glob_functions/jsonlab/examples/.svn/text-base/example3.json.svn-base +11 -0
  28. paradigma/ppg/glob_functions/jsonlab/examples/.svn/text-base/example4.json.svn-base +34 -0
  29. paradigma/ppg/glob_functions/jsonlab/examples/.svn/text-base/jsonlab_basictest.matlab.svn-base +662 -0
  30. paradigma/ppg/glob_functions/jsonlab/examples/.svn/text-base/jsonlab_selftest.m.svn-base +27 -0
  31. paradigma/ppg/glob_functions/jsonlab/examples/.svn/text-base/jsonlab_selftest.matlab.svn-base +144 -0
  32. paradigma/ppg/glob_functions/jsonlab/examples/.svn/text-base/jsonlab_speedtest.m.svn-base +21 -0
  33. paradigma/ppg/glob_functions/jsonlab/examples/demo_jsonlab_basic.m +180 -0
  34. paradigma/ppg/glob_functions/jsonlab/examples/demo_ubjson_basic.m +180 -0
  35. paradigma/ppg/glob_functions/jsonlab/examples/example1.json +23 -0
  36. paradigma/ppg/glob_functions/jsonlab/examples/example2.json +22 -0
  37. paradigma/ppg/glob_functions/jsonlab/examples/example3.json +11 -0
  38. paradigma/ppg/glob_functions/jsonlab/examples/example4.json +34 -0
  39. paradigma/ppg/glob_functions/jsonlab/examples/jsonlab_basictest.matlab +662 -0
  40. paradigma/ppg/glob_functions/jsonlab/examples/jsonlab_selftest.m +27 -0
  41. paradigma/ppg/glob_functions/jsonlab/examples/jsonlab_selftest.matlab +144 -0
  42. paradigma/ppg/glob_functions/jsonlab/examples/jsonlab_speedtest.m +21 -0
  43. paradigma/ppg/glob_functions/jsonlab/jsonopt.m +32 -0
  44. paradigma/ppg/glob_functions/jsonlab/loadjson.m +566 -0
  45. paradigma/ppg/glob_functions/jsonlab/loadubjson.m +528 -0
  46. paradigma/ppg/glob_functions/jsonlab/mergestruct.m +33 -0
  47. paradigma/ppg/glob_functions/jsonlab/savejson.m +475 -0
  48. paradigma/ppg/glob_functions/jsonlab/saveubjson.m +504 -0
  49. paradigma/ppg/glob_functions/jsonlab/varargin2struct.m +40 -0
  50. paradigma/ppg/glob_functions/sample_prob_final.m +49 -0
  51. paradigma/ppg/glob_functions/synchronization.m +76 -0
  52. paradigma/ppg/glob_functions/tsdf_scan_meta.m +22 -0
  53. paradigma/ppg/hr_functions/Long_TFD_JOT.m +37 -0
  54. paradigma/ppg/hr_functions/PPG_TFD_HR.m +59 -0
  55. paradigma/ppg/hr_functions/TFD toolbox JOT/.gitignore +4 -0
  56. paradigma/ppg/hr_functions/TFD toolbox JOT/CHANGELOG.md +23 -0
  57. paradigma/ppg/hr_functions/TFD toolbox JOT/LICENCE.md +27 -0
  58. paradigma/ppg/hr_functions/TFD toolbox JOT/README.md +251 -0
  59. paradigma/ppg/hr_functions/TFD toolbox JOT/README.pdf +0 -0
  60. paradigma/ppg/hr_functions/TFD toolbox JOT/common/gen_Doppler_kern.m +142 -0
  61. paradigma/ppg/hr_functions/TFD toolbox JOT/common/gen_Doppler_lag_kern.m +314 -0
  62. paradigma/ppg/hr_functions/TFD toolbox JOT/common/gen_lag_kern.m +123 -0
  63. paradigma/ppg/hr_functions/TFD toolbox JOT/dec_tfd.m +154 -0
  64. paradigma/ppg/hr_functions/TFD toolbox JOT/decimated_TFDs/dec_di_gdtfd.m +194 -0
  65. paradigma/ppg/hr_functions/TFD toolbox JOT/decimated_TFDs/dec_li_gdtfd.m +200 -0
  66. paradigma/ppg/hr_functions/TFD toolbox JOT/decimated_TFDs/dec_nonsep_gdtfd.m +229 -0
  67. paradigma/ppg/hr_functions/TFD toolbox JOT/decimated_TFDs/dec_sep_gdtfd.m +241 -0
  68. paradigma/ppg/hr_functions/TFD toolbox JOT/full_TFDs/di_gdtfd.m +157 -0
  69. paradigma/ppg/hr_functions/TFD toolbox JOT/full_TFDs/li_gdtfd.m +190 -0
  70. paradigma/ppg/hr_functions/TFD toolbox JOT/full_TFDs/nonsep_gdtfd.m +196 -0
  71. paradigma/ppg/hr_functions/TFD toolbox JOT/full_TFDs/sep_gdtfd.m +199 -0
  72. paradigma/ppg/hr_functions/TFD toolbox JOT/full_tfd.m +144 -0
  73. paradigma/ppg/hr_functions/TFD toolbox JOT/load_curdir.m +13 -0
  74. paradigma/ppg/hr_functions/TFD toolbox JOT/pics/decimated_TFDs_examples.png +0 -0
  75. paradigma/ppg/hr_functions/TFD toolbox JOT/pics/full_TFDs_examples.png +0 -0
  76. paradigma/ppg/hr_functions/TFD toolbox JOT/utils/check_dec_params_seq.m +79 -0
  77. paradigma/ppg/hr_functions/TFD toolbox JOT/utils/dispEE.m +9 -0
  78. paradigma/ppg/hr_functions/TFD toolbox JOT/utils/dispVars.m +26 -0
  79. paradigma/ppg/hr_functions/TFD toolbox JOT/utils/disp_bytes.m +25 -0
  80. paradigma/ppg/hr_functions/TFD toolbox JOT/utils/fold_vector_full.m +40 -0
  81. paradigma/ppg/hr_functions/TFD toolbox JOT/utils/fold_vector_half.m +34 -0
  82. paradigma/ppg/hr_functions/TFD toolbox JOT/utils/gen_LFM.m +29 -0
  83. paradigma/ppg/hr_functions/TFD toolbox JOT/utils/get_analytic_signal.m +76 -0
  84. paradigma/ppg/hr_functions/TFD toolbox JOT/utils/get_window.m +176 -0
  85. paradigma/ppg/hr_functions/TFD toolbox JOT/utils/isreal_fn.m +11 -0
  86. paradigma/ppg/hr_functions/TFD toolbox JOT/utils/padWin.m +97 -0
  87. paradigma/ppg/hr_functions/TFD toolbox JOT/utils/vtfd.m +149 -0
  88. paradigma/ppg/preprocessing/preprocessing_imu.m +15 -0
  89. paradigma/ppg/preprocessing/preprocessing_ppg.m +13 -0
  90. paradigma/ppg_preprocessing.py +313 -0
  91. paradigma/preprocessing_config.py +64 -0
  92. paradigma/quantification.py +58 -0
  93. paradigma/tremor/TremorFeaturesAndClassification.m +345 -0
  94. paradigma/tremor/feat_extraction/DerivativesExtract.m +22 -0
  95. paradigma/tremor/feat_extraction/ExtractBandSignalsRMS.m +72 -0
  96. paradigma/tremor/feat_extraction/MFCCExtract.m +100 -0
  97. paradigma/tremor/feat_extraction/PSDBandPower.m +52 -0
  98. paradigma/tremor/feat_extraction/PSDEst.m +63 -0
  99. paradigma/tremor/feat_extraction/PSDExtrAxis.m +88 -0
  100. paradigma/tremor/feat_extraction/PSDExtrOpt.m +95 -0
  101. paradigma/tremor/preprocessing/InterpData.m +32 -0
  102. paradigma/tremor/weekly_aggregates/WeeklyAggregates.m +295 -0
  103. paradigma/util.py +50 -0
  104. paradigma/windowing.py +217 -0
  105. paradigma-0.2.0.dist-info/LICENSE +192 -0
  106. paradigma-0.2.0.dist-info/METADATA +58 -0
  107. paradigma-0.2.0.dist-info/RECORD +108 -0
  108. paradigma/dummy.py +0 -3
  109. paradigma-0.1.2.dist-info/LICENSE +0 -201
  110. paradigma-0.1.2.dist-info/METADATA +0 -18
  111. paradigma-0.1.2.dist-info/RECORD +0 -6
  112. {paradigma-0.1.2.dist-info → paradigma-0.2.0.dist-info}/WHEEL +0 -0
@@ -0,0 +1,88 @@
1
+ function [PSDFeaturesOut] = PSDExtrAxis(Conf,Data,freq)
2
+ % #########################################################################
3
+ % Input
4
+ % Conf - Structure
5
+ % .freqrange - array - double - frequency Range for
6
+ % dominant power evaluation
7
+ % .SpectralIntervalPeak - scalar - double - number of samples around
8
+ % the peak to evaluate
9
+ % Fixed Dominant Power
10
+ % .StrAxis - string - signal axis (or Sum) specified to be
11
+ % considered for feature extraction
12
+ % .nfft - scalar - double - number of points for the
13
+ % FFT (number of samples)
14
+ % .Fs - scalar - double - sampling Rate
15
+ % .MinFreqOverallBand - scalar - double - minimum frequency for
16
+ % overall power evaluation
17
+ % .MaxFreqOverallBand - scalar - double - maximum frequency for
18
+ % overall power evaluation
19
+ %
20
+ % Data - PSD Matrix - matrix - double - N frequency values x
21
+ % (Nsignals + 1) - last column is the
22
+ % PSD sum (PSDx + PSDy + PSDz)
23
+ %
24
+ % freq - array - double - frequency vector associsted to the PSD;
25
+ % #########################################################################
26
+ % Output
27
+ % PSDFeaturesOut - matrix - double (1 x 2)
28
+ % (1) PowerAxis - power in the full range 0.5 - 25 Hz
29
+ % (2) DomPower - dominant power 1.25 Hz around the peak
30
+ % within the range: freqrange
31
+ % #########################################################################
32
+
33
+ % Get the estimation parameters
34
+ freqrange = Conf.freqrange;
35
+ SpectralIntervalPeak = Conf.SpectralIntervalPeak;
36
+ StrAxis = Conf.StrAxis;
37
+ nfft = Conf.nfft;
38
+ Fs = Conf.Fs;
39
+ MinFreqOverallBand = Conf.MinFreqOverallBand;
40
+ MaxFreqOverallBand = Conf.MaxFreqOverallBand;
41
+
42
+ % Getting the signal axis or sum according to what specified in the input
43
+ switch StrAxis
44
+ case 'X'
45
+ Pxx = Data(:,1);
46
+ case 'Y'
47
+ Pxx = Data(:,2);
48
+ case 'Z'
49
+ Pxx = Data(:,3);
50
+ case 'Sum'
51
+ Pxx = Data(:,4);
52
+ end
53
+
54
+ f0 = Fs/nfft; % Spectral Resolution
55
+
56
+ SpectrumInterval = SpectralIntervalPeak; % Number of samples taken around the spectral peak to compute dominant power
57
+ FreqLowerBound = freqrange(1); % lower frequency bound
58
+ FreqUpperBound = freqrange(2); % upper frequency bound
59
+
60
+ % Logical array specifying the specified frequency
61
+ BandFreq = (freq >= FreqLowerBound & freq <= FreqUpperBound);
62
+
63
+ % Total Power - area under PSD using an approximation by the left: 5
64
+ % frequency coefficients are considered for symmetry around the peak
65
+ % implying a frequency width of 1.25 Hz
66
+
67
+ InitialIndexFullBandPower = find(freq == MinFreqOverallBand); % Initial index for full-band power estimation - this is required to remove frequency components associated with gyroscope drift
68
+ FinalIndexFullBandPower = find(freq == (MaxFreqOverallBand-f0)); % Final index for full-band power estimation: area will be estimated using approximation by the left
69
+
70
+ TotalPower = f0*sum(Pxx(InitialIndexFullBandPower:FinalIndexFullBandPower)); % Total power up to 25 Hz
71
+
72
+ % Dominanting Frequency Characteristics
73
+ [max_power, ind_max_rel] = max(Pxx(BandFreq)); % Peak values and index within the specified band
74
+ indplus = find(BandFreq == 1); % Initial index of the band specified
75
+ ind_max = indplus(1) + ind_max_rel - 1; % index of the dominant frequency
76
+
77
+ FreqPeak = freq(ind_max); % Dominant frequency
78
+
79
+ LowerFixedPeakBound = max(1,ind_max - SpectrumInterval); % lower bound frequency index avoiding negative indexed for dominant frequency lower than 0.5 Hz
80
+ MaxFixedPeakBound = ind_max + SpectrumInterval; % upper bound frequency index
81
+
82
+ % Dominant power (area under PSD using approximation by the left)
83
+ FixedDomPower = f0*(sum(Pxx(LowerFixedPeakBound:MaxFixedPeakBound))); % this takes 5 PSD coefficients which implies a bandwidth of 1.25 Hz
84
+
85
+ % Concatening features:
86
+ PxxFeatures = [TotalPower FixedDomPower];
87
+
88
+ PSDFeaturesOut = PxxFeatures; % Defining the output
@@ -0,0 +1,95 @@
1
+ function [PSDFeaturesOut] = PSDExtrOpt(Conf,Data,freq)
2
+ % #########################################################################
3
+ % Input
4
+ % Conf - Structure
5
+ % .freqrange - array - double - Frequency Range for feature
6
+ % Extraction
7
+ % .SpectralIntervalPeak - scalar - double - number of samples around
8
+ % the peak to evaluate Fixed
9
+ % Dominant Power
10
+ % .StrAxis - string - signal axis (or Sum) specified to be
11
+ % considered for feature extraction
12
+ % .nfft - scalar - double - number of points for the
13
+ % FFT (number of samples)
14
+ % .Fs - scalar - double - sampling Rate
15
+ %
16
+ % Data - PSD Matrix - matrix - double - Frequency values x (NPSDsignals + 1)
17
+ % last column is the PSD sum
18
+ % (PSDx + PSDy + PSDz)
19
+ %
20
+ % freq - array - double - frequency vector associsted to the PSD;
21
+ % #########################################################################
22
+ % Output - Table with PSD features for the axis (or sum of the axis)
23
+ % selected
24
+ % PSDFeaturesOut - array - double (1 x 3)
25
+ % BandPower - power in the range
26
+ % FreqPeak - dominant frequency in the tremor range
27
+ % FixedDomPower - dominant power 1.25 Hz around the
28
+ % tremor peak
29
+ % #########################################################################
30
+
31
+ % Get the estimation parameters
32
+ freqrange = Conf.freqrange;
33
+ SpectralIntervalPeak = Conf.SpectralIntervalPeak;
34
+ StrAxis = Conf.StrAxis;
35
+ nfft = Conf.nfft;
36
+ Fs = Conf.Fs;
37
+
38
+ % Getting the signal axis or sum according to what specified in the input
39
+ switch StrAxis
40
+ case 'X'
41
+ Pxx = Data(:,1);
42
+ case 'Y'
43
+ Pxx = Data(:,2);
44
+ case 'Z'
45
+ Pxx = Data(:,3);
46
+ case 'Sum'
47
+ Pxx = Data(:,4);
48
+ end
49
+
50
+ f0 = Fs/nfft; % Spectral Resolution
51
+
52
+ SpectrumInterval = SpectralIntervalPeak; % Number of samples taken around
53
+ % the spectral peak to compute
54
+ % dominant power
55
+
56
+ FreqLowerBound = freqrange(1); % lower frequency bound
57
+ FreqUpperBound = freqrange(2); % upper frequency bound
58
+
59
+ % Logical array specifying the specified frequency
60
+ BandFreq = (freq >= FreqLowerBound & freq <= FreqUpperBound);
61
+
62
+ % Power - area under PSD using an approximation by the left
63
+ % Dominant Power: 5 frequency coefficients are considered around the peak
64
+ % (2 coefficients for each side) implying a frequency width of 1.25 Hz
65
+
66
+ % Initial index for bandpower estimation
67
+ InitialIndexBandForPower = find(freq == FreqLowerBound);
68
+
69
+ % Final index for bandpower estimation: area will be estimated using
70
+ % approximation by the left
71
+ FinalIndexBandForPower = find(freq == (FreqUpperBound-f0));
72
+
73
+ % Bandpower evaluation
74
+ BandPower = f0*sum(Pxx(InitialIndexBandForPower:FinalIndexBandForPower));
75
+
76
+ % Dominanting Frequency Characteristics
77
+ [max_power, ind_max_rel] = max(Pxx(BandFreq)); % Peak values and index within the specified band
78
+ indplus = find(BandFreq == 1); % Initial index of the band specified
79
+ ind_max = indplus(1) + ind_max_rel - 1; % index of the dominant frequency
80
+
81
+ FreqPeak = freq(ind_max); % Dominant frequency
82
+
83
+ LowerFixedPeakBound = max(1,ind_max - SpectrumInterval); % lower bound frequency index avoiding negative indexed for dominant frequency lower than 0.5 Hz
84
+ MaxFixedPeakBound = ind_max + SpectrumInterval; % upper bound frequency index
85
+
86
+ % Dominant power (area under PSD using approximation by the left)
87
+ FixedDomPower = f0*(sum(Pxx(LowerFixedPeakBound:MaxFixedPeakBound))); % this takes 5 PSD coefficients which implies a bandwidth of 1.25 Hz
88
+
89
+ % Dominant power normalized by the band power
90
+ % FixedDomPowerRatio = FixedDomPower/BandPower;
91
+
92
+ % Concatening features:
93
+ PxxFeatures = [BandPower FreqPeak FixedDomPower];
94
+
95
+ PSDFeaturesOut = PxxFeatures; % Defining the output
@@ -0,0 +1,32 @@
1
+ % Interpolate Data
2
+ % Diogo C. Soriano
3
+ % 15/08/2022
4
+
5
+ % #########################################################################
6
+ % Input:
7
+ % tr - array - double - running time in (s) after transformation from Unix time;
8
+ % y_curr_gyro - matrix - double - gyroscope matrix Nsamples x 3: columns [x,y,z]
9
+ % Fs - scalar - double - sampling rate (Hz);
10
+ % unix_ticks_ms - scalar - double - Unix ticks / ms
11
+ % ts - scalar - double - Unix time start
12
+
13
+ % Output:
14
+ % t_imu_proc{n} - cell - (double) - Unix time corrected (interpolated);
15
+ % v_imu_proc{n} - cell - (double) - Nsamples x Nchannels - Gyroscope
16
+ % signals interpolated. Columns: [x y z]
17
+ % #########################################################################
18
+ function [tcorrected,y_curr_gyro_interp] = InterpData(tr,y_curr_gyro,Fs,unix_ticks_ms,ts)
19
+
20
+ [tunique, indunique] = unique(tr);
21
+
22
+ y_curr_gyro = y_curr_gyro(indunique,:);
23
+
24
+ ti = (0:1/Fs:tunique(end))';
25
+
26
+ if length(y_curr_gyro(:,1)) > 3
27
+
28
+ y_curr_gyro_interp = interp1(tunique,y_curr_gyro,ti,'spline'); % Use splines to interpolate the data
29
+
30
+ end
31
+
32
+ tcorrected = ti*unix_ticks_ms + ts;
@@ -0,0 +1,295 @@
1
+ function WeeklyAggregates(ppp_pep_userid,week_vector)
2
+
3
+ % #########################################################################
4
+ % Input:
5
+ % ppp_pep_userid - id of the subject
6
+ % week_vector - array of week numbers you want to calculate weekly
7
+ % aggregates for
8
+
9
+ % Output: Saves two binary files (Tremor_weeks.bin and Tremor_aggregates.bin) and a metadata file in TSDF format
10
+ % Saved in Tremor_weeks.bin per week:
11
+ % - Week number
12
+ % - Data availability flag
13
+ % - Number of valid days
14
+ % - Total number of windows available
15
+ % - Number of windows available during daytime (08:00-22:00)
16
+ % Saved in Tremor_aggreagtes.bin per week:
17
+ % Tremor time/ arm activity time measures:
18
+ % - tremor proportion overall (24h)
19
+ % - tremor proportion during daytime (08:00-22:00)
20
+ % - tremor proportion overall and in rest (without arm activity)
21
+ % - tremor proportion during daytime and in rest
22
+ % - arm activity proportion overall
23
+ % - arm activity proportion during daytime
24
+ % - tremor proportion during daytime and non-rest (with arm
25
+ % activity)
26
+ % - tremor proportion during nighttime
27
+ % Tremor amplitude and frequency measures (during daytime, based on dominant power 1.25
28
+ % Hz around the tremor peak):
29
+ % - median tremor amplitude
30
+ % - modus of tremor amplitude
31
+ % - 90th percentile of tremor amplitude
32
+ % - IQR of tremor amplitude
33
+ % - median tremor amplitude in rest (without arm activity)
34
+ % - modus of tremor amplitude in rest
35
+ % - 90th percentile of tremor amplitude in rest
36
+ % - IQR of tremor amplitude in rest
37
+ % - median tremor frequency
38
+ % - IQR of tremor frequency
39
+ % - median tremor frequency in rest
40
+ % - IQR of tremor frequency in rest
41
+ % #########################################################################
42
+
43
+ NWeeks = length(week_vector);
44
+ unix_ticks_ms = 1000;
45
+ arm_activity_threshold = 10^0.88; % threshold for arm activity detection (based on 0.5-3 Hz band power)
46
+ tremor_amplitude_threshold = 0.02; % treshold for estimating the tremor amplitude (based on tremor time)
47
+ valid_day_threshold = 10; % threshold for valid day (based on number of hours/day)
48
+
49
+ % Initialize
50
+ start_time_iso = [];
51
+ DataFlag = [];
52
+ total_number_windows = [];
53
+ number_windows_daytime = [];
54
+ tremor_proportion_24h = [];
55
+ tremor_proportion_daytime = [];
56
+ tremor_proportion_24h_rest = [];
57
+ tremor_proportion_daytime_rest = [];
58
+ arm_activity_proportion_24h = [];
59
+ arm_activity_proportion_daytime = [];
60
+ tremor_proportion_daytime_nonrest = [];
61
+ tremor_proportion_nighttime = [];
62
+ tremor_amplitude_median = [];
63
+ tremor_amplitude_modus = [];
64
+ tremor_amplitude_90th = [];
65
+ tremor_amplitude_IQR = [];
66
+ tremor_amplitude_median_rest = [];
67
+ tremor_amplitude_modus_rest = [];
68
+ tremor_amplitude_90th_rest = [];
69
+ tremor_amplitude_IQR_rest = [];
70
+ tremor_frequency_median = [];
71
+ tremor_frequency_IQR = [];
72
+ tremor_frequency_median_rest = [];
73
+ tremor_frequency_IQR_rest = [];
74
+
75
+ %% In case you want to remove the day of first visit (because of OFF state)
76
+ % load('Visit1_day.mat')
77
+ % idnum = char(ppp_pep_userid);
78
+ % idnum = string(idnum(:,5:end));
79
+ % Visit1_date = Visit1_day.Date(ismember(Visit1_day.ID,idnum));
80
+ % Visit1_day_num = day(Visit1_date);
81
+
82
+ for i = 1:NWeeks
83
+
84
+ subjectfolder = strcat('C:\Users\z835211\Documents\Data\TSDF output\WatchData.IMU.Week',num2str(week_vector(i)),'\',ppp_pep_userid);
85
+
86
+ if isfolder(subjectfolder)
87
+
88
+ DataFlag(i) = 1; % 1 if there is data for this week, 0 if there is no data (of enough good quality)
89
+
90
+ % load tremor predictions and features for specific subject and week:
91
+ [metadata, data] = load_tsdf_metadata_from_path(strcat(subjectfolder,'\Tremor_predictions_meta.json'));
92
+ [~, data2] = load_tsdf_metadata_from_path(strcat(subjectfolder,'\Tremor_features_meta.json'));
93
+
94
+ metafile_template = metadata{1};
95
+
96
+ % extract the dates to determine the dates of valid days
97
+ tremor_time = datetime(data{1,1}/unix_ticks_ms, "ConvertFrom", "posixtime", 'Format', 'dd-MMM-yyyy HH:mm:ss Z', 'TimeZone', 'Europe/Amsterdam');
98
+
99
+ days = unique(day(tremor_time));
100
+
101
+ Valid_days = [];
102
+
103
+ for k = 1:length(days)
104
+
105
+ NumWindows_daytime = length(find(day(tremor_time)==days(k) & ismember(hour(tremor_time),[8,9,10,11,12,13,14,15,16,17,18,19,20,21]))); % Find number of windows during daytime
106
+
107
+ if NumWindows_daytime*4/3600 >= valid_day_threshold % Determine which days are valid days
108
+
109
+ Valid_days = [Valid_days; days(k)];
110
+
111
+ end
112
+ end
113
+
114
+ if ~isempty(Valid_days)
115
+
116
+ % if i == 1
117
+ % Valid_days(Valid_days==Visit1_day_num) = []; % remove because of OFF-state around visit 1
118
+ % end
119
+
120
+ number_valid_days(i) = length(Valid_days);
121
+
122
+ % Create several flags to indicate for every window whether
123
+ % specific conditions are met:
124
+ valid = ismember(day(tremor_time),Valid_days); % window belongs to a valid day
125
+ tremor_valid = valid & data{1,2}(:,2)==1; % window belongs to a valid day and is classified as tremor
126
+ daytime = ismember(hour(tremor_time),[8,9,10,11,12,13,14,15,16,17,18,19,20,21]); % window belongs to daytime
127
+ daytime_valid = valid & daytime; % window belongs to daytime and to a valid day
128
+ tremor_daytime_valid = daytime_valid & data{1,2}(:,2)==1; % window belongs to daytime and a valid day and is classified as tremor
129
+ nighttime_valid = valid & ~daytime; % window belongs to nighttime and to a valid day
130
+ tremor_nighttime_valid = nighttime_valid & data{1,2}(:,2)==1; % window belongs to nighttime and to a valid day and is classified as tremor
131
+
132
+ rest_valid = data2{1,2}(:,17)<arm_activity_threshold & valid; % window belongs to a valid day and rest (no arm activity)
133
+ tremor_rest_valid = rest_valid & data{1,2}(:,2)==1; % window belongs to a valid day and rest and is classified as tremor
134
+ nonrest_valid = data2{1,2}(:,17)>=arm_activity_threshold & valid; % window belongs to a valid day and non-rest (with arm activity)
135
+ daytime_rest_valid = daytime & rest_valid; % window belongs to daytime, a valid day and rest
136
+ tremor_daytime_rest_valid = daytime_rest_valid & data{1,2}(:,2)==1; % window belongs to daytime, a valid day and rest and is classified as tremor
137
+ daytime_nonrest_valid= daytime & nonrest_valid; % window belongs to daytime, a valid day and non-rest
138
+ tremor_daytime_nonrest_valid = daytime_nonrest_valid & data{1,2}(:,2)==1; % window belongs to daytime, a valid day and non-rest and is classified as tremor
139
+
140
+ total_number_windows(i) = length(find(valid==1)); % total number of windows available during valid days
141
+ number_windows_daytime(i) = length(find(daytime_valid==1)); % total number of windows available during daytime on valid days
142
+
143
+ % Calculate the weekly aggregated measures for tremor time, arm
144
+ % activity and tremor frequency:
145
+ tremor_proportion_24h(i) = length(find(tremor_valid==1))/length(find(valid==1));
146
+ tremor_proportion_24h_rest(i) = length(find(tremor_rest_valid==1))/length(find(rest_valid==1));
147
+ arm_activity_proportion_24h(i) = length(find(nonrest_valid==1))/length(find(valid==1));
148
+
149
+ tremor_proportion_daytime(i) = length(find(tremor_daytime_valid==1))/length(find(daytime_valid==1));
150
+ tremor_proportion_daytime_rest(i) = length(find(tremor_daytime_rest_valid==1))/length(find(daytime_rest_valid==1));
151
+ arm_activity_proportion_daytime(i) = length(find(daytime_nonrest_valid==1))/length(find(daytime_valid==1));
152
+
153
+ tremor_proportion_daytime_nonrest(i) = length(find(tremor_daytime_nonrest_valid==1))/length(find(daytime_nonrest_valid==1));
154
+ tremor_proportion_nighttime(i) = length(find(tremor_nighttime_valid==1))/length(find(nighttime_valid==1));
155
+
156
+ tremor_frequency_median(i) = median(data2{1,2}(tremor_daytime_valid,10));
157
+ tremor_frequency_IQR(i) = iqr(data2{1,2}(tremor_daytime_valid,10));
158
+ tremor_frequency_median_rest(i) = median(data2{1,2}(tremor_daytime_rest_valid,10));
159
+ tremor_frequency_IQR_rest(i) = iqr(data2{1,2}(tremor_daytime_rest_valid,10));
160
+
161
+ if tremor_proportion_daytime(i)>=tremor_amplitude_threshold % determine whether there is enough tremor detected to calculate the amplitude
162
+ tremor_amplitude_median(i) = median(log10(1+data2{1,2}(tremor_daytime_valid,13)));
163
+ tremor_amplitude_90th(i) = prctile(log10(1+data2{1,2}(tremor_daytime_valid,13)),90);
164
+ tremor_amplitude_IQR(i) = iqr(log10(1+data2{1,2}(tremor_daytime_valid,13)));
165
+ % determine the modus:
166
+ binEdges = linspace(0,8,41); % Define the edges of the bins
167
+ Histogram = histcounts(log10(1+data2{1,2}(tremor_daytime_valid,13)), binEdges);
168
+ [~, maxIndex] = max(Histogram);
169
+ tremor_amplitude_modus(i) = mean([binEdges(maxIndex), binEdges(maxIndex + 1)]);
170
+
171
+ tremor_amplitude_median_rest(i) = median(log10(1+data2{1,2}(tremor_daytime_rest_valid,13)));
172
+ tremor_amplitude_90th_rest(i) = prctile(log10(1+data2{1,2}(tremor_daytime_rest_valid,13)),90);
173
+ tremor_amplitude_IQR_rest(i) = iqr(log10(1+data2{1,2}(tremor_daytime_rest_valid,13)));
174
+ % determine the modus:
175
+ binEdges = linspace(0,8,41); % Define the edges of the bins
176
+ Histogram = histcounts(log10(1+data2{1,2}(tremor_daytime_rest_valid,13)), binEdges);
177
+ [~, maxIndex] = max(Histogram);
178
+ tremor_amplitude_modus_rest(i) = mean([binEdges(maxIndex), binEdges(maxIndex + 1)]);
179
+ else % tremor amplitude is not calculated
180
+ tremor_amplitude_median(i) = NaN;
181
+ tremor_amplitude_modus(i) = NaN;
182
+ tremor_amplitude_90th(i) = NaN;
183
+ tremor_amplitude_IQR(i) = NaN;
184
+ tremor_amplitude_median_rest(i) = NaN;
185
+ tremor_amplitude_modus_rest(i) = NaN;
186
+ tremor_amplitude_90th_rest(i) = NaN;
187
+ tremor_amplitude_IQR_rest(i) = NaN;
188
+ end
189
+ else % there are no valid days for this week
190
+ number_valid_days(i) = 0;
191
+ total_number_windows(i) = 0;
192
+ number_windows_daytime(i) = 0;
193
+ tremor_proportion_24h(i) = NaN;
194
+ tremor_proportion_24h_rest(i) = NaN;
195
+ arm_activity_proportion_24h(i) = NaN;
196
+ tremor_proportion_daytime(i) = NaN;
197
+ tremor_proportion_daytime_rest(i) = NaN;
198
+ arm_activity_proportion_daytime(i) = NaN;
199
+ tremor_proportion_daytime_nonrest(i) = NaN;
200
+ tremor_proportion_nighttime(i) = NaN;
201
+ tremor_amplitude_median(i) = NaN;
202
+ tremor_amplitude_modus(i) = NaN;
203
+ tremor_amplitude_90th(i) = NaN;
204
+ tremor_amplitude_IQR(i) = NaN;
205
+ tremor_amplitude_median_rest(i) = NaN;
206
+ tremor_amplitude_modus_rest(i) = NaN;
207
+ tremor_amplitude_90th_rest(i) = NaN;
208
+ tremor_amplitude_IQR_rest(i) = NaN;
209
+ tremor_frequency_median(i) = NaN;
210
+ tremor_frequency_IQR(i) = NaN;
211
+ tremor_frequency_median_rest(i) = NaN;
212
+ tremor_frequency_IQR_rest(i) = NaN;
213
+ end
214
+
215
+ % Determine the start time of the first week
216
+ if isempty(start_time_iso)
217
+ start_time_iso = datetime(data{1,1}(1)/unix_ticks_ms,"ConvertFrom", "posixtime", 'Format', 'dd-MMM-yyyy Z', 'TimeZone', 'Europe/Amsterdam');
218
+ end
219
+
220
+ else % theres is no data available for this week
221
+ DataFlag(i) = 0;
222
+ number_valid_days(i) = NaN;
223
+ total_number_windows(i) = NaN;
224
+ number_windows_daytime(i) = NaN;
225
+ tremor_proportion_24h(i) = NaN;
226
+ tremor_proportion_24h_rest(i) = NaN;
227
+ arm_activity_proportion_24h(i) = NaN;
228
+ tremor_proportion_daytime(i) = NaN;
229
+ tremor_proportion_daytime_rest(i) = NaN;
230
+ arm_activity_proportion_daytime(i) = NaN;
231
+ tremor_proportion_daytime_nonrest(i) = NaN;
232
+ tremor_proportion_nighttime(i) = NaN;
233
+ tremor_amplitude_median(i) = NaN;
234
+ tremor_amplitude_modus(i) = NaN;
235
+ tremor_amplitude_90th(i) = NaN;
236
+ tremor_amplitude_IQR(i) = NaN;
237
+ tremor_amplitude_median_rest(i) = NaN;
238
+ tremor_amplitude_modus_rest(i) = NaN;
239
+ tremor_amplitude_90th_rest(i) = NaN;
240
+ tremor_amplitude_IQR_rest(i) = NaN;
241
+ tremor_frequency_median(i) = NaN;
242
+ tremor_frequency_IQR(i) = NaN;
243
+ tremor_frequency_median_rest(i) = NaN;
244
+ tremor_frequency_IQR_rest(i) = NaN;
245
+ end
246
+ end
247
+
248
+ % Determine the endtime of the last week:
249
+ end_time_iso = datetime(data{1,1}(end)/unix_ticks_ms,"ConvertFrom", "posixtime", 'Format', 'dd-MMM-yyyy Z', 'TimeZone', 'Europe/Amsterdam');
250
+
251
+ % Save output in TSDF:
252
+
253
+ metafile_template.ppp_source_protobuf = [];
254
+ metafile_template.freq_sampling_original = [];
255
+ metafile_template.freq_sampling_adjusted = [];
256
+
257
+ metafile_template.start_iso8601 = start_time_iso;
258
+ metafile_template.end_iso8601 = end_time_iso;
259
+
260
+ metafile_template.arm_activity_threshold = arm_activity_threshold;
261
+ metafile_template.amplitude_estimation_threshold = tremor_amplitude_threshold;
262
+
263
+ data_tsdf{1} = [int64(week_vector)' int64(DataFlag)' int64(number_valid_days)' int64(total_number_windows)' int64(number_windows_daytime)'];
264
+ data_tsdf{2} = [tremor_proportion_24h' tremor_proportion_24h_rest' arm_activity_proportion_24h' tremor_proportion_daytime' tremor_proportion_daytime_rest'...
265
+ arm_activity_proportion_daytime' tremor_proportion_daytime_nonrest' tremor_proportion_nighttime' tremor_amplitude_median' tremor_amplitude_modus' tremor_amplitude_90th' tremor_amplitude_IQR' tremor_amplitude_median_rest'...
266
+ tremor_amplitude_modus_rest' tremor_amplitude_90th_rest' tremor_amplitude_IQR_rest' tremor_frequency_median' tremor_frequency_IQR' tremor_frequency_median_rest'...
267
+ tremor_frequency_IQR_rest'];
268
+
269
+ metafile_weeks = metafile_template;
270
+ metafile_aggregates = metafile_template;
271
+
272
+ metafile_weeks.channels = {'week number','data availability','number of valid days','total number of windows','number of windows daytime'};
273
+ metafile_weeks.units = {'','boolean_num','','',''};
274
+ metafile_weeks.file_name = 'Tremor_weeks.bin';
275
+
276
+ metafile_aggregates.channels = {'tremor proportion','tremor proportion in rest','arm activity proportion','daytime tremor proportion',...
277
+ 'daytime tremor proportion in rest','daytime arm activity proportion', 'daytime tremor proportion during arm activity','nighttime tremor proportion','median tremor amplitude','modus tremor amplitude',...
278
+ 'tremor amplitude 90th cent','tremor amplitude IQR','median tremor amplitude in rest','modus tremor amplitude in rest',...
279
+ 'tremor amplitude 90th cent in rest','tremor amplitude IQR in rest','median tremor frequency','tremor frequency IQR',...
280
+ 'median tremor frequency in rest','tremor frequency IQR in rest'};
281
+ metafile_aggregates.units = {'proportion','proportion','proportion','proportion','proportion','proportion','proportion','proportion','','','','','','','','','Hz','Hz','Hz','Hz'};
282
+ metafile_aggregates.file_name = 'Tremor_aggregates.bin';
283
+
284
+ meta_tsdf{1} = metafile_weeks;
285
+ meta_tsdf{2} = metafile_aggregates;
286
+
287
+ metadata_file_name = "Tremor_weekly_aggregates_meta.json";
288
+ location = ['C:\Users\z835211\Documents\Data\TSDF output\Weekly aggregates\',ppp_pep_userid, '\'];
289
+ mkdir(['C:\Users\z835211\Documents\Data\TSDF output\Weekly aggregates\',ppp_pep_userid]);
290
+
291
+ save_tsdf_data(meta_tsdf, data_tsdf, location, metadata_file_name);
292
+
293
+ clear all
294
+
295
+ end
paradigma/util.py ADDED
@@ -0,0 +1,50 @@
1
+ import os
2
+ import numpy as np
3
+ import pandas as pd
4
+ from datetime import timedelta
5
+ from dateutil import parser
6
+ from typing import Tuple
7
+
8
+ import tsdf
9
+ from tsdf import TSDFMetadata
10
+
11
+ def parse_iso8601_to_datetime(date_str):
12
+ return parser.parse(date_str)
13
+
14
+ def format_datetime_to_iso8601(datetime):
15
+ return datetime.strftime('%Y-%m-%dT%H:%M:%S') + 'Z'
16
+
17
+ def get_end_iso8601(start_iso8601, window_length_seconds):
18
+ start_date = parser.parse(start_iso8601)
19
+ end_date = start_date + timedelta(seconds=window_length_seconds)
20
+ return format_datetime_to_iso8601(end_date)
21
+
22
+ def write_data(metadata_time: TSDFMetadata, metadata_samples: TSDFMetadata,
23
+ output_path: str, output_filename: str, df: pd.DataFrame):
24
+ if not os.path.exists(output_path):
25
+ os.makedirs(output_path)
26
+
27
+ # Make sure the iso8601 format is correctly set
28
+ #TODO: this should be properly validated in the tsdf library instead
29
+ start_date = parser.parse(metadata_time.__getattribute__('start_iso8601'))
30
+ metadata_time.start_iso8601 = format_datetime_to_iso8601(start_date)
31
+ end_date = parser.parse(metadata_time.__getattribute__('end_iso8601'))
32
+ metadata_time.end_iso8601 = format_datetime_to_iso8601(end_date)
33
+ start_date = parser.parse(metadata_samples.__getattribute__('start_iso8601'))
34
+ metadata_samples.start_iso8601 = format_datetime_to_iso8601(start_date)
35
+ end_date = parser.parse(metadata_samples.__getattribute__('end_iso8601'))
36
+ metadata_samples.end_iso8601 = format_datetime_to_iso8601(end_date)
37
+
38
+ # TODO: improve the way the metadata is stored at a different location
39
+ metadata_time.file_dir_path = output_path
40
+ metadata_samples.file_dir_path = output_path
41
+
42
+ # store binaries and metadata
43
+ tsdf.write_dataframe_to_binaries(output_path, df, [metadata_time, metadata_samples])
44
+ tsdf.write_metadata([metadata_time, metadata_samples], output_filename)
45
+
46
+ def read_metadata(input_path: str, meta_filename: str, time_filename: str, values_filename: str) -> Tuple[TSDFMetadata, TSDFMetadata]:
47
+ metadata_dict = tsdf.load_metadata_from_path(os.path.join(input_path, meta_filename))
48
+ metadata_time = metadata_dict[time_filename]
49
+ metadata_samples = metadata_dict[values_filename]
50
+ return metadata_time, metadata_samples