fosanalysis
A framework to evaluate distributed fiber optic sensor data
Loading...
Searching...
No Matches
resizing.py
Go to the documentation of this file.
2r"""
3Contains functionality for resizing data:
4- Reduce 2D to 1D (or 0D): \ref Aggregate.
5- Combining several readings into one using aggregate functions: \ref Downsampler.
6- Changing spatial or temporal spacing of data using interpolation: \ref Resampler.
7
8\author Bertram Richter
9\date 2024
10"""
11
12from abc import abstractmethod
13import datetime
14import numpy as np
15import scipy
16
17from . import base
18from fosanalysis.utils import cropping, misc, windows
19from fosanalysis.utils.interpolation import scipy_interpolate1d
20
21
23 r"""
24 Base class for algorithms to replace/remove missing data with plausible values.
25 The sub-classes will take data containing dropouts (`NaN`s) and will return dropout-free data.
26 This is done by replacing the dropouts by plausible values and/or removing dropouts.
27 Because the shape of the arrays might be altered, \ref run() expects
28 and returns
29 - `x`: array of the the positional data along the sensor.
30 - `y`: array of the time stamps, and
31 - `z`: array of the strain data.
32 """
33
35 r"""
36 Change the dimension of an array using aggregate functions (such as
37 mean, median, min or max).
38 It can be used to reduce 2D to 1D strain data.
39 """
40 def __init__(self,
41 method: str or callable,
42 module = np,
43 timespace: str = "1d_space",
44 *args, **kwargs):
45 r"""
46 Construct an instance of the class.
47 \param method A string or callable representing the method.
48 \param module The module (default is numpy).
49 \param timespace \copybrief timespace For more, see \ref timespace.
50 \param *args Additional positional arguments, will be passed to the superconstructor.
51 \param **kwargs Additional keyword arguments, will be passed to the superconstructor.
52 """
53 super().__init__(*args, **kwargs)
54
67 self.timespace = timespace
68 self.setup(method, module)
69 def setup(self,
70 method: str or callable,
71 module = np):
72 r"""
73 Set the \ref kernel method for data processing, which can be
74 either a string representing function name in a given namespace
75 \ref module or a custom callable function.
76 If `"method"` is a string, retrieve the corresponding function from the specified module.
77 If `"method"` is a custom callable function, directly set it as the processing method.
78 \param method \copydoc method
79 \param module \copydoc module
80 """
81
83 self.method = method
84
86 self.module = module
87
89 self.kernel = method if callable(method) else getattr(module, method)
90 def run(self,
91 x: np.array,
92 y: np.array,
93 z: np.array,
94 timespace: str = None,
95 make_copy: bool = True,
96 *args, **kwargs) -> np.array:
97 r"""
98 Reduce a 2D array to a 1D array using aggregate functions.
99 The aggregate function is implemented in \ref reduce().
100 The array of the crushed axis is set to `np.array(None)`.
101 \param x Array of measuring point positions.
102 \param y Array of time stamps.
103 \param z Array of strain data in accordance to `x` and `y`.
104 \param timespace \copybrief timespace For more, see \ref timespace.
105 \param make_copy Switch, whether a deepcopy of the passed data should be done.
106 Defaults to `True`.
107 \param *args Additional positional arguments to customize the behaviour.
108 \param **kwargs Additional keyword arguments to customize the behaviour.
109 \return Returns a tuple like `(x, y, z)`.
110 They correspond to the input variables of the same name.
111 The resulting shape of the return values depending on \ref
112 timespace is as follows:
113
114 |`"timespace"`| x | y | z |
115 |:----------: |:--------------:|:--------------:|:----------------------:|
116 |`"1d_space"` | x |`np.array(None)`|1d array, same size as x|
117 |`"1d_time"` |`np.array(None)`| y |1d array, same size as y|
118 | `"2d"` |`np.array(None)`|`np.array(None)`| np.array(float) |
119 """
120 x, y, z = super().run(x, y, z, make_copy=make_copy, *args, **kwargs)
121 timespace = timespace if timespace is not None else self.timespace
122 if z.ndim == 1:
123 return x, y, z
124 elif z.ndim ==2:
125 axis = None
126 if timespace.lower() == "1d_space":
127 y = np.array(None)
128 axis = 0
129 elif timespace.lower() == "1d_time":
130 x = np.array(None)
131 axis = 1
132 reduced_array = self.reduce(z, axis, *args, **kwargs).flatten()
133 return x, y, reduced_array
134 else:
135 raise ValueError("Array is neither 1D nor 2D.")
136 def reduce(self,
137 data: np.array,
138 axis: int,
139 *args, **kwargs) -> np.array:
140 r"""
141 Reduce the given array using the \ref kernel funcition.
142 \param data Array of data with functional data according to `data`.
143 \param axis Axis in which the data should be consolidated.
144 This is in accordance with the `numpy` axis definitions.
145 \param *args Additional positional arguments, passed to \ref kernel.
146 \param **kwargs Additional keyword arguments, passed to \ref kernel.
147 \return Returns an array, where multiple readings are combined to one single array.
148 """
149 return self.kernel(data, axis=axis, *args, **kwargs)
150
152 r"""
153 Object, for cropping data sets and saving the preset.
154 """
155 def __init__(self,
156 start_pos: float = None,
157 end_pos: float = None,
158 length: float = None,
159 offset: float = None,
160 *args, **kwargs):
161 r"""
162 Construct an instance of the class.
163 \param start_pos \copydoc start_pos
164 \param end_pos \copydoc end_pos
165 \param length \copydoc length
166 \param offset \copydoc offset
167 \param *args Additional positional arguments, will be passed to the superconstructor.
168 \param **kwargs Additional keyword arguments, will be passed to the superconstructor.
169 """
170 super().__init__(*args, **kwargs)
171
173 self.start_pos = start_pos
174
177 self.end_pos = end_pos
178
179 self.offset = offset
180
182 self.length = length
183 def run(self,
184 x: np.array,
185 y: np.array,
186 z: np.array,
187 start_pos: float = None,
188 end_pos: float = None,
189 length: float = None,
190 offset: float = None,
191 *args, **kwargs) -> tuple:
192 r"""
193 This is a wrapper around \ref cropping.cropping() which.
194 \param x Array of measuring point positions.
195 \param y Array of time stamps.
196 \param z Array of strain data in accordance to `x` and `y`.
197 \param start_pos The starting position \f$s\f$ specifies the length of the sensor, before entering the measurement area.
198 Defaults to `None` (no data is removed at the beginning).
199 \param end_pos The end position \f$s\f$ specifies the length of the sensor, when leaving the measurement area.
200 If both `length` and `end_pos` are provided, `end_pos` takes precedence.
201 Defaults to `None` (no data is removed at the end).
202 \param length Length of the data excerpt. If set, it is used to determine the `end_pos`.
203 If both `length` and `end_pos` are provided, `end_pos` takes precedence.
204 \param offset Before cropping, \f$x\f$ data is shifted by the offset \f$o\f$, such that \f$x \gets x + o\f$, defaults to `0`.
205 \param *args Additional positional arguments, passed to \ref cropping.cropping().
206 \param **kwargs Additional keyword arguments, passed to \ref cropping.cropping().
207 """
208 start_pos = start_pos if start_pos is not None else self.start_pos
209 end_pos = end_pos if end_pos is not None else self.end_pos
210 length = length if length is not None else self.length
211 offset = offset if offset is not None else self.offset
212 x_cropped, z_cropped = cropping.cropping(x_values=x,
213 z_values=z,
214 start_pos=start_pos,
215 end_pos=end_pos,
216 length=length,
217 offset=offset,
218 *args, **kwargs)
219 return x_cropped, y, z_cropped
220
222 r"""
223 Class for reducing strain data size while keeping the data loss small
224 by combining several values into one value.
225 To achieve this, windows with a specified size (see \ref radius) are
226 placed on the original data in a regular grid of fixed \ref step_size
227 and a fixed \ref start_pixel.
228 Each window is then aggregated to one value, see \ref Aggregate.
229 In contrast to \ref Resampler, the grid is specified by array indices.
230 """
231 def __init__(self,
232 aggregator: Aggregate,
233 radius: int = None,
234 start_pixel: int = None,
235 step_size: int = None,
236 *args, **kwargs):
237 r"""
238 Initialize the down sampler.
239 This method can be extended for any necessary initialization logic.
240 \param aggregator An instance of `Aggregate` used for aggregation.
241 \param radius \copydoc radius
242 \param start_pixel \copydoc start_pixel
243 \param step_size \copydoc step_size
244 \param *args Additional positional arguments, will be passed to the superconstructor.
245 \param **kwargs Additional keyword arguments, will be passed to the superconstructor.
246 """
247 super().__init__(*args, **kwargs)
248
249 self.aggregator = aggregator
250
257 self.radius = radius
258
264 self.start_pixel = start_pixel
265
269 self.step_size = step_size
270 def run(self,
271 x: np.array,
272 y: np.array,
273 z: np.array,
274 radius: tuple = None,
275 start_pixel: tuple = None,
276 step_size: tuple = None,
277 ) -> tuple:
278 r"""
279 This method downsamples 2D and 1D Strain data using specified parameters.
280 \param x Array of x-axis values.
281 \param y Array of time-axis values.
282 \param z 2D array of strain data.
283 \param radius \copydoc radius
284 \param start_pixel \copydoc start_pixel
285 \param step_size \copydoc step_size
286 \return Tuple containing `(target_x_points, target_time_points, new_z)`.
287 \retval target_x_points The x-axis values after downsampling.
288 \retval target_time_points The time-axis values after downsampling.
289 \retval new_z Array of downsampled strain data.
290 """
291 x = np.array(x)
292 y = np.array(y)
293 z = np.array(z)
294 # Fall back to defaults if these parameters are not given
295 radius = radius if radius is not None else self.radius
296 start_pixel = start_pixel if start_pixel is not None else self.start_pixel
297 step_size = step_size if step_size is not None else self.step_size
298 # Estimate original indices for reduction of x and time arrays
299 moving_params = windows.determine_moving_parameters(
300 z, radius, start_pixel, step_size
301 )
302 orig_index_lists, radius, start_pixel, step_size = moving_params
303 target_x = x[orig_index_lists[0]] if x is not None else None
304 if z.ndim == 2:
305 target_time = y[orig_index_lists[1]] if y is not None else None
306 elif z.ndim == 1:
307 target_time = y[orig_index_lists[0]] if y is not None else None
308 else:
309 raise ValueError("Invalid input z.ndim defined")
310 # Initialize an array for downsampled strain data
311 new_z = np.zeros([len(l) for l in orig_index_lists], dtype=float)
312 # Iterate through windows and apply downsampling
313 for orig_pixel, target_pixel, window_content in windows.moving(z, radius, start_pixel, step_size):
314 downsampled_strain = self.aggregator.reduce(window_content, axis=None)
315 new_z[target_pixel] = downsampled_strain
316 return target_x, target_time, new_z
317
319 r"""
320 Class for resampling one-dimensional or two-dimensional strain data.
321 In contrast, to \ref Downsampler, the target points are given in
322 the respective dimensions (`datetime.datetime` objects in time; sensor
323 coordinates in space) and irregular spacing along an axis is possible.
324 """
325 def __init__(self,
326 target_x: np.array = None,
327 target_time: np.array = None,
328 method: str = None,
329 method_kwargs: dict = None,
330 timespace: str = "1d_space",
331 *args, **kwargs):
332 r"""
333 Construct a Resampler instance.
334 \param target_x \copydoc target_x
335 \param target_time \copydoc target_time
336 \param method \copydoc method
337 \param method_kwargs \copydoc method_kwargs
338 \param timespace \copydoc timespace
339 \param *args Additional positional arguments, will be passed to the superconstructor.
340 \param **kwargs Additional keyword arguments, will be passed to the superconstructor.
341 """
342 super().__init__(timespace=timespace, *args, **kwargs)
343
344 self.target_x = target_x
345
346 self.target_time = target_time
347
356 self.method = method
357
358 self.method_kwargs = method_kwargs if method_kwargs is not None else {}
359 def _run_1d(self,
360 x: np.array,
361 z: np.array,
362 *args, **kwargs) -> tuple:
363 r"""
364 Resamples (by interpolating) one-dimensional data.
365 \param x Array of measuring point positions or time stamps
366 \param z Array of strain data in accordance to `x`.
367 \param *args Additional positional arguments, ignored.
368 \param **kwargs Additional keyword arguments, ignored.
369 \return Returns a tuple like `(target_x, target_z)`.
370 \retval target_x Array of target points (space or time).
371 \retval target_z Array of resampled strain.
372 """
373 try:
374 # if x is temporal data
375 x = misc.datetime_to_timestamp(x)
376 target_coord = misc.datetime_to_timestamp(self.target_time)
377 target_x = self.target_time
378 except:
379 # x is spatial data
380 target_coord = self.target_x
381 target_x = self.target_x
382 if target_coord is None:
383 raise ValueError("Target coordinates are `None`, must be set before resampling.")
384 method = self.method if self.method is not None else "interp1d"
385 target_z = scipy_interpolate1d(x, z, target_coord, method=method, **self.method_kwargs)
386 return target_x, target_z
387 def _run_2d(self,
388 x: np.array,
389 y: np.array,
390 z: np.array,
391 *args, **kwargs) -> tuple:
392 r"""
393 Resample a strain array using both spatial and temporal coordinates.
394 \param x: Original spatial (x-coordinate) data.
395 \param y: Original temporal (y-coordinate) data.
396 \param z: Original strain values.
397 \param *args: Additional positional arguments, ignored.
398 \param **kwargs: Additional keyword arguments, ignored.
399 \return Returns a tuple like `(x, y, z)`.
400 \retval x This is the \ref target_x
401 \retval y \ref target_time
402 \retval z Resampled strain array, according to \ref target_x and
403 \ref target_time.
404 """
405 if self.target_x is None or self.target_time is None:
406 raise ValueError("Target x and time points must be set before resampling.")
407 try:
408 y = misc.datetime_to_timestamp(y)
409 except:
410 pass
411 target_time = misc.datetime_to_timestamp(self.target_time)
412 # Resample
413 method = self.method if self.method is not None else "linear"
414 interpolated_strain = scipy.interpolate.interpn(
415 (y, x), z,
416 xi=(target_time[:, np.newaxis], self.target_x),
417 method=method, **self.method_kwargs)
418 return self.target_x, self.target_time, interpolated_strain
Abstract base class for preprocessing classes.
Definition base.py:16
Abstract base class for preprocessing task classes.
Definition base.py:56
Change the dimension of an array using aggregate functions (such as mean, median, min or max).
Definition resizing.py:34
np.array reduce(self, np.array data, int axis, *args, **kwargs)
Reduce the given array using the kernel funcition.
Definition resizing.py:139
__init__(self, str or callable method, module=np, str timespace="1d_space", *args, **kwargs)
Construct an instance of the class.
Definition resizing.py:44
module
A Python module or namespace in which method is looked up when method is not a callable.
Definition resizing.py:86
np.array run(self, np.array x, np.array y, np.array z, str timespace=None, bool make_copy=True, *args, **kwargs)
Reduce a 2D array to a 1D array using aggregate functions.
Definition resizing.py:96
timespace
Setting, how to compact the 2d array.
Definition resizing.py:67
kernel
Callable function used to aggregate the data.
Definition resizing.py:89
setup(self, str or callable method, module=np)
Set the kernel method for data processing, which can be either a string representing function name in...
Definition resizing.py:71
method
Could be either a callable (function object) or a string representing a function name in the namespac...
Definition resizing.py:83
Object, for cropping data sets and saving the preset.
Definition resizing.py:151
length
Length of the data excerpt.
Definition resizing.py:182
tuple run(self, np.array x, np.array y, np.array z, float start_pos=None, float end_pos=None, float length=None, float offset=None, *args, **kwargs)
This is a wrapper around cropping.cropping() which.
Definition resizing.py:191
start_pos
The starting position specifies the length of the sensor, before entering the measurement area.
Definition resizing.py:173
__init__(self, float start_pos=None, float end_pos=None, float length=None, float offset=None, *args, **kwargs)
Construct an instance of the class.
Definition resizing.py:160
end_pos
The end position specifies the length of the sensor, when leaving the measurement area.
Definition resizing.py:177
offset
Before cropping, data is shifted by the offset , such that , defaults to 0.
Definition resizing.py:179
Class for reducing strain data size while keeping the data loss small by combining several values int...
Definition resizing.py:221
step_size
Step size how far the window moves in one step.
Definition resizing.py:269
radius
Inradius of the window's rectangle.
Definition resizing.py:257
__init__(self, Aggregate aggregator, int radius=None, int start_pixel=None, int step_size=None, *args, **kwargs)
Initialize the down sampler.
Definition resizing.py:236
aggregator
Aggregator to use, see Aggregate.
Definition resizing.py:249
tuple run(self, np.array x, np.array y, np.array z, tuple radius=None, tuple start_pixel=None, tuple step_size=None)
This method downsamples 2D and 1D Strain data using specified parameters.
Definition resizing.py:277
start_pixel
Index of the first window's central pixel.
Definition resizing.py:264
Class for resampling one-dimensional or two-dimensional strain data.
Definition resizing.py:318
target_time
Points in time, where strain values should be resampled.
Definition resizing.py:346
target_x
Points in space, where strain values should be resampled.
Definition resizing.py:344
method_kwargs
Additional keyword arguments for the interpolation function.
Definition resizing.py:358
tuple _run_1d(self, np.array x, np.array z, *args, **kwargs)
Resamples (by interpolating) one-dimensional data.
Definition resizing.py:362
method
Name of the interpolation method used.
Definition resizing.py:356
tuple _run_2d(self, np.array x, np.array y, np.array z, *args, **kwargs)
Resample a strain array using both spatial and temporal coordinates.
Definition resizing.py:391
__init__(self, np.array target_x=None, np.array target_time=None, str method=None, dict method_kwargs=None, str timespace="1d_space", *args, **kwargs)
Construct a Resampler instance.
Definition resizing.py:331
Base class for algorithms to replace/remove missing data with plausible values.
Definition resizing.py:22
Contains functionality for interpolating data.
Contains utility modules with general pupose.
Definition __init__.py:1