Level ref value can be changed in SLM, Qty stuff stored in measurement

This commit is contained in:
Anne de Jong 2020-08-22 11:00:08 +02:00
parent 0a8949e0cf
commit 4dd95cb80c
5 changed files with 104 additions and 19 deletions

View File

@ -10,8 +10,8 @@ Data Acquistiion (DAQ) device descriptors, and the DAQ devices themselves
"""
from dataclasses import dataclass, field
from dataclasses_json import dataclass_json
import numpy as np
from ..lasp_common import lasp_shelve, Qty
from ..lasp_common import lasp_shelve, Qty, SIQtys
from typing import List
@dataclass
@ -35,7 +35,7 @@ class DAQChannel:
channel_enabled: bool
channel_name: str
sensitivity: float
unit: Qty
qty: Qty
@dataclass_json
@ -83,12 +83,12 @@ class DAQConfiguration:
en_input_rate: int
en_output_rate: int
input_channel_configs: list
output_channel_configs: list
monitor_gen: bool
input_channel_configs: List[DAQChannel] = field(default_factory=list)
output_channel_configs: List[DAQChannel] = field(default_factory=list)
monitor_gen: bool = False
outputDelayBlocks: int
nFramesPerBlock: int
outputDelayBlocks: int = 0
nFramesPerBlock: int = 512
def firstEnabledInputChannelNumber(self):
"""
@ -135,6 +135,9 @@ class DAQConfiguration:
def getEnabledInputChannelNames(self):
return [ch.channel_name for ch in self.getEnabledInputChannels()]
def getEnabledInputChannelQtys(self):
return [ch.qty for ch in self.getEnabledInputChannels()]
def getEnabledInputChannelSensitivities(self):
return [float(channel.sensitivity) for channel in
self.getEnabledInputChannels()]
@ -146,23 +149,36 @@ class DAQConfiguration:
en_channels.append(chan)
return en_channels
def getEnabledOutputChannelQtys(self):
return [ch.qty for ch in self.getEnabledOutputChannels()]
def getEnabledOutputChannelSensitivities(self):
return [float(channel.sensitivity) for channel in
self.getEnabledOutputChannels()]
@staticmethod
def loadConfigsJSON():
with lasp_shelve() as sh:
configs_json = sh.load('daqconfigs', {})
return configs_json
@staticmethod
def loadConfigs():
"""
Returns a list of currently available configurations
"""
with lasp_shelve() as sh:
return sh.load('daqconfigs', {})
configs_json = DAQConfiguration.loadConfigsJSON()
configs = {}
for name, val in configs_json.items():
configs[name] = DAQConfiguration.from_json(val)
return configs
def saveConfig(self, name):
configs_json = DAQConfiguration.loadConfigsJSON()
with lasp_shelve() as sh:
cur_configs = self.loadConfigs()
cur_configs[name] = self
sh.store('daqconfigs', cur_configs)
configs_json[name] = self.to_json()
sh.store('daqconfigs', configs_json)
@staticmethod
def deleteConfig(name):

View File

@ -51,12 +51,15 @@ class AvStream:
if daqconfig.monitor_gen:
self.input_channel_names = self.output_channel_names
self.input_sensitivity = daqconfig.getEnabledOutputChannelSensitivities()
self.input_qtys = daqconfig.getEnabledOutputChannelQtys()
else:
self.input_channel_names = []
self.input_sensitivity = []
self.input_qtys = []
self.input_sensitivity += daqconfig.getEnabledInputChannelSensitivities()
self.input_sensitivity = np.asarray(self.input_sensitivity)
self.input_qtys += daqconfig.getEnabledInputChannelQtys()
# Fill in numpy data type, and sample width
self.input_numpy_dtype = get_numpy_dtype_from_format_string(

View File

@ -16,6 +16,8 @@ is assumed to be acoustic data.
'sensitivity': (Optionally) the stored sensitivity of the record channels.
This can be a single value, or a list of sensitivities for
each channel. Both representations are allowed.
'qtys' : (Optionally): list of quantities that is recorded for each channel', if
this array is not found. Quantities are defaulted to 'Number / Full scale'
- Datasets:
@ -182,6 +184,19 @@ class Measurement:
self._time = f.attrs['time']
try:
qtys_json = f.attrs['qtys']
self._qtys = [Qty.from_json(qty_json) for qty_json in qtys_json]
except KeyError:
self._qtys = [SIQtys.default for i in range(self.nchannels)]
def setAttribute(self, atrname, value):
with self.file('r+') as f:
# Update comment attribute in the file
f.attrs[atrname] = value
setattr(self, '_' + atrname, value)
@property
def name(self):
"""Returns filename base without extension."""
@ -191,6 +206,52 @@ class Measurement:
def channelNames(self):
return self._channel_names
@channelNames.setter
def channelNames(self, newchnames):
if len(newchnames) != self.nchannels:
raise RuntimeError('Invalid length of new channel names')
self.setAttribute('channelNames', newchnames)
@property
def channelConfig(self):
return [DAQChannel(channel_enabled=True,
channel_name=chname,
sensitivity=sens,
qty=qty)
for chname, sens, qty in zip(
self.channelNames,
self.sensitivity,
self.qtys)]
@channelConfig.setter
def channelConfig(self, chcfg):
chname = []
sens = []
qtys = []
for ch in chcfg:
chname.append(ch.channel_name)
sens.append(ch.sensitivity)
qtys.append(ch.qty)
self.channelNames = chname
self.sensitivity = sens
self.qtys = qtys
@property
def qtys(self):
return self._qtys
@qtys.setter
def qtys(self, newqtys):
if not len(newqtys) == len(self._qtys):
raise ValueError('Invalid number of quantities')
qtys_json = [qty.to_json() for qty in newqtys]
# Use setAttribute here, but thos store the jsonified version as well,
# which we have to overwrite again with the deserialized ones. This is
# actually not a very nice way of coding.
self.setAttribute('qtys', qtys_json)
self._qtys = newqtys
@contextmanager
def file(self, mode='r'):
"""Contextmanager which opens the storage file and yields the file.
@ -322,11 +383,11 @@ class Measurement:
@property
def sensitivity(self):
"""Sensitivity of the data in Pa^-1, from floating point data scaled
between -1.0 and 1.0 to Pascal.
"""Sensitivity of the data in U^-1, from floating point data scaled
between -1.0 and 1.0 to Units [U].
If the sensitivity is not stored in the measurement file, this
function returns 1.0
function returns 1.0 for each channel
"""
return self._sens
@ -361,6 +422,8 @@ class Measurement:
if isinstance(sens, float):
# Put all sensitivities equal
sens = sens * np.ones(self.nchannels)
elif isinstance(sens, list):
sens = np.asarray(sens)
valid = sens.ndim == 1
valid &= sens.shape[0] == self.nchannels

View File

@ -102,6 +102,7 @@ class Recording:
f.attrs['sensitivity'] = stream.input_sensitivity
f.attrs['channel_names'] = stream.input_channel_names
f.attrs['time'] = time.time()
f.attrs['qtys'] = [qty.to_json() for qty in stream.input_qtys]
self._running <<= True
if not stream.isRunning():

View File

@ -6,7 +6,7 @@ Sound level meter implementation
"""
from .wrappers import Slm as pyxSlm
import numpy as np
from .lasp_common import (TimeWeighting, P_REF, FreqWeighting)
from .lasp_common import (TimeWeighting, FreqWeighting, P_REF)
from .filter import SPLFilterDesigner
__all__ = ['SLM', 'Dummy']
@ -36,7 +36,8 @@ class SLM:
fw=FreqWeighting.A,
xmin = None,
xmax = None,
include_overall=True):
include_overall=True,
level_ref_value=P_REF):
"""
Initialize a sound level meter object.
@ -52,6 +53,7 @@ class SLM:
xmax: Filter designator of highest band
include_overall: If true, a non-functioning filter is added which
is used to compute the overall level.
level_ref_value: Reference value for computing the levels in dB
"""
@ -105,7 +107,7 @@ class SLM:
self.nom_txt.append('overall')
self.slm = pyxSlm(prefilter, sos,
fs, tw[0], P_REF)
fs, tw[0], level_ref_value)
dsfac = self.slm.downsampling_fac
if dsfac > 0: