diff --git a/drain/echoCanceller/Lms.cpp b/drain/echoCanceller/Lms.cpp index e0c0bb4..cc6b79a 100644 --- a/drain/echoCanceller/Lms.cpp +++ b/drain/echoCanceller/Lms.cpp @@ -8,9 +8,9 @@ #include 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; +} \ No newline at end of file diff --git a/drain/echoCanceller/Lms.h b/drain/echoCanceller/Lms.h index 2a3558b..b41dc7d 100644 --- a/drain/echoCanceller/Lms.h +++ b/drain/echoCanceller/Lms.h @@ -11,8 +11,9 @@ #include 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 m_filtre; //!< Current filter + std::vector m_filter; //!< Current filter std::vector m_feedBack; //!< Feedback history float m_mu; //!< mu step size + public: + // for debug only: + std::vector getFilter() { + return m_filter; + } }; } diff --git a/lutin_drain_test_LMS.py b/lutin_drain_test_LMS.py new file mode 100644 index 0000000..49ea7fe --- /dev/null +++ b/lutin_drain_test_LMS.py @@ -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 + + + + + + + + + diff --git a/testLMS/debug.cpp b/testLMS/debug.cpp new file mode 100644 index 0000000..5b25247 --- /dev/null +++ b/testLMS/debug.cpp @@ -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; +} + diff --git a/testLMS/debug.h b/testLMS/debug.h new file mode 100644 index 0000000..a62d9c7 --- /dev/null +++ b/testLMS/debug.h @@ -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 + +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 diff --git a/testLMS/main.cpp b/testLMS/main.cpp new file mode 100644 index 0000000..927dad4 --- /dev/null +++ b/testLMS/main.cpp @@ -0,0 +1,113 @@ +/** @file + * @author Edouard DUPIN + * @copyright 2015, Edouard DUPIN, all right reserved + * @license APACHE v2.0 (see license file) + */ + +#include +#include +#include +#include + + +#undef __class__ +#define __class__ "test" + + +static std::vector read(const std::string& _path) { + std::vector 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& _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& _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 fbData = read(fbName); + APPL_INFO(" " << fbData.size() << " samples"); + APPL_INFO("Read Microphone:"); + std::vector 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 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