Sweep bug fixed. There is still something weird with RtAudio: only one channel is outputting signal.

This commit is contained in:
Anne de Jong 2022-09-22 21:02:41 +02:00
parent b200b465f6
commit 5ce5fba50b
12 changed files with 228 additions and 83 deletions

View File

@ -9,6 +9,7 @@ option(LASP_DOUBLE_PRECISION "Compile as double precision floating point" ON)
option(LASP_HAS_RTAUDIO "Compile with RtAudio Daq backend" ON) option(LASP_HAS_RTAUDIO "Compile with RtAudio Daq backend" ON)
option(LASP_HAS_ULDAQ "Compile with UlDaq backend" ON) option(LASP_HAS_ULDAQ "Compile with UlDaq backend" ON)
option(LASP_BUILD_TUNED "Tune build for current machine" OFF) option(LASP_BUILD_TUNED "Tune build for current machine" OFF)
option(LASP_WITH_OPENMP "Use OpenMP parallelization" ON)
# Use ccache if available # Use ccache if available
find_program(CCACHE_PROGRAM ccache) find_program(CCACHE_PROGRAM ccache)
@ -42,6 +43,8 @@ set(CMAKE_POSITION_INDEPENDENT_CODE ON)
if(${CMAKE_BUILD_TYPE} STREQUAL "Debug") if(${CMAKE_BUILD_TYPE} STREQUAL "Debug")
set(LASP_DEBUG True) set(LASP_DEBUG True)
# This does not work nicely with RtAudio
# add_definitions(-D_GLIBCXX_DEBUG)
else() else()
set(LASP_DEBUG False) set(LASP_DEBUG False)
endif() endif()
@ -65,8 +68,12 @@ add_definitions(-DLASP_MAX_NFFT=33554432) # 2**25
# ####################################### End of user-adjustable variables section # ####################################### End of user-adjustable variables section
include(OSSpecific) include(OSSpecific)
# Enable openmp set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wall -Wextra -Wno-type-limits")
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} ${OpenMP_CXX_FLAGS} -Wall -Wextra -Wno-type-limits")
# Enable openmp, if set
if(LASP_WITH_OPENMP)
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} ${OpenMP_CXX_FLAGS}")
endif()
set(CMAKE_C_FLAGS_RELEASE "-O3 -flto -mfpmath=sse -march=x86-64 -mtune=native \ set(CMAKE_C_FLAGS_RELEASE "-O3 -flto -mfpmath=sse -march=x86-64 -mtune=native \
-fdata-sections -ffunction-sections -fomit-frame-pointer -finline-functions") -fdata-sections -ffunction-sections -fomit-frame-pointer -finline-functions")
@ -78,7 +85,6 @@ add_subdirectory(third_party/carma)
if(LASP_FFT_BACKEND STREQUAL "FFTW") if(LASP_FFT_BACKEND STREQUAL "FFTW")
find_library(fftw3 REQUIRED NAMES fftw fftw3) find_library(fftw3 REQUIRED NAMES fftw fftw3)
set(LASP_FFT_LIBS "fftw3") set(LASP_FFT_LIBS "fftw3")
message("LASP_FFT_LIBS = ${LASP_FFT_LIBS}")
elseif(LASP_FFT_BACKEND STREQUAL "Armadillo") elseif(LASP_FFT_BACKEND STREQUAL "Armadillo")
endif() endif()

View File

@ -28,6 +28,7 @@ pybind11_add_module(lasp_cpp MODULE lasp_cpp.cpp
pybind11/lasp_daq.cpp pybind11/lasp_daq.cpp
pybind11/lasp_deviceinfo.cpp pybind11/lasp_deviceinfo.cpp
pybind11/lasp_pyindatahandler.cpp pybind11/lasp_pyindatahandler.cpp
pybind11/lasp_siggen.cpp
) )
target_link_libraries(lasp_cpp PRIVATE lasp_device_lib lasp_dsp_lib target_link_libraries(lasp_cpp PRIVATE lasp_device_lib lasp_dsp_lib

View File

@ -60,7 +60,7 @@ public:
*/ */
DaqData() : DaqData(0, 0, DataTypeDescriptor::DataType::dtype_int8) {} DaqData() : DaqData(0, 0, DataTypeDescriptor::DataType::dtype_int8) {}
virtual ~DaqData() = default; virtual ~DaqData() = default;
DaqData& operator=(const DaqData&) = default; DaqData &operator=(const DaqData &) = default;
/** /**
* @brief Return pointer to the raw data corresponding to a certain sample. * @brief Return pointer to the raw data corresponding to a certain sample.
@ -74,6 +74,12 @@ public:
return &(_data.data()[sw * (frame + channel * nframes)]); return &(_data.data()[sw * (frame + channel * nframes)]);
} }
void setSlow(const us frame, const us channel, const int8_t* val) {
for(us i=0;i<sw;i++) {
_data.at(i+sw*(frame + channel*nframes)) = val[i];
}
}
/** /**
* @brief Return the total number of bytes * @brief Return the total number of bytes
* *

View File

@ -327,14 +327,14 @@ class RtAudioDaq : public Daq {
if (outputBuffer) { if (outputBuffer) {
std::vector<uint8_t *> ptrs; std::vector<uint8_t *> ptrs;
ptrs.reserve(neninchannels); ptrs.reserve(nenoutchannels);
DaqData data(nenoutchannels, nFramesPerBlock, dtype);
/* outCallback */ /* outCallback */
for (int ch = 0; ch <= getHighestOutChannel(); ch++) { for (int ch = 0; ch <= getHighestOutChannel(); ch++) {
/* DEBUGTRACE_PRINT(outchannel_config.at(ch).enabled); */
if (outchannel_config.at(ch).enabled) { if (outchannel_config.at(ch).enabled) {
ptrs.push_back(&static_cast<uint8_t *>( ptrs.push_back(&(static_cast<uint8_t *>(
outputBuffer)[sw * nenoutchannels * ch * nFramesPerBlock]); outputBuffer)[sw * nenoutchannels * ch * nFramesPerBlock]));
} }
} }
DaqData d{nenoutchannels, nFramesPerBlock, dtype}; DaqData d{nenoutchannels, nFramesPerBlock, dtype};

View File

@ -89,6 +89,25 @@ bool StreamMgr::inCallback(const DaqData &data) {
return true; return true;
} }
void StreamMgr::setSiggen(std::shared_ptr<Siggen> siggen) {
DEBUGTRACE_ENTER;
checkRightThread();
std::scoped_lock<std::mutex> lck(_siggen_mtx);
// If not set to nullptr, and a stream is running, we update the signal
// generator by resetting it.
if (isStreamRunningOK(StreamType::output) && siggen) {
const Daq *daq = getDaq(StreamType::output);
assert(daq != nullptr);
// Reset the signal generator.
siggen->reset(daq->samplerate());
}
_siggen = siggen;
}
#define DEBUG_FILLDATA 0
/** /**
* @brief Converts from double precision floating point to output signal in * @brief Converts from double precision floating point to output signal in
* non-interleaving format. * non-interleaving format.
@ -100,48 +119,45 @@ bool StreamMgr::inCallback(const DaqData &data) {
* @return * @return
*/ */
template <typename T> bool fillData(DaqData &data, const vd &signal) { template <typename T> bool fillData(DaqData &data, const vd &signal) {
/* DEBUGTRACE_ENTER; */
assert(data.nframes == signal.size()); assert(data.nframes == signal.size());
/* cerr << "SFSG: data.nframes:" << data.nframes << endl; */
/* cerr << "SFSG: data.nchannels:" << data.nchannels << endl; */
T *res = reinterpret_cast<T *>(data.raw_ptr()); T *res = reinterpret_cast<T *>(data.raw_ptr());
if (std::is_floating_point<T>()) { if (std::is_floating_point<T>()) {
for (us ch = 0; ch < data.nchannels; ch++) { for (us ch = 0; ch < data.nchannels; ch++) {
for (us frame = 0; frame < data.nframes; frame++) { for (us frame = 0; frame < data.nframes; frame++) {
#if DEBUG_FILLDATA == 1
DEBUGTRACE_PRINT("SLOW flt");
data.setSlow(frame, ch,
reinterpret_cast<const int8_t *>(&signal[frame]));
#else
res[ch * data.nframes + frame] = signal[frame]; res[ch * data.nframes + frame] = signal[frame];
#endif
} }
} }
} else { } else {
for (us ch = 0; ch < data.nchannels; ch++) { for (us ch = 0; ch < data.nchannels; ch++) {
for (us frame = 0; frame < data.nframes; frame++) { for (us frame = 0; frame < data.nframes; frame++) {
res[ch * data.nframes + frame] = const T val = (signal[frame] * std::numeric_limits<T>::max());
(signal[frame] * std::numeric_limits<T>::max()); #if DEBUG_FILLDATA == 1
data.setSlow(frame, ch, reinterpret_cast<const int8_t *>(&val));
#else
res[ch * data.nframes + frame] = val;
#endif
} }
} }
} }
return true; return true;
} }
void StreamMgr::setSiggen(std::shared_ptr<Siggen> siggen) {
checkRightThread();
std::scoped_lock<std::mutex> lck(_siggen_mtx);
_siggen = siggen;
// If not set to nullptr, and a stream is running, we update the signal
// generator by resetting it.
if (isStreamRunningOK(StreamType::output) && siggen) {
const Daq *daq = getDaq(StreamType::output);
assert(daq != nullptr);
// Reset the signal generator.
_siggen->reset(daq->samplerate());
}
}
bool StreamMgr::outCallback(DaqData &data) { bool StreamMgr::outCallback(DaqData &data) {
/* DEBUGTRACE_ENTER; */ /* DEBUGTRACE_ENTER; */
std::scoped_lock<std::mutex> lck(_siggen_mtx); std::scoped_lock<std::mutex> lck(_siggen_mtx);
if (_siggen) { if (_siggen) {
vd signal = _siggen->genSignal(data.nframes); vd signal = _siggen->genSignal(data.nframes);
switch (data.dtype) { switch (data.dtype) {
@ -237,6 +253,8 @@ void StreamMgr::startStream(const DaqConfiguration &config) {
if (isOutput) { if (isOutput) {
if (_siggen) { if (_siggen) {
DEBUGTRACE_PRINT("Resetting _siggen with new samplerate of ");
DEBUGTRACE_PRINT(daq->samplerate());
_siggen->reset(daq->samplerate()); _siggen->reset(daq->samplerate());
} }
outCallback = std::bind(&StreamMgr::outCallback, this, _1); outCallback = std::bind(&StreamMgr::outCallback, this, _1);
@ -248,6 +266,9 @@ void StreamMgr::startStream(const DaqConfiguration &config) {
if (isInput) { if (isInput) {
_inputStream = std::move(daq); _inputStream = std::move(daq);
if (daq->duplexMode()) {
assert(!_outputStream);
}
} else { } else {
assert(isOutput); assert(isOutput);
_outputStream = std::move(daq); _outputStream = std::move(daq);
@ -291,7 +312,7 @@ void StreamMgr::removeInDataHandler(InDataHandler &handler) {
} }
Daq::StreamStatus StreamMgr::getStreamStatus(const StreamType type) const { Daq::StreamStatus StreamMgr::getStreamStatus(const StreamType type) const {
DEBUGTRACE_ENTER; /* DEBUGTRACE_ENTER; */
checkRightThread(); checkRightThread();
// Default constructor, says stream is not running, but also no errors // Default constructor, says stream is not running, but also no errors

View File

@ -1,21 +1,25 @@
/* #define DEBUGTRACE_ENABLED */
#include "debugtrace.hpp"
#include "lasp_siggen.h" #include "lasp_siggen.h"
#include "lasp_mathtypes.h" #include "lasp_mathtypes.h"
#include <cassert> #include <cassert>
#include <type_traits> #include <type_traits>
using std::cerr;
using std::endl;
inline d level_amp(d level_dB){ inline d level_amp(d level_dB) { return pow(10, level_dB / 20); }
return pow(10, level_dB/20);
}
using mutexlock = std::scoped_lock<std::mutex>; using mutexlock = std::scoped_lock<std::mutex>;
vd Siggen::genSignal(const us nframes) { vd Siggen::genSignal(const us nframes) {
DEBUGTRACE_ENTER;
mutexlock lck(_mtx); mutexlock lck(_mtx);
vd signal(nframes, arma::fill::value(_dc_offset)); vd signal(nframes, arma::fill::value(_dc_offset));
if (!_muted) { if (!_muted) {
vd signal_dynamic = _level_linear*genSignalUnscaled(nframes); vd signal_dynamic = _level_linear * genSignalUnscaled(nframes);
if(_filter) { if (_filter) {
_filter->filter(signal_dynamic); _filter->filter(signal_dynamic);
} }
signal += signal_dynamic; signal += signal_dynamic;
@ -23,20 +27,24 @@ vd Siggen::genSignal(const us nframes) {
return signal; return signal;
} }
void Siggen::setFilter(std::shared_ptr<Filter>& filter) { void Siggen::setFilter(std::shared_ptr<Filter> filter) {
DEBUGTRACE_ENTER;
mutexlock lck(_mtx); mutexlock lck(_mtx);
_filter = filter; _filter = filter;
} }
void Siggen::setDCOffset(const d offset) { void Siggen::setDCOffset(const d offset) {
DEBUGTRACE_ENTER;
mutexlock lck(_mtx); mutexlock lck(_mtx);
_dc_offset = offset; _dc_offset = offset;
} }
void Siggen::setLevel(const d level,bool dB) { void Siggen::setLevel(const d level, bool dB) {
DEBUGTRACE_ENTER;
mutexlock lck(_mtx); mutexlock lck(_mtx);
_level_linear = dB ? level_amp(level) : level; _level_linear = dB ? level_amp(level) : level;
} }
void Siggen::reset(const d newFs) { void Siggen::reset(const d newFs) {
DEBUGTRACE_ENTER;
mutexlock lck(_mtx); mutexlock lck(_mtx);
fs = newFs; _fs = newFs;
resetImpl(); resetImpl();
} }

View File

@ -8,17 +8,27 @@ class StreamMgr;
class DaqData; class DaqData;
/** /**
* @brief Signal generation base class * \addtogroup dsp
* @{
*/
/**
* \defgroup siggen Signal generators
* @{
*/
/**
* @brief Signal generation abstract base class. Implementation is required for
* resetImpl(), genSignalUnscaled() and destructor.
*/ */
class Siggen { class Siggen {
private: private:
std::shared_ptr<Filter> _filter; std::shared_ptr<Filter> _filter;
d _dc_offset = 0, _level_linear = 1; d _dc_offset = 0, _level_linear = 1;
bool _muted = false; bool _muted = false;
std::mutex _mtx;
protected: protected:
d fs = -1; std::mutex _mtx;
d _fs = 0;
virtual void resetImpl() = 0; virtual void resetImpl() = 0;
virtual vd genSignalUnscaled(const us nframes) = 0; virtual vd genSignalUnscaled(const us nframes) = 0;
@ -32,7 +42,7 @@ public:
* *
* @param f The filter to install. * @param f The filter to install.
*/ */
void setFilter(std::shared_ptr<Filter>& f); void setFilter(std::shared_ptr<Filter> f);
/** /**
* @brief Set a linear DC offset value to the signal * @brief Set a linear DC offset value to the signal
@ -42,7 +52,8 @@ public:
void setDCOffset(d offset); void setDCOffset(d offset);
/** /**
* @brief Mute the signal. Passes through the DC offset. * @brief Mute the signal. Passes through the DC offset. No lock is hold. If
* it just works one block later, than that is just the case.
* *
* @param mute if tre * @param mute if tre
*/ */
@ -75,3 +86,6 @@ public:
*/ */
vd genSignal(const us nframes); vd genSignal(const us nframes);
}; };
/** @} */
/** @} */

View File

@ -5,11 +5,14 @@
// Description: // Description:
// Signal generators implementation // Signal generators implementation
////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////
/* #define TRACERPLUS (-5) */ #define DEBUGTRACE_ENABLED
#include "debugtrace.hpp"
#include "lasp_siggen_impl.h" #include "lasp_siggen_impl.h"
#include "debugtrace.hpp" #include "debugtrace.hpp"
#include "lasp_mathtypes.h" #include "lasp_mathtypes.h"
using rte = std::runtime_error;
DEBUGTRACE_VARIABLES; DEBUGTRACE_VARIABLES;
/** The fixed number of Newton iterations t.b.d. for tuning the sweep start and /** The fixed number of Newton iterations t.b.d. for tuning the sweep start and
@ -23,13 +26,14 @@ vd Noise::genSignalUnscaled(us nframes) {
} }
void Noise::resetImpl() {} void Noise::resetImpl() {}
Sine::Sine(const d freq) : omg(2 * arma::datum::pi * freq) {} Sine::Sine(const d freq) : omg(2 * arma::datum::pi * freq) { DEBUGTRACE_ENTER;}
vd Sine::genSignalUnscaled(const us nframes) { vd Sine::genSignalUnscaled(const us nframes) {
/* DEBUGTRACE_ENTER; */
const d pi = arma::datum::pi; const d pi = arma::datum::pi;
vd phase_vec = vd phase_vec =
arma::linspace(phase, phase + omg * (nframes - 1) / fs, nframes); arma::linspace(phase, phase + omg * (nframes - 1) / _fs, nframes);
phase += omg * nframes / fs; phase += omg * nframes / _fs;
while (phase > 2 * arma::datum::pi) { while (phase > 2 * arma::datum::pi) {
phase -= 2 * pi; phase -= 2 * pi;
} }
@ -37,10 +41,13 @@ vd Sine::genSignalUnscaled(const us nframes) {
} }
vd Periodic::genSignalUnscaled(const us nframes) { vd Periodic::genSignalUnscaled(const us nframes) {
us signal_idx = 0;
vd res(nframes); vd res(nframes);
while (signal_idx < nframes) { if(_signal.size() == 0) {
res[signal_idx] = _signal[_cur_pos]; throw rte("No signal defined while calling");
}
for(us i=0;i<nframes;i++) {
res(i) = _signal[_cur_pos];
_cur_pos++; _cur_pos++;
_cur_pos %= _signal.size(); _cur_pos %= _signal.size();
} }
@ -48,29 +55,35 @@ vd Periodic::genSignalUnscaled(const us nframes) {
} }
Sweep::Sweep(const d fl, const d fu, const d Ts, const d Tq, const us flags) Sweep::Sweep(const d fl, const d fu, const d Ts, const d Tq, const us flags)
: fl_(fl), fu_(fu), Ts(Ts), Tq(Tq), flags(flags) { : fl_(fl), fu_(fu), Ts(Ts), Tq(Tq), flags(flags) {
if (fl <= 0 || fu < fl || Ts <= 0) { if (fl <= 0 || fu < fl || Ts <= 0) {
throw std::runtime_error("Invalid sweep parameters"); throw std::runtime_error("Invalid sweep parameters");
}
if ((flags & ForwardSweep) && (flags & BackwardSweep)) {
throw std::runtime_error(
"Both forward and backward sweep flag set. Please only set either one "
"or none for a continuous sweep");
}
if ((flags & LinearSweep) && (flags & LogSweep)) {
throw std::runtime_error(
"Both logsweep and linear sweep flag set. Please only set either one.");
}
} }
if ((flags & ForwardSweep) && (flags & BackwardSweep)) {
throw std::runtime_error(
"Both forward and backward sweep flag set. Please only set either one "
"or none for a continuous sweep");
}
}
void Sweep::resetImpl() { void Sweep::resetImpl() {
DEBUGTRACE_ENTER;
_cur_pos = 0; _cur_pos = 0;
bool forward_sweep = flags & ForwardSweep; bool forward_sweep = flags & ForwardSweep;
bool backward_sweep = flags & BackwardSweep; bool backward_sweep = flags & BackwardSweep;
const d Dt = 1 / fs; // Deltat const d Dt = 1 / _fs; // Deltat
// Estimate N, the number of samples in the sweep part (non-quiescent part): // Estimate N, the number of samples in the sweep part (non-quiescent part):
const us Ns = (us)(Ts * fs); const us Ns = (us)(Ts * _fs);
const us Nq = (us)(Tq * fs); const us Nq = (us)(Tq * _fs);
const us N = Ns + Nq; const us N = Ns + Nq;
_signal = vd(N, arma::fill::zeros); _signal = vd(N, arma::fill::zeros);
@ -120,7 +133,7 @@ void Sweep::resetImpl() {
d phih = 2 * number_pi * Dt * (fl * Nf + 0.5 * (Nf - 1) * (fu - fl)); d phih = 2 * number_pi * Dt * (fl * Nf + 0.5 * (Nf - 1) * (fu - fl));
us K = us K =
(us)(phih / (2 * number_pi) + Dt * (fu * Nb - (Nb - 1) * (fu - fl))); (us)(phih / (2 * number_pi) + Dt * (fu * Nb - (Nb - 1) * (fu - fl)));
d eps_num1 = (K - phih / (2 * number_pi)) / Dt; d eps_num1 = (K - phih / (2 * number_pi)) / Dt;
d eps_num2 = -fu * Nb + (Nb - 1) * (fu - fl); d eps_num2 = -fu * Nb + (Nb - 1) * (fu - fl);
@ -151,7 +164,7 @@ void Sweep::resetImpl() {
} }
} else if (flags & LogSweep) { } else if (flags & LogSweep) {
DEBUGTRACE_PRINT("Exponential sweep"); DEBUGTRACE_PRINT("Log sweep");
if (forward_sweep || backward_sweep) { if (forward_sweep || backward_sweep) {
/* Forward or backward sweep */ /* Forward or backward sweep */
DEBUGTRACE_PRINT("Forward or backward sweep"); DEBUGTRACE_PRINT("Forward or backward sweep");
@ -185,9 +198,9 @@ void Sweep::resetImpl() {
const us Nb = N - Nf; const us Nb = N - Nf;
const d k1 = (fu / fl); const d k1 = (fu / fl);
const d phif1 = const d phif1 =
2 * number_pi * Dt * fl * (k1 - 1) / (d_pow(k1, 1.0 / Nf) - 1); 2 * number_pi * Dt * fl * (k1 - 1) / (d_pow(k1, 1.0 / Nf) - 1);
const us K = (us)(phif1 / (2 * number_pi) + const us K = (us)(phif1 / (2 * number_pi) +
Dt * fu * (1 / k1 - 1) / (d_pow(1 / k1, 1.0 / Nb) - 1)); Dt * fu * (1 / k1 - 1) / (d_pow(1 / k1, 1.0 / Nb) - 1));
d E; d E;
d k = k1; d k = k1;
@ -196,7 +209,7 @@ void Sweep::resetImpl() {
* continuous */ * continuous */
for (us iter = 0; iter < NITER_NEWTON; iter++) { for (us iter = 0; iter < NITER_NEWTON; iter++) {
E = (k - 1) / (d_pow(k, 1.0 / Nf) - 1) + E = (k - 1) / (d_pow(k, 1.0 / Nf) - 1) +
(k - 1) / (1 - d_pow(k, -1.0 / Nb)) - K / Dt / fl; (k - 1) / (1 - d_pow(k, -1.0 / Nb)) - K / Dt / fl;
DEBUGTRACE_PRINT(E); DEBUGTRACE_PRINT(E);
/* All parts of the derivative of above error E to k */ /* All parts of the derivative of above error E to k */
@ -204,9 +217,9 @@ void Sweep::resetImpl() {
d dEdk2 = (1 / k - 1) / (d_pow(k, -1.0 / Nb) - 1); d dEdk2 = (1 / k - 1) / (d_pow(k, -1.0 / Nb) - 1);
d dEdk3 = -1 / (k * (d_pow(k, -1.0 / Nb) - 1)); d dEdk3 = -1 / (k * (d_pow(k, -1.0 / Nb) - 1));
d dEdk4 = d_pow(k, -1.0 / Nb) * (1 / k - 1) / d dEdk4 = d_pow(k, -1.0 / Nb) * (1 / k - 1) /
(Nb * d_pow(d_pow(k, -1.0 / Nb) - 1, 2)); (Nb * d_pow(d_pow(k, -1.0 / Nb) - 1, 2));
d dEdk5 = -d_pow(k, 1.0 / Nf) * (k - 1) / d dEdk5 = -d_pow(k, 1.0 / Nf) * (k - 1) /
(Nf * k * d_pow(d_pow(k, 1.0 / Nf) - 1, 2)); (Nf * k * d_pow(d_pow(k, 1.0 / Nf) - 1, 2));
d dEdk = dEdk1 + dEdk2 + dEdk3 + dEdk4 + dEdk5; d dEdk = dEdk1 + dEdk2 + dEdk3 + dEdk4 + dEdk5;
/* Iterate! */ /* Iterate! */

View File

@ -1,7 +1,19 @@
#pragma once #pragma once
#include "lasp_siggen.h" #include "lasp_siggen.h"
#include "lasp_types.h" #include "lasp_types.h"
/**
* \addtogroup dsp
* @{
*/
/**
* \addtogroup siggen
* @{
*/
/**
* @brief Generate a random signal (noise)
*/
class Noise : public Siggen { class Noise : public Siggen {
d level_linear; d level_linear;
virtual vd genSignalUnscaled(const us nframes) override; virtual vd genSignalUnscaled(const us nframes) override;
@ -19,9 +31,16 @@ class Noise : public Siggen {
}; };
/**
* @brief Generate a sine wave
*/
class Sine : public Siggen { class Sine : public Siggen {
d phase = 0; d phase = 0;
d omg; d omg;
protected:
void resetImpl() override final { phase=0; }
virtual vd genSignalUnscaled(const us nframes) override final;
public: public:
@ -32,10 +51,14 @@ class Sine : public Siggen {
*/ */
Sine(const d freq_Hz); Sine(const d freq_Hz);
~Sine() = default; ~Sine() = default;
virtual vd genSignalUnscaled(const us nframes) override final; void setFreq(const d newFreq) { omg = 2*arma::datum::pi*newFreq; } ;
void setFreq(const d newFreq);
void resetImpl() override final { phase=0; }
}; };
/**
* @brief Base class for all periodic signals (that are exactly periodic based
* on the sampling frequency). Note that the sine wave generator is not exactly
* periodic as the frequency can be any floating point value.
*/
class Periodic: public Siggen { class Periodic: public Siggen {
protected: protected:
vd _signal { 1, arma::fill::zeros}; vd _signal { 1, arma::fill::zeros};
@ -47,20 +70,23 @@ class Periodic: public Siggen {
}; };
/**
* @brief Sweep signal
*/
class Sweep : public Periodic { class Sweep : public Periodic {
d fl_, fu_, Ts, Tq; d fl_, fu_, Ts, Tq;
us index; us index;
us flags; us flags;
void resetImpl() override;
public:
static constexpr int ForwardSweep = 1 << 0; static constexpr int ForwardSweep = 1 << 0;
static constexpr int BackwardSweep = 1 << 1; static constexpr int BackwardSweep = 1 << 1;
static constexpr int LinearSweep = 1 << 2; static constexpr int LinearSweep = 1 << 2;
static constexpr int LogSweep = 1 << 3; static constexpr int LogSweep = 1 << 3;
void resetImpl() override;
public:
/** /**
* Create a sweep signal * Create a sweep signal
* *
@ -77,3 +103,5 @@ class Sweep : public Periodic {
~Sweep() = default; ~Sweep() = default;
}; };
/** @} */
/** @} */

View File

@ -31,6 +31,7 @@ void init_daqconfiguration(py::module &m);
void init_daq(py::module &m); void init_daq(py::module &m);
void init_streammgr(py::module &m); void init_streammgr(py::module &m);
void init_datahandler(py::module &m); void init_datahandler(py::module &m);
void init_siggen(py::module &m);
PYBIND11_MODULE(lasp_cpp, m) { PYBIND11_MODULE(lasp_cpp, m) {
@ -40,6 +41,7 @@ PYBIND11_MODULE(lasp_cpp, m) {
init_daq(m); init_daq(m);
init_streammgr(m); init_streammgr(m);
init_datahandler(m); init_datahandler(m);
init_siggen(m);
// We store the version number of the code via CMake, and create an // We store the version number of the code via CMake, and create an
// attribute in the C++ code. // attribute in the C++ code.

View File

@ -2,8 +2,6 @@
#include "lasp_avpowerspectra.h" #include "lasp_avpowerspectra.h"
#include "lasp_biquadbank.h" #include "lasp_biquadbank.h"
#include "lasp_fft.h" #include "lasp_fft.h"
#include "lasp_siggen.h"
#include "lasp_siggen_impl.h"
#include "lasp_slm.h" #include "lasp_slm.h"
#include "lasp_window.h" #include "lasp_window.h"
#include <iostream> #include <iostream>
@ -47,13 +45,6 @@ void init_dsp(py::module &m) {
w.def_static("toTxt", &Window::toText); w.def_static("toTxt", &Window::toText);
/// Siggen
py::class_<Siggen, std::shared_ptr<Siggen>> siggen(m, "Siggen");
siggen.def("setLevel", &Siggen::setLevel,
"Set the level of the signal generator");
py::class_<Sine, std::shared_ptr<Sine>> sw(m, "Sine", siggen);
sw.def(py::init<const d>());
/// SeriesBiquad /// SeriesBiquad
py::class_<SeriesBiquad> sbq(m, "SeriesBiquad"); py::class_<SeriesBiquad> sbq(m, "SeriesBiquad");

View File

@ -0,0 +1,55 @@
#include <carma>
#include "lasp_avpowerspectra.h"
#include "lasp_biquadbank.h"
#include "lasp_fft.h"
#include "lasp_siggen.h"
#include "lasp_siggen_impl.h"
#include "lasp_slm.h"
#include "lasp_window.h"
#include <iostream>
#include <pybind11/pybind11.h>
using std::cerr;
namespace py = pybind11;
/**
* \ingroup pybind
* @{
*
*/
/**
* @brief Initialize Siggen wrappers
*
* @param m The Python module to add classes and methods to
*/
void init_siggen(py::module &m) {
/// Siggen
py::class_<Siggen, std::shared_ptr<Siggen>> siggen(m, "Siggen");
siggen.def("setLevel", &Siggen::setLevel,
"Set the level of the signal generator");
siggen.def("setDCOffset", &Siggen::setDCOffset);
siggen.def("setMute", &Siggen::setMute);
siggen.def("setLevel", &Siggen::setLevel);
siggen.def("setLevel", &Siggen::setLevel, py::arg("newLevel"), py::arg("dB") = true);
siggen.def("genSignal", &Siggen::genSignal);
py::class_<Noise,std::shared_ptr<Noise>> noise(m, "Noise", siggen);
noise.def(py::init<>());
py::class_<Sine, std::shared_ptr<Sine>> sine(m, "Sine", siggen);
sine.def(py::init<const d>());
sine.def("setFreq", &Sine::setFreq);
py::class_<Periodic, std::shared_ptr<Periodic>> periodic(m, "Periodic", siggen);
py::class_<Sweep, std::shared_ptr<Sweep>> sweep(m, "Sweep", periodic);
sweep.def(py::init<const d, const d, const d, const d, const us>());
sweep.def_readonly_static("ForwardSweep", &Sweep::ForwardSweep);
sweep.def_readonly_static("BackwardSweep", &Sweep::BackwardSweep);
sweep.def_readonly_static("LinearSweep", &Sweep::LinearSweep);
sweep.def_readonly_static("LogSweep", &Sweep::LogSweep);
}
/** @} */