#include "gtl_math_spec.h" namespace gtl { namespace math { spec::spec(types type, gtl::analog_data *ad) : QObject(ad) , _is_acq(true) , _av(1) , _un(gtl::units::unit) , _av_cnt(0) , _av_filled(false) , _ad(ad) , _type(type) { _fft = new gtl::math::fft(ad); connect(_fft, >l::math::fft::changed, this, &spec::data_changed); connect(_fft, >l::math::fft::initialized, this, &spec::init); connect(_fft, >l::math::fft::frequency_changed, this, &spec::frequency_changed); connect(_fft, >l::math::fft::resolution_changed, this, &spec::resolution_changed); connect(_fft, >l::math::fft::window_changed, this, &spec::window_changed); connect(_fft, >l::math::fft::lines_changed, this, &spec::lines_changed); connect(_fft, >l::math::fft::overlap_changed, this, &spec::overlap_changed); init(); } spec::~spec() { emit deleting(); cleanup(); if(_fft) delete _fft; } qreal spec::frequency() const { return _fft->frequency(); } void spec::set_frequency(qreal value) { _fft->set_frequency(value); } qreal spec::resolution() const { return _fft->resolution(); } void spec::set_resolution(qreal value) { _fft->set_resolution(value); } spec::windows spec::window() const { return (spec::windows) _fft->window(); } void spec::set_window(windows value) { _fft->set_window((fft::windows) value); } int spec::lines() const { return _fft->lines(); } void spec::set_lines(int value) { _fft->set_lines(value); } uint spec::average() const { return _av; } void spec::set_average(int value) { if( value != _av && value > 0) { _av = value; init(); emit average_changed(); } } qreal spec::overlap() const { return _fft->overlap(); } void spec::set_overlap(int value) { _fft->set_overlap(value); } units spec::unit() const { return _un; } units spec::get_unit() const { return _un; } void spec::set_unit(units value) { if( value != _un ) { _un = value; emit unit_changed(); } } analog_data *spec::ad() const { return _fft->ad(); } spec::types spec::type() const { return _type; } void spec::set_type(types type) { _type = type; init(); } qreal spec::acq_time() const { // int nl = _fft->lines(); // qreal f = _fft->frequency(); // qreal ol = _fft->overlap(); //// return (nl + 1)/f * ((_av - 1)* (1.0 - ol/100.0) + 1); // return (nl + 1)/f * ((_av)* (1.0 - ol/100.0) + 1); // int size = ad()->get_rate()/_fft->resolution(); qreal time = 1./_fft->resolution(); //size/ad()->get_rate() * 1.1; //1./_fft->resolution() return time * _av * (1.0 - _fft->overlap()/100.0); } int spec::samples() const { return _fft->samples(); } void spec::init() { _ad->lock_device(); cleanup(); _size_fft_out = _fft->size_fft_out(); _size_fft_calc = _fft->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(_type == spen) { _ispen_fft = new std::vector>(_fft->size()); _envelope = new std::vector(_fft->size()); _spen_fft = new std::vector>(_fft->size()); _ispen_plan = fftw_plan_dft_1d(_fft->size(), reinterpret_cast(_fft->data()), reinterpret_cast(_ispen_fft->data()), FFTW_BACKWARD, FFTW_ESTIMATE); _spen_plan = fftw_plan_dft_r2c_1d(_fft->size(), _envelope->data(), reinterpret_cast(_spen_fft->data()), FFTW_ESTIMATE); } _ad->unlock_device(); emit initialized(); emit acq_time_changed(); } void spec::cleanup() { _ad->lock_device(); if(_ispen_plan) { fftw_destroy_plan(_ispen_plan); _ispen_plan = NULL; } if(_spen_plan) { fftw_destroy_plan(_spen_plan); _spen_plan = NULL; } for(std::vector* ptr:_buffer_out) { if( ptr ) { ptr->clear(); ptr->shrink_to_fit(); delete ptr; } } _buffer_out.clear(); _buffer_out.shrink_to_fit(); if(_ispen_fft) { _ispen_fft->clear(); _ispen_fft->shrink_to_fit(); delete _ispen_fft; _ispen_fft = NULL; } if(_envelope) { _envelope->clear(); _envelope->shrink_to_fit(); delete _envelope; _envelope = NULL; } if(_spen_fft) { _spen_fft->clear(); _spen_fft->shrink_to_fit(); delete _spen_fft; _spen_fft = NULL; } clear(); shrink_to_fit(); _ad->unlock_device(); } void spec::calculate_ampl(std::vector> *in_it, std::vector::iterator out_it, int size) { qreal value; qreal ref = _ad->reference(); for( int i = 0; i < size && i < spec::size(); i++) { value = abs(in_it->at(i))/_size_fft_calc; if( _un == gtl::db ) { value = 20 * log(value/ref); } *(out_it + i) = value; } } void spec::calculate_phase(std::vector > *in_it, iterator out_it, int size) { for( int i = 0; i < size && i < spec::size(); i++) { *(out_it + i) = arg(in_it->at(i)); } } void spec::before_updating() { } void spec::after_updating() { } void spec::calculate() { if(_type == ausp) { calculate_ampl(_fft, _calculated_it, _size_fft_out); } else if(_type == spen) { if(_ispen_plan && _spen_plan) { for(size_t i = 0; i < _size_fft_calc; i++) { if( i > 0) { _fft->at(i) *= 2; } _fft->at(i) /= _size_fft_calc; } if(_ispen_plan) fftw_execute(_ispen_plan); for(size_t i = 0; i < _fft->size(); i++) _envelope->at(i) = abs(_ispen_fft->at(i)); if(_spen_plan) fftw_execute(_spen_plan); calculate_ampl(_spen_fft, _calculated_it, _size_fft_out); } } else if(_type == phase) { calculate_phase(_fft, _calculated_it, _size_fft_out); } } void spec::set_rate(qreal value) { _ad->set_rate(value); _fft->init(); } void spec::stop_acq() { _is_acq = false; } void spec::data_changed() { if(!_is_acq) return; _ad->lock_device(); 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 value = 0; for(int j = 0; j < avdiv; j++) value += _buffer_out[j]->at(i)/avdiv; at(i) = value; } } _av_cnt++; _ac = 100. * ( (qreal) _av_cnt )/_av; emit acquired(_ac); if(_av_cnt == _av) { _av_cnt = 0; _av_filled = true; } after_updating(); _ad->unlock_device(); emit changed(); // unsigned long ttt = QDateTime::currentDateTime().currentMSecsSinceEpoch(); // qDebug() << (ttt - _ttt)/1000.; // _ttt = ttt; // qDebug() << acq_time(); } } }