[TEST] test simple LMS ==> work not so bad

This commit is contained in:
Edouard DUPIN 2015-04-01 23:15:29 +02:00
parent 2483ad9fce
commit fa90026c6a
6 changed files with 228 additions and 14 deletions

View File

@ -8,9 +8,9 @@
#include <drain/echoCanceller/Lms.h>
drain::Lms::Lms(void) :
m_filtre(),
m_filter(),
m_feedBack(),
m_mu(0.08f) {
m_mu(0.03f) {
setFilterSize(256);
}
@ -20,7 +20,7 @@ drain::Lms::~Lms(void) {
void drain::Lms::reset(void) {
// simply reset filters.
setFilterSize(m_filtre.size());
setFilterSize(m_filter.size());
}
bool drain::Lms::process(int16_t* _output, const int16_t* _feedback, const int16_t* _microphone, int32_t _nbSample) {
@ -40,13 +40,13 @@ bool drain::Lms::process(int16_t* _output, const int16_t* _feedback, const int16
bool drain::Lms::process(float* _output, const float* _feedback, const float* _microphone, int32_t _nbSample) {
// add sample in the feedback history:
m_feedBack.resize(m_filtre.size(), 0.0f);
memcpy(&m_feedBack[m_filtre.size()], _feedback, _nbSample*sizeof(float));
m_feedBack.resize(m_filter.size()+_nbSample, 0.0f);
memcpy(&m_feedBack[m_filter.size()], _feedback, _nbSample*sizeof(float));
for (int32_t iii=0; iii < _nbSample; iii++) {
_output[iii] = processValue(&m_feedBack[m_filtre.size()+iii], _microphone[iii]);
_output[iii] = processValue(&m_feedBack[m_filter.size()+iii], _microphone[iii]);
}
// remove old value:
m_feedBack.erase(m_feedBack.begin(), m_feedBack.begin() + (m_feedBack.size()-m_filtre.size()) );
m_feedBack.erase(m_feedBack.begin(), m_feedBack.begin() + (m_feedBack.size()-m_filter.size()) );
return true;
}
@ -67,10 +67,10 @@ static void updateFilter(float* _filter, float* _data, float _value, int32_t _co
float drain::Lms::processValue(float* _feedback, float _microphone) {
// Error calculation.
float convolutionValue = convolution(_feedback, &m_filtre[0], m_filtre.size());
float convolutionValue = convolution(_feedback, &m_filter[0], m_filter.size());
float error = _microphone - convolutionValue;
float out = std::avg(-1.0f, error, 1.0f);
updateFilter(&m_filtre[0], _feedback, error*m_mu, m_filtre.size());
updateFilter(&m_filter[0], _feedback, error*m_mu, m_filter.size());
return out;
}
@ -79,9 +79,12 @@ void drain::Lms::setFilterSize(size_t _sampleRate, std11::chrono::microseconds _
}
void drain::Lms::setFilterSize(size_t _nbSample) {
m_filtre.clear();
m_filter.clear();
m_feedBack.clear();
m_filtre.resize(_nbSample, 0.0f);
m_filter.resize(_nbSample, 0.0f);
m_feedBack.resize(_nbSample, 0.0f);
}
void drain::Lms::setMu(float _val) {
m_mu = _val;
}

View File

@ -11,8 +11,9 @@
#include <etk/chrono.h>
namespace drain {
// Least Mean Square (LMS) algorithm "echo canceller"
/*
/**
* @brief Least Mean Square (LMS) algorithm "echo canceller"
* base on publication: http://www.arpapress.com/Volumes/Vol7Issue1/IJRRAS_7_1_05.pdf
Shcématic description:
/
o---o /|
@ -111,10 +112,20 @@ namespace drain {
* @param[in] _nbSample Sample size of the filter
*/
void setFilterSize(size_t _nbSample);
/**
* @brief Set Mu value for basic LMS value
* @param[in] _val new mu value
*/
void setMu(float _val);
private:
std::vector<float> m_filtre; //!< Current filter
std::vector<float> m_filter; //!< Current filter
std::vector<float> m_feedBack; //!< Feedback history
float m_mu; //!< mu step size
public:
// for debug only:
std::vector<float> getFilter() {
return m_filter;
}
};
}

29
lutin_drain_test_LMS.py Normal file
View File

@ -0,0 +1,29 @@
#!/usr/bin/python
import lutinModule as module
import lutinTools as tools
import lutinDebug as debug
def get_desc():
return "drain_test_LMS : Specific designed test for LMS ALGO"
def create(target):
myModule = module.Module(__file__, 'drain_test_LMS', 'BINARY')
myModule.add_src_file([
'testLMS/main.cpp',
'testLMS/debug.cpp'
])
myModule.add_module_depend(['drain', 'etk'])
return myModule

15
testLMS/debug.cpp Normal file
View File

@ -0,0 +1,15 @@
/**
* @author Edouard DUPIN
*
* @copyright 2010, Edouard DUPIN, all right reserved
*
* @license GPL v3 (see license file)
*/
#include "debug.h"
int32_t appl::getLogId() {
static int32_t g_val = etk::log::registerInstance("test-LMS");
return g_val;
}

43
testLMS/debug.h Normal file
View File

@ -0,0 +1,43 @@
/**
* @author Edouard DUPIN
*
* @copyright 2010, Edouard DUPIN, all right reserved
*
* @license GPL v3 (see license file)
*/
#ifndef __APPL_DEBUG_H__
#define __APPL_DEBUG_H__
#include <etk/log.h>
namespace appl {
int32_t getLogId();
};
#define APPL_BASE(info,data) TK_LOG_BASE(appl::getLogId(),info,data)
#define APPL_CRITICAL(data) APPL_BASE(1, data)
#define APPL_ERROR(data) APPL_BASE(2, data)
#define APPL_WARNING(data) APPL_BASE(3, data)
#ifdef DEBUG
#define APPL_INFO(data) APPL_BASE(4, data)
#define APPL_DEBUG(data) APPL_BASE(5, data)
#define APPL_VERBOSE(data) APPL_BASE(6, data)
#define APPL_TODO(data) APPL_BASE(4, "TODO : " << data)
#else
#define APPL_INFO(data) do { } while(false)
#define APPL_DEBUG(data) do { } while(false)
#define APPL_VERBOSE(data) do { } while(false)
#define APPL_TODO(data) do { } while(false)
#endif
#define APPL_ASSERT(cond,data) \
do { \
if (!(cond)) { \
APPL_CRITICAL(data); \
assert(!#cond); \
} \
} while (0)
#endif

113
testLMS/main.cpp Normal file
View File

@ -0,0 +1,113 @@
/** @file
* @author Edouard DUPIN
* @copyright 2015, Edouard DUPIN, all right reserved
* @license APACHE v2.0 (see license file)
*/
#include <test/debug.h>
#include <etk/etk.h>
#include <drain/echoCanceller/Lms.h>
#include <etk/os/FSNode.h>
#undef __class__
#define __class__ "test"
static std::vector<int16_t> read(const std::string& _path) {
std::vector<int16_t> out;
etk::FSNode node(_path);
if (node.fileOpenRead() == false) {
APPL_ERROR("can not open file : '" << node << "'");
return out;
}
uint64_t nbByte = node.fileSize();
out.resize(nbByte/2);
node.fileRead(&out[0], 2, nbByte/2);
node.fileClose();
return out;
}
static void write(const std::string& _path, const std::vector<int16_t>& _data) {
etk::FSNode node(_path);
if (node.fileOpenWrite() == false) {
APPL_ERROR("can not open file : '" << node << "'");
return;
}
node.fileWrite(&_data[0], 2, _data.size());
node.fileClose();
}
static void write(const std::string& _path, const std::vector<float>& _data) {
etk::FSNode node(_path);
if (node.fileOpenWrite() == false) {
APPL_ERROR("can not open file : '" << node << "'");
return;
}
node.fileWrite(&_data[0], 4, _data.size());
node.fileClose();
}
int main(int _argc, const char** _argv) {
// the only one init for etk:
etk::init(_argc, _argv);
std::string fbName = "";
std::string micName = "";
int32_t filterSize = 0;
float mu = 0.0f;
for (int32_t iii=0; iii<_argc ; ++iii) {
std::string data = _argv[iii];
if (etk::start_with(data,"--fb=")) {
fbName = &data[5];
} else if (etk::start_with(data,"--mic=")) {
micName = &data[6];
} else if (etk::start_with(data,"--filter-size=")) {
data = &data[14];
filterSize = etk::string_to_int32_t(data);
} else if (etk::start_with(data,"--mu=")) {
data = &data[5];
mu = etk::string_to_float(data);
} else if ( data == "-h"
|| data == "--help") {
APPL_INFO("Help : ");
APPL_INFO(" ./xxx --fb=file.raw --mic=file.raw");
APPL_INFO(" --fb Feedback file");
APPL_INFO(" --mic Microphone file");
APPL_INFO(" --filter-size Size of the filter");
APPL_INFO(" --mu Mu value -1.0< mu < -1.0");
exit(0);
}
}
if ( fbName == ""
|| micName == "") {
APPL_ERROR("Can not Process missing parameters...");
exit(-1);
}
APPL_INFO("Read FeedBack:");
std::vector<int16_t> fbData = read(fbName);
APPL_INFO(" " << fbData.size() << " samples");
APPL_INFO("Read Microphone:");
std::vector<int16_t> micData = read(micName);
APPL_INFO(" " << micData.size() << " samples");
drain::Lms algo;
if (filterSize != 0) {
algo.setFilterSize(filterSize);
}
if (mu != 0.0f) {
algo.setMu(mu);
}
std::vector<int16_t> output;
output.resize(std::min(fbData.size(), micData.size()), 0);
// process in chunk of 256 samples
int32_t blockSize = 256;
for (int32_t iii=0; iii<output.size()/blockSize; ++iii) {
APPL_INFO("Process : " << iii*blockSize << "/" << int32_t(output.size()/blockSize)*blockSize);
algo.process(&output[iii*blockSize], &fbData[iii*blockSize], &micData[iii*blockSize], blockSize);
}
write("output.raw", output);
write("filter.raw", algo.getFilter());
}