Math traces bugfixes + comments
This commit is contained in:
parent
cf31fd7908
commit
17454ebba2
@ -297,6 +297,8 @@ void Trace::fromMath()
|
|||||||
{
|
{
|
||||||
source = Source::Math;
|
source = Source::Math;
|
||||||
clear();
|
clear();
|
||||||
|
mathUpdateEnd = 0;
|
||||||
|
mathUpdateBegin = numeric_limits<unsigned int>::max();
|
||||||
updateMathTracePoints();
|
updateMathTracePoints();
|
||||||
scheduleMathCalculation(0, data.size());
|
scheduleMathCalculation(0, data.size());
|
||||||
emit typeChanged(this);
|
emit typeChanged(this);
|
||||||
@ -386,10 +388,10 @@ bool Trace::resolveMathSourceHashes()
|
|||||||
return success;
|
return success;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool Trace::updateMathTracePoints()
|
void Trace::updateMathTracePoints()
|
||||||
{
|
{
|
||||||
if(!mathSourceTraces.size()) {
|
if(!mathSourceTraces.size()) {
|
||||||
return false;
|
return;
|
||||||
}
|
}
|
||||||
double startX = std::numeric_limits<double>::lowest();
|
double startX = std::numeric_limits<double>::lowest();
|
||||||
double stopX = std::numeric_limits<double>::max();
|
double stopX = std::numeric_limits<double>::max();
|
||||||
@ -410,25 +412,20 @@ bool Trace::updateMathTracePoints()
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
unsigned int samples = round((stopX - startX) / stepSize + 1);
|
unsigned int samples = round((stopX - startX) / stepSize + 1);
|
||||||
bool fullUpdate = false;
|
// qDebug() << "Updated trace points, now"<<samples<<"points from"<<startX<<"to"<<stopX;
|
||||||
if(samples != data.size()) {
|
if(samples != data.size()) {
|
||||||
|
auto oldSize = data.size();
|
||||||
data.resize(samples);
|
data.resize(samples);
|
||||||
fullUpdate = true;
|
if(oldSize < samples) {
|
||||||
}
|
for(unsigned int i=oldSize;i<samples;i++) {
|
||||||
if(samples > 0 && (startX != data.front().x || stopX != data.back().x)) {
|
|
||||||
fullUpdate = true;
|
|
||||||
}
|
|
||||||
if(fullUpdate) {
|
|
||||||
// steps changed, complete update required
|
|
||||||
mathUpdateBegin = 0;
|
|
||||||
mathUpdateEnd = samples;
|
|
||||||
for(unsigned int i=0;i<samples;i++) {
|
|
||||||
data[i].x = startX + i * stepSize;
|
data[i].x = startX + i * stepSize;
|
||||||
data[i].y = numeric_limits<complex<double>>::quiet_NaN();
|
data[i].y = numeric_limits<complex<double>>::quiet_NaN();
|
||||||
}
|
}
|
||||||
return true;
|
}
|
||||||
} else {
|
}
|
||||||
return false;
|
if(samples > 0 && (startX != data.front().x || stopX != data.back().x)) {
|
||||||
|
mathUpdateBegin = 0;
|
||||||
|
mathUpdateEnd = samples;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -441,6 +438,7 @@ void Trace::mathSourceTraceDeleted(Trace *t)
|
|||||||
|
|
||||||
void Trace::scheduleMathCalculation(unsigned int begin, unsigned int end)
|
void Trace::scheduleMathCalculation(unsigned int begin, unsigned int end)
|
||||||
{
|
{
|
||||||
|
// qDebug() << "Scheduling calculation from"<<begin<<"to"<<end;
|
||||||
if(source != Source::Math) {
|
if(source != Source::Math) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@ -462,6 +460,7 @@ void Trace::calculateMath()
|
|||||||
{
|
{
|
||||||
lastMathUpdate = QTime::currentTime();
|
lastMathUpdate = QTime::currentTime();
|
||||||
if(mathUpdateBegin >= data.size() || mathUpdateEnd >= data.size() + 1) {
|
if(mathUpdateBegin >= data.size() || mathUpdateEnd >= data.size() + 1) {
|
||||||
|
qWarning() << "Not calculating math trace, out of limits. Requested from" << mathUpdateBegin << "to" << mathUpdateEnd <<" but data is of size" << data.size();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if(mathFormula.isEmpty()) {
|
if(mathFormula.isEmpty()) {
|
||||||
@ -573,8 +572,25 @@ bool Trace::addMathSource(Trace *t, QString variableName)
|
|||||||
connect(t, &Trace::dataChanged, this, [=](unsigned int begin, unsigned int end){
|
connect(t, &Trace::dataChanged, this, [=](unsigned int begin, unsigned int end){
|
||||||
updateMathTracePoints();
|
updateMathTracePoints();
|
||||||
auto startX = t->sample(begin).x;
|
auto startX = t->sample(begin).x;
|
||||||
auto stopX = t->sample(end).x;
|
auto stopX = t->sample(end-1).x;
|
||||||
scheduleMathCalculation(index(startX), index(stopX));
|
|
||||||
|
// qDebug() << "Source update from"<<startX<<"to"<<stopX<<". Index from"<<begin<<"to"<<end;
|
||||||
|
|
||||||
|
auto calcIndex = [&](double x) -> int {
|
||||||
|
if(data.size() == 0) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
auto lower = lower_bound(data.begin(), data.end(), x, [](const Data &lhs, const double x) -> bool {
|
||||||
|
return lhs.x < x;
|
||||||
|
});
|
||||||
|
if(lower == data.end()) {
|
||||||
|
// actually beyond the last sample, return the index of the last anyway to avoid access past data
|
||||||
|
return data.size() - 1;
|
||||||
|
}
|
||||||
|
return lower - data.begin();
|
||||||
|
};
|
||||||
|
|
||||||
|
scheduleMathCalculation(calcIndex(startX), calcIndex(stopX)+1);
|
||||||
});
|
});
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
@ -1050,6 +1066,28 @@ bool Trace::isVisible()
|
|||||||
return visible;
|
return visible;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool Trace::canBePaused()
|
||||||
|
{
|
||||||
|
switch(source) {
|
||||||
|
case Source::Live:
|
||||||
|
return true;
|
||||||
|
case Source::File:
|
||||||
|
return false;
|
||||||
|
case Source::Calibration:
|
||||||
|
return false;
|
||||||
|
case Source::Math:
|
||||||
|
// depends on the math, if it depends on any live data, it may be paused
|
||||||
|
for(auto ms : mathSourceTraces) {
|
||||||
|
if(ms.first->canBePaused()) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
default:
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void Trace::pause()
|
void Trace::pause()
|
||||||
{
|
{
|
||||||
if(!paused) {
|
if(!paused) {
|
||||||
|
@ -66,6 +66,7 @@ public:
|
|||||||
QString name() { return _name; }
|
QString name() { return _name; }
|
||||||
QColor color() { return _color; }
|
QColor color() { return _color; }
|
||||||
bool isVisible();
|
bool isVisible();
|
||||||
|
bool canBePaused();
|
||||||
void pause();
|
void pause();
|
||||||
void resume();
|
void resume();
|
||||||
bool isPaused();
|
bool isPaused();
|
||||||
@ -163,6 +164,9 @@ public:
|
|||||||
void setMathFormula(const QString &newMathFormula);
|
void setMathFormula(const QString &newMathFormula);
|
||||||
bool mathFormularValid() const;
|
bool mathFormularValid() const;
|
||||||
|
|
||||||
|
// When loading setups, some traces may be used as a math source before they are loaded.
|
||||||
|
// If that happens, their hashes are added to a list. Call this function for every new trace
|
||||||
|
// after all traces from the setup file have been created. It will look for the missing traces
|
||||||
bool resolveMathSourceHashes();
|
bool resolveMathSourceHashes();
|
||||||
|
|
||||||
public slots:
|
public slots:
|
||||||
@ -171,11 +175,23 @@ public slots:
|
|||||||
void addMarker(Marker *m);
|
void addMarker(Marker *m);
|
||||||
void removeMarker(Marker *m);
|
void removeMarker(Marker *m);
|
||||||
|
|
||||||
// functions for handling source == Source::Math
|
// Functions for handling source == Source::Math
|
||||||
|
|
||||||
|
// Checks whether the trace data depends on trace t.
|
||||||
|
// If onlyDirectDependency is true, only the direct math sources are checked (i.e. the math sources of this trace).
|
||||||
|
// If onlyDirectDependency is false, math sources and all their sources are checked recursively
|
||||||
bool mathDependsOn(Trace *t, bool onlyDirectDependency = false);
|
bool mathDependsOn(Trace *t, bool onlyDirectDependency = false);
|
||||||
|
// Checks whether a trace can potentially be used as a math source. It can not be used if:
|
||||||
|
// - it is the trace itself
|
||||||
|
// - it is in a different domain than an already used math source
|
||||||
|
// - it depends on this trace
|
||||||
bool canAddAsMathSource(Trace *t);
|
bool canAddAsMathSource(Trace *t);
|
||||||
|
// Adds another trace as a math source, with a custom variable name. The same trace may be added multiple times with
|
||||||
|
// different names, older variable names will be replaced with the new one
|
||||||
bool addMathSource(Trace *t, QString variableName);
|
bool addMathSource(Trace *t, QString variableName);
|
||||||
|
// Removes a trace as a math source (if its variable name is still used in the mathFormula, this will break the calculation)
|
||||||
void removeMathSource(Trace *t);
|
void removeMathSource(Trace *t);
|
||||||
|
// Retrieves the variable name used for the specified trace. If the trace is not used as a math source, an emptry string is returned
|
||||||
QString getSourceVariableName(Trace *t);
|
QString getSourceVariableName(Trace *t);
|
||||||
|
|
||||||
signals:
|
signals:
|
||||||
@ -194,13 +210,25 @@ signals:
|
|||||||
private slots:
|
private slots:
|
||||||
void markerVisibilityChanged(Marker *m);
|
void markerVisibilityChanged(Marker *m);
|
||||||
|
|
||||||
// functions for handling source == Source::Math
|
// Functions for handling source == Source::Math
|
||||||
bool updateMathTracePoints();
|
|
||||||
void mathSourceTraceDeleted(Trace *t);
|
|
||||||
void scheduleMathCalculation(unsigned int begin, unsigned int end);
|
|
||||||
void calculateMath();
|
|
||||||
void clearMathSources();
|
|
||||||
|
|
||||||
|
// Updates the datapoints, based on the available span of all math sources.
|
||||||
|
// The least common span is used for this trace. This function only creates the datapoints
|
||||||
|
// and sets the X coordinate. The Y coordinates are set in calculateMath()
|
||||||
|
void updateMathTracePoints();
|
||||||
|
// Keeps track of deleted traces and removes them from the math sources
|
||||||
|
void mathSourceTraceDeleted(Trace *t);
|
||||||
|
// Schedules an update of this trace, should be called whenever any source data changes.
|
||||||
|
// As it is likely that multiple source traces will change directly after each other, no
|
||||||
|
// calculation is performed directly. Instead the calculation is only scheduled and executed
|
||||||
|
// shortly after. This prevents calculating data that will be overwritten immediately afterwards
|
||||||
|
void scheduleMathCalculation(unsigned int begin, unsigned int end);
|
||||||
|
// Actually calculates the Y coordinate values of this trace. It expects that the data vector is
|
||||||
|
// already set up with the required amount of points and X coordinates
|
||||||
|
void calculateMath();
|
||||||
|
// Removes all math sources, use this when switching to a different source mode
|
||||||
|
void clearMathSources();
|
||||||
|
// Attempts to add a math source using the trace hash instead of a pointer (when loading setups)
|
||||||
bool addMathSource(unsigned int hash, QString variableName);
|
bool addMathSource(unsigned int hash, QString variableName);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
@ -209,6 +237,10 @@ private:
|
|||||||
QColor _color;
|
QColor _color;
|
||||||
Source source;
|
Source source;
|
||||||
|
|
||||||
|
// Hash for identifying the trace when loading/saving setup files.
|
||||||
|
// When writing setup files, the hash is created from the JSON representation of the trace.
|
||||||
|
// When loading setup files, the hash specified in the setup file is used (prevents different
|
||||||
|
// hashes when the JSON format changes in newer versions)
|
||||||
unsigned int hash;
|
unsigned int hash;
|
||||||
bool hashSet;
|
bool hashSet;
|
||||||
bool JSONskipHash;
|
bool JSONskipHash;
|
||||||
|
@ -63,7 +63,7 @@ void TraceModel::toggleVisibility(unsigned int index)
|
|||||||
|
|
||||||
void TraceModel::togglePause(unsigned int index)
|
void TraceModel::togglePause(unsigned int index)
|
||||||
{
|
{
|
||||||
if (index < traces.size()) {
|
if (index < traces.size() && traces[index]->canBePaused()) {
|
||||||
if(traces[index]->isPaused()) {
|
if(traces[index]->isPaused()) {
|
||||||
traces[index]->resume();
|
traces[index]->resume();
|
||||||
} else {
|
} else {
|
||||||
@ -118,7 +118,7 @@ QVariant TraceModel::data(const QModelIndex &index, int role) const
|
|||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case ColIndexPlayPause:
|
case ColIndexPlayPause:
|
||||||
if (role == Qt::DecorationRole && trace->getSource() == Trace::Source::Live) { // TODO trace needs function to check if it may change due to live data
|
if (role == Qt::DecorationRole && trace->canBePaused()) {
|
||||||
if (trace->isPaused()) {
|
if (trace->isPaused()) {
|
||||||
return QIcon(":/icons/pause.svg");
|
return QIcon(":/icons/pause.svg");
|
||||||
} else {
|
} else {
|
||||||
|
@ -530,6 +530,9 @@ void TraceWaterfall::traceDataChanged(unsigned int begin, unsigned int end)
|
|||||||
data.back()[i] = trace->sample(i);
|
data.back()[i] = trace->sample(i);
|
||||||
if(yAxis.getAutorange() && !YAxisUpdateRequired) {
|
if(yAxis.getAutorange() && !YAxisUpdateRequired) {
|
||||||
double val = yAxis.sampleToCoordinate(trace->sample(i));
|
double val = yAxis.sampleToCoordinate(trace->sample(i));
|
||||||
|
if(isnan(val) || isinf(val)) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
if(val < min) {
|
if(val < min) {
|
||||||
min = val;
|
min = val;
|
||||||
}
|
}
|
||||||
|
@ -781,6 +781,11 @@ void TraceXYPlot::updateAxisTicks()
|
|||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if(isnan(point.y()) || isinf(point.y())) {
|
||||||
|
// skip NaN and Infty values
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
if(point.y() > max) {
|
if(point.y() > max) {
|
||||||
max = point.y();
|
max = point.y();
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user