Jump to content

User Reference:Designing a Signal Processing Filter

From BCI2000 Wiki

This reference page will summarize how to use the available tools in BCI2000 to customize your own Signal Processing filter. Using these tools will allow you to widely adapt BCI2000 to your own goals, all with minimal coding.

Purpose

To create your custom SignalProcessing filter, there are two options:

  1. Create your own pipeline of filters, only by using the existing filters. This is simple, and will be encompassing for most purposes
  2. Follow the Programming Tutorial for how to create your own filter from scratch. This gives you flexibility, however might be more work than needed. First see if the work can be done with existing options, then add your own capabilities
  3. Combine the two options

This page shows how to create a SignalProcessing filter only by using existing filters in BCI2000. To go more in depth about how to make your own from scratch, please direct to this page.

Outline

See Programming Howto:Create a custom Signal Processing Module for detailed steps and images on how to create your filter template. A summarization of the steps are below:

  • Use NewBCI2000Module.exe under the build folder to create your own filter
    • Enter parent directory of src/contrib/SignalProcessing
  • Re-run CMake to include your new module
  • Open the new PipeDefinition.cpp that was created

Now we can create your own pipeline using the other filters.

Pipe Definition

To use multiple filters, we define a PipeDefinition for our Signal Processing module. This essentially means we define our Filters in order. See this page on Filters for details. Here is an example for a pipeline of 7 filters in our Signal Processing module:

#include "SpatialFilter.h"
Filter( SpatialFilter, 2.B );

#include "IIRBandpass.h"
Filter( IIRBandpass, 2.B3 );

#include "ARFilter.h"
Filter( ARFilter, 2.C );

#include "LinearClassifier.h"
Filter( LinearClassifier, 2.D );

#include "LPFilter.h"
Filter( LPFilter, 2.D1 );

#include "ExpressionFilter.h"
Filter( ExpressionFilter, 2.D2 );

#include "Normalizer.h"
Filter( Normalizer, 2.E );

If we build this project as is, we will be able to customize each filter's parameters, with the final output as the output from Normalizer. The order of the filters is organized by number and letter. We use 2 by convention to declare it as a Signal Processing Filter. The letters further define the order: B → B3 → C → D → D1 → D2 → E. See the Filter Chain page for more information.

Filters to mix and match

This is an extensive list of the shared filters of use, located at src/shared/modules/signalprocessing

Recommended for Use

  • AverageDisplay: Computes epoch averages of its input signal, and displays these in a visualization window.
  • ConditionalIntegrator: Integrates its input signal while a given expression evaluates to true. This filter is intended for offline simulations of application module behavior.
  • FrequencyEstimator: A filter that continuously estimates the dominant frequency of its input signal, similar to a frequency counter.
  • IIRBandpass: A generic IIR bandpass filter that also provides a notch. Built on IIR Filter Base Class
  • LinearClassifier
  • Low Pass (LP) filter
  • Normalizer
  • P3Temporal
  • PowerEstimator: A filter that estimates the power contained in its input.
  • RandomFilter: A filter that returns zero-mean white noise multiplied by the input signal's value.
  • SpatialFilter
  • SpectralEstimator: Allows for spectral estimation choice between AR or FFT
  • StateTransform: A filter that transforms state values according to rules. Whenever a given state's value changes, it replaces the new value by a user-defined expression.
  • SourceDecimation: Conducts low-pass on signal to decimate source. Helpful to lower the required computation time for filters ahead in the chain.
  • WindowingFilter: The WindowingFilter provides
    • Buffering of the signal into time windows that may be larger than SampleBlockSize,
    • Detrending options (mean or linear),
    • Window functions typically used with FFT (Hann, Hamming, Blackman). Typically, the Windowing filter provides its output to a spectral estimator (AR, FFT).

Not Recommended for Use

  • ARFilter: Used in SpectralEstimator. This is a LinearCombination of WindowingFilter and ARSpectrum
  • ARSpectrum: Used in ARFilter. Performs AR algorithm, see User Reference:SpectralEstimator for details
  • ExpressionFilter: Uses arithmetic expressions to compute its output. Can use capabilities without putting it in Filter Chain
  • FFTSpectrum: Performs FFT that is used in User Reference:SpectralEstimator
  • ComplexDemodulator: Computes the squared amplitudes for a small number of bands. Its operation is roughly equivalent to a short-term fourier transform followed by demodulation for selected frequency bins.
  • FFTFilter
  • IIRFilterBase: Abstract base class
  • Spectrum: Base class for spectral estimator threads
  • TaskAdapter: Purpose of this filter is to connect old-style application modules to the newer normalizer filter without changing their behavior.
  • ThreadedFilter: Template class for filters that use multiple threads to compute their results

Tools for Combining Filters

These are located in the source code at src/shared/filters. Can be used to create parallel filters, subchains, and easy toggling between filters.

Pipe Definition Examples

Contributions:PeakDetector: PeakDetector is the custom Filter, and uses it in a pipeline with other existing filters

#include "SpatialFilter.h"
#include "UPeakDetector.h"
#include "LinearClassifier.h"
#include "Normalizer.h"

Filter( SpatialFilter, 2.B );
Filter( PeakDetector, 2.C );
Filter( LinearClassifier, 2.D );
Filter( Normalizer, 2.E );

MatlabFilter sends the signal to Matlab within the BCI2000 chain. This lets you conduct a Matlab script and have it affect the signal sent to the Application.

#include "MatlabFilter.h"
Filter(MatlabFilter, 2.C);

Phase-amplitude coupling is when you analyze the correlation of the phase of one frequency of the signal with the amplitude of the other. We can easily do that with a unique filter chain. This chain uses the custom Hilbert Filter in parallel, once to get the phase, once to get the amplitude. These can be of different frequency bands, specified by varying parameters in the IIRBandpass filter. Next, the custom PACFilter receives the combined computations to simply calculate a correlation value between the phase and amplitude. Lastly, the SignalSharing Demo Filter shares the data so other applications can use it.

#include "IIRBandpass.h"
#include "HilbertFilter.h"
#include "SubchainFilter.h"
#include "FilterCombination.h"
#include "SourceDecimationFilter.h"
#include "SpatialFilter.h"

struct MySubchain : SubchainFilter
{
  MySubchain()
  {
    Add<IIRBandpass>();
    Add<HilbertFilter>();
  }
};
struct Phase : MySubchain {};
struct Amplitude : MySubchain {};
//combines parallel filters back into one chain
struct MyParallelFilter : ParallelCombination<Phase, Amplitude> {};


Filter(SourceDecimationFilter, 2.A1);
Filter(SpatialFilter, 2.A2);
Filter(MyParallelFilter, 2.B);

//custom filter to compute the output of the filters
#include "PACFilter.h"
Filter(PACFilter, 2.C);

#include "SignalSharingDemoFilter.h"
Filter(SignalSharingDemoFilter, 2.D);

Further Documentation