test_sdk/script/gtl_scr_spec.cpp

632 lines
18 KiB
C++

#include "gtl_scr_spec.h"
#include "qvariant.h"
#include <QDebug>
namespace gtl
{
namespace scr
{
spec::spec(gtl::math::spec::types type, gtl::analog_data *ad)
: gtl::math::spec(type, ad)
, _name(ad->name())
, _color(ad->color())
, _is_visible(true)
, _smoothing_factor(10)
, _smoothed_line_color(ad->color())
, _peak_level(6)
, _harm_tolerance(1)
, _max_harm_level(0)
{
connect(this, &gtl::math::spec::initialized, this, &gtl::scr::spec::reset);
}
QString spec::name() const
{
return _name;
}
int spec::color() const
{
return _color;
}
bool spec::is_visible() const
{
return _is_visible;
}
int spec::smoothing_factor() const
{
return _smoothing_factor;
}
int spec::smoothed_line_color() const
{
return _smoothed_line_color;
}
qreal spec::peak_level() const
{
return _peak_level;
}
void spec::get_smoothed_line(std::back_insert_iterator<std::vector<qreal> > data) const
{
std::copy(_smoothed_line.begin(), _smoothed_line.end(), data);
}
void spec::get_peaks(std::back_insert_iterator<std::vector<int> > peaks) const
{
std::copy(_peaks.begin(), _peaks.end(), peaks);
}
QVariant spec::get_harms_sets() const
{
return QVariant::fromValue(_harms_sets);
}
int spec::harms_sets_count() const
{
return _harms_sets.count();
}
spec_harms *spec::harms_set(uint idx) const
{
if(idx < _harms_sets.count())
return _harms_sets[idx];
return NULL;
}
void spec::get_harms(std::back_insert_iterator<std::vector<spec_harm *>> harms)
{
for(auto harms_set : _harms_sets)
{
if(harms_set->is_visible())
harms_set->get_harms(harms);
}
}
void spec::get_humps(std::back_insert_iterator<std::vector<spec_humps *>> humps)
{
std::copy(_humps_sets.begin(), _humps_sets.end(), humps);
}
qreal spec::harm_tolerance() const
{
return _harm_tolerance;
}
qreal spec::get_amplitude(qreal freq) const
{
return get_y(freq, *this);
}
void spec::get_state(QJsonObject &root) const
{
root.insert("name", name());
root.insert("type", type() == gtl::math::spec::ausp ? "ausp" : "spen");
root.insert("unit", gtl::math::spec::unit() == gtl::unit ? "units" : "db");
root.insert("res", gtl::math::spec::resolution());
root.insert("avg", (int)gtl::math::spec::average());
root.insert("overlap", (int)gtl::math::spec::overlap());
root.insert("window", (int)gtl::math::spec::window());
analog_data* analog_data_root = ad()->analog_data_root();
if(analog_data_root)
root.insert("ad_name", analog_data_root->name());
else
root.insert("ad_name", "");
QJsonObject spec;
spec.insert("color", _color);
spec.insert("data", data());
root.insert("spec", spec);
QJsonObject base_;
base_.insert("color", _smoothed_line_color);
base_.insert("factor", _smoothing_factor);
base_.insert("data", base());
root.insert("base", base_);
QJsonObject peaks;
peaks.insert("level", _peak_level);
QJsonArray peaks_indices;
for(auto it = _peaks.begin(); it != _peaks.end(); it++)
peaks_indices.append(*it);
peaks.insert("indices", peaks_indices);
root.insert("peaks", peaks);
QJsonObject harmonics;
harmonics.insert("tolerance", _harm_tolerance);
QJsonArray harms_sets;
for(auto harm_set : _harms_sets)
{
QJsonObject harm_set_object;
harm_set->save_state(harm_set_object);
harms_sets.append(harm_set_object);
}
harmonics.insert("harms_sets", harms_sets);
root.insert("harmonics", harmonics);
}
void spec::set_state(const QJsonObject &root)
{
_name = root["name"].toString();
analog_data* analog_data_root = ad()->analog_data_root();
if(analog_data_root)
analog_data_root->set_name(root["ad_name"].toString());
_type = (gtl::math::spec::types)(root["type"].toString() == "spen");
set_unit((gtl::units)(root["unit"].toString() == "db"));
set_average(root["avg"].toInt());
set_overlap(root["overlap"].toInt());
set_window((gtl::math::spec::windows)root["window"].toInt());
QJsonObject spec = root["spec"].toObject();
QJsonArray spec_data = spec["data"].toArray();
set_color(spec["color"].toInt());
set_frequency(root["res"].toDouble() * (spec_data.size() - 1));
set_lines(spec_data.size() - 1);
for(int i = 0; i < size(); i++)
(*this)[i] = spec_data[i].toDouble();
QJsonObject base = root["base"].toObject();
QJsonArray base_data = base["data"].toArray();
set_smoothed_line_color(base["color"].toInt());
_smoothed_line.clear();
for(int i = 0; i < base_data.size(); i++)
_smoothed_line.push_back(base_data[i].toDouble());
QJsonObject peaks = root["peaks"].toObject();
_peak_level = peaks["level"].toDouble();
QJsonArray peak_indices = peaks["indices"].toArray();
_peaks.clear();
for(auto it: peak_indices)
{
_peaks.push_back(it.toInt());
_peaks_freqs.push_back(_peaks.back()*resolution());
}
QJsonObject harmonics = root["harmonics"].toObject();
_harm_tolerance = harmonics["torlerance"].toDouble();
QJsonArray harms_set = harmonics["harms_sets"].toArray();
for(auto it: harms_set)
{
spec_harms *harms = new spec_harms(this);
harms->set_tolerance(_harm_tolerance);
harms->restore_state(it.toObject());
_harms_sets.push_back(harms);
connect(harms, &spec_harms::get_peak_freq, this, &spec::get_peak_freq);
connect(harms, &spec_harms::get_harm_amplitude, this, &spec::get_ampl);
connect(harms, &spec_harms::get_harm_base, this, &spec::get_base);
connect(harms, &spec_harms::visible_changed, this, &spec::harms_set_visible_changed);
connect(harms, &spec_harms::get_max_harm_level, this, &spec::get_max_harm_level);
}
set_max_harm_ampl();
emit spec_changed();
}
qreal spec::integral_index() const
{
qreal integral_index = 0;
for(auto harms_set : _harms_sets)
integral_index += harms_set->integral_index();
return integral_index;
}
void spec::get_avg(int points, const_iterator begin, const_iterator end, std::back_insert_iterator<std::vector<qreal> > out)
{
for(auto it = begin; it != end; it++)
{
int cnt = 0;
qreal value = 0;
for(
auto it1 = (std::distance(begin, it) < points ? begin : it - points);
it1 < (std::distance(it, end) <= points ? end : it + 1 + points);
it1++
)
{
value += *it1;
cnt++;
}
out = value/cnt;
out++;
}
}
qreal spec::get_y(qreal x, const std::vector<qreal> &series) const
{
if(qIsNaN(x))
return 0;
if(series.size() < 2)
return 0;
qreal x_[2];
qreal y_[2];
int idx = 0;
qreal dx = resolution();
if(x < 0)
{
//idx = 0;
return 0;
}
else if(x > (series.size() - 1)*dx)
{
//idx = size() - 2;
return 0;
}
else
{
idx = x/dx;
}
x_[0] = idx*dx;
x_[1] = (idx + 1) * dx;
y_[0] = series[idx];
y_[1] = series[idx + 1];
qreal a = (y_[0] - y_[1])/(x_[0] - x_[1]);
qreal b = y_[0] - a*x_[0];
return a*x + b;
}
QJsonArray spec::base() const
{
QJsonArray base;
for(auto it = _smoothed_line.begin(); it != _smoothed_line.end(); it++)
base.append(*it);
return base;
}
QJsonArray spec::data() const
{
QJsonArray data;
for(auto it = begin(); it != end(); it++)
data.append(*it);
return data;
}
QJsonArray spec::env() const
{
QJsonArray evl;
if(_envelope)
{
for(auto it : *_envelope)
evl.append(it);
}
return evl;
}
void spec::before_updating()
{
_smoothed_line.clear();
_peaks.clear();
_peaks_freqs.clear();
}
void spec::after_updating()
{
get_avg(_smoothing_factor, begin(), end(), std::back_inserter(_smoothed_line));
/*
for(int i = 0; i < size(); i++)
{
int cnt = 0;
qreal value = 0;
for(int j = qMax(0, i - _smoothing_factor); j <= qMin(i + _smoothing_factor, (int)size() - 1); j++)
{
value += at(j);
cnt++;
}
_smoothed_line.push_back(value/cnt);
}
*/
int peak_idx = -1;
qreal peak_value = 0;
qreal df = 1;
for(int i = 0; i < size(); i++)
{
if(at(i) - _smoothed_line[i] >= _peak_level)
{
if(peak_idx == -1)
{
peak_idx = i;
peak_value = at(i);
}
else if(at(i) > peak_value)
{
peak_idx = i;
peak_value = at(i);
}
}
else if(at(i) < _smoothed_line[i] || i == (int)size() - 1)
{
if(peak_idx != -1)
{
_peaks.push_back(peak_idx);
_peaks_freqs.push_back(peak_idx*resolution());
}
peak_idx = -1;
}
}
for(auto harms_set : _harms_sets)
harms_set->update();
for(auto humps : _humps_sets)
humps->update();
set_max_harm_ampl();
emit spec_changed();
}
qreal spec::get_freq_for_max_ampl(qreal freq, qreal tolerance)
{
qreal freq_left = freq - tolerance;
qreal freq_right = freq + tolerance;
qreal value = freq_left;
qreal ampl_max = get_y(freq_left, *this);
qreal ampl = get_y(freq_right, *this);
if(ampl > ampl_max)
{
value = freq_right;
ampl_max = ampl;
}
int left = std::max<int>(freq_left/resolution() + 1, 0);
int right = std::min<int>(freq_right/resolution(), size() - 1);
for(int i = left; i <= right; i++)
{
ampl = get_y(i*resolution(), *this);
if(ampl > ampl_max)
{
value = i*resolution();
ampl_max = ampl;
}
}
return value;
}
void spec::set_max_harm_ampl()
{
_max_harm_level = 0;
for(auto harms_set : _harms_sets)
harms_set->get_max_ampl(_max_harm_level);
emit integral_index_changed();
}
void spec::set_name(QString value)
{
if(value != _name)
{
_name = value;
emit name_changed();
}
}
void spec::set_color(int value)
{
if(value != _color)
{
_color = value;
emit color_changed();
}
}
void spec::set_visible(bool value)
{
if(_is_visible != value)
{
_is_visible = value;
emit visible_changed();
}
}
void spec::set_smoothing_factor(int value)
{
if(_smoothing_factor != value)
{
_smoothing_factor = value;
emit smoothing_factor_changed();
}
}
void spec::set_smoothed_line_color(int value)
{
if(_smoothed_line_color != value)
{
_smoothed_line_color = value;
emit smoothed_line_color_changed();
}
}
void spec::set_peak_level(qreal value)
{
if(_peak_level != value)
{
_peak_level = value;
emit peak_level_changed();
}
}
QJSValue spec::add_harms_set(qreal freq, int k, int color, qreal weight)
{
spec_harms *harms = new spec_harms(this, freq, k, color, weight);
harms->set_tolerance(_harm_tolerance);
_harms_sets.push_back(harms);
connect(harms, &spec_harms::get_peak_freq, this, &spec::get_peak_freq);
connect(harms, &spec_harms::get_harm_amplitude, this, &spec::get_ampl);
connect(harms, &spec_harms::get_harm_base, this, &spec::get_base);
connect(harms, &spec_harms::visible_changed, this, &spec::harms_set_visible_changed);
connect(harms, &spec_harms::get_max_harm_level, this, &spec::get_max_harm_level);
set_max_harm_ampl();
emit harms_sets_changed();
QJSValue js_object;
emit create_engine_object(harms, js_object);
return js_object;
}
QJSValue spec::addHarmsSet(const QJsonObject args)
{
return add_harms_set(
args.value("freq").toDouble(100),
args.value("count").toInt(5),
args.value("color").toInt(0),
args.value("weight").toInt(1)
);
}
QJSValue spec::addHumps(const QJsonObject& args)
{
spec_humps *humps = new spec_humps(
this,
args
);
_humps_sets.push_back(humps);
QJSValue js_object;
emit create_engine_object(humps, js_object);
return js_object;
}
void spec::clear_harms_sets()
{
for(auto harms : _harms_sets)
{
delete harms;
}
_harms_sets.clear();
set_max_harm_ampl();
}
void spec::clear_humps()
{
for(auto humps : _humps_sets)
{
delete humps;
}
_humps_sets.clear();
}
void spec::set_harm_tolerance(qreal value)
{
if(value != _harm_tolerance)
{
_harm_tolerance = value;
for(auto it : _harms_sets)
it->set_tolerance(_harm_tolerance);
emit harm_tolerance_changed();
}
}
qreal spec::max_harm_level() const
{
return _max_harm_level;
}
void spec::get_peak_freq(qreal freq, qreal tolerance, qreal &peak_freq)
{
if(!_peaks_freqs.empty())
{
auto it = std::lower_bound(_peaks_freqs.begin(), _peaks_freqs.end(), freq);
if(it != _peaks_freqs.begin())
{
if(freq - *prev(it) <= tolerance)
{
peak_freq = *prev(it);
return;
}
}
if(it != _peaks_freqs.end())
{
if(*it - freq <= tolerance)
{
peak_freq = *it;
return;
}
}
}
peak_freq = -1;
}
void spec::get_ampl(qreal freq, qreal &res)
{
res = get_y(freq, *this);
}
void spec::get_base(qreal freq, qreal &res)
{
res = get_y(freq, _smoothed_line);
}
void spec::reset()
{
_smoothed_line.clear();
_peaks.clear();
_peaks_freqs.clear();
}
void spec::get_max_harm_level(qreal &value) const
{
value = _max_harm_level;
}
}
}