Files
python3-damaris/src/damaris/data/MeasurementData.py
T

127 lines
4.5 KiB
Python

# -*- coding: iso-8859-1 -*-
from __future__ import annotations
import numpy
class MeasurementData:
"""Common channel-series access and numerical analysis for measurements.
Concrete result classes provide storage and ``get_ydata``; all calculations
in this class therefore use the public channel values rather than their
internal representation.
"""
def contains_data(self) -> bool:
"""Return whether the measurement contains samples."""
raise NotImplementedError
def get_ydata(self, channel: int = 0) -> numpy.ndarray:
"""Return public values for one channel."""
return self.y[channel]
def get_number_of_channels(self) -> int:
"""Return the number of data channels."""
return len(self.y)
def get_sampling_rate(self) -> float:
"""Return the sampling frequency in hertz."""
return self.sampling_rate
def __len__(self) -> int:
"""Return the number of samples per channel.
Example:
samples = len(timesignal)
"""
if not self.get_number_of_channels():
return 0
return len(self.get_ydata(0))
def get_ymean(self, start: float | None = None,
stop: float | None = None) -> numpy.ndarray:
"""Return the mean of every channel over a time interval.
Example:
means = timesignal.get_ymean(start=1e-6, stop=4e-6)
"""
if not self.contains_data():
return numpy.array([])
if (start is None) != (stop is None):
raise ValueError("start and stop must be specified together")
if start is None:
values = [self.get_ydata(channel).mean()
for channel in range(self.get_number_of_channels())]
else:
istart = int(self.get_sampling_rate() * start)
istop = int(self.get_sampling_rate() * stop)
values = [self.get_ydata(channel)[istart:istop].mean()
for channel in range(self.get_number_of_channels())]
return numpy.asarray(values)
def get_phase(self, pos: float | None = None) -> float:
"""Return the phase in degrees from the first two channels.
Example:
phase = timesignal.get_phase(pos=1e-6)
"""
if self.get_number_of_channels() < 2:
raise ValueError("phase requires at least two channels")
ipos = 0 if pos is None else int(self.get_sampling_rate() * pos)
return float(numpy.degrees(numpy.arctan2(
self.get_ydata(1)[ipos], self.get_ydata(0)[ipos])))
def get_ymin_channels(self) -> numpy.ndarray:
"""Return the minimum value of each channel.
Example:
minima = accu.get_ymin_channels()
"""
if not self.contains_data():
return numpy.array([])
return numpy.asarray([self.get_ydata(i).min()
for i in range(self.get_number_of_channels())])
def get_ymax_channels(self) -> numpy.ndarray:
"""Return the maximum value of each channel.
Example:
maxima = accu.get_ymax_channels()
"""
if not self.contains_data():
return numpy.array([])
return numpy.asarray([self.get_ydata(i).max()
for i in range(self.get_number_of_channels())])
def get_ymin(self) -> float | int:
"""Return the global minimum across all channels."""
values = self.get_ymin_channels()
return 0 if len(values) == 0 else values.min()
def get_ymax(self) -> float | int:
"""Return the global maximum across all channels."""
values = self.get_ymax_channels()
return 0 if len(values) == 0 else values.max()
def get_yrms(self) -> numpy.ndarray:
"""Return the root-mean-square value of each channel.
Example:
rms = timesignal.get_yrms()
"""
if not self.contains_data():
return numpy.array([])
return numpy.asarray([numpy.sqrt(numpy.mean(self.get_ydata(i) ** 2))
for i in range(self.get_number_of_channels())])
def get_ystd(self) -> numpy.ndarray:
"""Return the population standard deviation of each channel.
Example:
deviation = accu.get_ystd()
"""
if not self.contains_data():
return numpy.array([])
return numpy.asarray([numpy.std(self.get_ydata(i))
for i in range(self.get_number_of_channels())])