Noise + phase noise markers
This commit is contained in:
parent
5ed3547d3d
commit
7921c8db2f
@ -235,7 +235,7 @@ void SpectrumAnalyzer::NewDatapoint(Protocol::SpectrumAnalyzerResult d)
|
||||
d.port1 /= 126500000.0;
|
||||
d.port2 /= 126500000.0;
|
||||
d = average.process(d);
|
||||
traceModel.addSAData(d);
|
||||
traceModel.addSAData(d, settings);
|
||||
emit dataChanged();
|
||||
if(d.pointNum == settings.pointNum - 1) {
|
||||
UpdateAverageCount();
|
||||
|
@ -29,11 +29,12 @@ void Trace::clear() {
|
||||
return;
|
||||
}
|
||||
_data.clear();
|
||||
settings.valid = false;
|
||||
emit cleared(this);
|
||||
emit dataChanged();
|
||||
}
|
||||
|
||||
void Trace::addData(Trace::Data d) {
|
||||
void Trace::addData(const 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;
|
||||
@ -75,6 +76,20 @@ void Trace::addData(Trace::Data d) {
|
||||
}
|
||||
}
|
||||
|
||||
void Trace::addData(const Trace::Data &d, const Protocol::SweepSettings &s)
|
||||
{
|
||||
settings.VNA = s;
|
||||
settings.valid = true;
|
||||
addData(d);
|
||||
}
|
||||
|
||||
void Trace::addData(const Trace::Data &d, const Protocol::SpectrumAnalyzerSettings &s)
|
||||
{
|
||||
settings.SA = s;
|
||||
settings.valid = true;
|
||||
addData(d);
|
||||
}
|
||||
|
||||
void Trace::setName(QString name) {
|
||||
_name = name;
|
||||
emit nameChanged();
|
||||
@ -388,6 +403,19 @@ std::complex<double> Trace::getData(double frequency)
|
||||
}
|
||||
}
|
||||
|
||||
double Trace::getNoise(double frequency)
|
||||
{
|
||||
if(!isLive() || !settings.valid || (_liveParam != LiveParameter::Port1 && _liveParam != LiveParameter::Port2)) {
|
||||
// data not suitable for noise calculation
|
||||
return std::numeric_limits<double>::quiet_NaN();
|
||||
}
|
||||
// convert to dbm
|
||||
auto dbm = 20*log10(abs(getData(frequency)));
|
||||
// convert to 1Hz bandwidth
|
||||
dbm -= 10*log10(settings.SA.RBW);
|
||||
return dbm;
|
||||
}
|
||||
|
||||
int Trace::index(double frequency)
|
||||
{
|
||||
auto lower = lower_bound(_data.begin(), _data.end(), frequency, [](const Data &lhs, const double freq) -> bool {
|
||||
|
@ -7,6 +7,7 @@
|
||||
#include <QColor>
|
||||
#include <set>
|
||||
#include "touchstone.h"
|
||||
#include "Device/device.h"
|
||||
|
||||
class TraceMarker;
|
||||
|
||||
@ -49,7 +50,9 @@ public:
|
||||
|
||||
|
||||
void clear();
|
||||
void addData(Data d);
|
||||
void addData(const Data& d);
|
||||
void addData(const Data& d, const Protocol::SweepSettings& s);
|
||||
void addData(const Data& d, const Protocol::SpectrumAnalyzerSettings& s);
|
||||
void setName(QString name);
|
||||
void fillFromTouchstone(Touchstone &t, unsigned int parameter, QString filename = QString());
|
||||
void fromLivedata(LivedataType type, LiveParameter param);
|
||||
@ -79,6 +82,8 @@ public:
|
||||
QString getTouchstoneFilename() const;
|
||||
unsigned int getTouchstoneParameter() const;
|
||||
std::complex<double> getData(double frequency);
|
||||
/* Returns the noise in dbm/Hz for spectrum analyzer measurements. May return NaN if calculation not possible */
|
||||
double getNoise(double frequency);
|
||||
int index(double frequency);
|
||||
std::set<TraceMarker *> getMarkers() const;
|
||||
void setCalibration(bool value);
|
||||
@ -131,6 +136,13 @@ private:
|
||||
QString touchstoneFilename;
|
||||
unsigned int touchstoneParameter;
|
||||
std::set<TraceMarker*> markers;
|
||||
struct {
|
||||
union {
|
||||
Protocol::SweepSettings VNA;
|
||||
Protocol::SpectrumAnalyzerSettings SA;
|
||||
};
|
||||
bool valid;
|
||||
} settings;
|
||||
};
|
||||
|
||||
#endif // TRACE_H
|
||||
|
@ -88,6 +88,8 @@ QString TraceMarker::readableData()
|
||||
return Unit::ToString(freqDiff, "Hz", " kMG") + " / " + QString::number(toDecibel(), 'g', 4) + "db@" + QString::number(phase*180/M_PI, 'g', 4);
|
||||
}
|
||||
break;
|
||||
case Type::Noise:
|
||||
return Unit::ToString(parentTrace->getNoise(frequency), "dbm/Hz", " ", 3);
|
||||
case Type::PeakTable:
|
||||
return "Found " + QString::number(helperMarkers.size()) + " peaks";
|
||||
case Type::Lowpass:
|
||||
@ -135,6 +137,11 @@ QString TraceMarker::readableData()
|
||||
return "Fundamental: " + Unit::ToString(avgFundamental, "dbm", " ", 3) + ", distortion: " + Unit::ToString(avgDistortion, "dbm", " ", 3) + ", TOI: "+Unit::ToString(TOI, "dbm", " ", 3);
|
||||
}
|
||||
break;
|
||||
case Type::PhaseNoise: {
|
||||
auto carrier = toDecibel();
|
||||
auto phasenoise = parentTrace->getNoise(helperMarkers[0]->frequency) - carrier;
|
||||
return Unit::ToString(phasenoise, "dbc/Hz", " ", 3) +"@" + Unit::ToString(offset, "Hz", " kM", 4) + " offset (" + Unit::ToString(frequency, "Hz", " kMG", 6) + " carrier)";
|
||||
}
|
||||
default:
|
||||
return "Unknown marker type";
|
||||
}
|
||||
@ -147,14 +154,18 @@ QString TraceMarker::readableSettings()
|
||||
case Type::Maximum:
|
||||
case Type::Minimum:
|
||||
case Type::Delta:
|
||||
case Type::Noise:
|
||||
return Unit::ToString(frequency, "Hz", " kMG", 6);
|
||||
case Type::Lowpass:
|
||||
case Type::Highpass:
|
||||
case Type::Bandpass:
|
||||
case Type::PeakTable:
|
||||
return Unit::ToString(cutoffAmplitude, "db", " ", 3);
|
||||
case Type::PeakTable:
|
||||
return Unit::ToString(peakThreshold, "db", " ", 3);
|
||||
case Type::TOI:
|
||||
return "none";
|
||||
case Type::PhaseNoise:
|
||||
return Unit::ToString(offset, "Hz", " kM", 4);
|
||||
default:
|
||||
return "Unhandled case";
|
||||
}
|
||||
@ -239,7 +250,9 @@ std::set<TraceMarker::Type> TraceMarker::getSupportedTypes()
|
||||
case Trace::LiveParameter::Port1:
|
||||
case Trace::LiveParameter::Port2:
|
||||
// special SA marker types
|
||||
supported.insert(Type::Noise);
|
||||
supported.insert(Type::TOI);
|
||||
supported.insert(Type::PhaseNoise);
|
||||
break;
|
||||
}
|
||||
}
|
||||
@ -293,6 +306,7 @@ void TraceMarker::setType(TraceMarker::Type t)
|
||||
using helper_descr = struct {
|
||||
QString suffix;
|
||||
QString description;
|
||||
Type type;
|
||||
};
|
||||
vector<helper_descr> required_helpers;
|
||||
switch(type) {
|
||||
@ -320,13 +334,17 @@ void TraceMarker::setType(TraceMarker::Type t)
|
||||
break;
|
||||
case Type::Lowpass:
|
||||
case Type::Highpass:
|
||||
required_helpers = {{"c", "cutoff"}};
|
||||
required_helpers = {{"c", "cutoff", Type::Manual}};
|
||||
break;
|
||||
case Type::Bandpass:
|
||||
required_helpers = {{"l", "lower cutoff"}, {"h", "higher cutoff"} ,{"c", "center"}};
|
||||
required_helpers = {{"l", "lower cutoff", Type::Manual}, {"h", "higher cutoff", Type::Manual} ,{"c", "center", Type::Manual}};
|
||||
break;
|
||||
case Type::TOI:
|
||||
required_helpers = {{"p", "first peak"}, {"p", "second peak"}, {"l", "left intermodulation"}, {"r", "right intermodulation"}};
|
||||
required_helpers = {{"p", "first peak", Type::Manual}, {"p", "second peak", Type::Manual}, {"l", "left intermodulation", Type::Manual}, {"r", "right intermodulation", Type::Manual}};
|
||||
break;
|
||||
case Type::PhaseNoise:
|
||||
required_helpers = {{"o", "Offset", Type::Noise}};
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
@ -335,6 +353,7 @@ void TraceMarker::setType(TraceMarker::Type t)
|
||||
auto helper = new TraceMarker(model, number, this, h.description);
|
||||
helper->suffix = h.suffix;
|
||||
helper->assignTrace(parentTrace);
|
||||
helper->setType(h.type);
|
||||
helperMarkers.push_back(helper);
|
||||
}
|
||||
updateSymbol();
|
||||
@ -354,6 +373,8 @@ bool TraceMarker::isVisible()
|
||||
case Type::Delta:
|
||||
case Type::Maximum:
|
||||
case Type::Minimum:
|
||||
case Type::Noise:
|
||||
case Type::PhaseNoise:
|
||||
return true;
|
||||
default:
|
||||
return false;
|
||||
@ -475,6 +496,8 @@ SIUnitEdit *TraceMarker::getSettingsEditor()
|
||||
case Type::Maximum:
|
||||
case Type::Minimum:
|
||||
case Type::Delta:
|
||||
case Type::Noise:
|
||||
case Type::PhaseNoise:
|
||||
default:
|
||||
return new SIUnitEdit("Hz", " kMG");
|
||||
case Type::Lowpass:
|
||||
@ -493,6 +516,7 @@ void TraceMarker::adjustSettings(double value)
|
||||
case Type::Maximum:
|
||||
case Type::Minimum:
|
||||
case Type::Delta:
|
||||
case Type::Noise:
|
||||
default:
|
||||
setFrequency(value);
|
||||
/* no break */
|
||||
@ -502,9 +526,14 @@ void TraceMarker::adjustSettings(double value)
|
||||
if(value > 0.0) {
|
||||
value = -value;
|
||||
}
|
||||
/* no break */
|
||||
case Type::PeakTable:
|
||||
cutoffAmplitude = value;
|
||||
break;
|
||||
case Type::PeakTable:
|
||||
peakThreshold = value;
|
||||
break;
|
||||
case Type::PhaseNoise:
|
||||
offset = value;
|
||||
break;
|
||||
}
|
||||
update();
|
||||
}
|
||||
@ -518,6 +547,7 @@ void TraceMarker::update()
|
||||
switch(type) {
|
||||
case Type::Manual:
|
||||
case Type::Delta:
|
||||
case Type::Noise:
|
||||
// nothing to do
|
||||
break;
|
||||
case Type::Maximum:
|
||||
@ -528,7 +558,7 @@ void TraceMarker::update()
|
||||
break;
|
||||
case Type::PeakTable: {
|
||||
deleteHelperMarkers();
|
||||
auto peaks = parentTrace->findPeakFrequencies(100, cutoffAmplitude);
|
||||
auto peaks = parentTrace->findPeakFrequencies(100, peakThreshold);
|
||||
char suffix = 'a';
|
||||
for(auto p : peaks) {
|
||||
auto helper = new TraceMarker(model, number, this);
|
||||
@ -632,6 +662,10 @@ void TraceMarker::update()
|
||||
helperMarkers[3]->setFrequency(peaks[1] + freqDiff);
|
||||
}
|
||||
break;
|
||||
case Type::PhaseNoise:
|
||||
setFrequency(parentTrace->findExtremumFreq(true));
|
||||
helperMarkers[0]->setFrequency(frequency + offset);
|
||||
break;
|
||||
}
|
||||
emit dataChanged(this);
|
||||
}
|
||||
@ -660,6 +694,7 @@ bool TraceMarker::isMovable()
|
||||
switch(type) {
|
||||
case Type::Manual:
|
||||
case Type::Delta:
|
||||
case Type::Noise:
|
||||
return true;
|
||||
default:
|
||||
return false;
|
||||
|
@ -70,11 +70,13 @@ private:
|
||||
Maximum,
|
||||
Minimum,
|
||||
Delta,
|
||||
Noise,
|
||||
PeakTable,
|
||||
Lowpass,
|
||||
Highpass,
|
||||
Bandpass,
|
||||
TOI,
|
||||
PhaseNoise,
|
||||
};
|
||||
std::set<Type> getSupportedTypes();
|
||||
static QString typeToString(Type t) {
|
||||
@ -83,11 +85,13 @@ private:
|
||||
case Type::Maximum: return "Maximum";
|
||||
case Type::Minimum: return "Minimum";
|
||||
case Type::Delta: return "Delta";
|
||||
case Type::Noise: return "Noise";
|
||||
case Type::PeakTable: return "Peak Table";
|
||||
case Type::Lowpass: return "Lowpass";
|
||||
case Type::Highpass: return "Highpass";
|
||||
case Type::Bandpass: return "Bandpass";
|
||||
case Type::TOI: return "TOI/IP3";
|
||||
case Type::PhaseNoise: return "Phase noise";
|
||||
default: return QString();
|
||||
}
|
||||
}
|
||||
@ -111,7 +115,11 @@ private:
|
||||
TraceMarker *delta;
|
||||
std::vector<TraceMarker*> helperMarkers;
|
||||
TraceMarker *parent;
|
||||
double cutoffAmplitude;
|
||||
union {
|
||||
double cutoffAmplitude;
|
||||
double peakThreshold;
|
||||
double offset;
|
||||
};
|
||||
};
|
||||
|
||||
#endif // TRACEMARKER_H
|
||||
|
@ -141,14 +141,14 @@ bool TraceModel::PortExcitationRequired(int port)
|
||||
void TraceModel::clearVNAData()
|
||||
{
|
||||
for(auto t : traces) {
|
||||
if (!t->isTouchstone()) {
|
||||
if (t->isLive()) {
|
||||
// this trace is fed from live data
|
||||
t->clear();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void TraceModel::addVNAData(Protocol::Datapoint d)
|
||||
void TraceModel::addVNAData(const Protocol::Datapoint &d, const Protocol::SweepSettings& settings)
|
||||
{
|
||||
for(auto t : traces) {
|
||||
if (t->isLive() && !t->isPaused()) {
|
||||
@ -163,12 +163,12 @@ void TraceModel::addVNAData(Protocol::Datapoint d)
|
||||
// not a VNA trace, skip
|
||||
continue;
|
||||
}
|
||||
t->addData(td);
|
||||
t->addData(td, settings);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void TraceModel::addSAData(Protocol::SpectrumAnalyzerResult d)
|
||||
void TraceModel::addSAData(const Protocol::SpectrumAnalyzerResult& d, const Protocol::SpectrumAnalyzerSettings& settings)
|
||||
{
|
||||
for(auto t : traces) {
|
||||
if (t->isLive() && !t->isPaused()) {
|
||||
@ -181,7 +181,7 @@ void TraceModel::addSAData(Protocol::SpectrumAnalyzerResult d)
|
||||
// not a SA trace, skip
|
||||
continue;
|
||||
}
|
||||
t->addData(td);
|
||||
t->addData(td, settings);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -36,8 +36,8 @@ signals:
|
||||
|
||||
public slots:
|
||||
void clearVNAData();
|
||||
void addVNAData(Protocol::Datapoint d);
|
||||
void addSAData(Protocol::SpectrumAnalyzerResult d);
|
||||
void addVNAData(const Protocol::Datapoint& d, const Protocol::SweepSettings& settings);
|
||||
void addSAData(const Protocol::SpectrumAnalyzerResult& d, const Protocol::SpectrumAnalyzerSettings& settings);
|
||||
|
||||
private:
|
||||
std::vector<Trace*> traces;
|
||||
|
@ -427,7 +427,7 @@ void VNA::NewDatapoint(Protocol::Datapoint d)
|
||||
}
|
||||
portExtension.applyToMeasurement(d);
|
||||
|
||||
traceModel.addVNAData(d);
|
||||
traceModel.addVNAData(d, settings);
|
||||
emit dataChanged();
|
||||
if(d.pointNum == settings.points - 1) {
|
||||
UpdateAverageCount();
|
||||
|
Loading…
Reference in New Issue
Block a user