First part of signal generator implementation. White noise and sine waves are working.
This commit is contained in:
parent
3a86facb5a
commit
aa3581cf74
@ -14,6 +14,7 @@ add_library(lasp_lib
|
||||
lasp_aps.c
|
||||
lasp_ps.c
|
||||
lasp_mq.c
|
||||
lasp_siggen.c
|
||||
lasp_worker.c
|
||||
lasp_dfifo.c
|
||||
lasp_filterbank.c
|
||||
|
@ -30,6 +30,8 @@ void DBG_AssertFailedExtImplementation(const char* file,
|
||||
DBG_AssertFailedExtImplementation(__FILE__, __LINE__, assert_string ); \
|
||||
}
|
||||
|
||||
#define assertvalidptr(ptr) dbgassert(ptr,NULLPTRDEREF)
|
||||
|
||||
#else // LASP_DEBUG not defined
|
||||
|
||||
#define dbgassert(assertion, assert_string)
|
||||
|
141
lasp/c/lasp_siggen.c
Normal file
141
lasp/c/lasp_siggen.c
Normal file
@ -0,0 +1,141 @@
|
||||
// lasp_siggen.c
|
||||
//
|
||||
// Author: J.A. de Jong -ASCEE
|
||||
//
|
||||
// Description:
|
||||
// Signal generator implementation
|
||||
//////////////////////////////////////////////////////////////////////
|
||||
#define TRACERPLUS (-5)
|
||||
#include "lasp_alloc.h"
|
||||
#include "lasp_assert.h"
|
||||
#include "lasp_mat.h"
|
||||
|
||||
#define PRIVATE_SIZE 32
|
||||
|
||||
typedef enum {
|
||||
SINEWAVE = 0,
|
||||
WHITENOISE,
|
||||
PINKNOISE,
|
||||
SWEEP,
|
||||
|
||||
} SignalType;
|
||||
|
||||
|
||||
typedef struct {
|
||||
SignalType signaltype;
|
||||
d fs; // Sampling frequency [Hz]
|
||||
void* private;
|
||||
|
||||
char private_data[PRIVATE_SIZE];
|
||||
|
||||
} Siggen;
|
||||
|
||||
typedef struct {
|
||||
d curtime;
|
||||
d omg;
|
||||
} SinewaveSpecific;
|
||||
|
||||
|
||||
Siggen* Siggen_Sinewave_create(const d fs, const d freq) {
|
||||
fsTRACE(15);
|
||||
|
||||
Siggen* sinesiggen = a_malloc(sizeof(Siggen));
|
||||
sinesiggen->signaltype = SINEWAVE;
|
||||
sinesiggen->fs = fs;
|
||||
sinesiggen->private = sinesiggen->private_data;
|
||||
SinewaveSpecific* sp = (SinewaveSpecific*) sinesiggen->private;
|
||||
sp->curtime = 0;
|
||||
sp->omg = 2*number_pi*freq;
|
||||
|
||||
|
||||
feTRACE(15);
|
||||
return sinesiggen;
|
||||
}
|
||||
Siggen* Siggen_Whitenoise_create() {
|
||||
fsTRACE(15);
|
||||
|
||||
Siggen* whitenoise = a_malloc(sizeof(Siggen));
|
||||
whitenoise->signaltype = WHITENOISE;
|
||||
|
||||
feTRACE(15);
|
||||
return whitenoise;
|
||||
}
|
||||
void Siggen_free(Siggen* siggen) {
|
||||
fsTRACE(15);
|
||||
assertvalidptr(siggen);
|
||||
|
||||
if(siggen->signaltype == SWEEP) {
|
||||
/* Sweep specific stuff here */
|
||||
}
|
||||
|
||||
a_free(siggen);
|
||||
feTRACE(15);
|
||||
}
|
||||
static void Sinewave_genSignal(Siggen* siggen, SinewaveSpecific* sine, vd* samples) {
|
||||
fsTRACE(15);
|
||||
assertvalidptr(sine);
|
||||
d ts = 1/siggen->fs;
|
||||
d omg = sine->omg;
|
||||
|
||||
d curtime = sine->curtime;
|
||||
for(us i =0; i< samples->n_rows; i++) {
|
||||
setvecval(samples, i, sin(omg*curtime));
|
||||
curtime = curtime + ts;
|
||||
}
|
||||
sine->curtime = curtime;
|
||||
feTRACE(15);
|
||||
}
|
||||
|
||||
static d gaussrand() {
|
||||
static d V1, V2, S;
|
||||
static int phase = 0;
|
||||
d X;
|
||||
|
||||
if(phase == 0) {
|
||||
do {
|
||||
d U1 = (d)rand() / RAND_MAX;
|
||||
d U2 = (d)rand() / RAND_MAX;
|
||||
|
||||
V1 = 2 * U1 - 1;
|
||||
V2 = 2 * U2 - 1;
|
||||
S = V1 * V1 + V2 * V2;
|
||||
} while(S >= 1 || S == 0);
|
||||
|
||||
X = V1 * sqrt(-2 * log(S) / S);
|
||||
} else
|
||||
X = V2 * sqrt(-2 * log(S) / S);
|
||||
|
||||
phase = 1 - phase;
|
||||
|
||||
return X;
|
||||
}
|
||||
static void Whitenoise_genSignal(Siggen* siggen, vd* samples) {
|
||||
for(us i =0; i< samples->n_rows; i++) {
|
||||
d rn = gaussrand();
|
||||
setvecval(samples, i, rn);
|
||||
}
|
||||
|
||||
}
|
||||
void Siggen_genSignal(Siggen* siggen,vd* samples) {
|
||||
fsTRACE(15);
|
||||
assertvalidptr(siggen);
|
||||
assert_vx(samples);
|
||||
d fs = siggen->fs;
|
||||
|
||||
switch(siggen->signaltype) {
|
||||
case SINEWAVE:
|
||||
Sinewave_genSignal(siggen, (SinewaveSpecific*) siggen->private,
|
||||
samples);
|
||||
|
||||
break;
|
||||
case WHITENOISE:
|
||||
Whitenoise_genSignal(siggen, samples);
|
||||
|
||||
}
|
||||
|
||||
feTRACE(15);
|
||||
}
|
||||
|
||||
|
||||
|
||||
//////////////////////////////////////////////////////////////////////
|
57
lasp/c/lasp_siggen.h
Normal file
57
lasp/c/lasp_siggen.h
Normal file
@ -0,0 +1,57 @@
|
||||
// lasp_siggen.h
|
||||
//
|
||||
// Author: J.A. de Jong - ASCEE
|
||||
//
|
||||
// Description:
|
||||
// Header file for signal generation routines
|
||||
//
|
||||
//////////////////////////////////////////////////////////////////////
|
||||
#pragma once
|
||||
#ifndef LASP_SIGGEN_H
|
||||
#define LASP_SIGGEN_H
|
||||
#include "lasp_mat.h"
|
||||
|
||||
typedef struct {} Siggen;
|
||||
|
||||
/**
|
||||
* Create a sine wave signal generator
|
||||
*
|
||||
* @param[in] fs: Sampling frequency [Hz]
|
||||
* @param[freq] Sine wave frequency [Hz]
|
||||
*/
|
||||
Siggen* Siggen_Sinewave_create(const d fs,const d freq);
|
||||
|
||||
/**
|
||||
* Create a white noise signal generator
|
||||
*
|
||||
* @return Siggen* handle
|
||||
*/
|
||||
Siggen* Siggen_Whitenoise_create();
|
||||
|
||||
/**
|
||||
* Create a pink (1/f) noise signal generator
|
||||
*
|
||||
* @param[in] fs: Sampling frequency [Hz]
|
||||
* @return Siggen* handle
|
||||
*/
|
||||
Siggen* Siggen_Pinknoise_create(const us fs);
|
||||
|
||||
/* Siggen* Siggen_ForwardSweep_create(const d fs,; */
|
||||
/* Siggen* Siggen_(const d fs,; */
|
||||
|
||||
/**
|
||||
* Obtain a new piece of signal
|
||||
*
|
||||
* @param[in] Siggen* Signal generator private data
|
||||
* @param[out] samples Samples to fill. Vector should be pre-allocated
|
||||
*/
|
||||
void Siggen_genSignal(Siggen*,vd* samples);
|
||||
/**
|
||||
* Free Siggen data
|
||||
*
|
||||
* @param[in] Siggen* Signal generator private data
|
||||
*/
|
||||
void Siggen_free(Siggen*);
|
||||
|
||||
#endif LASP_SIGGEN_H
|
||||
//////////////////////////////////////////////////////////////////////
|
@ -65,6 +65,8 @@ class AvStream:
|
||||
rtaudio_inputparams = None
|
||||
rtaudio_outputparams = None
|
||||
|
||||
self.nframes_per_block = 2048
|
||||
|
||||
if self.duplex_mode or avtype == AvType.audio_output:
|
||||
rtaudio_outputparams = {'deviceid': device.index,
|
||||
# TODO: Add option to specify the number of output channels to use
|
||||
@ -92,7 +94,7 @@ class AvStream:
|
||||
rtaudio_inputparams, # Inputparams
|
||||
self.sampleformat, # Sampleformat
|
||||
self.samplerate,
|
||||
2048, # Buffer size in frames
|
||||
self.nframes_per_block, # Buffer size in frames
|
||||
self._audioCallback)
|
||||
|
||||
except Exception as e:
|
||||
|
@ -1,86 +0,0 @@
|
||||
#!/usr/bin/env python3.6
|
||||
# -*- coding: utf-8 -*-
|
||||
"""
|
||||
Description: Read data from image stream and record sound at the same time
|
||||
"""
|
||||
from .lasp_atomic import Atomic
|
||||
from threading import Thread, Condition, Lock
|
||||
from .lasp_avstream import AvType, AvStream
|
||||
import numpy as np
|
||||
|
||||
class SignalGenerator:
|
||||
"""
|
||||
Base class for all signal generator types
|
||||
"""
|
||||
|
||||
def __init__(self, stream):
|
||||
|
||||
if not (stream.avtype == AvType.audio_output or (stream.avtype ==
|
||||
AvType.audio_input and
|
||||
stream.duplex_mode)):
|
||||
raise RuntimeError('Invalid stream type. Does not support audio'
|
||||
'output')
|
||||
|
||||
self.stream = stream
|
||||
self._samplerate = stream.samplerate
|
||||
stream.addCallback(self.streamCallback, AvType.audio_output)
|
||||
|
||||
def stop(self):
|
||||
"""
|
||||
Stop generating the signal
|
||||
"""
|
||||
self.stream.removeCallback(self.streamCallback, AvType.audio_output)
|
||||
|
||||
def streamCallback(self, indata, outdata, blockctr):
|
||||
"""
|
||||
Callback from AvStream.
|
||||
"""
|
||||
signal = self.getSignal(blockctr*outdata.shape[0], outdata.shape[0])
|
||||
dtype = self.stream.numpy_dtype
|
||||
|
||||
if dtype == np.float32 or dtype == np.float64:
|
||||
fac = 1
|
||||
else:
|
||||
bitdepth_fixed = self.stream.sampwidth*8
|
||||
fac = 2**(bitdepth_fixed-1)
|
||||
|
||||
outdata[:, :] = (fac*signal).astype(dtype)[:, np.newaxis]
|
||||
|
||||
|
||||
class SineGenerator(SignalGenerator):
|
||||
def __init__(self, stream, freq):
|
||||
self._omg = 2*freq*np.pi
|
||||
super().__init__(stream)
|
||||
|
||||
def getSignal(self, startidx, frames):
|
||||
samplerate = self._samplerate
|
||||
streamtime = startidx/samplerate
|
||||
t = np.linspace(streamtime, streamtime + frames/samplerate, frames)
|
||||
|
||||
return 0.1*np.sin(self._omg*t)
|
||||
|
||||
|
||||
class NoiseGenerator(SignalGenerator):
|
||||
def __init__(self, stream, noisetype):
|
||||
super().__init__(stream)
|
||||
|
||||
def getSignal(self, startidx, frames):
|
||||
return 0.1*np.random.randn(frames)
|
||||
|
||||
class NoiseType:
|
||||
white = (0, 'White noise', )
|
||||
pink = (1, 'Pink noise')
|
||||
types = (white, pink)
|
||||
|
||||
@staticmethod
|
||||
def fillComboBox(combo):
|
||||
for type_ in NoiseType.types:
|
||||
combo.addItem(type_[1])
|
||||
|
||||
@staticmethod
|
||||
def getCurrent(cb):
|
||||
return NoiseType.types[cb.currentIndex()]
|
||||
|
||||
|
||||
|
||||
|
@ -467,3 +467,54 @@ cdef class SPLowpass:
|
||||
vd_free(&input_vd)
|
||||
|
||||
return result
|
||||
|
||||
|
||||
cdef extern from "lasp_siggen.h":
|
||||
ctypedef struct c_Siggen "Siggen"
|
||||
c_Siggen* Siggen_Whitenoise_create()
|
||||
c_Siggen* Siggen_Sinewave_create(d fs, d freq)
|
||||
void Siggen_genSignal(c_Siggen*, vd* samples) nogil
|
||||
void Siggen_free(c_Siggen*)
|
||||
|
||||
|
||||
cdef class Siggen:
|
||||
cdef c_Siggen *_siggen
|
||||
|
||||
def __cinit__(self):
|
||||
self._siggen = NULL
|
||||
|
||||
def __dealloc__(self):
|
||||
if self._siggen:
|
||||
Siggen_free(self._siggen)
|
||||
|
||||
def genSignal(self, us nsamples):
|
||||
output = np.empty(nsamples, dtype=np.float)
|
||||
assert self._siggen != NULL
|
||||
|
||||
cdef d[:] output_view = output
|
||||
|
||||
cdef dmat output_dmat = dmat_foreign_data(nsamples,
|
||||
1,
|
||||
&output_view[0],
|
||||
False)
|
||||
with nogil:
|
||||
Siggen_genSignal(self._siggen,
|
||||
&output_dmat)
|
||||
|
||||
return output
|
||||
|
||||
|
||||
@staticmethod
|
||||
def sineWave(fs, freq):
|
||||
cdef c_Siggen* c_siggen = Siggen_Sinewave_create(fs, freq)
|
||||
siggen = Siggen()
|
||||
siggen._siggen = c_siggen
|
||||
return siggen
|
||||
|
||||
|
||||
@staticmethod
|
||||
def whiteNoise():
|
||||
cdef c_Siggen* c_siggen = Siggen_Whitenoise_create()
|
||||
siggen = Siggen()
|
||||
siggen._siggen = c_siggen
|
||||
return siggen
|
||||
|
Loading…
Reference in New Issue
Block a user