Added a setLevel function to siggen.h, Some bugfix and partially working signal generator

This commit is contained in:
Anne de Jong 2021-04-30 21:56:54 +02:00
parent 11cc623363
commit 547b00f116
13 changed files with 111 additions and 47 deletions

View File

@ -1,11 +1,10 @@
from .lasp_atomic import *
from .lasp_avstream import *
from .lasp_common import *
from .lasp_avstream import *
from .wrappers import *
from .lasp_atomic import *
from .lasp_imptube import *
from .lasp_measurement import *
from .lasp_octavefilter import *
from .lasp_slm import *
from .lasp_siggen import *
from .lasp_weighcal import *
from .wrappers import *
from .device import AvType

View File

@ -332,6 +332,13 @@ us Siggen_getN(const Siggen* siggen) {
feTRACE(15);
return 0;
}
void Siggen_setLevel(Siggen* siggen, const d new_level_dB) {
fsTRACE(15);
siggen->level_amp = d_pow(10, new_level_dB/20);
feTRACE(15);
}
void Siggen_free(Siggen* siggen) {
fsTRACE(15);

View File

@ -46,6 +46,14 @@ Siggen* Siggen_Sinewave_create(const d fs,const d freq,const d level_dB);
*/
Siggen* Siggen_Noise_create(const d fs, const d level_dB, Sosfilterbank* colorfilter);
/**
* Set the level of the signal generator
* @param[in] Siggen* Signal generator handle
*
* @param[in] new_level_dB The new level, in dBFS
*/
void Siggen_setLevel(Siggen*, const d new_level_dB);
/**
* Obtain the repetition period for a periodic excitation.

View File

@ -1,6 +1,4 @@
#!/usr/bin/python3
from .lasp_device_common import *
from .lasp_daq import *
from .lasp_deviceinfo import *
from .lasp_daqconfig import *
from .lasp_daq import *

View File

@ -4,7 +4,7 @@ from .lasp_daqconfig cimport DaqConfiguration
from cpython.ref cimport PyObject,Py_INCREF, Py_DECREF
import numpy as np
from .lasp_device_common import AvType
from ..lasp_common import AvType
__all__ = ['Daq']

View File

@ -1,4 +1,3 @@
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
"""!
Author: J.A. de Jong - ASCEE

View File

@ -1,17 +1,10 @@
__all__ = ['AvType', 'DaqChannel']
__all__ = ['DaqChannel']
from ..lasp_common import Qty, SIQtys
from dataclasses import dataclass, field
from dataclasses_json import dataclass_json
from typing import List
import json
class AvType:
"""Specificying the type of data, for adding and removing callbacks from
the stream."""
audio_input = 1
audio_output = 2
video = 4
@dataclass_json
@dataclass
class DaqChannel:

View File

@ -1,3 +1,12 @@
# -*- coding: utf-8 -*-
"""!
Author: J.A. de Jong - ASCEE
Description:
DeviceInfo C++ object wrapper
"""
__all__ = ['DeviceInfo']

View File

@ -1,20 +1,15 @@
#!/usr/bin/env python3.6
# -*- coding: utf-8 -*-
"""
Description: Read data from image stream and record sound at the same time
"""
#import cv2 as cv
from .lasp_atomic import Atomic
from .lasp_common import AvType
from .device import (Daq, DeviceInfo, DaqConfiguration)
from threading import Thread, Lock
import numpy as np
class DAQConfiguration:
pass
import time
from .device import (Daq, DeviceInfo,
AvType,
)
__all__ = ['AvStream']
@ -28,7 +23,7 @@ class AvStream:
def __init__(self,
avtype: AvType,
device: DeviceInfo,
daqconfig: DAQConfiguration,
daqconfig: DaqConfiguration,
video=None):
"""Open a stream for audio in/output and video input. For audio output,
by default all available channels are opened for outputting data.

View File

@ -20,6 +20,7 @@ __all__ = [
'P_REF', 'FreqWeighting', 'TimeWeighting', 'getTime', 'getFreq', 'Qty',
'SIQtys',
'lasp_shelve', 'this_lasp_shelve', 'W_REF', 'U_REF', 'I_REF', 'dBFS_REF',
'AvType'
]
# Reference sound pressure level
@ -42,6 +43,14 @@ U_REF = 5e-8 # 50 nano meter / s
# hence this is the reference level as specified below.
dBFS_REF = 0.5*2**0.5 # Which level would be -3.01 dBFS
class AvType:
"""Specificying the type of data, for adding and removing callbacks from
the stream."""
audio_input = 1
audio_output = 2
video = 4
@dataclass_json
@dataclass
class Qty:

View File

@ -11,6 +11,8 @@ from .lasp_measurement import Measurement
from numpy import pi, sqrt, exp
import numpy as np
from scipy.interpolate import UnivariateSpline
from lrftubes import PrsDuct
from functools import lru_cache
class TwoMicImpedanceTube:
def __init__(self, mnormal: Measurement,
@ -22,6 +24,8 @@ class TwoMicImpedanceTube:
fu: float = None,
periodic_method=False,
mat= Air(),
D_imptube = 50e-3,
thermoviscous = True,
**kwargs):
"""
@ -60,6 +64,9 @@ class TwoMicImpedanceTube:
kmax = ksmax/s
self.fu = kmax*mat.c0/2/pi
self.thermoviscous = thermoviscous
self.D_imptube = D_imptube
self.periodic_method = periodic_method
self.channels = [kwargs.pop('chan0', 0), kwargs.pop('chan1', 1)]
# Compute calibration correction
@ -82,8 +89,9 @@ class TwoMicImpedanceTube:
# Calibration correction factor
# self.K = 0*self.freq + 1.0
K = sqrt(C2[:,0,1]*C1[:,0,0]/(C2[:,1,1]*C1[:,1,0]))
self.K = UnivariateSpline(self.freq, K.real)(self.freq) +\
1j*UnivariateSpline(self.freq, K.imag)(self.freq)
# self.K = UnivariateSpline(self.freq, K.real)(self.freq) +\
# 1j*UnivariateSpline(self.freq, K.imag)(self.freq)
self.K = K
def cut_to_limits(self, ar):
return ar[self.il:self.ul]
@ -94,6 +102,7 @@ class TwoMicImpedanceTube:
"""
return self.cut_to_limits(self.freq)
@lru_cache
def G_AB(self, meas):
if meas is self.mnormal:
C = self.C1

View File

@ -14,8 +14,10 @@ from typing import Tuple
import numpy as np
from .filter import PinkNoise
from .lasp_octavefilter import SosOctaveFilterBank, SosThirdOctaveFilterBank
from .filter import OctaveBankDesigner, PinkNoise, ThirdOctaveBankDesigner
from .lasp_avstream import AvStream, AvType
from .wrappers import Siggen as pyxSiggen
from .wrappers import Siggen as pyxSiggen, Equalizer
QUEUE_BUFFER_TIME = 0.3 # The amount of time used in the queues for buffering
# of data, larger is more stable, but also enlarges latency
@ -89,7 +91,7 @@ class SiggenData:
def siggenFcn(siggendata: SiggenData, nblocks_buffer: int,
queues: list
dataq: mp.Queue, pipe
):
"""
Main function running in a different process, is responsible for generating
@ -100,12 +102,10 @@ def siggenFcn(siggendata: SiggenData, nblocks_buffer: int,
nframes_per_block = siggendata.nframes_per_block
level_dB = siggendata.level_dB
dtype = siggendata.dtype
eq = None
signaltype = siggendata.signaltype
signaltypedata = siggendata.signaltypedata
dataq, msgq, statusq = queues
def generate(siggen, eq):
"""
@ -119,6 +119,31 @@ def siggenFcn(siggendata: SiggenData, nblocks_buffer: int,
signal *= 2 ** (bitdepth_fixed - 1) - 1
dataq.put(signal.astype(dtype))
def createEqualizer(eqdata):
"""
Create an equalizer object from equalizer data
Args:
eqdata: dictionary containing equalizer data. TODO: document the
requiring fields.
"""
if eqdata is None:
return None
eq_type = eqdata['type']
eq_levels = eqdata['levels']
if eq_type == 'three':
fb = SosThirdOctaveFilterBank(fs)
elif eq_type == 'one':
fb = SosOctaveFilterBank(fs)
eq = Equalizer(fb._fb)
if eq_levels is not None:
eq.setLevels(eq_levels)
return eq
eq = createEqualizer(siggendata.eqdata)
def newSiggen():
"""
Create a signal generator based on parameters specified in global
@ -156,14 +181,14 @@ def siggenFcn(siggendata: SiggenData, nblocks_buffer: int,
siggen = newSiggen()
except Exception as e:
statusq.put((SiggenMessage.error, str(e)))
pipe.send((SiggenMessage.error, str(e)))
return 1
finally:
statusq.put((SiggenMessage.done, None))
pipe.send((SiggenMessage.done, None))
while True:
msg, data = msgq.get()
msg, data = pipe.recv()
if msg == SiggenMessage.stop:
logging.debug("Signal generator caught 'stop' message. Exiting.")
return 0
@ -174,14 +199,17 @@ def siggenFcn(siggendata: SiggenData, nblocks_buffer: int,
# Generate new data and put it in the queue!
generate(siggen, eq)
except SiggenWorkerDone:
statusq.put(SiggenMessage.done)
pipe.send(SiggenMessage.done)
return 0
elif msg == SiggenMessage.adjustVolume:
logging.debug(f"Signal generator caught 'adjustVolume' message. New volume = {level_dB:.1f} dB FS")
level_dB = data
siggen = newSiggen()
siggen.setLevel(level_dB)
elif msg == SiggenMessage.newEqSettings:
eqdata = data
eq = createEqualizer(eqdata)
else:
statusq.put(
pipe.send(
SiggenMessage.error, "BUG: Generator caught unknown message. Quiting"
)
return 1
@ -201,11 +229,12 @@ class Siggen:
)
qs = [mp.Queue() for i in range(3)]
self.dataq, self.msgq, self.statusq = qs
self.dataq = mp.Queue()
self.pipe, client_end = mp.Pipe(duplex=True)
self.process = mp.Process(
target=siggenFcn,
args=(siggendata, self.nblocks_buffer, qs),
args=(siggendata, self.nblocks_buffer, self.dataq, client_end),
)
self.process.start()
@ -222,11 +251,14 @@ class Siggen:
Args:
new_level: The new level in [dBFS]
"""
self.msgq.put((SiggenMessage.adjustVolume, new_level))
self.pipe.send((SiggenMessage.adjustVolume, new_level))
def setEqData(self, eqdata):
self.pipe.send((SiggenMessage.newEqSettings, eqdata))
def handle_msgs(self):
while not self.statusq.empty():
msg, data = self.statusq.get()
while self.pipe.poll():
msg, data = self.pipe.recv()
if msg == SiggenMessage.error:
self.stop()
raise RuntimeError(
@ -239,6 +271,9 @@ class Siggen:
self.stop()
def start(self):
if self.stopped:
raise RuntimeError('BUG: This Siggen object cannot be used again.')
self.stream.addCallback(self.streamCallback, AvType.audio_output)
self.handle_msgs()
@ -249,9 +284,8 @@ class Siggen:
self.stream.removeCallback(self.streamCallback, AvType.audio_output)
while not self.dataq.empty():
self.dataq.get()
while not self.statusq.empty():
self.statusq.get()
self.msgq.put((SiggenMessage.stop, None))
self.pipe.send((SiggenMessage.stop, None))
self.pipe.close()
logging.debug('Joining siggen process')
self.process.join()
@ -276,4 +310,4 @@ class Siggen:
outdata[:, :] = 0
if self.dataq.qsize() < self.nblocks_buffer:
self.msgq.put((SiggenMessage.generate, None))
self.pipe.send((SiggenMessage.generate, None))

View File

@ -74,7 +74,7 @@ cdef extern from "lasp_python.h":
__all__ = ['AvPowerSpectra', 'SosFilterBank', 'FilterBank', 'Siggen',
'sweep_flag_forward', 'sweep_flag_backward', 'sweep_flag_linear',
'sweep_flag_exponential',
'load_fft_wisdom', 'store_fft_wisdom']
'load_fft_wisdom', 'store_fft_wisdom', 'Window']
setTracerLevel(15)
@ -635,6 +635,7 @@ cdef extern from "lasp_siggen.h":
c_Siggen* Siggen_Sweep_create(d fs, d fl,
d fu, d Ts,d Tq, us sweep_flags,
d level_dB)
void Siggen_setLevel(c_Siggen*,d new_level_dB)
us Siggen_getN(const c_Siggen*)
void Siggen_genSignal(c_Siggen*, vd* samples) nogil
void Siggen_free(c_Siggen*)
@ -659,6 +660,9 @@ cdef class Siggen:
if self._siggen:
Siggen_free(self._siggen)
def setLevel(self,d level_dB):
Siggen_setLevel(self._siggen, level_dB)
def genSignal(self, us nsamples):
output = np.empty(nsamples, dtype=np.float)
assert self._siggen != NULL