diff --git a/PC_front.png b/PC_front.png
deleted file mode 100644
index 50f3d26..0000000
Binary files a/PC_front.png and /dev/null differ
diff --git a/PhaseCalculator_flow.pdf b/PhaseCalculator_flow.pdf
deleted file mode 100644
index 9ed3d50..0000000
Binary files a/PhaseCalculator_flow.pdf and /dev/null differ
diff --git a/PhaseCalculator_flow.xml b/PhaseCalculator_flow.xml
deleted file mode 100644
index 07c26eb..0000000
--- a/PhaseCalculator_flow.xml
+++ /dev/null
@@ -1 +0,0 @@
-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
\ No newline at end of file
diff --git a/README.md b/README.md
index 8669e32..c1c6e48 100644
--- a/README.md
+++ b/README.md
@@ -1,14 +1,15 @@
-# Phase Calculator Plugin [![DOI](https://zenodo.org/badge/DOI/10.5281/zenodo.2548723.svg)](https://doi.org/10.5281/zenodo.2548723)
+# Phase Calculator Plugin [![DOI](https://zenodo.org/badge/134900173.svg)](https://zenodo.org/badge/latestdoi/134900173)
A plugin for the [Open Ephys GUI](https://github.com/open-ephys/plugin-GUI) to estimate the phase of inputs within a specified passband in real time. Its primary purpose is to enable closed-loop stimulation, typically in combination with the [Crossing Detector](https://github.com/tne-lab/crossing-detector) and either the Pulse Pal or an external stimulation system that receives ZeroMQ events (for example, the LabVIEW implementation [here](https://github.com/tne-lab/closed-loop-stim)). It can also output the magnitude or imaginary component of the band-limited analytic signal instead of the phase. (The "PH+MAG" mode outputs both phase and magnitude, in separate channels.) Finally, the visualization tab or window can receive TTL events and display the delayed but precise phase of a specified input at the event onset samples in a rose plot. This allows real-time monitoring of stimulation accuracy.
-The following article describes the algorithm used by this plugin and the closed-loop stimulation pipeline as a whole:
+The following article describes the algorithm used by the previous version of this plugin and the closed-loop stimulation pipeline as a whole:
Blackwood, E., Lo, M., Widge, A. S. (2018). Continuous phase estimation for phase-locked neural stimulation using an autoregressive model for signal prediction. 40th International Conference of the IEEE Engineering in Medicine and Biology Society (EMBC), Honolulu, HI, 4736-4739.
If you are just using the plugin in your project, you can cite this version of the code using the DOI listed in the header of this file.
-
+
+
## Installation
@@ -16,11 +17,11 @@ If you are just using the plugin in your project, you can cite this version of t
### Step 1: Decide which version to use.
-* You are on the `master` branch, which uses the Fourier-transform-based [Hilbert transform](https://en.wikipedia.org/wiki/Hilbert_transform) over a sliding window to estimate the analytic signal (from which we derive the phase). We have been testing variants of this algorithm in our lab since mid-2016, and it is now fairly polished, but is somewhat less computationally efficient than the newer version.
+* You are on the `master` branch, which uses a [Hilbert transformer](https://www.intechopen.com/books/matlab-a-fundamental-tool-for-scientific-computing-and-engineering-applications-volume-1/digital-fir-hilbert-transformers-fundamentals-and-efficient-design-methods) FIR filter - actually one of several, depending on the frequency band you are filtering to. This is more efficient than the original (published) algorithm since it doesn't require as much AR model-based prediction nor calculating an FFT on each step.
-* If you want, you can switch to the `hilbert-transformer` branch, which uses a [Hilbert transformer](https://www.intechopen.com/books/matlab-a-fundamental-tool-for-scientific-computing-and-engineering-applications-volume-1/digital-fir-hilbert-transformers-fundamentals-and-efficient-design-methods) FIR filter instead - actually one of several, depending on the frequency band you are filtering to. This is more efficient since it doesn't require as much AR model-based prediction nor calculating an FFT on each step. However, it's not as well-tested.
+* If you want, you can switch to the `old-version` branch, which uses the Fourier-transform-based [Hilbert transform](https://en.wikipedia.org/wiki/Hilbert_transform) over a sliding window to estimate the analytic signal (from which we derive the phase). We have been testing variants of this algorithm in our lab since mid-2016, and it is now fairly polished, but is somewhat less computationally efficient than the newer version.
-* Alternatively, you can use the `tnel-development` (old algorithm) or `hilbert-transformer` (new algorithm) branch of [tne-lab/plugin-GUI](https://github.com/tne-lab/plugin-GUI/tree/tnel-development), which is a fork of the Open Ephys GUI source code with this plugin and some other useful ones already built in. Then you don't even need this repository or the rest of the instructions! (If you're on Linux though, you'll still have to install FFTW as described below.) Beware though, these are development branches and will be more unstable than `open-ephys/plugin-GUI/master`.
+* Alternatively, you can use the `tnel-development` branch of [tne-lab/plugin-GUI](https://github.com/tne-lab/plugin-GUI/tree/tnel-development), which is a fork of the Open Ephys GUI source code with this plugin and some other useful ones already built in. Then you don't even need this repository or the rest of the instructions! (If you're on Linux though, you'll still have to install FFTW as described below.) Beware though, these are development branches and will be more unstable than `open-ephys/plugin-GUI/master`.
### All platforms:
@@ -57,9 +58,9 @@ If you are just using the plugin in your project, you can cite this version of t
* ***Important!*** Since the phase estimation algorithm is somewhat processor-intensive, by default all input channels are disabled. To enable the channels you would like to estimate the phase (or other component) of, select them in the "PARAM" section of the drawer. If "PH+MAG" is selcected as the output, this will also create the additional magnitude outputs for each selected input.
-* Use "Low cut" and "High cut" to select the desired frequency passband. (Inputs should be unfiltered; the Phase Calculator uses its own bandpass filter.)
+* In the "freq range" dropdown menu, choose a range of frequencies that includes the band you want to filter to. This determines which of the pre-designed Hilbert transformer filters is used internally (since if we tried to use one filter for all frequencies, it would end up with terrible performance everywhere). Note that the delta band is just too low to get a reasonably accurate phase estimate, even when downsampling to 500 Hz as this plugin does (before interpolating the output).
-* The "Buffer length," "Past," and "Future" settings control the size and contents of the "Hilbert buffer" that is passed through the Hilbert transform to get the analytic (complex) signal for each channel. The "Past" length is the number of received samples to include on each iteration, including the current "processing buffer" (buffer of new data, whose size can be changed in the Audio Settings). The "Future" length is the number of samples of band-limited signal predicted using an autoregressive model to include. (See Blackwood, Lo & Widge, 2018 (once published) for more explanation of the algorithm.) The defaults are reasonable for a 4-8 Hz passband with a short processing buffer size. A longer buffer length generally increases the estimation accuracy at the cost of greater processing time. Also, one should optimally center the last (current) processing buffer of "past" data within the Hilbert buffer by setting "Future" to half of "Buffer Length" minus half of the processing buffer size. This ensures the maximal accuracy of the region of the Hilbert output corresponding to the current buffer.
+* Use "Low cut" and "High cut" to select the desired frequency passband. (Inputs should be unfiltered; the Phase Calculator uses its own bandpass filter internally.) Changing the frequency range will automatically set a default high and low cut, but they can be changed to filter to any band within the range.
* "AR Refresh" and "Order" control the autoregressive model used to predict the "future" portion of the Hilbert buffer. AR parameters are estimated using Burg's method. The default settings seem to work well, but other settings (particularly lower orders) may also work well.
diff --git a/Source/ARModeler.h b/Source/ARModeler.h
index a82e520..357c3c1 100644
--- a/Source/ARModeler.h
+++ b/Source/ARModeler.h
@@ -24,14 +24,9 @@
class ARModeler {
public:
- ARModeler() : arOrder(1), inputLength(2)
+ ARModeler(int order = 1, int length = 2, int strideIn = 1, bool* success = nullptr)
{
- reallocateStorage();
- }
-
- ARModeler(int order, int length, bool* success = nullptr) : ARModeler()
- {
- bool s = setParams(order, length);
+ bool s = setParams(order, length, strideIn);
if (success != nullptr)
{
*success = s;
@@ -41,15 +36,18 @@ class ARModeler {
~ARModeler() { }
// returns true if successful.
- bool setParams(int order, int length)
+ bool setParams(int order, int length, int strideIn)
{
- if (order < 1 || order >= length)
+ int newStridedLength = calcStridedLength(length, strideIn);
+ if (order < 1 || newStridedLength < order + 1)
{
jassertfalse;
return false;
}
arOrder = order;
inputLength = length;
+ stride = strideIn;
+ stridedLength = newStridedLength;
reallocateStorage();
return true;
}
@@ -76,12 +74,12 @@ class ARModeler {
double sn = 0.0;
double sd = 0.0;
int j;
- int jj = inputLength - n;
+ int jj = stridedLength - n;
for (j = 0; j < jj; j++)
{
- t1 = inputseries[j + n] + pef[j];
- t2 = inputseries[j] + per[j];
+ t1 = inputseries[stride * (j + n)] + pef[j];
+ t2 = inputseries[stride * j] + per[j];
sn -= 2.0 * t1 * t2;
sd += (t1 * t1) + (t2 * t2);
}
@@ -99,8 +97,8 @@ class ARModeler {
for (j = 0; j < jj; j++)
{
- per[j] = per[j] + t1 * pef[j] + t1 * inputseries[j + n];
- pef[j] = pef[j + 1] + t1 * per[j + 1] + t1 * inputseries[j + 1];
+ per[j] = per[j] + t1 * pef[j] + t1 * inputseries[stride * (j + n)];
+ pef[j] = pef[j + 1] + t1 * per[j + 1] + t1 * inputseries[stride * (j + 1)];
}
}
}
@@ -116,13 +114,21 @@ class ARModeler {
void resetPredictionError()
{
j_per.clearQuick();
- j_per.insertMultiple(0, 0, inputLength);
+ j_per.insertMultiple(0, 0, stridedLength);
j_pef.clearQuick();
- j_pef.insertMultiple(0, 0, inputLength);
+ j_pef.insertMultiple(0, 0, stridedLength);
+ }
+
+ static int calcStridedLength(int inputLength, int stride)
+ {
+ jassert(stride > 0);
+ return (inputLength + (stride - 1)) / stride;
}
int arOrder;
int inputLength;
+ int stridedLength;
+ int stride;
Array j_per;
Array j_pef;
Array j_h;
diff --git a/Source/HTransformers.cpp b/Source/HTransformers.cpp
new file mode 100644
index 0000000..457ed7d
--- /dev/null
+++ b/Source/HTransformers.cpp
@@ -0,0 +1,155 @@
+/*
+------------------------------------------------------------------
+
+This file is part of a plugin for the Open Ephys GUI
+Copyright (C) 2018 Translational NeuroEngineering Lab
+
+------------------------------------------------------------------
+
+This program is free software: you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation, either version 3 of the License, or
+(at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program. If not, see .
+
+*/
+
+#include "HTransformers.h"
+
+namespace Hilbert
+{
+ namespace
+ {
+ const Array HIGH_GAM_VALID({ 60, 200 });
+ const Array HIGH_GAM_DEFAULT({ 70, 150 });
+ const Array HIGH_GAM_EXTREMA({ 81.6443, 123.1104, 169.3574 });
+ const int HIGH_GAM_DELAY = 3;
+ // from Matlab: firls(6, [60 200]/250, [1 1], 'hilbert')
+ const double HIGH_GAM_TRANSFORMER[HIGH_GAM_DELAY] = {
+ -0.10383410506573287,
+ 0.0040553935691102303,
+ -0.59258484603659545
+ };
+
+ const Array MID_GAM_VALID({ 40, 90 });
+ const Array MID_GAM_DEFAULT({ 40, 90 });
+ const Array MID_GAM_EXTREMA({ 64.4559 });
+ const int MID_GAM_DELAY = 2;
+ // from Matlab: firls(4, [35 90]/250, [1 1], 'hilbert')
+ const double MID_GAM_TRANSFORMER[MID_GAM_DELAY] = {
+ -0.487176162115735,
+ -0.069437334858668653
+ };
+
+ const Array LOW_GAM_VALID({ 30, 55 });
+ const Array LOW_GAM_DEFAULT({ 30, 55 });
+ const Array LOW_GAM_EXTREMA({ 43.3609 });
+ const int LOW_GAM_DELAY = 2;
+ // from Matlab: firls(4, [30 55]/250, [1 1], 'hilbert')
+ const double LOW_GAM_TRANSFORMER[LOW_GAM_DELAY] = {
+ -1.5933788446351915,
+ 1.7241339075391682
+ };
+
+ const Array BETA_VALID({ 10, 40 });
+ const Array BETA_DEFAULT({ 12, 30 });
+ const Array BETA_EXTREMA({ 21.5848 });
+ const int BETA_DELAY = 9;
+ // from Matlab: firpm(18, [12 30 40 240]/250, [1 1 0.7 0.7], 'hilbert')
+ const double BETA_TRANSFORMER[BETA_DELAY] = {
+ -0.099949575596234311,
+ -0.020761484963254036,
+ -0.080803573080958854,
+ -0.027365064225587619,
+ -0.11114477443975329,
+ -0.025834076852645271,
+ -0.16664116044989324,
+ -0.015661948619847599,
+ -0.45268524264113719
+ };
+
+ const Array ALPHA_THETA_VALID({ 4, 18 });
+ const Array ALPHA_THETA_DEFAULT({ 4, 8 });
+ const Array ALPHA_THETA_EXTREMA({ /* none */ });
+ const int ALPHA_THETA_DELAY = 9;
+ // from Matlab: firpm(18, [4 246]/250, [1 1], 'hilbert')
+ const double ALPHA_THETA_TRANSFORMER[ALPHA_THETA_DELAY] = {
+ -0.28757250783614413,
+ 0.000027647225074994485,
+ -0.094611325643268351,
+ -0.00025887439499763831,
+ -0.129436276914844,
+ -0.0001608427426424053,
+ -0.21315096860055227,
+ -0.00055322197399797961,
+ -0.63685698210351149
+ };
+
+ const String C_GAMMA{ L"\u03b3" };
+ const String C_BETA{ L"\u03b2" };
+ const String C_ALPHA_THETA{ L"\u03b1/\u03b8" };
+ }
+
+ String validBandToString(const Array& band)
+ {
+ jassert(band.size() == 2);
+ return " (" + String(band[0]) + "-" + String(band[1]) + " Hz)";
+ }
+
+ // exported constants
+
+ extern const std::map BAND_NAME = {
+ { HIGH_GAM, "Hi " + C_GAMMA + validBandToString(HIGH_GAM_VALID) },
+ { MID_GAM, "Mid " + C_GAMMA + validBandToString(MID_GAM_VALID) },
+ { LOW_GAM, "Lo " + C_GAMMA + validBandToString(LOW_GAM_VALID) },
+ { BETA, C_BETA + validBandToString(BETA_VALID) },
+ { ALPHA_THETA, C_ALPHA_THETA + validBandToString(ALPHA_THETA_VALID) }
+ };
+
+ extern const std::map> VALID_BAND = {
+ { HIGH_GAM, HIGH_GAM_VALID },
+ { MID_GAM, MID_GAM_VALID },
+ { LOW_GAM, LOW_GAM_VALID },
+ { BETA, BETA_VALID },
+ { ALPHA_THETA, ALPHA_THETA_VALID }
+ };
+
+ extern const std::map> DEFAULT_BAND = {
+ { HIGH_GAM, HIGH_GAM_DEFAULT },
+ { MID_GAM, MID_GAM_DEFAULT },
+ { LOW_GAM, LOW_GAM_DEFAULT },
+ { BETA, BETA_DEFAULT },
+ { ALPHA_THETA, ALPHA_THETA_DEFAULT }
+ };
+
+ extern const std::map> EXTREMA = {
+ { HIGH_GAM, HIGH_GAM_EXTREMA },
+ { MID_GAM, MID_GAM_EXTREMA },
+ { LOW_GAM, LOW_GAM_EXTREMA },
+ { BETA, BETA_EXTREMA },
+ { ALPHA_THETA, ALPHA_THETA_EXTREMA }
+ };
+
+ extern const std::map DELAY = {
+ { HIGH_GAM, HIGH_GAM_DELAY },
+ { MID_GAM, MID_GAM_DELAY },
+ { LOW_GAM, LOW_GAM_DELAY },
+ { BETA, BETA_DELAY },
+ { ALPHA_THETA, ALPHA_THETA_DELAY }
+ };
+
+ extern const std::map TRANSFORMER = {
+ { HIGH_GAM, HIGH_GAM_TRANSFORMER },
+ { MID_GAM, MID_GAM_TRANSFORMER },
+ { LOW_GAM, LOW_GAM_TRANSFORMER },
+ { BETA, BETA_TRANSFORMER },
+ { ALPHA_THETA, ALPHA_THETA_TRANSFORMER }
+ };
+}
\ No newline at end of file
diff --git a/Source/HTransformers.h b/Source/HTransformers.h
new file mode 100644
index 0000000..11e84f2
--- /dev/null
+++ b/Source/HTransformers.h
@@ -0,0 +1,78 @@
+/*
+------------------------------------------------------------------
+
+This file is part of a plugin for the Open Ephys GUI
+Copyright (C) 2018 Translational NeuroEngineering Lab
+
+------------------------------------------------------------------
+
+This program is free software: you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation, either version 3 of the License, or
+(at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program. If not, see .
+
+*/
+
+#ifndef H_TRANSFORMERS_H_INCLUDED
+#define H_TRANSFORMERS_H_INCLUDED
+
+#include