Added a setLevel function to siggen.h, Some bugfix and partially working signal generator
This commit is contained in:
parent
11cc623363
commit
547b00f116
@ -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
|
||||
|
@ -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);
|
||||
|
@ -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.
|
||||
|
@ -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 *
|
||||
|
@ -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']
|
||||
|
||||
|
@ -1,4 +1,3 @@
|
||||
#!/usr/bin/env python3
|
||||
# -*- coding: utf-8 -*-
|
||||
"""!
|
||||
Author: J.A. de Jong - ASCEE
|
||||
|
@ -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:
|
||||
|
@ -1,3 +1,12 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
"""!
|
||||
Author: J.A. de Jong - ASCEE
|
||||
|
||||
Description:
|
||||
|
||||
DeviceInfo C++ object wrapper
|
||||
|
||||
"""
|
||||
__all__ = ['DeviceInfo']
|
||||
|
||||
|
||||
|
@ -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.
|
||||
|
@ -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:
|
||||
|
@ -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
|
||||
|
@ -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))
|
||||
|
@ -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
|
||||
|
Loading…
Reference in New Issue
Block a user