diff --git a/CMakeLists.txt b/CMakeLists.txt index 7ec236e..bb5b296 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -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_ULDAQ "Compile with UlDaq backend" ON) option(LASP_BUILD_TUNED "Tune build for current machine" OFF) +option(LASP_WITH_OPENMP "Use OpenMP parallelization" ON) # Use ccache if available find_program(CCACHE_PROGRAM ccache) @@ -42,6 +43,8 @@ set(CMAKE_POSITION_INDEPENDENT_CODE ON) if(${CMAKE_BUILD_TYPE} STREQUAL "Debug") set(LASP_DEBUG True) + # This does not work nicely with RtAudio + # add_definitions(-D_GLIBCXX_DEBUG) else() set(LASP_DEBUG False) endif() @@ -65,8 +68,12 @@ add_definitions(-DLASP_MAX_NFFT=33554432) # 2**25 # ####################################### End of user-adjustable variables section include(OSSpecific) -# Enable openmp -set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} ${OpenMP_CXX_FLAGS} -Wall -Wextra -Wno-type-limits") +set(CMAKE_CXX_FLAGS "${CMAKE_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 \ -fdata-sections -ffunction-sections -fomit-frame-pointer -finline-functions") @@ -78,7 +85,6 @@ add_subdirectory(third_party/carma) if(LASP_FFT_BACKEND STREQUAL "FFTW") find_library(fftw3 REQUIRED NAMES fftw fftw3) set(LASP_FFT_LIBS "fftw3") -message("LASP_FFT_LIBS = ${LASP_FFT_LIBS}") elseif(LASP_FFT_BACKEND STREQUAL "Armadillo") endif() diff --git a/src/lasp/CMakeLists.txt b/src/lasp/CMakeLists.txt index d185739..5bfb393 100644 --- a/src/lasp/CMakeLists.txt +++ b/src/lasp/CMakeLists.txt @@ -28,6 +28,7 @@ pybind11_add_module(lasp_cpp MODULE lasp_cpp.cpp pybind11/lasp_daq.cpp pybind11/lasp_deviceinfo.cpp pybind11/lasp_pyindatahandler.cpp + pybind11/lasp_siggen.cpp ) target_link_libraries(lasp_cpp PRIVATE lasp_device_lib lasp_dsp_lib diff --git a/src/lasp/device/lasp_daqdata.h b/src/lasp/device/lasp_daqdata.h index 1700aee..4cdfba7 100644 --- a/src/lasp/device/lasp_daqdata.h +++ b/src/lasp/device/lasp_daqdata.h @@ -60,7 +60,7 @@ public: */ DaqData() : DaqData(0, 0, DataTypeDescriptor::DataType::dtype_int8) {} 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. @@ -74,6 +74,12 @@ public: return &(_data.data()[sw * (frame + channel * nframes)]); } + void setSlow(const us frame, const us channel, const int8_t* val) { + for(us i=0;i ptrs; - ptrs.reserve(neninchannels); - DaqData data(nenoutchannels, nFramesPerBlock, dtype); + ptrs.reserve(nenoutchannels); /* outCallback */ for (int ch = 0; ch <= getHighestOutChannel(); ch++) { + /* DEBUGTRACE_PRINT(outchannel_config.at(ch).enabled); */ if (outchannel_config.at(ch).enabled) { - ptrs.push_back(&static_cast( - outputBuffer)[sw * nenoutchannels * ch * nFramesPerBlock]); + ptrs.push_back(&(static_cast( + outputBuffer)[sw * nenoutchannels * ch * nFramesPerBlock])); } } DaqData d{nenoutchannels, nFramesPerBlock, dtype}; diff --git a/src/lasp/device/lasp_streammgr.cpp b/src/lasp/device/lasp_streammgr.cpp index 3f817cf..5752156 100644 --- a/src/lasp/device/lasp_streammgr.cpp +++ b/src/lasp/device/lasp_streammgr.cpp @@ -89,6 +89,25 @@ bool StreamMgr::inCallback(const DaqData &data) { return true; } +void StreamMgr::setSiggen(std::shared_ptr siggen) { + + DEBUGTRACE_ENTER; + checkRightThread(); + + std::scoped_lock 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 * non-interleaving format. @@ -100,48 +119,45 @@ bool StreamMgr::inCallback(const DaqData &data) { * @return */ template bool fillData(DaqData &data, const vd &signal) { + /* DEBUGTRACE_ENTER; */ assert(data.nframes == signal.size()); + /* cerr << "SFSG: data.nframes:" << data.nframes << endl; */ + /* cerr << "SFSG: data.nchannels:" << data.nchannels << endl; */ T *res = reinterpret_cast(data.raw_ptr()); if (std::is_floating_point()) { for (us ch = 0; ch < data.nchannels; ch++) { for (us frame = 0; frame < data.nframes; frame++) { +#if DEBUG_FILLDATA == 1 + DEBUGTRACE_PRINT("SLOW flt"); + data.setSlow(frame, ch, + reinterpret_cast(&signal[frame])); +#else res[ch * data.nframes + frame] = signal[frame]; +#endif } } } else { for (us ch = 0; ch < data.nchannels; ch++) { for (us frame = 0; frame < data.nframes; frame++) { - res[ch * data.nframes + frame] = - (signal[frame] * std::numeric_limits::max()); + const T val = (signal[frame] * std::numeric_limits::max()); +#if DEBUG_FILLDATA == 1 + data.setSlow(frame, ch, reinterpret_cast(&val)); +#else + res[ch * data.nframes + frame] = val; +#endif } } } return true; } - -void StreamMgr::setSiggen(std::shared_ptr siggen) { - checkRightThread(); - - std::scoped_lock 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) { /* DEBUGTRACE_ENTER; */ std::scoped_lock lck(_siggen_mtx); + if (_siggen) { vd signal = _siggen->genSignal(data.nframes); switch (data.dtype) { @@ -237,6 +253,8 @@ void StreamMgr::startStream(const DaqConfiguration &config) { if (isOutput) { if (_siggen) { + DEBUGTRACE_PRINT("Resetting _siggen with new samplerate of "); + DEBUGTRACE_PRINT(daq->samplerate()); _siggen->reset(daq->samplerate()); } outCallback = std::bind(&StreamMgr::outCallback, this, _1); @@ -248,6 +266,9 @@ void StreamMgr::startStream(const DaqConfiguration &config) { if (isInput) { _inputStream = std::move(daq); + if (daq->duplexMode()) { + assert(!_outputStream); + } } else { assert(isOutput); _outputStream = std::move(daq); @@ -291,7 +312,7 @@ void StreamMgr::removeInDataHandler(InDataHandler &handler) { } Daq::StreamStatus StreamMgr::getStreamStatus(const StreamType type) const { - DEBUGTRACE_ENTER; + /* DEBUGTRACE_ENTER; */ checkRightThread(); // Default constructor, says stream is not running, but also no errors diff --git a/src/lasp/dsp/lasp_siggen.cpp b/src/lasp/dsp/lasp_siggen.cpp index 1e74adb..6ece244 100644 --- a/src/lasp/dsp/lasp_siggen.cpp +++ b/src/lasp/dsp/lasp_siggen.cpp @@ -1,21 +1,25 @@ +/* #define DEBUGTRACE_ENABLED */ +#include "debugtrace.hpp" #include "lasp_siggen.h" #include "lasp_mathtypes.h" #include #include +using std::cerr; +using std::endl; -inline d level_amp(d level_dB){ - return pow(10, level_dB/20); -} +inline d level_amp(d level_dB) { return pow(10, level_dB / 20); } using mutexlock = std::scoped_lock; vd Siggen::genSignal(const us nframes) { + + DEBUGTRACE_ENTER; mutexlock lck(_mtx); vd signal(nframes, arma::fill::value(_dc_offset)); if (!_muted) { - vd signal_dynamic = _level_linear*genSignalUnscaled(nframes); - if(_filter) { + vd signal_dynamic = _level_linear * genSignalUnscaled(nframes); + if (_filter) { _filter->filter(signal_dynamic); } signal += signal_dynamic; @@ -23,20 +27,24 @@ vd Siggen::genSignal(const us nframes) { return signal; } -void Siggen::setFilter(std::shared_ptr& filter) { +void Siggen::setFilter(std::shared_ptr filter) { + DEBUGTRACE_ENTER; mutexlock lck(_mtx); _filter = filter; } void Siggen::setDCOffset(const d offset) { + DEBUGTRACE_ENTER; mutexlock lck(_mtx); _dc_offset = offset; } -void Siggen::setLevel(const d level,bool dB) { +void Siggen::setLevel(const d level, bool dB) { + DEBUGTRACE_ENTER; mutexlock lck(_mtx); _level_linear = dB ? level_amp(level) : level; } void Siggen::reset(const d newFs) { + DEBUGTRACE_ENTER; mutexlock lck(_mtx); - fs = newFs; + _fs = newFs; resetImpl(); } diff --git a/src/lasp/dsp/lasp_siggen.h b/src/lasp/dsp/lasp_siggen.h index f95fe6c..969ade9 100644 --- a/src/lasp/dsp/lasp_siggen.h +++ b/src/lasp/dsp/lasp_siggen.h @@ -8,17 +8,27 @@ class StreamMgr; 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 { private: std::shared_ptr _filter; d _dc_offset = 0, _level_linear = 1; bool _muted = false; - std::mutex _mtx; protected: - d fs = -1; + std::mutex _mtx; + d _fs = 0; virtual void resetImpl() = 0; virtual vd genSignalUnscaled(const us nframes) = 0; @@ -32,7 +42,7 @@ public: * * @param f The filter to install. */ - void setFilter(std::shared_ptr& f); + void setFilter(std::shared_ptr f); /** * @brief Set a linear DC offset value to the signal @@ -42,7 +52,8 @@ public: 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 */ @@ -75,3 +86,6 @@ public: */ vd genSignal(const us nframes); }; + +/** @} */ +/** @} */ diff --git a/src/lasp/dsp/lasp_siggen_impl.cpp b/src/lasp/dsp/lasp_siggen_impl.cpp index 95b0962..870ce63 100644 --- a/src/lasp/dsp/lasp_siggen_impl.cpp +++ b/src/lasp/dsp/lasp_siggen_impl.cpp @@ -5,11 +5,14 @@ // Description: // Signal generators implementation ////////////////////////////////////////////////////////////////////// -/* #define TRACERPLUS (-5) */ +#define DEBUGTRACE_ENABLED +#include "debugtrace.hpp" #include "lasp_siggen_impl.h" #include "debugtrace.hpp" #include "lasp_mathtypes.h" +using rte = std::runtime_error; + DEBUGTRACE_VARIABLES; /** 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() {} -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) { + /* DEBUGTRACE_ENTER; */ const d pi = arma::datum::pi; vd phase_vec = - arma::linspace(phase, phase + omg * (nframes - 1) / fs, nframes); - phase += omg * nframes / fs; + arma::linspace(phase, phase + omg * (nframes - 1) / _fs, nframes); + phase += omg * nframes / _fs; while (phase > 2 * arma::datum::pi) { phase -= 2 * pi; } @@ -37,10 +41,13 @@ vd Sine::genSignalUnscaled(const us nframes) { } vd Periodic::genSignalUnscaled(const us nframes) { - us signal_idx = 0; + vd res(nframes); - while (signal_idx < nframes) { - res[signal_idx] = _signal[_cur_pos]; + if(_signal.size() == 0) { + throw rte("No signal defined while calling"); + } + for(us i=0;i @@ -47,13 +45,6 @@ void init_dsp(py::module &m) { w.def_static("toTxt", &Window::toText); - /// Siggen - py::class_> siggen(m, "Siggen"); - siggen.def("setLevel", &Siggen::setLevel, - "Set the level of the signal generator"); - - py::class_> sw(m, "Sine", siggen); - sw.def(py::init()); /// SeriesBiquad py::class_ sbq(m, "SeriesBiquad"); diff --git a/src/lasp/pybind11/lasp_siggen.cpp b/src/lasp/pybind11/lasp_siggen.cpp new file mode 100644 index 0000000..bec0689 --- /dev/null +++ b/src/lasp/pybind11/lasp_siggen.cpp @@ -0,0 +1,55 @@ +#include +#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 +#include + +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(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(m, "Noise", siggen); + noise.def(py::init<>()); + + py::class_> sine(m, "Sine", siggen); + sine.def(py::init()); + sine.def("setFreq", &Sine::setFreq); + + py::class_> periodic(m, "Periodic", siggen); + + py::class_> sweep(m, "Sweep", periodic); + sweep.def(py::init()); + 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); + +} +/** @} */