383 lines
9.7 KiB
C++
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, >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<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();
|
||
|
}
|
||
|
}
|
||
|
}
|