def test_inverted_sync_sweep_spectrum():
    FFTLEN = 1024
    sweep = SyncSweep(10, 1000, 2, 2000)
    ispec = InvertedSyncSweepSpectrum.from_sweep(sweep, fftlen=FFTLEN)
    assume(ispec.fftlen == FFTLEN)
    assume(len(ispec.freq) == (FFTLEN // 2 + 1))
    assume(len(ispec.spectrum) == (FFTLEN // 2 + 1))
    assume(ispec.spectrum[0] == 0j)
    expected_invspec = np.zeros_like(ispec.spectrum)
    expected_invspec[0] = 0j
    expected_invspec[1:] = (
        2 * np.sqrt(ispec.freq[1:] / sweep.sweepperiod) *
        np.exp(-2j * np.pi * ispec.freq[1:] * sweep.sweepperiod *
               (1 - np.log(ispec.freq[1:] / sweep.startfreq)) +
               1j * np.pi / 4))
    assume(np.allclose(ispec.spectrum, expected_invspec))

    ispec.fftlen = 2 * FFTLEN
    assume(ispec.fftlen == 2 * FFTLEN)
    assume(len(ispec.freq) == (2 * FFTLEN // 2 + 1))
    assume(len(ispec.spectrum) == (2 * FFTLEN // 2 + 1))
    assume(len(ispec) == len(ispec.spectrum))
    assume(np.all(ispec.spectrum[::-1] == ispec[::-1]))
    assume(np.array(ispec, dtype='complex64').dtype == np.complex64)
    assume(ispec.__repr__().startswith('InvertedSyncSweepSpectrum('))
def test_linear_model():
    sweep = SyncSweep(startfreq=16,
                      stopfreq=16000,
                      durationappr=10,
                      samplerate=96000)

    def nonlinear_system(sig):
        return 0.5 * sig + 0.25 * sig**2 + 0.125 * sig**3

    outsweep = nonlinear_system(np.array(sweep))
    hhir = HigherHarmonicImpulseResponse.from_sweeps(sweep, outsweep)
    lm = LinearModel.from_higher_harmonic_impulse_response(hhir, length=1024)
    x = np.array([1] + 127 * [0])
    y = lm.filter(x)
    with pytest.raises(ValueError):
        hm = LinearModel.from_higher_harmonic_impulse_response(hhir,
                                                               96e4,
                                                               delay=0)
def test_higher_harmonic_impulse_response():
    sweep = SyncSweep(10, 10000, 5, 20000)
    hhir = HigherHarmonicImpulseResponse.from_sweeps(sweep, sweep)
    assume(np.all(np.array(hhir) == hhir.hhir))
    hir = hhir.harmonic_impulse_response(order=1,
                                         length=1024,
                                         delay=0,
                                         window=True)
    assume(type(hir) == np.ndarray)
    assume(len(hir) == 1024)
    assume(np.argmax(hir) == 512)
    hir = hhir.harmonic_impulse_response(order=1,
                                         length=1024,
                                         delay=0,
                                         window=np.linspace(0, 1, 1024))
    assume(type(hir) == np.ndarray)
    assume(len(hir) == 1024)
    assume(np.argmax(hir) == 512)
def test_sync_sweep_instantiation():
    SyncSweep(20, 20000, 4, 44100)
    SyncSweep(16, 16000, 5, 48000)
    with pytest.raises(TypeError):
        # must not be callable without arguments.
        SyncSweep()
def test_sync_sweep_instantiation_errors(startfreq, stopfreq, durationappr,
                                         samplerate):
    with pytest.raises(ValueError):
        SyncSweep(startfreq, stopfreq, durationappr, samplerate)
Esempio n. 6
0
class Measurement(object):
    def __init__(self, config):
        self._config = config or DEFAULTS
        self._sweep = None

    def save_config(self, path):
        with open(_pathlib.Path(path)/_cfg.CONFIGFILENAME, 'w') as fp:
            return _yaml.dump(fp, self._config)

    @classmethod
    def from_config_file(cls, filepath):
        config = _cfg.load_config(filepath)
        return cls(**config)

    def run_adaptive_delay_and_decay_measurement(self):
        cfg = {
            **self._config, 
            **self._config['measurement'], 
            **self._config['sounddevice']
            }

        stream_kwargs = {k: cfg[k] for k in (
            'samplerate', 'device', 'channels', 'dtype', 'blocksize')}
        callback = SounddeviceQueueCallback()
        with _sd.Stream(
                callback=callback,
                **stream_kwargs):
            noise, data, delay, decay = estimate_adaptive_delay_and_decay(
                input_queue=callback.input_queue, 
                output_queue=callback.output_queue,
                noise_level_dbfs=cfg['noise']['level_dbfs'],
                noise_duration=cfg['noise']['duration'], 
                **cfg)
        return noise, data, delay, decay

    def run_sweep_measurement(self):
        cfg = {
            **self._config, 
            **self._config['sweep'], 
            **self._config['measurement'],
            **self._config['sounddevice']}
        if not self._sweep:
            self._sweep = SyncSweep(
                startfreq=cfg['startfreq'],
                stopfreq=cfg['stopfreq'],
                durationappr=cfg['durationappr'],
                samplerate=cfg['samplerate'],
            )

        sweep_playback_signal = self._sweep.get_windowed_signal(
            left=cfg['flanksamples'],
            right=cfg['flanksamples'],
            pausestart=cfg['pausestart'],
            pausestop=cfg['pausestop'],
            amplitude=10**(cfg['sweep']['level_dbfs']/20))

        measured_sweep = _sd.playrec(
            sweep_playback_signal, 
            samplerate=cfg['samplerate'], 
            device=cfg['device'],
            input_mapping=cfg['channelmap_input'], 
            output_mapping=cfg['channelmap_output'], 
            blocking=True)
        return sweep_playback_signal, measured_sweep

    def run(self):
        cfg = {
            **self._config, 
            **self._config['measurement']}
        auto = cfg['auto']
        delays = cfg['delays']
        irlength = cfg['irlength']
        pausestart = cfg['pausestart']
        pausestop = cfg['pausestop']
        window = cfg['window']
        _time.sleep(cfg['wait_before_start_sec'])
        if auto:
            (noise, 
            measured_noises, 
            delays,
            decay) = self.run_adaptive_delay_and_decay_measurement()
            pausestop = max(pausestop, decay)
            self._config['measurement']['pausestop'] = pausestop
            irlength = max(irlength, decay)
        else:
            measured_noises = None
        sweep, measured_sweeps = self.run_sweep_measurement()
        delays_total = _np.array(delays) + pausestart
        delays_total[:] = _np.median(delays_total).astype(_np.int)
        linear_models = estimate_lm_from_sweeps(self._sweep, measured_sweeps, irlength, delays_total, window)
        rirs = _np.array([lm.kernel.ir for lm in linear_models]).transpose()

        res = Result(
            uid=_uuid.uuid4().hex,
            config=self._config,
            input_sweep=sweep,
            input_noise=noise,
            measured_sweeps=measured_sweeps, 
            measured_noises=measured_noises,
            delays=delays,
            delays_total=delays_total,
            samplerate=self._config['measurement']['samplerate'],
            rirs=rirs)
        return res
Esempio n. 7
0
    [1.0, -1.8996, 0.9025],
    [1.0, -1.9075, 0.9409],
    [1.0, -1.8471, 0.8649],
    ]
B = [
    [1.0, -1.9027, 0.9409],
    [1.0, -1.8959, 0.9025],
    [0.5, -0.9176, 0.4512],
    ]
orders = [1, 2, 3]
kernels_theo = [IirFilterKernel(*ba) for ba in zip(B, A)]
hm_theo = HammersteinModel(kernels_theo, orders)


# system identification of the theoretical system
sweep = SyncSweep(f1, f2, dursec, samplerate)
sweep_sig = sweep.get_windowed_signal(1024, 1024, pausestart=0, pausestop=512)
outsweep = hm_theo.filter(sweep_sig)
hhir = HigherHarmonicImpulseResponse.from_sweeps(sweep, outsweep, regularize=False)
hm_identified = HammersteinModel.from_higher_harmonic_impulse_response(
    hhir=hhir,
    length=nfft,
    orders=orders,
    delay=0,
    window=True,
)

# bode diagram of the theoretical and identification results
figure()
for theo, kernel, order in zip(hm_theo.kernels, hm_identified.kernels, orders):
    freq = kernel.freq
Esempio n. 8
0
import numpy as np
from syncsweptsine import SyncSweep
from syncsweptsine import HigherHarmonicImpulseResponse
from syncsweptsine import HammersteinModel
import matplotlib.pyplot as plt

sweep = SyncSweep(startfreq=16,
                  stopfreq=16000,
                  durationappr=10,
                  samplerate=96000)


def nonlinear_system(sig):
    return 1.0 * sig + 0.25 * sig**2 + 0.125 * sig**3


outsweep = nonlinear_system(np.array(sweep))
# hhir = HigherHarmonicImpulseResponse.from_sweeps(sweep, outsweep)
#hm = HammersteinModel.from_higher_harmonic_impulse_response(
#    hhir, 2048, orders=(1, 2, 3), delay=0)
hm = HammersteinModel.from_sweeps(sweep,
                                  outsweep,
                                  orders=(1, 2, 3),
                                  regularize=False)
for kernel, order in zip(hm.kernels, hm.orders):
    plt.plot(abs(kernel.frf))
    print('Coefficient estimate of nonlinear system:',
          np.round(np.max(abs(kernel.frf[500:1000])), 3), 'Order', order)

plt.show()