#include "gtl_math_apfc.h" namespace gtl { namespace math { apfc::apfc(gtl::analog_data *ref, gtl::analog_data *data) : _is_acq(true), _av(1), _afc(afcs::magnitude), _pfc(pfcs::deg), _av_cnt(0), _av_filled(false), _threshold(50), _ref(nullptr), _data(nullptr) { _device = static_cast(data->root()); if(_device) _device->lock_ai(); _ref = new gtl::math::fft(ref); _data = new gtl::math::fft(data); connect(_device, >l::device::recieved_data, this, >l::math::apfc::device_recieved_data); connect(_data, >l::math::fft::initialized, this, &apfc::init); connect(_data, >l::math::fft::frequency_changed, this, &apfc::frequency_changed); connect(_data, >l::math::fft::resolution_changed, this, &apfc::resolution_changed); connect(_data, >l::math::fft::window_changed, this, &apfc::window_changed); connect(_data, >l::math::fft::lines_changed, this, &apfc::lines_changed); connect(_data, >l::math::fft::overlap_changed, this, &apfc::overlap_changed); init(); if(_device) _device->unlock_ai(); } apfc::~apfc() { emit deleting(); cleanup(); if(_ref) delete _ref; if(_data) delete _data; } void apfc::set_ref(analog_data *ref) { if(_device) _device->lock_ai(); if(_ref) delete _ref; _ref = new gtl::math::fft(ref); _ref->set_frequency(_data->frequency()); _ref->set_resolution(_data->resolution()); _ref->set_overlap(_data->overlap()); _ref->set_window(_data->window()); init(); if(_device) _device->unlock_ai(); } void apfc::set_data(analog_data *data) { _device = static_cast(data->root()); if(_device) _device->lock_ai(); disconnect(_device, >l::device::recieved_data, this, >l::math::apfc::device_recieved_data); disconnect(_data, >l::math::fft::initialized, this, &apfc::init); disconnect(_data, >l::math::fft::frequency_changed, this, &apfc::frequency_changed); disconnect(_data, >l::math::fft::resolution_changed, this, &apfc::resolution_changed); disconnect(_data, >l::math::fft::window_changed, this, &apfc::window_changed); disconnect(_data, >l::math::fft::lines_changed, this, &apfc::lines_changed); disconnect(_data, >l::math::fft::overlap_changed, this, &apfc::overlap_changed); if(_data) delete _data; _data = new gtl::math::fft(data); _data->set_frequency(_ref->frequency()); _data->set_resolution(_ref->resolution()); _data->set_overlap(_ref->overlap()); _data->set_window(_ref->window()); connect(_device, >l::device::recieved_data, this, >l::math::apfc::device_recieved_data); connect(_data, >l::math::fft::initialized, this, >l::math::apfc::init); connect(_data, >l::math::fft::frequency_changed, this, >l::math::apfc::frequency_changed); connect(_data, >l::math::fft::resolution_changed, this, >l::math::apfc::resolution_changed); connect(_data, >l::math::fft::window_changed, this, >l::math::apfc::window_changed); connect(_data, >l::math::fft::lines_changed, this, >l::math::apfc::lines_changed); connect(_data, >l::math::fft::overlap_changed, this, >l::math::apfc::overlap_changed); init(); if(_device) _device->unlock_ai(); } qreal apfc::frequency() const { return _data->frequency(); } void apfc::set_frequency(qreal value) { _ref->set_frequency(value); _data->set_frequency(value); init(); } qreal apfc::resolution() const { return _data->resolution(); } void apfc::set_resolution(qreal value) { _ref->set_resolution(value); _data->set_resolution(value); init(); } apfc::windows apfc::window() const { return (apfc::windows) _data->window(); } void apfc::set_window(windows value) { _ref->set_window((fft::windows) value); _data->set_window((fft::windows) value); } int apfc::lines() const { return _data->lines(); } void apfc::set_lines(int value) { _ref->set_lines(value); _data->set_lines(value); init(); } uint apfc::average() const { return _av; } void apfc::set_average(int value) { if( value != _av && value > 0) { _av = value; init(); emit average_changed(); } } qreal apfc::overlap() const { return _data->overlap(); } void apfc::set_overlap(int value) { _ref->set_overlap(value); _data->set_overlap(value); } qreal apfc::acq_time() const { int nl = _data->lines(); qreal f = _data->frequency(); qreal ol = _data->overlap(); return (nl + 1)/f * ((_av - 1)* (1.0 - ol/100.0) + 1); } apfc::afcs apfc::afc() const { return _afc; } void apfc::set_afc(afcs value) { if( value != _afc ) { _afc = value; emit afc_changed(); } } apfc::pfcs apfc::pfc() const { return _pfc; } void apfc::set_pfc(pfcs value) { if( value != _pfc ) { _pfc = value; emit pfc_changed(); } } qreal apfc::threshold() const { return _threshold; } void apfc::set_threshold(qreal newThreshold) { if (qFuzzyCompare(_threshold, newThreshold)) return; _threshold = newThreshold; emit threshold_changed(); } void apfc::calculate() { qreal ref_a = 0; qreal data_a = 0; qreal ref_p = 0; qreal data_p = 0; qreal ref_akf = 0; qreal data_akf = 0; qreal vkf = 0; vector ref_a_arr(_size_fft_out); qreal ref_a_max = 0; for(int i = 0; i < _size_fft_out; i++) { ref_a_arr[i] = abs(_ref->at(i))/_size_fft_calc; if(ref_a_arr[i] > ref_a_max) ref_a_max = ref_a_arr[i]; } for(int i = 0; i < _size_fft_out; i++) { ref_a = ref_a_arr[i];//abs(_ref->at(i))/_size_fft_calc; data_a = abs(_data->at(i))/_size_fft_calc; if(ref_a >= ref_a_max*(_threshold/100.)) { if(ref_a > 1e-5 && data_a > 1e-5) { qreal calc_value = 0; ////AMPL//// if(_afc == magnitude) calc_value = data_a/ref_a; else if(_afc == db) calc_value= 20*log(data_a/ref_a); else if(_afc == coherence) { vkf = pow(abs(_ref->at(i)*std::conj(_data->at(i)))/_size_fft_calc, 2); // Модуль ВКФ в квадрате ref_akf = abs(_ref->at(i)*std::conj(_ref->at(i)))/_size_fft_calc; // АКФ ref data_akf = abs(_data->at(i)*std::conj(_data->at(i)))/_size_fft_calc; // АКФ data calc_value = vkf/(ref_akf*data_akf); } (_calculated_it + i)->first = roundf(calc_value*1000)/1000; ////PHASE//// ref_p = arg(_ref->at(i)); data_p = arg(_data->at(i)); qreal delta_phase = data_p - ref_p; if(delta_phase < 0) delta_phase += 2*M_PI; if(_pfc == deg) calc_value = 180.*delta_phase/M_PI; else if(_pfc == rad) calc_value = delta_phase; (_calculated_it + i)->second = roundf(calc_value*1000)/1000; } } else { (_calculated_it + i)->first = 0; (_calculated_it + i)->second = 0; } } } void apfc::before_updating() { } void apfc::after_updating() { } void apfc::device_recieved_data() { if(_ref->samples() != _data->samples()) return; if(_device) _device->lock_ai(); before_updating(); // Вычисление , усреднение int avdiv = _av_filled ? _av : _av_cnt + 1; if( _av > 1 ) _calculated_it = _buffer_out[_av_cnt]->begin(); else _calculated_it = begin(); calculate(); if( _av > 1 ) { for(int i = 0; i < _size_fft_out; i++) { qreal ampl = 0; qreal phase = 0; for(int j = 0; j < avdiv; j++) { ampl += _buffer_out[j]->at(i).first/avdiv; phase += _buffer_out[j]->at(i).second/avdiv; } at(i).first = ampl; at(i).second = phase; } } _av_cnt++; _ac = 100. * ( (qreal) _av_cnt )/_av; emit acquired(_ac); if(_av_cnt == _av) { _av_cnt = 0; _av_filled = true; } after_updating(); if(_device) _device->unlock_ai(); emit changed(); } void apfc::cleanup() { if(_device) _device->lock_ai(); for(std::vector>* ptr:_buffer_out) { if( ptr ) { ptr->clear(); ptr->shrink_to_fit(); delete ptr; } } _buffer_out.clear(); _buffer_out.shrink_to_fit(); clear(); shrink_to_fit(); if(_device) _device->unlock_ai(); } void apfc::init() { if(_device) _device->lock_ai(); cleanup(); _size_fft_out = std::min(_data->size_fft_out(), _ref->size_fft_out()); _size_fft_calc = std::min(_data->size_fft_calc(), _ref->size_fft_calc()); _av_cnt = 0; _av_filled = false; for(int i = 0; i < _av; i++) _buffer_out.push_back(new std::vector>(_size_fft_out)); _calculated_it = _buffer_out[0]->begin(); resize(_size_fft_out); if(_device) _device->unlock_ai(); emit initialized(); emit acq_time_changed(); } void apfc::stop_acq() { _is_acq = false; } } // namespace math } // namespace gtl