test_sdk/math/gtl_math_spec.cpp

383 lines
9.7 KiB
C++

#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, &gtl::math::fft::changed, this, &spec::data_changed);
connect(_fft, &gtl::math::fft::initialized, this, &spec::init);
connect(_fft, &gtl::math::fft::frequency_changed, this, &spec::frequency_changed);
connect(_fft, &gtl::math::fft::resolution_changed, this, &spec::resolution_changed);
connect(_fft, &gtl::math::fft::window_changed, this, &spec::window_changed);
connect(_fft, &gtl::math::fft::lines_changed, this, &spec::lines_changed);
connect(_fft, &gtl::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<qreal>(_size_fft_out));
_calculated_it = _buffer_out[0]->begin();
resize(_size_fft_out);
if(_type == spen)
{
_ispen_fft = new std::vector<std::complex<double>>(_fft->size());
_envelope = new std::vector<qreal>(_fft->size());
_spen_fft = new std::vector<std::complex<double>>(_fft->size());
_ispen_plan = fftw_plan_dft_1d(_fft->size(), reinterpret_cast<fftw_complex*>(_fft->data()), reinterpret_cast<fftw_complex*>(_ispen_fft->data()), FFTW_BACKWARD, FFTW_ESTIMATE);
_spen_plan = fftw_plan_dft_r2c_1d(_fft->size(), _envelope->data(), reinterpret_cast<fftw_complex*>(_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<qreal>* 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<std::complex<double>> *in_it, std::vector<qreal>::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<std::complex<double> > *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();
}
}
}