diff --git a/lasp/CMakeLists.txt b/lasp/CMakeLists.txt index edbd0eb..be47c4d 100644 --- a/lasp/CMakeLists.txt +++ b/lasp/CMakeLists.txt @@ -20,7 +20,7 @@ include_directories( # DEPENDS MakeTable # ) -set(ui_files ui_apsrt ui_mainwindow ui_figure ui_about ui_apswidget ui_revtime ui_slmwidget ui_daq) +set(ui_files ui_apsrtsettings ui_mainwindow ui_figure ui_about ui_apswidget ui_revtime ui_slmwidget ui_daq ui_apssettings) foreach(fn ${ui_files}) add_custom_command( OUTPUT "${fn}.py" diff --git a/lasp/c/lasp_python.h b/lasp/c/lasp_python.h index f99e823..8a351e0 100644 --- a/lasp/c/lasp_python.h +++ b/lasp/c/lasp_python.h @@ -8,6 +8,7 @@ #pragma once #ifndef LASP_PYTHON_H #define LASP_PYTHON_H +#define TRACERPLUS (-10) #include #ifdef LASP_DOUBLE_PRECISION #define LASP_NUMPY_FLOAT_TYPE NPY_FLOAT64 diff --git a/lasp/device/lasp_daqconfig.py b/lasp/device/lasp_daqconfig.py index efcd5df..7faff98 100644 --- a/lasp/device/lasp_daqconfig.py +++ b/lasp/device/lasp_daqconfig.py @@ -115,7 +115,7 @@ roga_plugndaq = DAQConfiguration(name='Roga-instruments Plug.n.DAQ USB', en_format=0, en_input_rate=2, en_input_channels=[0], - input_sensitivity=[1., 1.], + input_sensitivity=[46.92e-3, 46.92e-3], input_gain_settings=[-20, 0, 20], en_input_gain_setting=[1, 1], en_output_rate=1, @@ -128,8 +128,8 @@ default_soundcard = DAQConfiguration(name="Default device", device_name='default', en_format=0, en_input_rate=2, - en_input_channels=[0, 1], - input_sensitivity=[1., 1.], + en_input_channels=[0], + input_sensitivity=[1.0, 1.0], input_gain_settings=[0], en_input_gain_setting=[0, 0], en_output_rate=1, diff --git a/lasp/device/lasp_daqdevice.pyx b/lasp/device/lasp_daqdevice.pyx index 6ae470f..59c6ed6 100644 --- a/lasp/device/lasp_daqdevice.pyx +++ b/lasp/device/lasp_daqdevice.pyx @@ -66,7 +66,7 @@ cdef extern from "alsa/asoundlib.h": int snd_pcm_info_get_card(snd_pcm_info_t*) int snd_pcm_drain(snd_pcm_t*) - int snd_pcm_readi(snd_pcm_t*,void* buf,snd_pcm_uframes_t nframes) + int snd_pcm_readi(snd_pcm_t*,void* buf,snd_pcm_uframes_t nframes) nogil int snd_pcm_hw_params(snd_pcm_t*,snd_pcm_hw_params_t*) int snd_pcm_hw_params_test_rate(snd_pcm_t*, snd_pcm_hw_params_t*, unsigned int val,int dir) @@ -444,7 +444,8 @@ cdef class DAQDevice: buf = self._getEmptyBuffer() # buf2 = self._getEmptyBuffer() cdef cnp.int16_t[:, ::1] bufv = buf - rval = snd_pcm_readi(self.pcm, &bufv[0, 0], self.blocksize) + with nogil: + rval = snd_pcm_readi(self.pcm, &bufv[0, 0], self.blocksize) # rval = 2048 if rval > 0: # print('Samples obtained:' , rval) diff --git a/lasp/lasp_avstream.py b/lasp/lasp_avstream.py index fce30ac..6959ea0 100644 --- a/lasp/lasp_avstream.py +++ b/lasp/lasp_avstream.py @@ -1,15 +1,14 @@ #!/usr/bin/env python3 # -*- coding: utf-8 -*- """ -Created on Sat Mar 10 08:28:03 2018 - -@author: Read data from image stream and record sound at the same time +Description: Read data from image stream and record sound at the same time """ import cv2 as cv from .lasp_atomic import Atomic from threading import Thread, Condition, Lock import time from .device import DAQDevice, roga_plugndaq +import numpy as np __all__ = ['AvType', 'AvStream'] video_x, video_y = 640, 480 @@ -30,6 +29,7 @@ class AvStream: self.nchannels = len(daq.channels_en) self.samplerate = daq.input_rate self.blocksize = daq.blocksize + self.sensitivity = np.asarray(daqconfig.input_sensitivity)[daq.channels_en] except Exception as e: raise RuntimeError(f'Could not initialize DAQ device: {str(e)}') @@ -92,6 +92,7 @@ class AvStream: # contains quite some rubbish. data = daq.read() while self._running: + # print('read data...') data = daq.read() self._audioCallback(data) except RuntimeError as e: diff --git a/lasp/lasp_measurement.py b/lasp/lasp_measurement.py index 53861b8..4f54d45 100644 --- a/lasp/lasp_measurement.py +++ b/lasp/lasp_measurement.py @@ -35,7 +35,7 @@ The video dataset can possibly be not present in the data. """ -__all__ = ['Measurement'] +__all__ = ['Measurement', 'scaleBlockSens'] from contextlib import contextmanager import h5py as h5 import numpy as np @@ -93,6 +93,24 @@ def getSampWidth(dtype): raise ValueError('Invalid data type: %s' % dtype) +def scaleBlockSens(block, sens): + """ + Scale a block of raw data to return raw acoustic + pressure data. + + Args: + block: block of raw data with integer data type + sensitivity: array of sensitivity coeficients for + each channel + + """ + assert sens.ndim == 1 + assert sens.size == block.shape[1] + sw = getSampWidth(block.dtype) + fac = 2**(8*sw - 1) - 1 + return block.astype(LASP_NUMPY_FLOAT_TYPE)/fac/sens[np.newaxis, :] + + def exportAsWave(fn, fs, data, force=False): if '.wav' not in fn[-4:]: fn += '.wav' @@ -154,7 +172,8 @@ class Measurement: # Sensitivity try: - self._sens = f.attrs['sensitivity'] + sens = f.attrs['sensitivity'] + self._sens = sens*np.ones(self.nchannels) if isinstance(sens, float) else sens except KeyError: self._sens = np.ones(self.nchannels) @@ -201,17 +220,7 @@ class Measurement: # When the data is stored as integers, we assume dB full-scale scaling. # Hence, when we convert the data to floats, we divide by the maximum # possible value. - if block.dtype == np.int32: - fac = 2**31 - elif block.dtype == np.int16: - fac = 2**15 - elif block.dtype == np.float64: - fac = 1.0 - else: - raise RuntimeError( - f'Unimplemented data type from recording: {block.dtype}.') - sens = self._sens - return block.astype(LASP_NUMPY_FLOAT_TYPE)/fac/sens[np.newaxis, :] + return scaleBlockSens(block, self.sensitivity) @property def prms(self): diff --git a/lasp/lasp_record.py b/lasp/lasp_record.py index d6924e6..588560b 100644 --- a/lasp/lasp_record.py +++ b/lasp/lasp_record.py @@ -104,7 +104,6 @@ class Recording: self._vCallback(data) def _aCallback(self, frames, aframe): - # print(self._aframeno()) print('.', end='') curT = self._aframeno()*self.blocksize/self.samplerate if self.rectime is not None and curT > self.rectime: diff --git a/scripts/lasp_apsrt b/scripts/lasp_apsrt new file mode 100755 index 0000000..2d5a3e0 --- /dev/null +++ b/scripts/lasp_apsrt @@ -0,0 +1,41 @@ +#!/usr/bin/env python +import sys +from lasp.lasp_rtapsdialog import RealTimeAPSDialog +from lasp.lasp_avstream import AvStream +from lasp.device.lasp_daqconfig import default_soundcard, roga_plugndaq +from lasp.lasp_gui_tools import Branding, ASCEEColors, warningdialog +from PySide import QtGui + + +def main(): + app = QtGui.QApplication(sys.argv) # A new instance of QApplication + app.setFont(Branding.font()) + + stream = AvStream(default_soundcard) + # stream = AvStream(roga_plugndaq) + mw = RealTimeAPSDialog(None, stream) + + mw.show() # Show the form + + # Install exception hook to catch exceptions + def excepthook(cls, exception, traceback): + """ + This exception hook is installed as the global exception hook. Shows a + simple QMessageBox in case of an exception that is not caught. + """ + if __debug__: + import traceback as tb + tbtxt = ''.join(tb.format_tb(sys.last_traceback)) + warningdialog(mw, str(exception), tbtxt) + else: + warningdialog(mw, str(exception)) + + # Set custom exception hook that catches all exceptions + sys.excepthook = excepthook + stream.start() + app.exec_() # and execute the app + stream.stop() + + +if __name__ == '__main__': + main() # run the main function diff --git a/scripts/lasp_record b/scripts/lasp_record old mode 100644 new mode 100755