343 lines
8.7 KiB
C++
343 lines
8.7 KiB
C++
#include "graphic_analysis.h"
|
|
|
|
#include "graphic_analysis_stat.h"
|
|
#include "qad_types.h"
|
|
#include "ui_graphic_analysis.h"
|
|
|
|
#include <QTimer>
|
|
#include <pifft.h>
|
|
|
|
|
|
PIVector<double> getAmplitude(const PIVector<complexd> & result) {
|
|
PIVector<double> ret;
|
|
ret.resize(result.size());
|
|
double tmp;
|
|
for (uint i = 0; i < result.size(); i++) {
|
|
tmp = sqrt(result[i].real() * result[i].real() + result[i].imag() * result[i].imag());
|
|
ret[i] = tmp;
|
|
}
|
|
return ret;
|
|
}
|
|
|
|
|
|
PIVector<double> spectrumPIVector(PIFFTWd & fft, const PIVector<double> & in, double frequency, QPointF * fft_mul = nullptr) {
|
|
PIVector<double> ret;
|
|
if (in.size() <= 2 || frequency <= 0.) return ret;
|
|
ret = getAmplitude(fft.calcFFT(in));
|
|
ret.resize(ret.size_s() / 2);
|
|
ret[0] = 0.;
|
|
if (fft_mul) *fft_mul = QPointF(frequency / ret.size_s() / 2., 1. / ret.size_s());
|
|
return ret;
|
|
}
|
|
|
|
|
|
QPolygonF spectrumQPolygonF(PIFFTWd & fft, const PIVector<double> & in, double frequency, QPointF * fft_mul = nullptr) {
|
|
QPolygonF ret;
|
|
QPointF mul;
|
|
PIVector<double> spec = spectrumPIVector(fft, in, frequency, &mul);
|
|
if (spec.isEmpty()) return ret;
|
|
ret.resize(spec.size_s());
|
|
for (int i = 0; i < ret.size(); ++i)
|
|
ret[i] = QPointF(i * mul.x(), spec[i] * mul.y());
|
|
if (fft_mul) *fft_mul = mul;
|
|
return ret;
|
|
}
|
|
|
|
|
|
// GraphicAnalysis
|
|
|
|
|
|
PRIVATE_DEFINITION_START(GraphicAnalysis)
|
|
PIFFTWd fft;
|
|
PRIVATE_DEFINITION_END(GraphicAnalysis)
|
|
|
|
|
|
GraphicAnalysis::GraphicAnalysis(QWidget * parent): GraphicRanges(parent) {
|
|
widget_toolbox = new QWidget();
|
|
ui = new Ui::GraphicAnalysis();
|
|
ui->setupUi(widget_toolbox);
|
|
ui->widgetSpectrum->hide();
|
|
window_stat = new GraphicAnalysisStatistics();
|
|
connect(ui->checkSpectrum, SIGNAL(toggled(bool)), this, SLOT(checkSpectrum_toggled(bool)));
|
|
connect(ui->buttonSpectrumRange, SIGNAL(toggled(bool)), this, SLOT(buttonSpectrumRange_toggled(bool)));
|
|
connect(ui->checkSpectrumFixDuration, SIGNAL(toggled(bool)), this, SLOT(checkSpectrumFixDuration_toggled(bool)));
|
|
connect(ui->buttonStatistics, SIGNAL(toggled(bool)), this, SLOT(buttonStatistics_toggled(bool)));
|
|
auto * lay = qobject_cast<QBoxLayout *>(layout());
|
|
lay->insertWidget(0, widget_toolbox);
|
|
connect(ui->spinSpectrumDuration, SIGNAL(valueChanged(double)), this, SIGNAL(configChanged()));
|
|
connect(this, SIGNAL(rangeSelected(double, double)), this, SLOT(gaRangeSelected(double, double)));
|
|
connect(this, SIGNAL(graphicMousePressEvent(QPointF, int)), this, SLOT(gaMousePressEvent(QPointF, int)));
|
|
connect(this, SIGNAL(graphicMouseMoveEvent(QPointF, int)), this, SLOT(gaMouseMoveEvent(QPointF, int)));
|
|
connect(this, SIGNAL(graphicMouseReleaseEvent(QPointF, int)), this, SLOT(gaMouseReleaseEvent(QPointF, int)));
|
|
}
|
|
|
|
|
|
GraphicAnalysis::~GraphicAnalysis() {
|
|
delete window_stat;
|
|
delete ui;
|
|
}
|
|
|
|
|
|
void GraphicAnalysis::setGraphicData(const QPolygonF & g, int graphic, bool update_) {
|
|
if (graphic < 0 || graphic >= graphicsCount()) return;
|
|
src_data[graphic] = g;
|
|
updateGraphic(graphic);
|
|
if (update_) viewport()->update();
|
|
}
|
|
|
|
|
|
bool GraphicAnalysis::isSpectrumFixedDuration() const {
|
|
return ui->checkSpectrumFixDuration->isChecked();
|
|
}
|
|
|
|
|
|
void GraphicAnalysis::setIsSpectrumFixedDuration(bool on) {
|
|
ui->checkSpectrumFixDuration->setChecked(on);
|
|
}
|
|
|
|
|
|
double GraphicAnalysis::spectrumFixedDuration() const {
|
|
return ui->spinSpectrumDuration->value();
|
|
}
|
|
|
|
|
|
void GraphicAnalysis::setSpectrumFixedDuration(double val) {
|
|
ui->spinSpectrumDuration->setValue(val);
|
|
}
|
|
|
|
|
|
bool GraphicAnalysis::isToolboxVisible() const {
|
|
return widget_toolbox->isVisible();
|
|
}
|
|
|
|
|
|
void GraphicAnalysis::setToolboxVisible(bool yes) {
|
|
widget_toolbox->setVisible(yes);
|
|
}
|
|
|
|
|
|
void GraphicAnalysis::setLabelX(const QString & str) {
|
|
data_label_x = str;
|
|
if (!show_fft) Graphic::setLabelX(str);
|
|
}
|
|
|
|
|
|
QWidget * GraphicAnalysis::toolboxWidget() {
|
|
return widget_toolbox;
|
|
}
|
|
|
|
|
|
void GraphicAnalysis::setShowSpectrum(bool on) {
|
|
ui->checkSpectrum->setChecked(on);
|
|
}
|
|
|
|
|
|
bool GraphicAnalysis::isShowSpectrum() const {
|
|
return show_fft;
|
|
}
|
|
|
|
|
|
void GraphicAnalysis::changeEvent(QEvent * e) {
|
|
Graphic::changeEvent(e);
|
|
if (e->type() == QEvent::LanguageChange) {
|
|
ui->retranslateUi(this);
|
|
return;
|
|
}
|
|
}
|
|
|
|
|
|
void GraphicAnalysis::updateGraphic(int index) {
|
|
if (!show_fft) {
|
|
if (tf_gr)
|
|
Graphic::setGraphicData(tf_gr(src_data.value(index)), index, false);
|
|
else
|
|
Graphic::setGraphicData(src_data.value(index), index, false);
|
|
} else {
|
|
const QPolygonF & src(src_data[index]);
|
|
int si = 0, ei = src.size() - 1;
|
|
for (int i = 0; i < src.size(); ++i) {
|
|
if (src[i].x() >= range_fft.start) {
|
|
si = i;
|
|
break;
|
|
}
|
|
}
|
|
for (int i = si; i < src.size(); ++i) {
|
|
if (src[i].x() > range_fft.end) {
|
|
ei = i;
|
|
break;
|
|
}
|
|
}
|
|
if (ei - si < 4) {
|
|
Graphic::setGraphicData({}, index, false);
|
|
return;
|
|
}
|
|
if (tf_fft)
|
|
Graphic::setGraphicData(tf_fft(calcToFFT(&(src[si]), ei - si)), index, false);
|
|
else
|
|
Graphic::setGraphicData(calcToFFT(&(src[si]), ei - si), index, false);
|
|
}
|
|
}
|
|
|
|
|
|
void GraphicAnalysis::updateAllGraphic() {
|
|
for (int i = 0; i < graphicsCount(); ++i)
|
|
updateGraphic(i);
|
|
updateGraphics();
|
|
}
|
|
|
|
|
|
void GraphicAnalysis::setFFT(bool on) {
|
|
if (show_fft) {
|
|
setFFTInternal(false);
|
|
}
|
|
if (on) {
|
|
range_fft = rangeVisible();
|
|
setFFTInternal(true);
|
|
}
|
|
}
|
|
|
|
|
|
void GraphicAnalysis::setFFTInternal(bool on) {
|
|
bool need_autofit = false;
|
|
if (!show_fft && on) {
|
|
saved_view = visualRect();
|
|
saved_autofit = isAutofitted();
|
|
need_autofit = true;
|
|
}
|
|
if (show_fft && !on) {
|
|
setVisualRect(saved_view);
|
|
if (saved_autofit) need_autofit = true;
|
|
}
|
|
show_fft = on;
|
|
Graphic::setLabelX(on ? tr("Hz") : data_label_x);
|
|
emit showSpectrumChanged(show_fft);
|
|
updateAllGraphic();
|
|
if (need_autofit) {
|
|
autofit();
|
|
}
|
|
}
|
|
|
|
|
|
QPolygonF GraphicAnalysis::calcToFFT(const QPointF * in, int count) {
|
|
PIVector<double> fft_in, fft_out;
|
|
fft_in.reserve(count);
|
|
for (int i = 0; i < count; ++i)
|
|
fft_in << in[i].y();
|
|
double freq = double(count - 1) / (in[count - 1].x() - in[0].x());
|
|
return spectrumQPolygonF(PRIVATE->fft, fft_in, freq);
|
|
}
|
|
|
|
|
|
void GraphicAnalysis::checkRangeRequest() {
|
|
if (!ui->buttonSpectrumRange->isChecked()) return;
|
|
viewport()->unsetCursor();
|
|
if (!ui->checkSpectrumFixDuration->isChecked()) {
|
|
rangeRequest();
|
|
} else {
|
|
cancelRangeRequest(false);
|
|
viewport()->setCursor(Qt::CrossCursor);
|
|
}
|
|
}
|
|
|
|
|
|
void GraphicAnalysis::clear() {
|
|
src_data.clear();
|
|
Graphic::clear();
|
|
}
|
|
|
|
|
|
void GraphicAnalysis::setGraphicsCount(int cnt, bool update) {
|
|
for (int i = cnt; i < graphicsCount(); ++i)
|
|
src_data.remove(i);
|
|
Graphic::setGraphicsCount(cnt, update);
|
|
}
|
|
|
|
|
|
void GraphicAnalysis::addPoint(const QPointF & p, int graphic, bool update_) {
|
|
src_data[graphic] << p;
|
|
if (show_fft) return;
|
|
Graphic::addPoint(p, graphic, update_);
|
|
}
|
|
|
|
|
|
void GraphicAnalysis::setGraphicTransformFunction(std::function<QPolygonF(const QPolygonF &)> f) {
|
|
tf_gr = f;
|
|
updateAllGraphic();
|
|
}
|
|
|
|
|
|
void GraphicAnalysis::setSpectrumTransformFunction(std::function<QPolygonF(const QPolygonF &)> f) {
|
|
tf_fft = f;
|
|
updateAllGraphic();
|
|
}
|
|
|
|
|
|
void GraphicAnalysis::gaMousePressEvent(QPointF point, int buttons) {
|
|
if (!ui->buttonSpectrumRange->isChecked() || buttons != Qt::LeftButton || !ui->checkSpectrumFixDuration->isChecked()) return;
|
|
setNavigationEnabled(false);
|
|
graphicMouseMoveEvent(point, buttons);
|
|
}
|
|
|
|
|
|
void GraphicAnalysis::gaMouseMoveEvent(QPointF point, int buttons) {
|
|
if (!ui->buttonSpectrumRange->isChecked() || buttons != Qt::LeftButton || !ui->checkSpectrumFixDuration->isChecked()) return;
|
|
setCurrentRange(point.x(), point.x() + ui->spinSpectrumDuration->value());
|
|
}
|
|
|
|
|
|
void GraphicAnalysis::gaMouseReleaseEvent(QPointF point, int buttons) {
|
|
if (!ui->buttonSpectrumRange->isChecked() || buttons != Qt::LeftButton || !ui->checkSpectrumFixDuration->isChecked()) return;
|
|
auto r = currentRange();
|
|
clearCurrentRange();
|
|
gaRangeSelected(r.start, r.end);
|
|
viewport()->setCursor(Qt::ArrowCursor);
|
|
QTimer::singleShot(10, [this]() {
|
|
setNavigationEnabled(true);
|
|
update();
|
|
});
|
|
}
|
|
|
|
|
|
void GraphicAnalysis::gaRangeSelected(double start, double end) {
|
|
if (ui->buttonSpectrumRange->isChecked()) {
|
|
ui->buttonSpectrumRange->setChecked(false);
|
|
range_fft = GraphicRanges::Range(start, end);
|
|
updateAllGraphic();
|
|
}
|
|
if (ui->buttonStatistics->isChecked()) {
|
|
ui->buttonStatistics->setChecked(false);
|
|
window_stat->show(this, GraphicRanges::Range(start, end));
|
|
}
|
|
}
|
|
|
|
|
|
void GraphicAnalysis::checkSpectrum_toggled(bool on) {
|
|
if (!on) ui->buttonSpectrumRange->setChecked(false);
|
|
setFFT(on);
|
|
}
|
|
|
|
|
|
void GraphicAnalysis::buttonSpectrumRange_toggled(bool on) {
|
|
setFFT(!on);
|
|
if (on) {
|
|
ui->buttonStatistics->setChecked(false);
|
|
checkRangeRequest();
|
|
} else
|
|
viewport()->unsetCursor();
|
|
}
|
|
|
|
|
|
void GraphicAnalysis::checkSpectrumFixDuration_toggled(bool on) {
|
|
checkRangeRequest();
|
|
emit configChanged();
|
|
}
|
|
|
|
|
|
void GraphicAnalysis::buttonStatistics_toggled(bool on) {
|
|
if (on) {
|
|
ui->buttonSpectrumRange->setChecked(false);
|
|
rangeRequest();
|
|
} else
|
|
viewport()->unsetCursor();
|
|
}
|