diff --git a/Makefile b/Makefile index 7a8b267..b4c3757 100644 --- a/Makefile +++ b/Makefile @@ -1,10 +1,33 @@ -CXX=g++ -CXX_FLAGS=-std=c++11 -Iinclude +PLUGIN_NAME = rtxilfpRatiometer -LD_FLAGS=-lfftw3 -lm +HEADERS = rtxi-lfpRatiometer.h -all: build/lfpRatiometer.o - $(CXX) $(CXX_FLAGS) -o build/test src/main.cpp build/lfpRatiometer.o $(LD_FLAGS) +SOURCES = rtxi-lfpRatiometer.cpp \ + moc_rtxi-lfpRatiometer.cpp -build/lfpRatiometer.o: - $(CXX) $(CXX_FLAGS) -o build/lfpRatiometer.o -c src/lfpRatiometer.cpp +LIBS = + +OS := $(shell uname) +CXX = g++ + +# FFTW3 (not sure if necessary) +#CXXFLAGS := $(CXXFLAGS) $(shell pkg-config --cflags fftw3) +#LDFLAGS := $(LDFLAGS) $(shell pkg-config --libs fftw3) + +# lfpRatiometer +#CXXFLAGS := $(CXXFLAGS) $(shell pkg-config --cflags lfpRatiometer) +#LDFLAGS := $(LDFLAGS) $(shell pkg-config --libs lfpRatiometer) +CXXFLAGS := $(CXXFLAGS) -I/home/amborsa10/.local/include +#LDFLAGS := $(LDFLAGS) -L/usr/lib/x86_64-linux-gnu -lfftw3 -L/home/amborsa10/.local/lib -llfpRatiometer + +LDFLAGS := $(LDFLAGS) -Wl,-rpath -Wl,/home/amborsa10/.local/lib -L/home/amborsa10/.local/lib -llfpRatiometer + +# CXXFLAGS := $(CXXFLAGS) -rpath /home/amborsa10/.local/lib + +# RTXI plug-in stuff +include Makefile.plugin_compile + +print-% : ; @echo $* = $($*) + +cleanrtxi : + sudo rm -rf /usr/local/lib/rtxi/$(PLUGIN_NAME).* diff --git a/Makefile.plugin_compile b/Makefile.plugin_compile new file mode 100644 index 0000000..9519d2a --- /dev/null +++ b/Makefile.plugin_compile @@ -0,0 +1,43 @@ +exec_modeldir = /usr/local/lib/rtxi + +LIBTOOL = /usr/local/share/rtxi/libtool +CXX = g++ +CXXLD = g++ +CXXCOMPILE = $(LIBTOOL) --mode=compile $(CXX) +CXXLINK = $(LIBTOOL) --mode=link $(CXXLD) +MOC = /usr/bin/moc + +CXXFLAGS := $(CXXFLAGS) -I. -I/usr/local/include/rtxi -I/usr/local/include/rtxi/plugins -I/usr/local/include/rtxi/libs -pipe -I/usr/local/include -I/usr/include/x86_64-linux-gnu/qt5/QtOpenGL -I/usr/include/x86_64-linux-gnu/qt5 -I/usr/include/x86_64-linux-gnu/qt5/QtPrintSupport -I/usr/include/x86_64-linux-gnu/qt5 -I/usr/include/x86_64-linux-gnu/qt5/QtXml -I/usr/include/x86_64-linux-gnu/qt5 -I/usr/include/x86_64-linux-gnu/qt5/QtSvg -I/usr/include/x86_64-linux-gnu/qt5 -I/usr/include/x86_64-linux-gnu/qt5/QtWidgets -I/usr/include/x86_64-linux-gnu/qt5 -I/usr/include/x86_64-linux-gnu/qt5/QtGui -I/usr/include/x86_64-linux-gnu/qt5 -I/usr/include/x86_64-linux-gnu/qt5/QtNetwork -I/usr/include/x86_64-linux-gnu/qt5 -I/usr/include/x86_64-linux-gnu/qt5/QtCore -I/usr/include/x86_64-linux-gnu/qt5 -I/usr/X11R6/include -I/usr/include/hdf5/serial -I/usr/include/qwt -I/usr/local/include/qwt -DQT_XML_LIB -DQT_GUI_LIB -DQT_CORE_LIB -DQT_WIDGETS_LIB -DQT_SVG_LIB -DQT_SHARED -w -O3 -std=c++11 -fPIC + +LDFLAGS := $(LDFLAGS) -L/usr/local/lib/rtxi/libs -L/usr/local/lib -lQt5OpenGL -lQt5PrintSupport -lQt5Xml -lQt5Svg -lQt5Widgets -lQt5Gui -lQt5Network -lQt5Core -lgit2 -lqwt-qt5 -L/usr/lib/x86_64-linux-gnu/hdf5/serial -lhdf5 -lhdf5_hl -lGL -lpthread -lgsl -lgslcblas -lm -ldl -Wl,--no-as-needed -Wl,@/usr/xenomai/lib/modechk.wrappers -lalchemy -lcopperplate /usr/xenomai/lib/xenomai/bootstrap-pic.o -L/usr/xenomai/lib -lcobalt -lmodechk -lpthread -lrt -module -avoid-version + +ifdef DEBUG +CXXFLAGS += -DDEBUG +endif + +# 2018-01-17 : MFB edited to prepend julia stuff to existing OBJECTS variable. +OBJECTS += $(shell echo $(SOURCES) | sed "s/\.cpp[ \t\n]*/\.lo /g") +MOOBJECTS = $(shell echo $(HEADERS) | sed "s/\.h[ \t\n]*/\.lo /g") + +all: $(PLUGIN_NAME).la + +%.lo: %.cpp + $(CXXCOMPILE) $(CXXFLAGS) -c $< -o $@ + +$(PLUGIN_NAME).la: $(OBJECTS) $(SOURCES) $(HEADERS) + $(CXXLINK) $(CXXFLAGS) $(LIBS) $(LDFLAGS) -rpath `readlink -f $(exec_modeldir)` -o $(PLUGIN_NAME).la $(OBJECTS) + +install: $(PLUGIN_NAME).la + $(LIBTOOL) --mode=install cp $(PLUGIN_NAME).la `readlink -f $(exec_modeldir)` + +clean: + rm -f $(OBJECTS) + rm -f $(MOOBJECTS) + rm -f moc_* + rm -f *.o + rm -f $(PLUGIN_NAME).la + rm -f $(PLUGIN_NAME).o + rm -rf .libs + +moc_%.cpp: %.h + $(MOC) -o $@ $< \ No newline at end of file diff --git a/include/lfpRatiometer.h b/include/lfpRatiometer.h deleted file mode 100644 index 414029f..0000000 --- a/include/lfpRatiometer.h +++ /dev/null @@ -1,79 +0,0 @@ -#ifndef LFPRATIOMETER_H -#define LFPRATIOMETER_H - -#include -#include -#include -#include - -#include -#include - -#include - -class lfpRatiometer { - public: - // constructor - lfpRatiometer(int N_input, double sampling_input); - - // destructor - ~lfpRatiometer(void); - - // execute - void execute(); - - protected: - - private: - - int N; // time window in samples - int f_size; // nonredundant size of DFT - double sampling; // sampling rate (Hz) - double *in; // pointer to (windowed) time series - std::vector in_raw; // vector to hold raw time series - fftw_complex *out; // pointer to DFT - fftw_plan p; // stores FFTW3 plan - - std::vector allfreqs; - std::vector psd; - double lf_hf_ratio; - double lf_low; - double lf_high; - double hf_low; - double hf_high; - - std::vector window; // time domain of window - double s2; // window scaling factor - - // method sets window as rectangle - void window_rect(){ - window.clear(); - s2 = 0; - for (int j=0; j + +using namespace std; + +extern "C" Plugin::Object *createRTXIPlugin(void){ + return new rtxilfpRatiometer(); +} + +static DefaultGUIModel::variable_t vars[] = { +{ + "Time Window (s)", "Time Window (s)", + DefaultGUIModel::PARAMETER | DefaultGUIModel::DOUBLE + }, +{ + "Sampling Rate (Hz)", "Sampling Rate (Hz)", + DefaultGUIModel::STATE | DefaultGUIModel::DOUBLE, + }, +{ + "LF Lower Bound", "LF Lower Bound", + DefaultGUIModel::PARAMETER | DefaultGUIModel::DOUBLE, + }, +{ + "LF Upper Bound", "LF Upper Bound", + DefaultGUIModel::PARAMETER | DefaultGUIModel::DOUBLE, + }, +{ + "HF Lower Bound", "HF Lower Bound", + DefaultGUIModel::PARAMETER | DefaultGUIModel::DOUBLE, + }, +{ + "HF Upper Bound", "HF Upper Bound", + DefaultGUIModel::PARAMETER | DefaultGUIModel::DOUBLE, + }, +{ + "input_LFP", "Input LFP", + DefaultGUIModel::INPUT | DefaultGUIModel::DOUBLE, + }, +{ + "ratio", "Output LFP Power Ratio", + DefaultGUIModel::OUTPUT | DefaultGUIModel::DOUBLE, + }, +{ + "LF Power", "Power in LF Band", + DefaultGUIModel::OUTPUT | DefaultGUIModel::DOUBLE, + }, +{ + "HF Power", "Power in HF Band", + DefaultGUIModel::OUTPUT | DefaultGUIModel::DOUBLE, + } +}; + +static size_t num_vars = sizeof(vars) / sizeof(DefaultGUIModel::variable_t); + +// defining what's in the object's constructor +// sampling set by RT period +rtxilfpRatiometer::rtxilfpRatiometer(void) : +DefaultGUIModel("lfpRatiometer with Custom GUI", ::vars, ::num_vars), +period(((double)RT::System::getInstance()->getPeriod())*1e-9), // grabbing RT period +sampling(1.0/period), // calculating RT sampling rate +lfpratiometer(N, sampling) // constructing lfpRatiometer object +{ + setWhatsThis("

lfpRatiometer:
Given an input, this module calculates the LF/HF ratio over a specified causal time window.

"); + DefaultGUIModel::createGUI(vars, num_vars); + customizeGUI(); + update(INIT); + refresh(); + QTimer::singleShot(0, this, SLOT(resizeMe())); +} + +// defining what's in the object's destructor +rtxilfpRatiometer::~rtxilfpRatiometer(void) { } + +// real-time RTXI function +void rtxilfpRatiometer::execute(void) { + + // push new time series reading to lfpRatiometer + lfpratiometer.pushTimeSample(input(0)); + + // calculate LF/HF ratio + lfpratiometer.calcRatio(); + + // put the LF/HF ratio into the output + output(0) = lfpratiometer.getRatio(); + output(1) = lfpratiometer.getLFpower(); + output(2) = lfpratiometer.getHFpower(); + +} + +// update function (not running in real time) +void rtxilfpRatiometer::update(DefaultGUIModel::update_flags_t flag) +{ + switch (flag) { + case INIT: + setParameter("Time Window (s)", sampling/N); + setState("Sampling Rate (Hz)", sampling); + // get bounds from lfpratiometer object + setParameter("LF Lower Bound", lfpratiometer.getFreqBounds()[0]); + setParameter("LF Upper Bound", lfpratiometer.getFreqBounds()[1]); + setParameter("HF Lower Bound", lfpratiometer.getFreqBounds()[2]); + setParameter("HF Upper Bound", lfpratiometer.getFreqBounds()[3]); + break; + + case MODIFY: + // defining parameters needed for constructor + period = ((double)RT::System::getInstance()->getPeriod())*1e-9; + sampling = 1.0/period; + setState("Sampling Rate (Hz)", sampling); // updating GUI + N = (int) (getParameter("Time Window (s)").toDouble() * sampling); + + // making new FFT plan + lfpratiometer.changeFFTPlan(N, sampling); + + // setting frequency bounds based on user input + lfpratiometer.setRatioParams(getParameter("LF Lower Bound").toDouble(), + getParameter("LF Upper Bound").toDouble(), + getParameter("HF Lower Bound").toDouble(), + getParameter("HF Upper Bound").toDouble()); + + // setting DFT windowing function choice + if (windowShape->currentIndex() == 0) { + lfpratiometer.window_rect(); + } + else if (windowShape->currentIndex() == 1) { + lfpratiometer.window_hamming(); + } + + // clearing time series + lfpratiometer.clrTimeSeries(); + + break; + + case UNPAUSE: + break; + + case PAUSE: + lfpratiometer.clrTimeSeries(); + break; + + case PERIOD: + break; + + default: + break; + } +} + +// RTXI's customizeGUI function +void rtxilfpRatiometer::customizeGUI(void) +{ + QGridLayout* customlayout = DefaultGUIModel::getLayout(); + + // adding dropdown menu for choosing FFT window shape + windowShape = new QComboBox; + windowShape->insertItem(1, "Rectangular"); + windowShape->insertItem(2, "Hamming"); + + customlayout->addWidget(windowShape, 2, 0); + setLayout(customlayout); +} \ No newline at end of file diff --git a/rtxi-lfpRatiometer.h b/rtxi-lfpRatiometer.h new file mode 100644 index 0000000..e0f684b --- /dev/null +++ b/rtxi-lfpRatiometer.h @@ -0,0 +1,47 @@ +#ifndef RTXILFPRATIOMETER_H +#define RTXILFPRATIOMETER_H + +#include +#include +#include + +class rtxilfpRatiometer : public DefaultGUIModel { + + Q_OBJECT + + public: + // constructor + rtxilfpRatiometer(void); + + // destructor + virtual ~rtxilfpRatiometer(void); + + // execute + void execute(void); + + // functions to make GUI + void createGUI(DefaultGUIModel::variable_t*, int); + void customizeGUI(void); + + protected: + + // update function + virtual void update(DefaultGUIModel::update_flags_t); + + private: + + // needed to initialize lfpratiometer object + int N = 1000; // initialized to 1000 samples (1s for 1kHz sampling) + double period; // set from RT period + double sampling; // set based on RT period + + // lfpRatiometer object + lfpRatiometer lfpratiometer; + + // variables for GUI + QComboBox* windowShape; + +}; + + +#endif \ No newline at end of file diff --git a/src/lfpRatiometer.cpp b/src/lfpRatiometer.cpp deleted file mode 100644 index 627b070..0000000 --- a/src/lfpRatiometer.cpp +++ /dev/null @@ -1,130 +0,0 @@ -#include - -using namespace std; - - -// defining what's in the object's constructor -// user defines time window length (in samples) and sampling rate -lfpRatiometer::lfpRatiometer(int N_input, double sampling_input) { - // setting user defined variables - N=N_input; - f_size=N/2 + 1; - sampling=sampling_input; - - // setting default variables - lf_low = 1; - lf_high = 25; - hf_low = 30; - hf_high = 90; - - // setting default window - window_hamming(); - - // establishing frequencies that will be associated with DFT output - for (int n=0; n= lf_low && allfreqs.at(n) <= lf_high) { - lf_total = lf_total + psd.at(n); - } - if (allfreqs.at(n) >= hf_low && allfreqs.at(n) <= hf_high){ - hf_total = hf_total + psd.at(n); - } - } - - // take ratio - lf_hf_ratio = lf_total/hf_total; -} \ No newline at end of file diff --git a/src/main.cpp b/src/main.cpp deleted file mode 100644 index 1f0a4f1..0000000 --- a/src/main.cpp +++ /dev/null @@ -1,11 +0,0 @@ -#include - -int main () { - int N = 10; - double sampling = 200; - lfpRatiometer lfpratiometer(N, sampling); - lfpratiometer.execute(); - - return 0; - -} \ No newline at end of file