#include "trace.h" using namespace std; Trace::Trace(QString name, QColor color, LiveParameter live) : _name(name), _color(color), _liveType(LivedataType::Overwrite), _liveParam(live), reflection(true), visible(true), paused(false), touchstone(false), calibration(false) { } Trace::~Trace() { emit deleted(this); } void Trace::clear() { if(paused) { return; } _data.clear(); emit cleared(this); emit dataChanged(); } void Trace::addData(Trace::Data d) { // add or replace data in vector while keeping it sorted with increasing frequency auto lower = lower_bound(_data.begin(), _data.end(), d, [](const Data &lhs, const Data &rhs) -> bool { return lhs.frequency < rhs.frequency; }); if(lower == _data.end()) { // highest frequency yet, add to vector _data.push_back(d); } else if(lower->frequency == d.frequency) { switch(_liveType) { case LivedataType::Overwrite: // replace this data element *lower = d; break; case LivedataType::MaxHold: // replace this data element if(abs(d.S) > abs(lower->S)) { *lower = d; } break; case LivedataType::MinHold: // replace this data element if(abs(d.S) < abs(lower->S)) { *lower = d; } break; } } else { // insert at this position _data.insert(lower, d); } emit dataAdded(this, d); emit dataChanged(); } void Trace::setName(QString name) { _name = name; emit nameChanged(); } void Trace::fillFromTouchstone(Touchstone &t, unsigned int parameter, QString filename) { if(parameter >= t.ports()*t.ports()) { throw runtime_error("Parameter for touchstone out of range"); } clear(); setTouchstoneParameter(parameter); setTouchstoneFilename(filename); for(unsigned int i=0;i Trace::getMarkers() const { return markers; } void Trace::setVisible(bool visible) { if(visible != this->visible) { this->visible = visible; emit visibilityChanged(this); } } bool Trace::isVisible() { return visible; } void Trace::pause() { paused = true; } void Trace::resume() { paused = false; } bool Trace::isPaused() { return paused; } bool Trace::isTouchstone() { return touchstone; } bool Trace::isCalibration() { return calibration; } bool Trace::isLive() { return !isCalibration() && !isTouchstone(); } bool Trace::isReflection() { return reflection; } double Trace::findExtremumFreq(bool max) { double compare = max ? numeric_limits::min() : numeric_limits::max(); double freq = 0.0; for(auto d : _data) { double amplitude = abs(d.S); if((max && (amplitude > compare)) || (!max && (amplitude < compare))) { // higher/lower extremum found compare = amplitude; freq = d.frequency; } } return freq; } std::vector Trace::findPeakFrequencies(unsigned int maxPeaks, double minLevel, double minValley) { using peakInfo = struct peakinfo { double frequency; double level_dbm; }; vector peaks; double frequency = 0.0; double max_dbm = -200.0; double min_dbm = 200.0; for(auto d : _data) { double dbm = 20*log10(abs(d.S)); if((dbm >= max_dbm) && (min_dbm <= dbm - minValley)) { // potential peak frequency frequency = d.frequency; max_dbm = dbm; } if(dbm <= min_dbm) { min_dbm = dbm; } if((dbm <= max_dbm - minValley) && (max_dbm >= minLevel)) { // peak was high enough and dropped below minValley afterwards peakInfo peak; peak.frequency = frequency; peak.level_dbm = max_dbm; peaks.push_back(peak); // reset frequency = 0.0; max_dbm = min_dbm = dbm; } } if(peaks.size() > maxPeaks) { // found more peaks than requested, remove excess peaks // sort with descending peak level sort(peaks.begin(), peaks.end(), [](peakInfo higher, peakInfo lower) { return higher.level_dbm >= lower.level_dbm; }); // only keep the requested number of peaks peaks.resize(maxPeaks); // sort again with ascending frequencies sort(peaks.begin(), peaks.end(), [](peakInfo lower, peakInfo higher) { return higher.frequency >= lower.frequency; }); } vector frequencies; for(auto p : peaks) { frequencies.push_back(p.frequency); } return frequencies; } QString Trace::getTouchstoneFilename() const { return touchstoneFilename; } void Trace::setTouchstoneFilename(const QString &value) { touchstoneFilename = value; } unsigned int Trace::getTouchstoneParameter() const { return touchstoneParameter; } std::complex Trace::getData(double frequency) { if(_data.size() == 0 || frequency < minFreq() || frequency > maxFreq()) { return std::numeric_limits>::quiet_NaN(); } return sample(index(frequency)).S; } int Trace::index(double frequency) { auto lower = lower_bound(_data.begin(), _data.end(), frequency, [](const Data &lhs, const double freq) -> bool { return lhs.frequency < freq; }); return lower - _data.begin(); } void Trace::setTouchstoneParameter(int value) { touchstoneParameter = value; }