3030if TYPE_CHECKING :
3131 from matplotlib import image
3232
33+
3334logger = logging .getLogger (__name__ )
3435
3536
37+ MeasurementUnit = Literal [
38+ "strain rate" ,
39+ "strain" ,
40+ "acceleration" ,
41+ "velocity" ,
42+ "displacement" ,
43+ "velocity" ,
44+ ]
45+
46+
3647class Blast :
3748 data : np .ndarray
3849 start_time : datetime
3950 sampling_rate : float
4051 processing_flow : list
4152
53+ unit : MeasurementUnit
54+
4255 start_channel : int
4356 channel_spacing : float
4457
@@ -49,6 +62,7 @@ def __init__(
4962 sampling_rate : float ,
5063 start_channel : int = 0 ,
5164 channel_spacing : float = 0.0 ,
65+ unit : MeasurementUnit = "strain rate" ,
5266 ):
5367 self .data = data
5468 self .start_time = start_time
@@ -285,6 +299,70 @@ def trim_time(self, begin: float = 0.0, end: float = -1.0) -> None:
285299 self .data = self .data [:, start_sample :end_sample ]
286300 self .start_time += timedelta (seconds = begin )
287301
302+ def to_strain (self , detrend : bool = True ) -> Blast :
303+ """Convert the traces to strain.
304+
305+ Args:
306+ detrend (bool, optional): Detrend trace before integration.
307+ Defaults to True.
308+
309+ Raises:
310+ TypeError: Raised when the input blast is not in strain rate.
311+
312+ Returns:
313+ Blast: As strain strain.
314+ """
315+ if self .unit == "strain" :
316+ return self .copy ()
317+ if self .unit != "strain rate" :
318+ raise TypeError (f"Blast has a bad unit { self .unit } , expected 'strain_rate'" )
319+ blast = self .copy ()
320+ if detrend :
321+ blast .detrend ()
322+ blast .data = np .cumsum (blast .data , axis = 1 )
323+ blast .unit = "strain"
324+ return blast
325+
326+ def to_relative_velocity (self , detrend : bool = True ) -> Blast :
327+ """Convert the traces to relative velocity.
328+
329+ Args:
330+ detrend (bool, optional): Detrend trace before spatial differentiation.
331+ Defaults to True.
332+
333+ Raises:
334+ TypeError: Raised when the input blast is not in strain rate.
335+
336+ Returns:
337+ Blast: As strain strain.
338+ """
339+ blast = self .to_strain (detrend = detrend )
340+ if detrend :
341+ blast .detrend ()
342+ blast .data = np .diff (blast .data , n = 1 , axis = 0 ) / blast .channel_spacing
343+ blast .unit = "velocity"
344+ return blast
345+
346+ def to_relative_displacement (self , detrend : bool = True ) -> Blast :
347+ """Convert the traces to relative displacement.
348+
349+ Args:
350+ detrend (bool, optional): Detrend trace before spatial integration.
351+ Defaults to True.
352+
353+ Raises:
354+ TypeError: Raised when the input blast is not in strain rate.
355+
356+ Returns:
357+ Blast: As strain strain.
358+ """
359+ blast = self .to_strain ()
360+ if detrend :
361+ blast .detrend ()
362+ blast .data = np .cumsum (blast .data , axis = 0 ) * blast .channel_spacing
363+ blast .unit = "displacement"
364+ return blast
365+
288366 def plot (
289367 self ,
290368 axes : plt .Axes | None = None ,
@@ -464,3 +542,67 @@ def __len__(self) -> int:
464542
465543 mute_median = shared_function (Blast .mute_median )
466544 one_bit_normalization = shared_function (Blast .one_bit_normalization )
545+ afk_filter = shared_function (Blast .afk_filter )
546+ decimate = shared_function (Blast .decimate )
547+
548+ trim_time = shared_function (Blast .trim_time )
549+ trim_channels = shared_function (Blast .trim_channels )
550+
551+ mute_median = shared_function (Blast .mute_median )
552+ one_bit_normalization = shared_function (Blast .one_bit_normalization )
553+ afk_filter = shared_function (Blast .afk_filter )
554+ decimate = shared_function (Blast .decimate )
555+
556+ trim_time = shared_function (Blast .trim_time )
557+ trim_channels = shared_function (Blast .trim_channels )
558+
559+ mute_median = shared_function (Blast .mute_median )
560+ one_bit_normalization = shared_function (Blast .one_bit_normalization )
561+ afk_filter = shared_function (Blast .afk_filter )
562+ decimate = shared_function (Blast .decimate )
563+
564+ trim_time = shared_function (Blast .trim_time )
565+ trim_channels = shared_function (Blast .trim_channels )
566+
567+ mute_median = shared_function (Blast .mute_median )
568+ one_bit_normalization = shared_function (Blast .one_bit_normalization )
569+ afk_filter = shared_function (Blast .afk_filter )
570+ decimate = shared_function (Blast .decimate )
571+
572+ trim_time = shared_function (Blast .trim_time )
573+ trim_channels = shared_function (Blast .trim_channels )
574+
575+ mute_median = shared_function (Blast .mute_median )
576+ one_bit_normalization = shared_function (Blast .one_bit_normalization )
577+ afk_filter = shared_function (Blast .afk_filter )
578+ decimate = shared_function (Blast .decimate )
579+
580+ trim_time = shared_function (Blast .trim_time )
581+ trim_channels = shared_function (Blast .trim_channels )
582+
583+ mute_median = shared_function (Blast .mute_median )
584+ one_bit_normalization = shared_function (Blast .one_bit_normalization )
585+ afk_filter = shared_function (Blast .afk_filter )
586+ decimate = shared_function (Blast .decimate )
587+
588+ trim_time = shared_function (Blast .trim_time )
589+ trim_channels = shared_function (Blast .trim_channels )
590+
591+ mute_median = shared_function (Blast .mute_median )
592+ one_bit_normalization = shared_function (Blast .one_bit_normalization )
593+ afk_filter = shared_function (Blast .afk_filter )
594+ decimate = shared_function (Blast .decimate )
595+
596+ trim_time = shared_function (Blast .trim_time )
597+ trim_channels = shared_function (Blast .trim_channels )
598+
599+ mute_median = shared_function (Blast .mute_median )
600+ one_bit_normalization = shared_function (Blast .one_bit_normalization )
601+ afk_filter = shared_function (Blast .afk_filter )
602+ decimate = shared_function (Blast .decimate )
603+
604+ trim_time = shared_function (Blast .trim_time )
605+ trim_channels = shared_function (Blast .trim_channels )
606+
607+ mute_median = shared_function (Blast .mute_median )
608+ one_bit_normalization = shared_function (Blast .one_bit_normalization )
0 commit comments