#include "gtl_math_octv.h" namespace gtl { namespace math { octv::octv(gtl::analog_data *ad) : QObject(ad) , _ad(ad) , _min(10) , _max(1024) , _r(octv::ratios::two) , _l(octv::looks::amplitude) , _frac(octv::fractions::one) , _r_rbw(5) { _frequencies = new std::vector; _spec = new gtl::math::spec(gtl::math::spec::types::ausp, _ad); _spec->set_window(gtl::math::spec::windows::blackman); _spec->set_unit(gtl::units::unit); _spec->set_overlap(0); _spec->set_average(1); connect(_spec, >l::math::spec::changed, this, &octv::spec_changed); // connect(_spec, >l::math::spec::average_changed, this, &octv::average_changed); // connect(_spec, >l::math::spec::overlap_changed, this, &octv::overlap_changed); // connect(_spec, >l::math::spec::unit_changed, this, &octv::unit_changed); connect(_spec, >l::math::spec::acquired, this, &octv::acquired); init(); } qreal octv::left(int idx) { if(idx < _frequencies->size()) { return _gfl * _frequencies->at(idx); } return 0.; } qreal octv::right(int idx) { if(idx < _frequencies->size()) { return _gfh * _frequencies->at(idx); } return 0.; } qreal octv::minimum() const { return _min; } void octv::set_minimum(qreal value) { if(value != _min && value > 0.1) { _min = value; init(); } } qreal octv::maximum() const { return _max; } void octv::set_maximum(qreal value) { if(value > _ad->get_rate()) value = _ad->get_rate(); if(value != _max && value >= 1) { _max = value; init(); } } octv::ratios octv::ratio() const { return _r; } void octv::set_ratio(ratios value) { if(value != _r) { _r = value; init(); } } octv::looks octv::look() const { return _l; } void octv::set_look(looks value) { if(value != _l) { _l = value; } } octv::fractions octv::fraction() const { return _frac; } void octv::set_fraction(fractions value) { if(value != _frac) { _frac = value; init(); } } units octv::unit() const { return _unit; } void octv::set_unit(units value) { if( value != _unit ) { _unit = value; emit unit_changed(); } } // int octv::average() const // { // if(_spec) // { // return _spec->average(); // } // return 1; // } // void octv::set_average(int value) // { // if(_spec) // { // _spec->set_average(value); // } // } // qreal octv::overlap() const // { // if(_spec) // { // return _spec->overlap(); // } // return 0; // } // void octv::set_overlap(int value) // { // if(_spec) // { // _spec->set_overlap(value); // } // } void octv::init() { _frac_num = 1; if(_frac == gtl::math::octv::fractions::one_third) _frac_num = 3; else if(_frac == gtl::math::octv::fractions::one_sixth) _frac_num = 6; else if(_frac == gtl::math::octv::fractions::one_twelwe) _frac_num = 12; qreal frac_num = (qreal) _frac_num; _gfl = g_pow((-1.)/(2.*frac_num), true); _gfh = g_pow(1./(2.*frac_num), true); /// Calculate frequencies/// qreal tmp_min = g_pow(_min/1000., false); qreal tmp_max = g_pow(_max/1000., false); if(_frac_num%2) { tmp_min = tmp_min*frac_num + 30.; tmp_max = tmp_max*frac_num + 30.; } else { tmp_min = (tmp_min*frac_num*2. + 59.)/2.; tmp_max = (tmp_max*frac_num*2. + 59.)/2.; } int min = std::floor(tmp_min); int max = std::ceil(tmp_max); if(min > max) max = min; _frequencies->clear(); for(int i = min; i <= max; i++) { qreal frequency = _frac_num%2 ? g_pow((i - 30.)/frac_num, true) : g_pow((2.*i - 59.)/(2.*frac_num), true); frequency *= 1000.; if(_gfl * frequency < _max && _gfh * frequency > _min) { _frequencies->push_back(frequency); } } ///////////////////////////// _spec->set_resolution(left(0)/_r_rbw); _spec->set_frequency(right(_frequencies->size() - 1)); calculate(); emit initialized(); } std::pair octv::calculate_band_indexes(qreal frequency) { qreal res = _spec->resolution(); std::pair band; band.first = (int) (_gfl * frequency / res); band.second = (int) (_gfh * frequency / res) - 1; if(band.first > band.second) band.second = band.first; return band; } qreal octv::calculate_octave(std::vector::iterator begin, std::vector::iterator end) { qreal result = 0; if(_l == octv::looks::amplitude) { result = *std::max_element(begin, end); } else if(_l == octv::looks::rms) { qreal sum = 0; for(auto it = begin; it < end; ++it) { sum += pow(*it, 2); } sum /= std::distance(begin, end); result = sqrt(sum); } if( _unit == gtl::db ) { result = 20 * log(result/_ad->reference()); } return result; } qreal octv::g_pow(qreal value, bool direction) { if(_r == octv::ratios::two) { if(direction) { return pow(2., value); } else { return log2(value); } } else if(_r == octv::ratios::ten) { if(direction) { return pow(10., value * 3./10.); } else { return log(value) * 10./3.; } } return 0.; } void octv::calculate() { clear(); std::pair band_indexes; std::pair result; for(auto it : *_frequencies) { result.first = it; band_indexes = calculate_band_indexes(it); if(band_indexes.second >= _spec->size()) band_indexes.second = _spec->size() - 1; result.second = calculate_octave(_spec->begin() + band_indexes.first, _spec->begin() + band_indexes.second); push_back(result); } } void octv::before_updating() { } void octv::after_updating() { } void octv::spec_changed() { _ad->lock_device(); calculate(); _ad->unlock_device(); emit changed(); } void octv::set_rate(qreal value) { _ad->set_rate(value); init(); } } }