biomechzoo 0.5.9__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 (58) hide show
  1. __init__.py +33 -0
  2. biomechzoo/__init__.py +0 -0
  3. biomechzoo/__main__.py +6 -0
  4. biomechzoo/biomech_ops/__init__.py +0 -0
  5. biomechzoo/biomech_ops/continuous_relative_phase_data.py +31 -0
  6. biomechzoo/biomech_ops/continuous_relative_phase_line.py +36 -0
  7. biomechzoo/biomech_ops/filter_data.py +58 -0
  8. biomechzoo/biomech_ops/filter_line.py +85 -0
  9. biomechzoo/biomech_ops/movement_onset.py +53 -0
  10. biomechzoo/biomech_ops/normalize_data.py +36 -0
  11. biomechzoo/biomech_ops/normalize_line.py +51 -0
  12. biomechzoo/biomech_ops/phase_angle_data.py +39 -0
  13. biomechzoo/biomech_ops/phase_angle_line.py +48 -0
  14. biomechzoo/biomechzoo.py +447 -0
  15. biomechzoo/conversion/__init__.py +0 -0
  16. biomechzoo/conversion/c3d2zoo_data.py +95 -0
  17. biomechzoo/conversion/mvnx2zoo_data.py +113 -0
  18. biomechzoo/conversion/opencap2zoo_data.py +23 -0
  19. biomechzoo/conversion/table2zoo_data.py +114 -0
  20. biomechzoo/imu/__init__.py +0 -0
  21. biomechzoo/imu/kinematics.py +0 -0
  22. biomechzoo/imu/tilt_algorithm.py +112 -0
  23. biomechzoo/linear_algebra_ops/__init__.py +0 -0
  24. biomechzoo/linear_algebra_ops/compute_magnitude_data.py +43 -0
  25. biomechzoo/mvn/__init__.py +0 -0
  26. biomechzoo/mvn/load_mvnx.py +514 -0
  27. biomechzoo/mvn/main_mvnx.py +75 -0
  28. biomechzoo/mvn/mvn.py +232 -0
  29. biomechzoo/mvn/mvnx_file_accessor.py +464 -0
  30. biomechzoo/processing/__init__.py +0 -0
  31. biomechzoo/processing/addchannel_data.py +71 -0
  32. biomechzoo/processing/addevent_data.py +116 -0
  33. biomechzoo/processing/explodechannel_data.py +69 -0
  34. biomechzoo/processing/partition_data.py +46 -0
  35. biomechzoo/processing/removechannel_data.py +46 -0
  36. biomechzoo/processing/removeevent_data.py +57 -0
  37. biomechzoo/processing/renamechannel_data.py +79 -0
  38. biomechzoo/processing/renameevent_data.py +62 -0
  39. biomechzoo/processing/split_trial_data.py +40 -0
  40. biomechzoo/statistics/eventval.py +118 -0
  41. biomechzoo/utils/__init__.py +0 -0
  42. biomechzoo/utils/batchdisp.py +21 -0
  43. biomechzoo/utils/compute_sampling_rate_from_time.py +25 -0
  44. biomechzoo/utils/engine.py +88 -0
  45. biomechzoo/utils/findfield.py +11 -0
  46. biomechzoo/utils/get_split_events.py +33 -0
  47. biomechzoo/utils/peak_sign.py +24 -0
  48. biomechzoo/utils/set_zoosystem.py +66 -0
  49. biomechzoo/utils/version.py +5 -0
  50. biomechzoo/utils/zload.py +57 -0
  51. biomechzoo/utils/zplot.py +61 -0
  52. biomechzoo/utils/zsave.py +54 -0
  53. biomechzoo-0.5.9.dist-info/METADATA +46 -0
  54. biomechzoo-0.5.9.dist-info/RECORD +58 -0
  55. biomechzoo-0.5.9.dist-info/WHEEL +5 -0
  56. biomechzoo-0.5.9.dist-info/entry_points.txt +2 -0
  57. biomechzoo-0.5.9.dist-info/licenses/LICENSE +21 -0
  58. biomechzoo-0.5.9.dist-info/top_level.txt +2 -0
@@ -0,0 +1,114 @@
1
+ import pandas as pd
2
+ import os
3
+ import re
4
+
5
+ from biomechzoo.utils.set_zoosystem import set_zoosystem
6
+ from biomechzoo.utils.compute_sampling_rate_from_time import compute_sampling_rate_from_time
7
+
8
+
9
+ def table2zoo_data(fl, extension, skip_rows=0, freq=None):
10
+
11
+ if extension == 'csv':
12
+ df, metadata, freq = _csv2zoo(fl, skip_rows=skip_rows, freq=freq)
13
+
14
+ elif extension == 'parquet':
15
+ df, metadata, freq = _parquet2zoo(fl, skip_rows=skip_rows, freq=freq)
16
+ else:
17
+ raise ValueError('extension {} not implemented'.format(extension))
18
+
19
+ # assemble zoo data
20
+ data = {'zoosystem': set_zoosystem()}
21
+ for ch in df.columns:
22
+ data[ch] = {
23
+ 'line': df[ch].values,
24
+ 'event': []
25
+ }
26
+
27
+
28
+ # now try to calculate freq from a time column
29
+ if freq is None:
30
+ time_col = [col for col in df.columns if 'time' in col.lower()]
31
+ if time_col is not None and len(time_col) > 0:
32
+ time_data = df[time_col].to_numpy()[:, 0]
33
+ freq = compute_sampling_rate_from_time(time_data)
34
+ else:
35
+ raise ValueError('Unable to compute sampling rate for time column, please specify a sampling frequency'
36
+ )
37
+ # add metadata
38
+ data['zoosystem']['Video']['Freq'] = freq
39
+ data['zoosystem']['Analog']['Freq'] = 'None'
40
+
41
+ if metadata is not None:
42
+ data['zoosystem']['Other'] = metadata
43
+
44
+ return data
45
+
46
+
47
+ def _parquet2zoo(fl, skip_rows=0, freq=None):
48
+ df = pd.read_parquet(fl)
49
+ metadata = None
50
+ return df, metadata, freq
51
+
52
+ def _csv2zoo(fl, skip_rows=0, freq=None):
53
+ header_lines = []
54
+ with open(fl, 'r') as f:
55
+ for line in f:
56
+ header_lines.append(line.strip())
57
+ if line.strip().lower() == 'endheader':
58
+ break
59
+ # Parse metadata
60
+ metadata = _parse_metadata(header_lines)
61
+
62
+ # try to find frequency in metadata
63
+ if freq is None:
64
+ if 'freq' in metadata:
65
+ freq = metadata['freq']
66
+ elif 'sampling_rate' in metadata:
67
+ freq = metadata['sampling_rate']
68
+ else:
69
+ freq = None # or raise an error
70
+
71
+ # read csv
72
+ df = pd.read_csv(fl, skiprows=skip_rows)
73
+
74
+ return df, metadata, freq
75
+
76
+
77
+
78
+
79
+ def _parse_metadata(header_lines):
80
+ metadata = {}
81
+ for line in header_lines:
82
+ if '=' in line:
83
+ key, val = line.split('=', 1)
84
+ key = key.strip()
85
+ val = val.strip()
86
+
87
+ # Strip trailing commas and whitespace explicitly
88
+ val = val.rstrip(',').strip()
89
+
90
+ # Extract first numeric token if any
91
+ match = re.search(r'[-+]?\d*\.?\d+', val)
92
+ if match:
93
+ num_str = match.group(0)
94
+ try:
95
+ val_num = int(num_str)
96
+ except ValueError:
97
+ val_num = float(num_str)
98
+ else:
99
+ # Now val should be clean of trailing commas, so just lower case it
100
+ val_num = val.lower()
101
+
102
+ metadata[key] = val_num
103
+ return metadata
104
+
105
+
106
+
107
+
108
+ if __name__ == '__main__':
109
+ """ for unit testing"""
110
+ current_dir = os.path.dirname(os.path.abspath(__file__))
111
+ project_root = os.path.dirname(current_dir)
112
+ csv_file = os.path.join(project_root, 'data', 'other', 'opencap_walking1.csv')
113
+
114
+ data = table2zoo_data(csv_file)
File without changes
File without changes
@@ -0,0 +1,112 @@
1
+ import numpy as np
2
+ import math
3
+ import pandas as pd
4
+ from biomechzoo.processing.addchannel_data import addchannel_data
5
+
6
+ def tilt_algorithm_data(data,ch_vert, ch_medlat, ch_antpost, plot_or_not=None):
7
+
8
+ # extract channels from data
9
+ avert = data[ch_vert]['line']
10
+ amedlat = data[ch_medlat]['line']
11
+ aantpost = data[ch_antpost]['line']
12
+
13
+ _, avert_corr, amedlat_corr, aantpost_corr = tilt_algorithm_line(avert, amedlat, aantpost)
14
+
15
+ data = addchannel_data(data, ch_vert + '_tilt_corr', avert_corr)
16
+ data = addchannel_data(data, ch_medlat + '_tilt_corr', amedlat_corr)
17
+ data = addchannel_data(data, ch_antpost + '_tilt_corr', aantpost_corr)
18
+
19
+ return data
20
+
21
+
22
+ def tilt_algorithm_line(avert, amedlat, aantpost, plot_or_not=None):
23
+ """
24
+ TiltAlgorithm - to account for gravity and improper tilt alignment of a tri-axial trunk accelerometer.
25
+ Step 1: Extract raw measured (mean) accelerations
26
+ Step 2: Calculate tilt angles
27
+ Step 3: Calculate horizontal dynamic accelerations vectors
28
+ Step 4: Calculate estimated provisional vertical vector
29
+ Step 5: Calculate vertical dynamic vector
30
+ step 6.1: Calculate the contribution of static components
31
+ step 6.2 Transpose static component matrices
32
+ step 7: Remove the static components from the templates of pre and post
33
+
34
+ :param avert: signal predominantly in vertical direction
35
+ :param amedlat: signal predominantly in medio-lateral direction
36
+ :param aantpost: signal predominantly in anterior-posterior direction
37
+ :param plot_or_not: whether to plot the results
38
+ :return: dataframe of the tilt corrected and gravity subtracted vertical, medio-lateral and anterior-posterior
39
+ acceleration signals
40
+ """
41
+ #
42
+
43
+ a_vt = avert.mean()
44
+ a_ml = amedlat.mean()
45
+ a_ap = aantpost.mean()
46
+
47
+ # if avert is negative than turn the sensor around.
48
+ if a_vt < 0.5:
49
+ avert *= -1
50
+ amedlat *= -1
51
+ a_vt = avert.mean()
52
+ a_ml = amedlat.mean()
53
+
54
+ # Anterior tilt
55
+ TiltAngle_ap_rad = np.arcsin(a_ap)
56
+ TiltAngle_ap_deg = math.degrees(TiltAngle_ap_rad)
57
+
58
+ # mediolateral tilt
59
+ TiltAngle_ml_rad = np.arcsin(a_ml)
60
+ TiltAngle_ml_deg = math.degrees(TiltAngle_ml_rad)
61
+
62
+ # Anterior posterior
63
+ a_AP = (a_ap * np.cos(TiltAngle_ap_rad)) - (a_vt * np.sin(TiltAngle_ap_rad))
64
+ # AMediolateral
65
+ a_ML = (a_ml * np.cos(TiltAngle_ml_rad)) - (a_vt * np.sin(TiltAngle_ml_rad))
66
+
67
+ # a_vt_prov = a_ap*Sin(theta_ap) + a_vt*Cos(theta_ap)
68
+ a_vt_prov = (a_ap * np.sin(TiltAngle_ap_rad)) + (a_vt * np.cos(TiltAngle_ap_rad))
69
+
70
+ # a_VT = a_ml*sin(theta_ml) + a_vt_prov*cos(theta_ml) - 1
71
+ a_VT = (a_ml * np.sin(TiltAngle_ml_rad)) + (a_vt_prov * np.cos(TiltAngle_ml_rad)) - 1
72
+
73
+ a_AP_static = a_ap - a_AP
74
+ a_ML_static = a_ml - a_ML
75
+ a_VT_static = a_vt - a_VT
76
+
77
+ a_AP_static = np.transpose(a_AP_static)
78
+ a_ML_static = np.transpose(a_ML_static)
79
+ a_VT_static = np.transpose(a_VT_static)
80
+
81
+ amedlat2 = amedlat - a_ML_static
82
+ avert2 = avert - a_VT_static
83
+ aantpost2 = aantpost - a_AP_static
84
+
85
+ data = {'avert': avert2,
86
+ 'amedlat': amedlat2,
87
+ 'aantpost': aantpost2}
88
+ df_corrected = pd.DataFrame(data)
89
+
90
+ # if plot_or_not:
91
+ # f, ax = plt.subplots(nrows=3, ncols=1, sharex=True, dpi=300)
92
+ # sns.despine(offset=10)
93
+ # f.tight_layout()
94
+ # offset = 0.1
95
+ # f.subplots_adjust(left=0.15, top=0.95)
96
+ #
97
+ # sns.lineplot(avert, ax=ax[0], label='Raw')
98
+ # sns.lineplot(avert2, ax=ax[0], label='tilt corrected')
99
+ # ax[0].set_ylabel('vert acc (g)')
100
+ # ax[0].set_title('Vertical acceleration corrected with {}'.format(np.round(a_VT_static, 2)))
101
+ #
102
+ # sns.lineplot(amedlat, ax=ax[1], label='Raw')
103
+ # sns.lineplot(amedlat2, ax=ax[1], label='Tilt corrected')
104
+ # ax[1].set_ylabel('ml acc (g)')
105
+ # ax[1].set_title('Medio-lateral tilt angle corrected with {} degrees'.format(np.round(TiltAngle_ml_deg, 2)))
106
+ #
107
+ # sns.lineplot(aantpost, ax=ax[2], label='Raw')
108
+ # sns.lineplot(aantpost2, ax=ax[2], label='Tilt corrected')
109
+ # ax[2].set_ylabel('ap acc (g)')
110
+ # ax[2].set_title('Anterior-posterior tilt angle corrected with {} degrees'.format(np.round(TiltAngle_ap_deg, 2)))
111
+
112
+ return df_corrected, avert2, amedlat2, aantpost2
File without changes
@@ -0,0 +1,43 @@
1
+ import numpy as np
2
+ from biomechzoo.processing.addchannel_data import addchannel_data
3
+ def compute_magnitude_line(x,y,z):
4
+ magnitude = np.sqrt((x**2) + (y**2) + (z **2))
5
+ return magnitude
6
+
7
+ def compute_magnitude_data(data, ch_x, ch_y, ch_z, ch_new_name=None):
8
+ """
9
+ Compute the magnitude of acceleration data from IMU channels (BiomechZoo format).
10
+
11
+ Returns the magnitude
12
+ """
13
+ # extract channels from data
14
+ x = data[ch_x]['line']
15
+ y = data[ch_y]['line']
16
+ z = data[ch_z]['line']
17
+
18
+ #calculate the magnitude of the data
19
+ magnitude_data = compute_magnitude_line(x,y,z)
20
+
21
+ # get name of new channel:
22
+ if ch_new_name is None:
23
+ ch_new_name = common_substring_or_concat(ch_x, ch_y, ch_z)
24
+
25
+ #add channels
26
+ data = addchannel_data(data, ch_new_name=ch_new_name + '_mag', ch_new_data=magnitude_data )
27
+
28
+ return data
29
+
30
+
31
+ def common_substring_or_concat(str1, str2, str3):
32
+ common = ""
33
+ for i in range(len(str1)):
34
+ for j in range(i + 1, len(str1) + 1):
35
+ sub = str1[i:j]
36
+ if sub in str2 and sub in str3 and len(sub) > len(common):
37
+ common = sub
38
+
39
+ # If no common substring found, concatenate all three
40
+ if not common:
41
+ return str1 + str2 + str3
42
+ return common
43
+
File without changes