Commit 92c2dcb9 authored by mzed's avatar mzed
Browse files

Merge branch 'dev' into rapidmix-api

parents 5f5d5797 73001b7a
......@@ -13,7 +13,7 @@ RL_SVM=src/svmClassification.cpp dependencies/libsvm/libsvm.cpp
RL_NN=src/neuralNetwork.cpp src/regression.cpp
RL_MS=src/modelSet.cpp
RL_DTW=src/warpPath.cpp src/searchWindow.cpp src/dtw.cpp src/fastDTW.cpp src/seriesClassification.cpp
RL_STREAM=src/rapidStream.cpp
RL_STREAM=src/rapidStream.cpp dependencies/bayesfilter/src/BayesianFilter.cpp dependencies/bayesfilter/src/filter_utilities.cpp
SOURCE_RAPID = $(RL_MS) $(RL_NN) $(RL_KNN) $(RL_SVM) $(RL_DTW) $(RL_STREAM)
# destination .js file
......
......@@ -14,6 +14,8 @@
BE325F511DB50BFE00F199A8 /* regression.cpp in Sources */ = {isa = PBXBuildFile; fileRef = BE325F4A1DB50BFE00F199A8 /* regression.cpp */; };
BE3852881EE847730008E1BD /* dtw.cpp in Sources */ = {isa = PBXBuildFile; fileRef = BE3852871EE847730008E1BD /* dtw.cpp */; };
BE38528B1EE94D740008E1BD /* seriesClassification.cpp in Sources */ = {isa = PBXBuildFile; fileRef = BE3852891EE94D740008E1BD /* seriesClassification.cpp */; };
BE3C12711FC85425009446A8 /* BayesianFilter.cpp in Sources */ = {isa = PBXBuildFile; fileRef = BE3C126D1FC85425009446A8 /* BayesianFilter.cpp */; };
BE3C12721FC85425009446A8 /* filter_utilities.cpp in Sources */ = {isa = PBXBuildFile; fileRef = BE3C126F1FC85425009446A8 /* filter_utilities.cpp */; };
BE553E2F1EE05FE1004EB00F /* svmClassification.cpp in Sources */ = {isa = PBXBuildFile; fileRef = BE553E2E1EE05FE1004EB00F /* svmClassification.cpp */; };
BE59A4521F1698E500B26E85 /* jsoncpp.cpp in Sources */ = {isa = PBXBuildFile; fileRef = BE59A44E1F1698E500B26E85 /* jsoncpp.cpp */; };
BE59A4531F1698E500B26E85 /* libsvm.cpp in Sources */ = {isa = PBXBuildFile; fileRef = BE59A4501F1698E500B26E85 /* libsvm.cpp */; };
......@@ -54,6 +56,10 @@
BE3852871EE847730008E1BD /* dtw.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = dtw.cpp; sourceTree = "<group>"; };
BE3852891EE94D740008E1BD /* seriesClassification.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = seriesClassification.cpp; sourceTree = "<group>"; };
BE38528A1EE94D740008E1BD /* seriesClassification.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = seriesClassification.h; sourceTree = "<group>"; };
BE3C126D1FC85425009446A8 /* BayesianFilter.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = BayesianFilter.cpp; sourceTree = "<group>"; };
BE3C126E1FC85425009446A8 /* BayesianFilter.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = BayesianFilter.h; sourceTree = "<group>"; };
BE3C126F1FC85425009446A8 /* filter_utilities.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = filter_utilities.cpp; sourceTree = "<group>"; };
BE3C12701FC85425009446A8 /* filter_utilities.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = filter_utilities.h; sourceTree = "<group>"; };
BE553E2D1EE05F03004EB00F /* svmClassification.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = svmClassification.h; sourceTree = "<group>"; };
BE553E2E1EE05FE1004EB00F /* svmClassification.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = svmClassification.cpp; sourceTree = "<group>"; };
BE553E301EE06AB0004EB00F /* trainingExample.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = trainingExample.h; sourceTree = "<group>"; };
......@@ -143,9 +149,22 @@
path = ../../src;
sourceTree = "<group>";
};
BE3C126C1FC85425009446A8 /* src */ = {
isa = PBXGroup;
children = (
BE3C126D1FC85425009446A8 /* BayesianFilter.cpp */,
BE3C126E1FC85425009446A8 /* BayesianFilter.h */,
BE3C126F1FC85425009446A8 /* filter_utilities.cpp */,
BE3C12701FC85425009446A8 /* filter_utilities.h */,
);
name = src;
path = bayesfilter/src;
sourceTree = "<group>";
};
BE59A44A1F1698E500B26E85 /* dependencies */ = {
isa = PBXGroup;
children = (
BE3C126C1FC85425009446A8 /* src */,
BE59A44B1F1698E500B26E85 /* json */,
BE59A44E1F1698E500B26E85 /* jsoncpp.cpp */,
BE59A44F1F1698E500B26E85 /* libsvm */,
......@@ -233,7 +252,9 @@
BE325F351DB50BE100F199A8 /* main.cpp in Sources */,
BEF47B181F790BC7005B0C35 /* neuralNetwork.cpp in Sources */,
BE6783241F6FFA5C005E73D0 /* warpPath.cpp in Sources */,
BE3C12711FC85425009446A8 /* BayesianFilter.cpp in Sources */,
BE325F4E1DB50BFE00F199A8 /* knnClassification.cpp in Sources */,
BE3C12721FC85425009446A8 /* filter_utilities.cpp in Sources */,
BE59A4531F1698E500B26E85 /* libsvm.cpp in Sources */,
BE325F4F1DB50BFE00F199A8 /* modelSet.cpp in Sources */,
BE325F4D1DB50BFE00F199A8 /* classification.cpp in Sources */,
......
......@@ -6,9 +6,15 @@
#include "regression.h"
#include "classification.h"
#include "seriesClassification.h"
#include "rapidStream.h"
int main(int argc, const char * argv[]) {
rapidStream<double> rapidProcess;
for (int i = 0; i < 100; ++i) {
std::cout << "bayes " << rapidProcess.bayesFilter(i/100.) << std::endl;
}
//vanAllenTesting
seriesClassification testDTW;
std::vector<trainingSeries> testVector;
......@@ -25,7 +31,11 @@ int main(int argc, const char * argv[]) {
testDTW.train(testVector);
std::cout << testDTW.run(tempSeriesTest.input) << std::endl;
//////////////////////////////////////////////////////////////////////////////////simple multilayer test
//////////////////////////////////////////////////////////////////////////////simple multilayer test
//This takes forever, I don't always run it
//#define MULTILAYER 1
#ifdef MULTILAYER
regression myNN2;
std::vector<trainingExample> trainingSet1;
......@@ -67,30 +77,13 @@ int main(int argc, const char * argv[]) {
inputVec1 = { 0.9, 0.7 };
std::cout << myNN2.run(inputVec1)[0] <<std::endl;
//////////////////////////////////////////////////////////////////////////////////bug?
regression myNNJS;
trainingSet1.clear();
tempExample1.input = { 8.0 };
tempExample1.output = { 5.0 };
trainingSet1.push_back(tempExample1);
tempExample1.input = { 2.0 };
tempExample1.output = { 3.0 };
trainingSet1.push_back(tempExample1);
myNNJS.train(trainingSet1);
inputVec1 = { 8 };
std::cout << "wtf? " << myNNJS.run(inputVec1)[0] << std::endl;
#endif
////////////////////////////////////////////////////////////////////////////////
regression myNN;
classification myKnn;
classification mySVM(classification::svm);
//classification mySVM(classification::svm);
std::vector<trainingExample> trainingSet;
trainingExample tempExample;
......@@ -115,18 +108,70 @@ int main(int argc, const char * argv[]) {
myNNfromFile.readJSON(filepath);
std::vector<double> inputVec = { 2.0, 44.2 };
std::cout << "before: " << myNN.run(inputVec)[0] << std::endl;
std::cout << "from string: " << myNNfromString.run(inputVec)[0] << std::endl;
// std::cout << myNNfromString.getJSON() << std::endl;
std::cout << "from file: " << myNNfromFile.run(inputVec)[0] << std::endl;
//std::cout << "from string: " << myNNfromString.run(inputVec)[0] << std::endl;
//std::cout << "from file: " << myNNfromFile.run(inputVec)[0] << std::endl;
assert(myNN.run(inputVec)[0] == 20.14);
//assert(myNN.run(inputVec)[0] == myNNfromString.run(inputVec)[0]);
//assert(myNN.run(inputVec)[0] == myNNfromFile.run(inputVec)[0]);
//Testing exceptions for regression
std::vector<double> emptyVec = {};
try {
myNN.run(emptyVec);
}
catch (const std::length_error &e){
assert(e.what() == std::string("bad input size: 0"));
}
std::vector<double> wrongSizeVector = {1, 1, 1, 1, 1, 1};
try {
myNN.run(wrongSizeVector);
}
catch (const std::length_error &e){
assert(e.what() == std::string("bad input size: 6"));
}
regression badNN;
std::vector<trainingExample> badSet;
trainingExample badExample;
badExample.input = { 0.1, 0.2 };
badExample.output = { 3.0 };
badSet.push_back(badExample);
badExample.input = { 1.0, 2.0, 3.0 };
badExample.output = { 4.0 };
badSet.push_back(badExample);
try {
badNN.train(badSet);
}
catch (const std::length_error &e) {
assert(e.what() == std::string("unequal feature vectors in input."));
}
badSet.clear();
badExample.input = { 0.1, 0.2 };
badExample.output = { 3.0 };
badSet.push_back(badExample);
assert(myNN.run(inputVec)[0] == myNNfromString.run(inputVec)[0]);
assert(myNN.run(inputVec)[0] == myNNfromFile.run(inputVec)[0]);
badExample.input = { 1.0, 2.0 };
badExample.output = { 4.0, 5.0 };
badSet.push_back(badExample);
try {
badNN.train(badSet);
}
catch(const std::length_error &e) {
assert(e.what() == std::string("unequal output vectors."));
}
///////////////////////////
myKnn.train(trainingSet);
mySVM.train(trainingSet);
//mySVM.train(trainingSet);
// std::cout << myKnn.getJSON() << std::endl;
std::string filepath2 = "/var/tmp/modelSetDescription_knn.json";
......@@ -139,18 +184,34 @@ int main(int argc, const char * argv[]) {
myKnnFromFile.readJSON(filepath2);
std::cout << "knn before: " << myKnn.run(inputVec)[0] << std::endl;
std::cout << "svm: " << mySVM.run(inputVec)[0] << std::endl;
std::cout << "knn from string: " << myKnnFromString.run(inputVec)[0] << std::endl;
std::cout << "knn from file: " << myKnnFromFile.run(inputVec)[0] << std::endl;
//std::cout << "svm: " << mySVM.run(inputVec)[0] << std::endl;
//std::cout << "knn from string: " << myKnnFromString.run(inputVec)[0] << std::endl;
//std::cout << "knn from file: " << myKnnFromFile.run(inputVec)[0] << std::endl;
assert(myKnn.run(inputVec)[0] == 20);
//assert(myKnn.run(inputVec)[0] == myKnnFromString.run(inputVec)[0]);
//assert(myKnn.run(inputVec)[0] == myKnnFromFile.run(inputVec)[0]);
assert(myKnn.run(inputVec)[0] == myKnnFromString.run(inputVec)[0]);
assert(myKnn.run(inputVec)[0] == myKnnFromFile.run(inputVec)[0]);
try {
myKnn.run(emptyVec);
}
catch (const std::length_error &e){
std::cout << "error: " << e.what() << std::endl;
assert(e.what() == std::string("bad input size: 0"));
}
try {
myKnn.run(wrongSizeVector);
}
catch (const std::length_error &e){
std::cout << "error: " << e.what() << std::endl;
assert(e.what() == std::string("bad input size: 6"));
}
assert(myKnn.getK()[0] == 1);
myKnn.setK(0, 2);
assert(myKnn.getK()[0] == 2);
// regression<float> bigVector;
// regression<float> bigVector;
std::vector<trainingExampleTemplate<float> > trainingSet2;
trainingExampleTemplate<float> tempExample2;
std::default_random_engine generator;
......@@ -165,33 +226,34 @@ int main(int argc, const char * argv[]) {
tempExample2.output = { distribution(generator) };
trainingSet2.push_back(tempExample2);
}
// bigVector.train(trainingSet2);
// bigVector.train(trainingSet2);
std::vector<float> inputVec2;
for (int i=0; i < vecLength; ++i) {
inputVec2.push_back(distribution(generator));
}
// assert (isfinite(bigVector.run(inputVec2)[0]));
// assert (isfinite(bigVector.run(inputVec2)[0]));
/////////
classification mySVM2(classification::svm);
std::vector<trainingExample> trainingSet3;
trainingExample tempExample3;
tempExample3.input = { 0., 0. };
tempExample3.output = { 0. };
trainingSet3.push_back(tempExample3);
tempExample3.input = { 1., 0. };
tempExample3.output = { 1. };
trainingSet3.push_back(tempExample3);
tempExample3.input = { 1., 8. };
tempExample3.output = { 5. };
trainingSet3.push_back(tempExample3);
/*
classification mySVM2(classification::svm);
std::vector<trainingExample> trainingSet3;
trainingExample tempExample3;
tempExample3.input = { 0., 0. };
tempExample3.output = { 0. };
trainingSet3.push_back(tempExample3);
tempExample3.input = { 1., 0. };
tempExample3.output = { 1. };
trainingSet3.push_back(tempExample3);
tempExample3.input = { 1., 8. };
tempExample3.output = { 5. };
trainingSet3.push_back(tempExample3);
*/
/*
......@@ -200,13 +262,13 @@ int main(int argc, const char * argv[]) {
trainingSet3.push_back(tempExample3);
*/
mySVM2.train(trainingSet3);
//mySVM2.train(trainingSet3);
std::vector<double>inputVec4 = { 1., 0. };
std::cout << "svm: " << mySVM2.run(inputVec4)[0] << std::endl;
//std::cout << "svm: " << mySVM2.run(inputVec4)[0] << std::endl;
std::vector<double> inputVec3 = { 0., 0. };
std::cout << "svm2: " << mySVM2.run(inputVec3)[0] << std::endl;
//std::cout << "svm2: " << mySVM2.run(inputVec3)[0] << std::endl;
......@@ -253,10 +315,10 @@ int main(int argc, const char * argv[]) {
assert(myDTW.run(seriesTwo) == "second series");
//std::cout << myDTW.getCosts()[0] << std::endl;
//std::cout << myDTW.getCosts()[1] << std::endl;
//testing match against single label
assert(myDTW.run(seriesOne, "second series") == 19.325403217417502);
//Training set stats
assert(myDTW.getMaxLength() == 5);
assert(myDTW.getMinLength() == 4);
......@@ -324,6 +386,6 @@ int main(int argc, const char * argv[]) {
////////////////////////////////////////////////////////////////////////
return 0;
}
**/.DS_Store
**/Thumbs.db
# INSTALLATION
## Requirements
* Swig
* Python 2.7 + Numpy / Scipy (I think Numpy v1.8+ is required)
## Building
move 'python' directory and type:
make
make install
make clean
To install in a specific location:
make install INSTALL_DIR=/path/to/install/location/
To specify swig location:
make install SWIG=/path/to/swig/
# usage
Place the built python library somewhere in your python path. To add personal
libraries located in '/Path/To/Libs' to the python path, add the following
lines to your ".bash_profile":
PYTHONPATH=$PYTHONPATH:/Path/To/Libs
export PYTHONPATH
Basic usage:
import bayesfilter
filt = bayesfilter.BayesianFilter()
filt.init()
for t in RAW_EMG_MATRIX.shape[0]:
envelope_at_t = filt.update(RAW_EMG_MATRIX[t,:])
# credits
bayesfilter has been authored by Jules Françoise : jules.francoise@ircam.fr
\ No newline at end of file
/**
* @file BayesianFilter.cpp
* @author Jules Francoise jules.francoise@ircam.fr
* @date 2013-12-24
*
* @brief Non-linear Bayesian filtering for EMG Enveloppe Extraction.
* Based on Matlab code by Terence Sanger : kidsmove.org/bayesemgdemo.html
* Reference:
* - Sanger, T. (2007). Bayesian filtering of myoelectric signals. Journal of neurophysiology, 1839–1845.
*
* @copyright
* Copyright (C) 2013-2014 by IRCAM - Centre Pompidou.
* All Rights Reserved.
*
* License (BSD 3-clause)
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. Neither the name of the copyright holder nor the names of its
* contributors may be used to endorse or promote products derived from
* this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*/
#include "BayesianFilter.h"
#include "filter_utilities.h"
#pragma mark -
#pragma mark Constructors
BayesianFilter::BayesianFilter()
{
mvc.assign(channels, 1.);
init();
}
BayesianFilter::~BayesianFilter()
{
}
void BayesianFilter::resize(std::size_t size)
{
if (size > 0) {
channels = size;
init();
}
}
std::size_t BayesianFilter::size() const
{
return channels;
}
#pragma mark -
#pragma mark Main Algorithm
void BayesianFilter::init()
{
mvc.resize(channels, 1.);
output.assign(channels, 0.);
prior.resize(channels);
state.resize(channels);
g.resize(channels);
for (unsigned int i=0; i<channels; i++) {
prior[i].resize(levels);
state[i].resize(levels);
g[i].resize(3);
double val(1.);
for (unsigned int t=0; t<levels; t++) {
state[i][t] = val * mvc[i] / double(levels);
val += 1;
prior[i][t] = 1. / levels;
}
double diff = diffusion * diffusion / (samplerate * std::pow(mvc[i] / levels, 2));
g[i][0] = diff / 2.;
g[i][1] = 1. - diff - this->jump_rate;
g[i][2] = diff / 2.;
}
}
void BayesianFilter::update(vector<float> const& observation)
{
if (observation.size() != this->channels) {
resize(observation.size());
}
for (std::size_t i=0; i<channels; i++)
{
// -- 1. Propagate
// -----------------------------------------
vector<double> a(1, 1.);
vector<double> oldPrior(prior[i].size());
// oldPrior.swap(prior[i]);
copy(prior[i].begin(), prior[i].end(), oldPrior.begin());
filtfilt(g[i], a, oldPrior, prior[i]);
// set probability of a sudden jump
for (unsigned int t=0; t<levels; t++) {
prior[i][t] = prior[i][t] + jump_rate / mvc[i];
}
// -- 4. Calculate the posterior likelihood function
// -----------------------------------------
// calculate posterior density using Bayes rule
vector<double> posterior(levels);
double sum_posterior(0.);
for (unsigned int t=0; t<levels; t++) {
double x_2 = state[i][t] * state[i][t];
posterior[t] = this->prior[i][t] * exp(- observation[i] * observation[i] / x_2) / x_2;
sum_posterior += posterior[t];
}
// -- 5. Output the signal estimate output(x(t)) = argmax P(x,t);
// -----------------------------------------
// find the maximum of the posterior density
unsigned int pp(0);
double tmpMax(posterior[0]);
for (unsigned int t=0; t<levels; t++) {
if (posterior[t] > tmpMax) {
tmpMax = posterior[t];
pp = t;
}
posterior[t] /= sum_posterior;
}
// convert index of peak value to scaled EMG value
output[i] = state[i][pp] / mvc[i];
// -- 7. Repeat from step 2 > prior for next iteration is posterior from this iteration
// -----------------------------------------
copy(posterior.begin(), posterior.end(), prior[i].begin());
}
}
/**
* @file BayesianFilter.h
* @author Jules Francoise jules.francoise@ircam.fr
* @date 2013-12-24
*
* @brief Non-linear Bayesian filtering for EMG Enveloppe Extraction.
* Based on Matlab code by Terence Sanger : kidsmove.org/bayesemgdemo.html
* Reference:
* - Sanger, T. (2007). Bayesian filtering of myoelectric signals. Journal of neurophysiology, 1839–1845.
*
* @copyright
* Copyright (C) 2013-2014 by IRCAM - Centre Pompidou.
* All Rights Reserved.
*
* License (BSD 3-clause)
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. Neither the name of the copyright holder nor the names of its
* contributors may be used to endorse or promote products derived from
* this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*/
#ifndef __emg_bayesfilter__BayesianFilter__
#define __emg_bayesfilter__BayesianFilter__
#include <algorithm>
#include <iostream>
#include <cmath>
#include <vector>
using namespace std;
/*!
@mainpage
# Bayesian Filtering for EMG envelope extraction
Non-linear baysian filter.
Code is based on Matlab example code from Terence Sanger, available at [kidsmove.org/bayesemgdemo.html](kidsmove.org/bayesemgdemo.html)
## Reference:
* Sanger, T. (2007). __Bayesian filtering of myoelectric signals.__ _Journal of neurophysiology_, 1839–1845.
## Contact
@copyright Copyright (C) 2012-2014 by IRCAM. All Rights Reserved.
@author Jules Francoise - Ircam - jules.francoise@ircam.fr
@date 2013-12-26