OpenIRF 0.2.0__tar.gz → 0.3.0__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (50) hide show
  1. {openirf-0.2.0 → openirf-0.3.0}/PKG-INFO +5 -1
  2. {openirf-0.2.0 → openirf-0.3.0}/README.md +4 -0
  3. openirf-0.3.0/docs/experimental_irf.rst +1 -0
  4. openirf-0.3.0/docs/index.rst +14 -0
  5. openirf-0.3.0/docs/numerical_irf.rst +1 -0
  6. openirf-0.3.0/docs/utils.rst +29 -0
  7. {openirf-0.2.0 → openirf-0.3.0}/pyproject.toml +3 -0
  8. {openirf-0.2.0 → openirf-0.3.0}/src/OpenIRF.egg-info/PKG-INFO +5 -1
  9. {openirf-0.2.0 → openirf-0.3.0}/src/OpenIRF.egg-info/SOURCES.txt +6 -0
  10. {openirf-0.2.0 → openirf-0.3.0}/src/OpenIRF.egg-info/scm_file_list.json +6 -0
  11. openirf-0.3.0/src/OpenIRF.egg-info/scm_version.json +8 -0
  12. {openirf-0.2.0 → openirf-0.3.0}/src/openirf/experimental_irf.py +93 -79
  13. openirf-0.3.0/src/openirf/logo_small.png +0 -0
  14. {openirf-0.2.0 → openirf-0.3.0}/src/openirf/numerical_irf.py +1 -1
  15. openirf-0.3.0/src/openirf/utils.py +872 -0
  16. openirf-0.3.0/tests/experimental_irf_calculation_test.py +396 -0
  17. openirf-0.3.0/tests/experimental_time_series_plot_test.py +463 -0
  18. openirf-0.3.0/tests/interactive_retrigger_test.py +846 -0
  19. openirf-0.3.0/tests/plot_style_test.py +127 -0
  20. openirf-0.3.0/tests/retrigger_data_test.py +263 -0
  21. {openirf-0.2.0 → openirf-0.3.0}/tests/string_print_test.py +5 -3
  22. openirf-0.3.0/tests/time_series_import_test.py +409 -0
  23. openirf-0.2.0/docs/experimental_irf.rst +0 -1
  24. openirf-0.2.0/docs/index.rst +0 -6
  25. openirf-0.2.0/docs/numerical_irf.rst +0 -1
  26. openirf-0.2.0/src/OpenIRF.egg-info/scm_version.json +0 -8
  27. openirf-0.2.0/src/openirf/utils.py +0 -165
  28. openirf-0.2.0/tests/retrigger_data_test.py +0 -236
  29. openirf-0.2.0/tests/time_series_import_test.py +0 -324
  30. {openirf-0.2.0 → openirf-0.3.0}/.gitignore +0 -0
  31. {openirf-0.2.0 → openirf-0.3.0}/.gitlab-ci.yml +0 -0
  32. {openirf-0.2.0 → openirf-0.3.0}/.readthedocs.yaml +0 -0
  33. {openirf-0.2.0 → openirf-0.3.0}/.vscode/settings.json +0 -0
  34. {openirf-0.2.0 → openirf-0.3.0}/LICENSE +0 -0
  35. {openirf-0.2.0 → openirf-0.3.0}/docs/Makefile +0 -0
  36. {openirf-0.2.0 → openirf-0.3.0}/docs/conf.py +0 -0
  37. {openirf-0.2.0 → openirf-0.3.0}/docs/make.bat +0 -0
  38. {openirf-0.2.0 → openirf-0.3.0}/docs/requirements.in +0 -0
  39. {openirf-0.2.0 → openirf-0.3.0}/docs/requirements.txt +0 -0
  40. {openirf-0.2.0 → openirf-0.3.0}/requirements.txt +0 -0
  41. {openirf-0.2.0 → openirf-0.3.0}/requirements_dev.txt +0 -0
  42. {openirf-0.2.0 → openirf-0.3.0}/ruff.toml +0 -0
  43. {openirf-0.2.0 → openirf-0.3.0}/setup.cfg +0 -0
  44. {openirf-0.2.0 → openirf-0.3.0}/src/OpenIRF.egg-info/dependency_links.txt +0 -0
  45. {openirf-0.2.0 → openirf-0.3.0}/src/OpenIRF.egg-info/requires.txt +0 -0
  46. {openirf-0.2.0 → openirf-0.3.0}/src/OpenIRF.egg-info/top_level.txt +0 -0
  47. {openirf-0.2.0 → openirf-0.3.0}/src/openirf/__init__.py +0 -0
  48. {openirf-0.2.0 → openirf-0.3.0}/tests/convolution_matrix_test.py +0 -0
  49. {openirf-0.2.0 → openirf-0.3.0}/tests/mck_import_test.py +0 -0
  50. {openirf-0.2.0 → openirf-0.3.0}/tests/numerical_irf_test.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: OpenIRF
3
- Version: 0.2.0
3
+ Version: 0.3.0
4
4
  Summary: An Open-Source Package for Impulse Response Function Estimation of Mechanical Systems
5
5
  Author-email: Oliver Maximilian Zobel <oliver.zobel@tum.de>
6
6
  License-Expression: MIT
@@ -35,3 +35,7 @@ A collection of tools for the time domain analysis of mechanical systems.
35
35
  To install OpenIRF through pip, use the following command:
36
36
 
37
37
  `pip install openirf`
38
+
39
+ ## AI Usage Disclosure
40
+
41
+ Claude Code was used to create parts of the tests and plotting functions, as well as to set up the project infrastructure, packaging, and the documentation infrastructure. The main computation code was written by humans and verified using real data.
@@ -13,3 +13,7 @@ A collection of tools for the time domain analysis of mechanical systems.
13
13
  To install OpenIRF through pip, use the following command:
14
14
 
15
15
  `pip install openirf`
16
+
17
+ ## AI Usage Disclosure
18
+
19
+ Claude Code was used to create parts of the tests and plotting functions, as well as to set up the project infrastructure, packaging, and the documentation infrastructure. The main computation code was written by humans and verified using real data.
@@ -0,0 +1 @@
1
+ .. image:: ../src/openirf/logo_small.png
2
  :members:
@@ -0,0 +1,14 @@
1
+ .. image:: ../src/openirf/logo_small.png
2
+ :alt: OpenIRF
3
+ :align: center
4
+ :width: 80%
5
+
6
+ **An Open-Source Package for Impulse Response Function Estimation of Mechanical Systems**
7
+
8
+ OpenIRF Documentation
9
+ =======================
10
+
11
+ .. toctree::
12
+ numerical_irf
13
+ experimental_irf
14
+ utils
@@ -0,0 +1 @@
1
+ .. image:: ../src/openirf/logo_small.png
2
  :members:
@@ -0,0 +1,29 @@
1
+ .. image:: ../src/openirf/logo_small.png
2
+ :alt: OpenIRF
3
+ :align: center
4
+ :width: 80%
5
+
6
+ Utility Functions
7
+ =================
8
+
9
+ Interactive Selection Tools
10
+ ---------------------------
11
+
12
+ .. autofunction:: openirf.interactive_retrigger
13
+
14
+ Plotting Functions
15
+ ------------------
16
+
17
+ .. autofunction:: openirf.experimental_time_series_plot
18
+
19
+ .. autofunction:: openirf.numerical_irf_plot
20
+
21
+ General Utility Functions
22
+ -------------------------
23
+
24
+ .. autofunction:: openirf.build_convolution_matrix
25
+
26
+ .. autofunction:: openirf.newmark_integration
27
+
28
+ .. autofunction:: openirf.extract_impulse_time_series
29
+
@@ -31,6 +31,9 @@ classifiers = [
31
31
  [project.urls]
32
32
  Homepage = "https://gitlab.com/opentds/openirf"
33
33
 
34
+ [tool.setuptools.package-data]
35
+ openirf = ["*.png"]
36
+
34
37
  [tool.setuptools_scm]
35
38
  version_scheme = "post-release"
36
39
  local_scheme = "node-and-date"
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: OpenIRF
3
- Version: 0.2.0
3
+ Version: 0.3.0
4
4
  Summary: An Open-Source Package for Impulse Response Function Estimation of Mechanical Systems
5
5
  Author-email: Oliver Maximilian Zobel <oliver.zobel@tum.de>
6
6
  License-Expression: MIT
@@ -35,3 +35,7 @@ A collection of tools for the time domain analysis of mechanical systems.
35
35
  To install OpenIRF through pip, use the following command:
36
36
 
37
37
  `pip install openirf`
38
+
39
+ ## AI Usage Disclosure
40
+
41
+ Claude Code was used to create parts of the tests and plotting functions, as well as to set up the project infrastructure, packaging, and the documentation infrastructure. The main computation code was written by humans and verified using real data.
@@ -16,6 +16,7 @@ docs/make.bat
16
16
  docs/numerical_irf.rst
17
17
  docs/requirements.in
18
18
  docs/requirements.txt
19
+ docs/utils.rst
19
20
  src/OpenIRF.egg-info/PKG-INFO
20
21
  src/OpenIRF.egg-info/SOURCES.txt
21
22
  src/OpenIRF.egg-info/dependency_links.txt
@@ -25,11 +26,16 @@ src/OpenIRF.egg-info/scm_version.json
25
26
  src/OpenIRF.egg-info/top_level.txt
26
27
  src/openirf/__init__.py
27
28
  src/openirf/experimental_irf.py
29
+ src/openirf/logo_small.png
28
30
  src/openirf/numerical_irf.py
29
31
  src/openirf/utils.py
30
32
  tests/convolution_matrix_test.py
33
+ tests/experimental_irf_calculation_test.py
34
+ tests/experimental_time_series_plot_test.py
35
+ tests/interactive_retrigger_test.py
31
36
  tests/mck_import_test.py
32
37
  tests/numerical_irf_test.py
38
+ tests/plot_style_test.py
33
39
  tests/retrigger_data_test.py
34
40
  tests/string_print_test.py
35
41
  tests/time_series_import_test.py
@@ -14,17 +14,23 @@
14
14
  "docs/numerical_irf.rst",
15
15
  "docs/requirements.in",
16
16
  "docs/requirements.txt",
17
+ "docs/utils.rst",
17
18
  "pyproject.toml",
18
19
  "requirements.txt",
19
20
  "requirements_dev.txt",
20
21
  "ruff.toml",
21
22
  "src/openirf/__init__.py",
22
23
  "src/openirf/experimental_irf.py",
24
+ "src/openirf/logo_small.png",
23
25
  "src/openirf/numerical_irf.py",
24
26
  "src/openirf/utils.py",
25
27
  "tests/convolution_matrix_test.py",
28
+ "tests/experimental_irf_calculation_test.py",
29
+ "tests/experimental_time_series_plot_test.py",
30
+ "tests/interactive_retrigger_test.py",
26
31
  "tests/mck_import_test.py",
27
32
  "tests/numerical_irf_test.py",
33
+ "tests/plot_style_test.py",
28
34
  "tests/retrigger_data_test.py",
29
35
  "tests/string_print_test.py",
30
36
  "tests/time_series_import_test.py"
@@ -0,0 +1,8 @@
1
+ {
2
+ "tag": "0.3.0",
3
+ "distance": 0,
4
+ "node": "g8d2df7f4a383fb6659b88fe05767fddceada62e4",
5
+ "dirty": false,
6
+ "branch": "HEAD",
7
+ "node_date": "2026-08-31"
8
+ }
@@ -12,9 +12,10 @@ class ExperimentalIRF:
12
12
 
13
13
  Shape of time series arrays
14
14
  ---------------------------
15
- - 3D: Multiple dofs, multiple measurements (dof,number_of_measurements,points)
16
- - 2D: Single dof, multiple measurements (number_of_measurements,points)
17
- - 1D: Single dof, one measurement (points)
15
+ - SISO: ``y_vec`` with shape ``(n_t)``, ``f_vec`` with shape ``(n_t)``
16
+ - SISO with averaging: ``y_vec`` with shape ``(n_avg,n_t)``, ``f_vec`` with shape ``(n_avg,n_t)``
17
+ - MIMO: ``y_vec`` with shape ``(n_resp, n_exc, n_t)``, ``f_vec`` with shape ``(n_exc, n_t)``
18
+ - MIMO with averaging: ``y_vec`` with shape ``(n_resp, n_exc, n_avg, n_t)``, ``f_vec`` with shape ``(n_exc, n_avg, n_t)``
18
19
 
19
20
  Constraints
20
21
  -----------
@@ -26,25 +27,25 @@ class ExperimentalIRF:
26
27
  ----------
27
28
  :param t_vec: Time vector of time series ``y_vec`` and ``f_vec``.
28
29
  :type t_vec: ndarray
29
- :param y_vec: Time series of system responses.
30
+ :param y_vec: Time series of the system responses.
30
31
  :type y_vec: ndarray
31
- :param f_vec: Time series of applied forces.
32
+ :param f_vec: Time series of the applied forces.
32
33
  :type f_vec: ndarray
33
34
  :param H: Calculated IRF matrix.
34
35
  :type H: ndarray
35
- :param t_vec_IRF: Time vector for calculated IRFs.
36
+ :param t_vec_IRF: Time vector for the calculated IRFs.
36
37
  :type t_vec_IRF: ndarray
37
38
 
38
39
  """
39
40
 
40
41
  # Declare parameters as attributes
41
42
  t_vec = np.empty(0)
42
- y_vec = np.empty((0, 0, 0))
43
+ y_vec = np.empty((0, 0, 0, 0))
43
44
  f_vec = np.empty((0, 0, 0))
44
45
  H = np.empty((0, 0, 0))
45
46
  t_vec_IRF = np.empty(0)
46
47
 
47
- def __init__(self, t_vec=np.empty((0)), y_vec=np.empty((0, 0, 0)), f_vec=np.empty((0, 0, 0))):
48
+ def __init__(self, y_vec=np.empty((0, 0, 0, 0)), f_vec=np.empty((0, 0, 0)), t_vec=np.empty((0))):
48
49
  # Initialize ExperimentalIRF class with provided data
49
50
  if t_vec.size != 0:
50
51
  self.t_vec = convert_to_1d_array(t_vec)
@@ -52,24 +53,6 @@ class ExperimentalIRF:
52
53
  if y_vec.size != 0 or f_vec.size != 0:
53
54
  self.add_time_series(y_vec, f_vec, t_vec=self.t_vec)
54
55
 
55
- # Convert any array passed to ExperimentalIRF into a 3D array for concise internal storage.
56
- def _convert_to_3d_array(self, array):
57
- # Input convention:
58
- # 3D: Multiple dofs, multiple measurements (dof,number_of_measurements,points)
59
- # 2D: Single dof, multiple measurements (number_of_measurements,points)
60
- # 1D: Single dof, one measurement (points)
61
-
62
- if array.ndim == 1:
63
- array = array[np.newaxis, np.newaxis, :]
64
- elif array.ndim == 2:
65
- array = array[np.newaxis, :, :]
66
- elif array.ndim == 3:
67
- pass
68
- else:
69
- raise ValueError(f"Expected 1D, 2D, or 3D array. Got {array.ndim}D.")
70
-
71
- return array
72
-
73
56
  def __str__(self):
74
57
  # Prints a formatted object summary of the ExperimentalIRF object
75
58
  def print_array(arr):
@@ -100,9 +83,10 @@ class ExperimentalIRF:
100
83
 
101
84
  Shape of time series arrays
102
85
  ---------------------------
103
- - 3D: Multiple dofs, multiple measurements (dof,number_of_measurements,points)
104
- - 2D: Single dof, multiple measurements (number_of_measurements,points)
105
- - 1D: Single dof, one measurement (points)
86
+ - SISO: ``y_vec`` with shape ``(n_t)``, ``f_vec`` with shape ``(n_t)``
87
+ - SISO with averaging: ``y_vec`` with shape ``(n_avg,n_t)``, ``f_vec`` with shape ``(n_avg,n_t)``
88
+ - MIMO: ``y_vec`` with shape ``(n_resp, n_exc, n_t)``, ``f_vec`` with shape ``(n_exc, n_t)``
89
+ - MIMO with averaging: ``y_vec`` with shape ``(n_resp, n_exc, n_avg, n_t)``, ``f_vec`` with shape ``(n_exc, n_avg, n_t)``
106
90
 
107
91
  Constraints
108
92
  -----------
@@ -114,17 +98,30 @@ class ExperimentalIRF:
114
98
  ----------
115
99
  :param t_vec: Time vector of time series ``y_vec`` and ``f_vec``.
116
100
  :type t_vec: ndarray
117
- :param y_vec: Time series of system responses.
101
+ :param y_vec: Time series of the system responses.
118
102
  :type y_vec: ndarray
119
- :param f_vec: Time series of applied forces.
103
+ :param f_vec: Time series of the applied forces.
120
104
  :type f_vec: ndarray, optional
121
105
 
122
106
  """
123
107
  # Shape input data
124
108
  if t_vec is not None:
125
109
  t_vec = convert_to_1d_array(t_vec)
126
- y_vec = self._convert_to_3d_array(y_vec)
127
- f_vec = self._convert_to_3d_array(f_vec)
110
+
111
+ # Detect input data mode
112
+ if y_vec.ndim == 1 and f_vec.ndim == 1: # SISO
113
+ f_vec = f_vec[np.newaxis, np.newaxis, :]
114
+ y_vec = y_vec[np.newaxis, np.newaxis, np.newaxis, :]
115
+ elif y_vec.ndim == 2 and f_vec.ndim == 2: # SISO with averaging
116
+ f_vec = f_vec[np.newaxis, :]
117
+ y_vec = y_vec[np.newaxis, np.newaxis, :, :]
118
+ elif y_vec.ndim == 3 and f_vec.ndim == 2: # SISO with averaging
119
+ f_vec = f_vec[:, np.newaxis, :]
120
+ y_vec = y_vec[:, :, np.newaxis, :]
121
+ elif y_vec.ndim == 4 and f_vec.ndim == 3: # SISO with averaging
122
+ pass
123
+ else:
124
+ raise Exception("Shape of provided time series for y_vec and f_vec does not match a supported format.")
128
125
 
129
126
  # Input check - Time Vector
130
127
  if self.t_vec.size != 0 and t_vec is not None:
@@ -135,15 +132,21 @@ class ExperimentalIRF:
135
132
  raise Exception("No t_vec provided for data.")
136
133
  self.t_vec = t_vec
137
134
 
138
- # Input check - Data
135
+ # Input Check - Number of time samples
139
136
  if y_vec.shape[-1] != len(self.t_vec):
140
137
  raise Exception("Provided y_vec does not match length of stored t_vec.")
141
138
  if f_vec.shape[-1] != len(self.t_vec):
142
139
  raise Exception("Provided f_vec does not match length of stored t_vec.")
143
140
 
141
+ # Input Check - Match of n_exc, and n_avg dimensions
142
+ if y_vec.shape[1] != f_vec.shape[0]: # Mismatch of n_exc axis
143
+ raise Exception("Number of excitation dofs in y_vec and f_vec does not match.")
144
+ if y_vec.shape[2] != f_vec.shape[1]: # Mismatch of n_avg axis
145
+ raise Exception("Number of averages in y_vec and f_vec does not match.")
146
+
144
147
  if self.y_vec.size != 0: # Only y_vec or f_vec must be checked here, since they can only be initialized in pairs.
145
- y_vec_new = np.append(self.y_vec, y_vec, axis=0)
146
- f_vec_new = np.append(self.f_vec, f_vec, axis=0)
148
+ y_vec_new = np.append(self.y_vec, y_vec, axis=2)
149
+ f_vec_new = np.append(self.f_vec, f_vec, axis=1)
147
150
  else:
148
151
  y_vec_new = y_vec
149
152
  f_vec_new = f_vec
@@ -164,32 +167,34 @@ class ExperimentalIRF:
164
167
  :type trigger_level: float
165
168
 
166
169
  """
167
- n_dof = self.y_vec.shape[0]
168
- n_run = self.y_vec.shape[1]
169
- t_trigg_idx = np.zeros(n_run, dtype=int)
170
+ n_resp_dof = self.y_vec.shape[0] # Response dofs
171
+ n_exc_dof = self.y_vec.shape[1] # Excitation dofs
172
+ n_avg = self.y_vec.shape[2]
173
+ t_trigg_idx = np.zeros((n_exc_dof, n_avg), dtype=int)
174
+ t_vec_len_old = len(self.t_vec)
170
175
 
171
176
  # Get trigger index for each provided force time series
172
- for run in range(0, n_run):
173
- while self.f_vec[0, run, t_trigg_idx[run]] < trigger_level:
174
- t_trigg_idx[run] += 1
177
+ for exc_dof in range(0, n_exc_dof):
178
+ for run in range(0, n_avg):
179
+ t_trigg_idx[exc_dof, run] = get_trigger_index(self.f_vec[exc_dof, run], trigger_level)
175
180
 
176
181
  # Construct trimmed time vector
177
182
  self.t_vec = self.t_vec[np.max(t_trigg_idx) :] - self.t_vec[np.max(t_trigg_idx)]
178
- new_len = len(self.t_vec)
183
+ t_vec_len_new = len(self.t_vec)
179
184
 
180
185
  # Trim force and response time series
181
- y_vec_trimmed = np.zeros([n_dof, n_run, new_len])
182
- f_vec_trimmed = np.zeros([1, n_run, new_len])
183
-
184
- for run in range(0, n_run):
185
- idx = t_trigg_idx[run]
186
- f_vec_trimmed[0, run] = self.f_vec[0, run, idx : idx + new_len]
186
+ y_vec_trimmed = np.zeros([n_resp_dof, n_exc_dof, n_avg, t_vec_len_new])
187
+ f_vec_trimmed = np.zeros([n_exc_dof, n_avg, t_vec_len_new])
187
188
 
188
- for dof in range(0, n_dof):
189
- y_vec_trimmed[dof, run] = self.y_vec[dof, run, idx : idx + new_len]
189
+ for exc_dof in range(0, n_exc_dof):
190
+ for run in range(0, n_avg):
191
+ idx = t_trigg_idx[exc_dof, run]
192
+ f_vec_trimmed[exc_dof, run] = self.f_vec[exc_dof, run, idx : idx + t_vec_len_new]
193
+ y_vec_trimmed[:, exc_dof, run] = self.y_vec[:, exc_dof, run, idx : idx + t_vec_len_new]
190
194
 
191
195
  self.y_vec = y_vec_trimmed
192
196
  self.f_vec = f_vec_trimmed
197
+ print(f"[OpenIRF]: Time data retriggered. Length of t_vec {t_vec_len_old} -> {t_vec_len_new}.")
193
198
 
194
199
  def calculate_IRF(self, t_len, extract_impulse=True, resp_dofs=None, exci_dofs=None, deconvolve_type="truncated_convolution", averaged_runs="all"):
195
200
  """
@@ -224,53 +229,62 @@ class ExperimentalIRF:
224
229
 
225
230
  """
226
231
 
232
+ n_resp_dof = self.y_vec.shape[0] # Response dofs
233
+ n_exc_dof = self.y_vec.shape[1] # Excitation dofs
234
+
227
235
  # Selection of runs to average
228
236
  if np.all(averaged_runs == "all"):
229
237
  f_vec = self.f_vec
230
238
  y_vec = self.y_vec
231
239
  else:
232
240
  f_vec = self.f_vec[:, averaged_runs]
233
- y_vec = self.y_vec[:, averaged_runs]
241
+ y_vec = self.y_vec[:, :, averaged_runs]
242
+
243
+ n_avg = y_vec.shape[2] # Number of averages considering the user selection
234
244
 
245
+ # Determin index for requested IRF length
235
246
  h_len = np.argmin(np.abs(self.t_vec - t_len))
236
247
 
237
- y_vec_trimmed = y_vec[:, :, 0:h_len]
248
+ # Trim responses to requested length
249
+ y_vec_trimmed = y_vec[:, :, :, 0:h_len]
238
250
 
239
- F_exp_list = []
251
+ # Preallocate final IRF matrix
252
+ H = np.zeros([n_resp_dof, n_exc_dof, h_len])
240
253
 
241
- # Build force convolution matrices
242
- for idx in tqdm(range(0, f_vec.shape[1]), desc="[OpenIRF]: Building Force Convolution Matrices"):
243
- if extract_impulse:
244
- f_vec_trimmed = extract_impulse_time_series(f_vec[:, idx], self.t_vec)
245
- else:
246
- f_vec_trimmed = f_vec[:, idx]
254
+ for exc_dof in range(0, n_exc_dof): # Loop over the different force excitation dofs
255
+ F_exp_list = []
247
256
 
248
- # Trim to requested IRF length
249
- f_vec_trimmed = f_vec_trimmed[0:h_len]
257
+ # Build force convolution matrices
258
+ for run in tqdm(range(0, n_avg), desc=f"[OpenIRF]: Building Force Convolution Matrices for excitation dof ({exc_dof + 1}/{n_exc_dof})"):
259
+ if extract_impulse:
260
+ f_vec_trimmed = extract_impulse_time_series(f_vec[exc_dof, run], self.t_vec)
261
+ else:
262
+ f_vec_trimmed = f_vec[exc_dof, run]
250
263
 
251
- # Build force convolution matrix
252
- F_exp_run = build_convolution_matrix(f_vec_trimmed)
264
+ # Trim to requested IRF length
265
+ f_vec_trimmed = f_vec_trimmed[0:h_len]
253
266
 
254
- F_exp_list.append(F_exp_run)
267
+ # Build force convolution matrix
268
+ F_exp_run = build_convolution_matrix(f_vec_trimmed)
255
269
 
256
- # Build and invert auto-correlation matrix
257
- F_exp = np.vstack(F_exp_list)
258
- R = F_exp.transpose() @ F_exp
259
- R_inv = np.linalg.inv(R)
270
+ F_exp_list.append(F_exp_run)
260
271
 
261
- # Build pseudo-inverse
262
- F_plus = R_inv @ F_exp.transpose()
272
+ # Build and invert auto-correlation matrix
273
+ F_exp = np.vstack(F_exp_list)
274
+ R = F_exp.transpose() @ F_exp
275
+ R_inv = np.linalg.inv(R)
263
276
 
264
- # Cleanup temporary variables
265
- del F_exp_run, F_exp_list, R, R_inv, F_exp
277
+ # Build pseudo-inverse
278
+ F_plus = R_inv @ F_exp.transpose()
266
279
 
267
- H = np.zeros([y_vec_trimmed.shape[0], f_vec.shape[0], h_len])
280
+ # Cleanup temporary variables
281
+ del F_exp_run, F_exp_list, R, R_inv, F_exp
268
282
 
269
- # Build stacked response vector and calculate IRF
270
- for dof in tqdm(range(0, y_vec_trimmed.shape[0]), desc="[OpenIRF]: Calculating IRFs"):
271
- y_stacked = y_vec_trimmed[dof].reshape(-1)
272
- H[dof, 0] = F_plus @ y_stacked / self.t_vec[1]
283
+ # Build stacked response vector and calculate IRF
284
+ for resp_dof in tqdm(range(0, n_resp_dof), desc=f"[OpenIRF]: Calculating Experimental IRFs for excitation dof ({exc_dof + 1}/{n_exc_dof})"):
285
+ y_stacked = y_vec_trimmed[resp_dof, exc_dof].reshape(-1)
286
+ H[resp_dof, exc_dof] = F_plus @ y_stacked / self.t_vec[1]
273
287
 
274
- # Assign H to class instance
288
+ # Assign IRF matrix to class instance
275
289
  self.H = H
276
290
  self.t_vec_IRF = self.t_vec[:h_len]
Binary file
@@ -55,7 +55,7 @@ class NumericalIRF:
55
55
  def __init__(self, M=np.empty((0, 0)), C=np.empty((0, 0)), K=np.empty((0, 0))):
56
56
  # Initialize NumericalIRF class with provided data
57
57
  if M.size == 0 and K.size != 0:
58
- raise Exception("No mass matrix M was provided.") # noqa: TRY002
58
+ raise Exception("No mass matrix M was provided.")
59
59
  elif K.size == 0 and M.size != 0:
60
60
  raise Exception("No stiffness matrix K was provided.")
61
61
  elif M.size == 0 and K.size == 0 and C.size != 0: