mirror of
https://github.com/jankae/LibreVNA.git
synced 2025-12-06 07:12:10 +01:00
Improve graph divisions and markers
- Added group delay option to markers - Additional configuration for calculation of group delay in the preferences - Specify divisions as amount of divisions instead of spacing - Add option for auto divisions on graph with manual min/max limits
This commit is contained in:
parent
fe08937bb7
commit
b2d07d532d
BIN
Documentation/UserManual/Screenshots/GraphEyeDiagram.png
Normal file
BIN
Documentation/UserManual/Screenshots/GraphEyeDiagram.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 83 KiB |
BIN
Documentation/UserManual/Screenshots/GraphEyeDiagramSetup.png
Normal file
BIN
Documentation/UserManual/Screenshots/GraphEyeDiagramSetup.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 68 KiB |
Binary file not shown.
|
Before Width: | Height: | Size: 47 KiB After Width: | Height: | Size: 44 KiB |
Binary file not shown.
|
|
@ -1029,7 +1029,7 @@ Different types are also available for the Y-axes. The Y-axis type determines ho
|
|||
\hline
|
||||
Inductance & Extracted inductance from a reflection measurement\\
|
||||
\hline
|
||||
Quality Facotr & Quality Factor of the impedance from a reflection measurement\\
|
||||
Quality Factor & Quality Factor of the impedance from a reflection measurement\\
|
||||
\hline
|
||||
Group Delay & Group Delay of a transmission measurement\\
|
||||
\hline
|
||||
|
|
@ -1137,6 +1137,11 @@ Both plots are still completely independent of each other. For the alignment to
|
|||
The Polar Chart looks similar to the smithchart but doesn't perform the transformation from S-paramter to impedance. Furthermore, through measurements can be displayed as well. The available settings are identical to the smithchart but the Polar Chart does not support adding custom constant lines:
|
||||
\screenshot{0.6}{GraphPolarchartSetup.png}
|
||||
|
||||
\subsection{Eye Diagram}
|
||||
\screenshot{1.0}{GraphEyeDiagram.png}
|
||||
The eye diagram graph shows how a simulated signal would look like after being passed through a transmission line. The transmission line is created from a through measurement (e.g. S21). The simulated signal is a PRBS sequence with additional noise, jitter and limited rise and fall times. All parameters can be edited in the setup dialog:
|
||||
\screenshot{1.0}{GraphEyeDiagramSetup.png}
|
||||
|
||||
\section{Markers}
|
||||
Markers provide an easy read-out of trace data at specific points. Each marker is assigned to one trace and will show up on any graph that show the trace at the marker position.
|
||||
|
||||
|
|
@ -1234,7 +1239,7 @@ This marker type is only available for through measurements on power sweeps. It
|
|||
\subsection{Marker Data}
|
||||
The trace data at the marker position can be displayed in the marker dock and on the graphs in various formats. The available formats depend on the marker type as well as the domain of the trace data. Only one of the available formats can be displayed in the marker dock at a time. On graphs, any amount of formats can be displayed at once. The shown formats can be selected in the context menu of the marker.
|
||||
|
||||
|
||||
\begin{footnotesize}
|
||||
\begin{center}
|
||||
\begin{threeparttable}
|
||||
\begin{tabularx}{\textwidth}{L{3cm}|X|L{7cm}}
|
||||
|
|
@ -1303,6 +1308,8 @@ $Quality factor$\\
|
|||
& & dB + angle\\
|
||||
\cline{3-3}
|
||||
& & Real/Imaginary \\
|
||||
\cline{3-3}
|
||||
& & Group Delay \\
|
||||
\cline{3-3}
|
||||
& & \multirow{6}{*}{$\left.\begin{array}{l}
|
||||
$Impedance$\\
|
||||
|
|
@ -1355,6 +1362,7 @@ $Quality factor$\\
|
|||
\end{tabularx}
|
||||
\end{threeparttable}
|
||||
\end{center}
|
||||
\end{footnotesize}
|
||||
|
||||
\subsection{Linking markers}
|
||||
\label{marker:linking}
|
||||
|
|
|
|||
|
|
@ -1249,8 +1249,8 @@ void SpectrumAnalyzer::createDefaultTracesAndGraphs(int ports)
|
|||
{
|
||||
tiles->clear();
|
||||
auto traceXY = new TraceXYPlot(traceModel);
|
||||
traceXY->setYAxis(0, YAxis::Type::Magnitude, false, false, -120,0,10);
|
||||
traceXY->setYAxis(1, YAxis::Type::Disabled, false, true, 0,0,1);
|
||||
traceXY->setYAxis(0, YAxis::Type::Magnitude, false, false, -120,0,12,false);
|
||||
traceXY->setYAxis(1, YAxis::Type::Disabled, false, true, 0, 0, 10, false);
|
||||
traceXY->updateSpan(settings.freqStart, settings.freqStop);
|
||||
|
||||
tiles->setPlot(traceXY);
|
||||
|
|
|
|||
|
|
@ -127,6 +127,7 @@ QString Marker::formatToString(Marker::Format f)
|
|||
case Format::Capacitance: return "Capacitance";
|
||||
case Format::Inductance: return "Inductance";
|
||||
case Format::QualityFactor: return "Quality Factor";
|
||||
case Format::GroupDelay: return "Group Delay";
|
||||
case Format::TOI: return "Third order intercept";
|
||||
case Format::AvgTone: return "Average Tone Level";
|
||||
case Format::AvgModulationProduct: return "Average Modulation Product Level";
|
||||
|
|
@ -234,6 +235,7 @@ std::vector<Marker::Format> Marker::applicableFormats()
|
|||
ret.push_back(Format::dB);
|
||||
ret.push_back(Format::dBAngle);
|
||||
ret.push_back(Format::RealImag);
|
||||
ret.push_back(Format::GroupDelay);
|
||||
}
|
||||
if(parentTrace) {
|
||||
if(parentTrace->isReflection()) {
|
||||
|
|
@ -346,6 +348,9 @@ std::vector<Marker::Format> Marker::defaultActiveFormats()
|
|||
if(pref.Marker.defaultBehavior.showQualityFactor) {
|
||||
ret.push_back(Format::QualityFactor);
|
||||
}
|
||||
if(pref.Marker.defaultBehavior.showGroupDelay) {
|
||||
ret.push_back(Format::GroupDelay);
|
||||
}
|
||||
if(pref.Marker.defaultBehavior.showNoise) {
|
||||
ret.push_back(Format::Noise);
|
||||
}
|
||||
|
|
@ -477,6 +482,7 @@ QString Marker::readableData(Format f)
|
|||
case Format::Capacitance: return "Δ:"+Unit::ToString(Util::SparamToCapacitance(data, position, trace()->getReferenceImpedance()) - Util::SparamToCapacitance(delta->data, delta->position, trace()->getReferenceImpedance()), "F", "pnum ", 4);
|
||||
case Format::Inductance: return "Δ:"+Unit::ToString(Util::SparamToInductance(data, position, trace()->getReferenceImpedance()) - Util::SparamToInductance(delta->data, delta->position, trace()->getReferenceImpedance()), "H", "pnum ", 4);
|
||||
case Format::QualityFactor: return "ΔQ:" + Unit::ToString(Util::SparamToQualityFactor(data) - Util::SparamToQualityFactor(delta->data), "", " ", 3);
|
||||
case Format::GroupDelay: return "Δτg:"+Unit::ToString(trace()->getGroupDelay(position) - delta->trace()->getGroupDelay(delta->position), "s", "pnum ", 4);
|
||||
case Format::Noise: return "Δ:"+Unit::ToString(parentTrace->getNoise(position) - delta->parentTrace->getNoise(delta->position), "dbm/Hz", " ", 3);
|
||||
default: return "Invalid";
|
||||
}
|
||||
|
|
@ -501,6 +507,7 @@ QString Marker::readableData(Format f)
|
|||
case Format::Capacitance: return Unit::ToString(Util::SparamToCapacitance(data, position, trace()->getReferenceImpedance()), "F", "pnum ", 4);
|
||||
case Format::Inductance: return Unit::ToString(Util::SparamToInductance(data, position, trace()->getReferenceImpedance()), "H", "pnum ", 4);
|
||||
case Format::QualityFactor: return "Q:" + Unit::ToString(Util::SparamToQualityFactor(data), "", " ", 3);
|
||||
case Format::GroupDelay: return "τg:"+Unit::ToString(trace()->getGroupDelay(position), "s", "pnum ", 4);
|
||||
case Format::Noise: return Unit::ToString(parentTrace->getNoise(position), "dbm/Hz", " ", 3);
|
||||
case Format::TOI: {
|
||||
auto avgFundamental = (helperMarkers[0]->toDecibel() + helperMarkers[1]->toDecibel()) / 2;
|
||||
|
|
|
|||
|
|
@ -34,6 +34,7 @@ public:
|
|||
Capacitance,
|
||||
Inductance,
|
||||
QualityFactor,
|
||||
GroupDelay,
|
||||
// Noise marker parameters
|
||||
Noise,
|
||||
PhaseNoise,
|
||||
|
|
|
|||
|
|
@ -32,7 +32,7 @@
|
|||
<property name="title">
|
||||
<string>X Axis</string>
|
||||
</property>
|
||||
<layout class="QFormLayout" name="formLayout_3">
|
||||
<layout class="QFormLayout" name="formLayout_4">
|
||||
<item row="0" column="0">
|
||||
<widget class="QLabel" name="label_19">
|
||||
<property name="text">
|
||||
|
|
@ -75,7 +75,18 @@
|
|||
</widget>
|
||||
</item>
|
||||
<item row="3" column="1">
|
||||
<widget class="SIUnitEdit" name="Xdivs"/>
|
||||
<layout class="QHBoxLayout" name="horizontalLayout_2">
|
||||
<item>
|
||||
<widget class="QSpinBox" name="Xdivs"/>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QCheckBox" name="XautoDivs">
|
||||
<property name="text">
|
||||
<string>Auto</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
|
|
@ -85,7 +96,7 @@
|
|||
<property name="title">
|
||||
<string>Y Axis</string>
|
||||
</property>
|
||||
<layout class="QFormLayout" name="formLayout_5">
|
||||
<layout class="QFormLayout" name="formLayout_3">
|
||||
<item row="0" column="0">
|
||||
<widget class="QLabel" name="label_15">
|
||||
<property name="text">
|
||||
|
|
@ -128,7 +139,18 @@
|
|||
</widget>
|
||||
</item>
|
||||
<item row="3" column="1">
|
||||
<widget class="SIUnitEdit" name="Ydivs"/>
|
||||
<layout class="QHBoxLayout" name="horizontalLayout_3">
|
||||
<item>
|
||||
<widget class="QSpinBox" name="Ydivs"/>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QCheckBox" name="YautoDivs">
|
||||
<property name="text">
|
||||
<string>Auto</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
|
|
|
|||
|
|
@ -45,8 +45,8 @@ EyeDiagramPlot::EyeDiagramPlot(TraceModel &model, QWidget *parent)
|
|||
calcData = &data[0];
|
||||
displayData = &data[1];
|
||||
|
||||
xAxis.set(XAxis::Type::Time, false, true, 0, 0.000001, 1);
|
||||
yAxis.set(YAxis::Type::Real, false, true, -1, 1, 1);
|
||||
xAxis.set(XAxis::Type::Time, false, true, 0, 0.000001, 10, true);
|
||||
yAxis.set(YAxis::Type::Real, false, true, -1, 1, 10, true);
|
||||
initializeTraceInfo();
|
||||
|
||||
destructing = false;
|
||||
|
|
@ -101,10 +101,10 @@ void EyeDiagramPlot::enableTrace(Trace *t, bool enabled)
|
|||
void EyeDiagramPlot::replot()
|
||||
{
|
||||
if(xAxis.getAutorange()) {
|
||||
xAxis.set(xAxis.getType(), false, true, 0, calculatedTime(), 8);
|
||||
xAxis.set(xAxis.getType(), false, true, 0, calculatedTime(), 10, false);
|
||||
}
|
||||
if(yAxis.getAutorange()) {
|
||||
yAxis.set(yAxis.getType(), false, true, minDisplayVoltage(), maxDisplayVoltage(), 8);
|
||||
yAxis.set(yAxis.getType(), false, true, minDisplayVoltage(), maxDisplayVoltage(), 10, false);
|
||||
}
|
||||
TracePlot::replot();
|
||||
}
|
||||
|
|
@ -115,13 +115,13 @@ void EyeDiagramPlot::move(const QPoint &vect)
|
|||
// can only move axis in linear mode
|
||||
// calculate amount of movement
|
||||
double distance = xAxis.inverseTransform(vect.x(), 0, plotAreaWidth) - xAxis.getRangeMin();
|
||||
xAxis.set(xAxis.getType(), false, false, xAxis.getRangeMin() - distance, xAxis.getRangeMax() - distance, xAxis.getRangeDiv());
|
||||
xAxis.set(xAxis.getType(), false, false, xAxis.getRangeMin() - distance, xAxis.getRangeMax() - distance, xAxis.getDivs(), xAxis.getAutoDivs());
|
||||
}
|
||||
if(!yAxis.getLog()) {
|
||||
// can only move axis in linear mode
|
||||
// calculate amount of movement
|
||||
double distance = yAxis.inverseTransform(vect.y(), 0, plotAreaTop - plotAreaBottom) - yAxis.getRangeMin();
|
||||
yAxis.set(yAxis.getType(), false, false, yAxis.getRangeMin() - distance, yAxis.getRangeMax() - distance, yAxis.getRangeDiv());
|
||||
yAxis.set(yAxis.getType(), false, false, yAxis.getRangeMin() - distance, yAxis.getRangeMax() - distance, yAxis.getDivs(), yAxis.getAutoDivs());
|
||||
}
|
||||
replot();
|
||||
}
|
||||
|
|
@ -134,7 +134,7 @@ void EyeDiagramPlot::zoom(const QPoint ¢er, double factor, bool horizontally
|
|||
double cp = xAxis.inverseTransform(center.x(), plotAreaLeft, plotAreaLeft + plotAreaWidth);
|
||||
double min = ((xAxis.getRangeMin() - cp) * factor) + cp;
|
||||
double max = ((xAxis.getRangeMax() - cp) * factor) + cp;
|
||||
xAxis.set(xAxis.getType(), false, false, min, max, xAxis.getRangeDiv() * factor);
|
||||
xAxis.set(xAxis.getType(), false, false, min, max, xAxis.getDivs(), xAxis.getAutoDivs());
|
||||
}
|
||||
if(vertically) {
|
||||
// can only move axis in linear mode
|
||||
|
|
@ -142,7 +142,7 @@ void EyeDiagramPlot::zoom(const QPoint ¢er, double factor, bool horizontally
|
|||
double cp = yAxis.inverseTransform(center.y(), plotAreaBottom, plotAreaTop);
|
||||
double min = ((yAxis.getRangeMin() - cp) * factor) + cp;
|
||||
double max = ((yAxis.getRangeMax() - cp) * factor) + cp;
|
||||
yAxis.set(yAxis.getType(), false, false, min, max, yAxis.getRangeDiv() * factor);
|
||||
yAxis.set(yAxis.getType(), false, false, min, max, yAxis.getDivs(), yAxis.getAutoDivs());
|
||||
}
|
||||
replot();
|
||||
}
|
||||
|
|
@ -150,10 +150,10 @@ void EyeDiagramPlot::zoom(const QPoint ¢er, double factor, bool horizontally
|
|||
void EyeDiagramPlot::setAuto(bool horizontally, bool vertically)
|
||||
{
|
||||
if(horizontally) {
|
||||
xAxis.set(xAxis.getType(), xAxis.getLog(), true, xAxis.getRangeMin(), xAxis.getRangeMax(), xAxis.getRangeDiv());
|
||||
xAxis.set(xAxis.getType(), xAxis.getLog(), true, xAxis.getRangeMin(), xAxis.getRangeMax(), xAxis.getDivs(), xAxis.getAutoDivs());
|
||||
}
|
||||
if(vertically) {
|
||||
yAxis.set(yAxis.getType(), yAxis.getLog(), true, yAxis.getRangeMin(), yAxis.getRangeMax(), yAxis.getRangeDiv());
|
||||
yAxis.set(yAxis.getType(), yAxis.getLog(), true, yAxis.getRangeMin(), yAxis.getRangeMax(), yAxis.getDivs(), yAxis.getAutoDivs());
|
||||
}
|
||||
replot();
|
||||
}
|
||||
|
|
@ -164,15 +164,25 @@ void EyeDiagramPlot::fromJSON(nlohmann::json j)
|
|||
bool xAuto = jX.value("autorange", xAxis.getAutorange());
|
||||
double xMin = jX.value("min", xAxis.getRangeMin());
|
||||
double xMax = jX.value("max", xAxis.getRangeMax());
|
||||
double xDivs = jX.value("div", xAxis.getRangeDiv());
|
||||
xAxis.set(xAxis.getType(), false, xAuto, xMin, xMax, xDivs);
|
||||
double xDivs = jX.value("divs", xAxis.getDivs());
|
||||
// older formats specified the spacing instead of the number of divisions
|
||||
if(jX.contains("div")) {
|
||||
xDivs = (xMax - xMin) / jX.value("div", (xMax - xMin) / xDivs);
|
||||
}
|
||||
auto xautodivs = jX.value("autoDivs", false);
|
||||
xAxis.set(xAxis.getType(), false, xAuto, xMin, xMax, xDivs, xautodivs);
|
||||
|
||||
auto jY = j["YAxis"];
|
||||
bool yAuto = jY.value("autorange", yAxis.getAutorange());
|
||||
double yMin = jY.value("min", yAxis.getRangeMin());
|
||||
double yMax = jY.value("max", yAxis.getRangeMax());
|
||||
double yDivs = jY.value("div", yAxis.getRangeDiv());
|
||||
yAxis.set(yAxis.getType(), false, yAuto, yMin, yMax, yDivs);
|
||||
double yDivs = jY.value("divs", yAxis.getDivs());
|
||||
// older formats specified the spacing instead of the number of divisions
|
||||
if(jY.contains("div")) {
|
||||
yDivs = (yMax - yMin) / jY.value("div", (yMax - yMin) / yDivs);
|
||||
}
|
||||
auto yautodivs = jY.value("autoDivs", false);
|
||||
yAxis.set(yAxis.getType(), false, yAuto, yMin, yMax, yDivs, yautodivs);
|
||||
|
||||
datarate = j.value("datarate", datarate);
|
||||
risetime = j.value("risetime", risetime);
|
||||
|
|
@ -211,13 +221,15 @@ nlohmann::json EyeDiagramPlot::toJSON()
|
|||
jX["autorange"] = yAxis.getAutorange();
|
||||
jX["min"] = xAxis.getRangeMin();
|
||||
jX["max"] = xAxis.getRangeMax();
|
||||
jX["div"] = xAxis.getRangeDiv();
|
||||
jX["divs"] = xAxis.getDivs();
|
||||
jX["autoDivs"] = xAxis.getAutoDivs();
|
||||
j["XAxis"] = jX;
|
||||
nlohmann::json jY;
|
||||
jY["autorange"] = yAxis.getAutorange();
|
||||
jY["min"] = yAxis.getRangeMin();
|
||||
jY["max"] = yAxis.getRangeMax();
|
||||
jY["div"] = yAxis.getRangeDiv();
|
||||
jY["divs"] = yAxis.getDivs();
|
||||
jY["autoDivs"] = yAxis.getAutoDivs();
|
||||
j["YAxis"] = jY;
|
||||
nlohmann::json jtraces;
|
||||
for(auto t : traces) {
|
||||
|
|
@ -286,10 +298,6 @@ void EyeDiagramPlot::axisSetupDialog()
|
|||
ui->Xmax->setPrefixes("pnum ");
|
||||
ui->Xmax->setPrecision(5);
|
||||
|
||||
ui->Xdivs->setUnit("s");
|
||||
ui->Xdivs->setPrefixes("pnum ");
|
||||
ui->Xdivs->setPrecision(3);
|
||||
|
||||
ui->Ymin->setUnit("V");
|
||||
ui->Ymin->setPrefixes("um ");
|
||||
ui->Ymin->setPrecision(4);
|
||||
|
|
@ -298,10 +306,6 @@ void EyeDiagramPlot::axisSetupDialog()
|
|||
ui->Ymax->setPrefixes("um ");
|
||||
ui->Ymax->setPrecision(4);
|
||||
|
||||
ui->Ydivs->setUnit("V");
|
||||
ui->Ydivs->setPrefixes("um ");
|
||||
ui->Ydivs->setPrecision(3);
|
||||
|
||||
// set initial values
|
||||
ui->datarate->setValue(datarate);
|
||||
ui->risetime->setValue(risetime);
|
||||
|
|
@ -322,22 +326,30 @@ void EyeDiagramPlot::axisSetupDialog()
|
|||
connect(ui->Xauto, &QCheckBox::toggled, [=](bool checked) {
|
||||
ui->Xmin->setEnabled(!checked);
|
||||
ui->Xmax->setEnabled(!checked);
|
||||
ui->Xdivs->setEnabled(!checked && !ui->XautoDivs->isChecked());
|
||||
ui->XautoDivs->setEnabled(!checked);
|
||||
});
|
||||
connect(ui->XautoDivs, &QCheckBox::toggled, [=](bool checked) {
|
||||
ui->Xdivs->setEnabled(!checked);
|
||||
});
|
||||
ui->Xauto->setChecked(xAxis.getAutorange());
|
||||
ui->Xmin->setValue(xAxis.getRangeMin());
|
||||
ui->Xmax->setValue(xAxis.getRangeMax());
|
||||
ui->Xdivs->setValue(xAxis.getRangeDiv());
|
||||
ui->Xdivs->setValue(xAxis.getDivs());
|
||||
|
||||
connect(ui->Yauto, &QCheckBox::toggled, [=](bool checked) {
|
||||
ui->Ymin->setEnabled(!checked);
|
||||
ui->Ymax->setEnabled(!checked);
|
||||
ui->Ydivs->setEnabled(!checked && !ui->YautoDivs->isChecked());
|
||||
ui->YautoDivs->setEnabled(!checked);
|
||||
});
|
||||
connect(ui->YautoDivs, &QCheckBox::toggled, [=](bool checked) {
|
||||
ui->Ydivs->setEnabled(!checked);
|
||||
});
|
||||
ui->Yauto->setChecked(yAxis.getAutorange());
|
||||
ui->Ymin->setValue(yAxis.getRangeMin());
|
||||
ui->Ymax->setValue(yAxis.getRangeMax());
|
||||
ui->Ydivs->setValue(yAxis.getRangeDiv());
|
||||
ui->Ydivs->setValue(yAxis.getDivs());
|
||||
|
||||
auto updateValues = [=](){
|
||||
std::lock_guard<std::mutex> guard(calcMutex);
|
||||
|
|
@ -357,8 +369,8 @@ void EyeDiagramPlot::axisSetupDialog()
|
|||
xSamples = ui->pointsPerCycle->value();
|
||||
traceBlurring = ui->traceBlurring->value();
|
||||
|
||||
xAxis.set(xAxis.getType(), false, ui->Xauto->isChecked(), ui->Xmin->value(), ui->Xmax->value(), ui->Xdivs->value());
|
||||
yAxis.set(yAxis.getType(), false, ui->Yauto->isChecked(), ui->Ymin->value(), ui->Ymax->value(), ui->Ydivs->value());
|
||||
xAxis.set(xAxis.getType(), false, ui->Xauto->isChecked(), ui->Xmin->value(), ui->Xmax->value(), ui->Xdivs->value(), ui->XautoDivs->isChecked());
|
||||
yAxis.set(yAxis.getType(), false, ui->Yauto->isChecked(), ui->Ymin->value(), ui->Ymax->value(), ui->Ydivs->value(), ui->YautoDivs->isChecked());
|
||||
};
|
||||
|
||||
connect(ui->buttonBox->button(QDialogButtonBox::Ok), &QPushButton::clicked, [=](){
|
||||
|
|
|
|||
|
|
@ -1572,6 +1572,48 @@ double Trace::getNoise(double frequency)
|
|||
return dbm;
|
||||
}
|
||||
|
||||
double Trace::getGroupDelay(double frequency)
|
||||
{
|
||||
if(!isVNAParameter(liveParam) || lastMath->getDataType() != DataType::Frequency) {
|
||||
// data not suitable for group delay calculation
|
||||
return std::numeric_limits<double>::quiet_NaN();
|
||||
}
|
||||
|
||||
// get index that matches frequency best
|
||||
unsigned int sample = index(frequency);
|
||||
|
||||
auto &p = Preferences::getInstance();
|
||||
const unsigned int requiredSamples = p.Acquisition.groupDelaySamples;
|
||||
if(size() < requiredSamples) {
|
||||
// unable to calculate
|
||||
return std::numeric_limits<double>::quiet_NaN();
|
||||
|
||||
}
|
||||
// needs at least some samples before/after current sample for calculating the derivative.
|
||||
// For samples too far at either end of the trace, return group delay of "inner" trace sample instead
|
||||
if(sample < requiredSamples / 2) {
|
||||
sample = requiredSamples / 2;
|
||||
} else if(sample >= size() - requiredSamples / 2) {
|
||||
sample = size() - requiredSamples / 2 - 1;
|
||||
}
|
||||
|
||||
// got enough samples at either end to calculate derivative.
|
||||
// acquire phases of the required samples
|
||||
std::vector<double> phases;
|
||||
phases.reserve(requiredSamples);
|
||||
for(unsigned int index = sample - requiredSamples / 2;index <= sample + requiredSamples / 2;index++) {
|
||||
phases.push_back(arg(this->sample(index).y));
|
||||
}
|
||||
// make sure there are no phase jumps
|
||||
Util::unwrapPhase(phases);
|
||||
// calculate linearRegression to get derivative
|
||||
double B_0, B_1;
|
||||
Util::linearRegression(phases, B_0, B_1);
|
||||
// B_1 now contains the derived phase vs. the sample. Scale by frequency to get group delay
|
||||
double freq_step = this->sample(sample).x - this->sample(sample - 1).x;
|
||||
return -B_1 / (2.0*M_PI * freq_step);
|
||||
}
|
||||
|
||||
int Trace::index(double x)
|
||||
{
|
||||
auto lower = lower_bound(lastMath->rData().begin(), lastMath->rData().end(), x, [](const Data &lhs, const double x) -> bool {
|
||||
|
|
|
|||
|
|
@ -104,6 +104,7 @@ public:
|
|||
unsigned int getFileParameter() const;
|
||||
/* Returns the noise in dbm/Hz for spectrum analyzer measurements. May return NaN if calculation not possible */
|
||||
double getNoise(double frequency);
|
||||
double getGroupDelay(double frequency);
|
||||
int index(double x);
|
||||
std::set<Marker *> getMarkers() const;
|
||||
void setCalibration();
|
||||
|
|
|
|||
|
|
@ -1,23 +1,24 @@
|
|||
#include "traceaxis.h"
|
||||
#include "Util/util.h"
|
||||
#include "preferences.h"
|
||||
|
||||
#include <cmath>
|
||||
|
||||
using namespace std;
|
||||
|
||||
static void createEvenlySpacedTicks(vector<double>& ticks, double start, double stop, double step) {
|
||||
static void createEvenlySpacedTicks(vector<double>& ticks, double start, double stop, unsigned int divisions) {
|
||||
ticks.clear();
|
||||
if(start > stop) {
|
||||
swap(start, stop);
|
||||
}
|
||||
step = abs(step);
|
||||
auto step = (stop - start) / divisions;
|
||||
constexpr unsigned int maxTicks = 100;
|
||||
for(double tick = start; tick - stop < numeric_limits<double>::epsilon() && ticks.size() <= maxTicks;tick+= step) {
|
||||
ticks.push_back(tick);
|
||||
}
|
||||
}
|
||||
|
||||
static double createAutomaticTicks(vector<double>& ticks, double start, double stop, int minDivisions) {
|
||||
static unsigned int createAutomaticTicks(vector<double>& ticks, double start, double stop, int minDivisions) {
|
||||
Q_ASSERT(stop > start);
|
||||
ticks.clear();
|
||||
double max_div_step = (stop - start) / minDivisions;
|
||||
|
|
@ -37,7 +38,7 @@ static double createAutomaticTicks(vector<double>& ticks, double start, double s
|
|||
for(double tick = start_div;tick <= stop;tick += div_step) {
|
||||
ticks.push_back(tick);
|
||||
}
|
||||
return div_step;
|
||||
return (stop - start) / div_step;
|
||||
}
|
||||
|
||||
static void createLogarithmicTicks(vector<double>& ticks, double start, double stop, int minDivisions) {
|
||||
|
|
@ -132,37 +133,11 @@ double YAxis::sampleToCoordinate(Trace::Data data, Trace *t, unsigned int sample
|
|||
return Util::SparamToInductance(data.y, data.x);
|
||||
case YAxis::Type::QualityFactor:
|
||||
return Util::SparamToQualityFactor(data.y);
|
||||
case YAxis::Type::GroupDelay: {
|
||||
constexpr int requiredSamples = 5;
|
||||
if(!t || t->size() < requiredSamples) {
|
||||
// unable to calculate
|
||||
case YAxis::Type::GroupDelay:
|
||||
if(!t) {
|
||||
return 0.0;
|
||||
|
||||
}
|
||||
// needs at least some samples before/after current sample for calculating the derivative.
|
||||
// For samples too far at either end of the trace, return group delay of "inner" trace sample instead
|
||||
if(sample < requiredSamples / 2) {
|
||||
return sampleToCoordinate(data, t, requiredSamples / 2);
|
||||
} else if(sample >= t->size() - requiredSamples / 2) {
|
||||
return sampleToCoordinate(data, t, t->size() - requiredSamples / 2 - 1);
|
||||
} else {
|
||||
// got enough samples at either end to calculate derivative.
|
||||
// acquire phases of the required samples
|
||||
std::vector<double> phases;
|
||||
phases.reserve(requiredSamples);
|
||||
for(unsigned int index = sample - requiredSamples / 2;index <= sample + requiredSamples / 2;index++) {
|
||||
phases.push_back(arg(t->sample(index).y));
|
||||
}
|
||||
// make sure there are no phase jumps
|
||||
Util::unwrapPhase(phases);
|
||||
// calculate linearRegression to get derivative
|
||||
double B_0, B_1;
|
||||
Util::linearRegression(phases, B_0, B_1);
|
||||
// B_1 now contains the derived phase vs. the sample. Scale by frequency to get group delay
|
||||
double freq_step = t->sample(sample).x - t->sample(sample - 1).x;
|
||||
return -B_1 / (2.0*M_PI * freq_step);
|
||||
}
|
||||
}
|
||||
return t->getGroupDelay(data.x);
|
||||
case YAxis::Type::ImpulseReal:
|
||||
return real(data.y);
|
||||
case YAxis::Type::ImpulseMag:
|
||||
|
|
@ -190,14 +165,15 @@ double YAxis::sampleToCoordinate(Trace::Data data, Trace *t, unsigned int sample
|
|||
return 0.0;
|
||||
}
|
||||
|
||||
void YAxis::set(Type type, bool log, bool autorange, double min, double max, double div)
|
||||
void YAxis::set(Type type, bool log, bool autorange, double min, double max, unsigned int divs, bool autoDivs)
|
||||
{
|
||||
this->type = type;
|
||||
this->log = log;
|
||||
this->autorange = autorange;
|
||||
this->rangeMin = min;
|
||||
this->rangeMax = max;
|
||||
this->rangeDiv = div;
|
||||
this->divs = divs;
|
||||
this->autoDivs = autoDivs;
|
||||
if(type != Type::Disabled) {
|
||||
updateTicks();
|
||||
}
|
||||
|
|
@ -440,9 +416,13 @@ void Axis::updateTicks()
|
|||
rangeMin -= 1.0;
|
||||
rangeMax += 1.0;
|
||||
}
|
||||
rangeDiv = createAutomaticTicks(ticks, rangeMin, rangeMax, 8);
|
||||
divs = createAutomaticTicks(ticks, rangeMin, rangeMax, 8);
|
||||
} else {
|
||||
createEvenlySpacedTicks(ticks, rangeMin, rangeMax, rangeDiv);
|
||||
if(autoDivs) {
|
||||
divs = createAutomaticTicks(ticks, rangeMin, rangeMax, 8);
|
||||
} else {
|
||||
createEvenlySpacedTicks(ticks, rangeMin, rangeMax, divs);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -451,9 +431,14 @@ const std::vector<double> &Axis::getTicks() const
|
|||
return ticks;
|
||||
}
|
||||
|
||||
double Axis::getRangeDiv() const
|
||||
unsigned int Axis::getDivs() const
|
||||
{
|
||||
return rangeDiv;
|
||||
return divs;
|
||||
}
|
||||
|
||||
bool Axis::getAutoDivs() const
|
||||
{
|
||||
return autoDivs;
|
||||
}
|
||||
|
||||
double Axis::getRangeMax() const
|
||||
|
|
@ -495,7 +480,7 @@ double XAxis::sampleToCoordinate(Trace::Data data, Trace *t, unsigned int sample
|
|||
}
|
||||
}
|
||||
|
||||
void XAxis::set(Type type, bool log, bool autorange, double min, double max, double div)
|
||||
void XAxis::set(Type type, bool log, bool autorange, double min, double max, unsigned int divs, bool autoDivs)
|
||||
{
|
||||
if(max <= min) {
|
||||
auto info = DeviceDriver::getInfo(DeviceDriver::getActiveDriver());
|
||||
|
|
@ -529,7 +514,8 @@ void XAxis::set(Type type, bool log, bool autorange, double min, double max, dou
|
|||
this->autorange = autorange;
|
||||
this->rangeMin = min;
|
||||
this->rangeMax = max;
|
||||
this->rangeDiv = div;
|
||||
this->divs = divs;
|
||||
this->autoDivs = autoDivs;
|
||||
updateTicks();
|
||||
}
|
||||
|
||||
|
|
@ -589,7 +575,8 @@ Axis::Axis()
|
|||
autorange = true;
|
||||
rangeMin = -1.0;
|
||||
rangeMax = 1.0;
|
||||
rangeDiv = 1.0;
|
||||
divs = 10;
|
||||
autoDivs = false;
|
||||
ticks.clear();
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -17,7 +17,8 @@ public:
|
|||
bool getAutorange() const;
|
||||
double getRangeMin() const;
|
||||
double getRangeMax() const;
|
||||
double getRangeDiv() const;
|
||||
unsigned int getDivs() const;
|
||||
bool getAutoDivs() const;
|
||||
const std::vector<double> &getTicks() const;
|
||||
|
||||
protected:
|
||||
|
|
@ -26,7 +27,8 @@ protected:
|
|||
bool autorange;
|
||||
double rangeMin;
|
||||
double rangeMax;
|
||||
double rangeDiv;
|
||||
unsigned int divs;
|
||||
bool autoDivs;
|
||||
std::vector<double> ticks;
|
||||
};
|
||||
|
||||
|
|
@ -42,7 +44,7 @@ public:
|
|||
};
|
||||
XAxis();
|
||||
double sampleToCoordinate(Trace::Data data, Trace *t = nullptr, unsigned int sample = 0) override;
|
||||
void set(Type type, bool log, bool autorange, double min, double max, double div);
|
||||
void set(Type type, bool log, bool autorange, double min, double max, unsigned int divs, bool autoDivs);
|
||||
static QString TypeToName(Type type);
|
||||
static Type TypeFromName(QString name);
|
||||
static QString Unit(Type type);
|
||||
|
|
@ -88,7 +90,7 @@ public:
|
|||
YAxis();
|
||||
double sampleToCoordinate(Trace::Data data, Trace *t = nullptr, unsigned int sample = 0) override;
|
||||
|
||||
void set(Type type, bool log, bool autorange, double min, double max, double div);
|
||||
void set(Type type, bool log, bool autorange, double min, double max, unsigned int divs, bool autoDivs);
|
||||
static QString TypeToName(Type type);
|
||||
static Type TypeFromName(QString name);
|
||||
static QString Unit(Type type, TraceModel::DataSource source = TraceModel::DataSource::VNA);
|
||||
|
|
|
|||
|
|
@ -94,7 +94,7 @@ void TraceCSVExport::on_buttonBox_accepted()
|
|||
for(auto trace : traces) {
|
||||
for(auto ytype : getSelectedYAxisTypes()) {
|
||||
auto axis = YAxis();
|
||||
axis.set(ytype, false, false, 0, 1, 1);
|
||||
axis.set(ytype, false, false, 0, 1, 10, false);
|
||||
auto samples = trace->numSamples();
|
||||
vector<double> values;
|
||||
for(unsigned int i=0;i<samples;i++) {
|
||||
|
|
|
|||
|
|
@ -26,8 +26,8 @@ TraceWaterfall::TraceWaterfall(TraceModel &model, QWidget *parent)
|
|||
plotAreaWidth = 0;
|
||||
plotAreaBottom = 0;
|
||||
|
||||
xAxis.set(XAxis::Type::Frequency, false, true, 0, 6000000000, 500000000);
|
||||
yAxis.set(YAxis::Type::Magnitude, false, true, -1, 1, 1);
|
||||
xAxis.set(XAxis::Type::Frequency, false, true, 0, 6000000000, 10, false);
|
||||
yAxis.set(YAxis::Type::Magnitude, false, true, -1, 1, 10, false);
|
||||
initializeTraceInfo();
|
||||
}
|
||||
|
||||
|
|
@ -163,11 +163,11 @@ bool TraceWaterfall::configureForTrace(Trace *t)
|
|||
|
||||
switch(t->outputType()) {
|
||||
case Trace::DataType::Frequency:
|
||||
xAxis.set(XAxis::Type::Frequency, false, true, 0, 1, 0.1);
|
||||
xAxis.set(XAxis::Type::Frequency, false, true, 0, 1, 10, false);
|
||||
yDefault = YAxis::Type::Magnitude;
|
||||
break;
|
||||
case Trace::DataType::Power:
|
||||
xAxis.set(XAxis::Type::Power, false, true, 0, 1, 0.1);
|
||||
xAxis.set(XAxis::Type::Power, false, true, 0, 1, 10, false);
|
||||
yDefault = YAxis::Type::Magnitude;
|
||||
break;
|
||||
case Trace::DataType::Time:
|
||||
|
|
@ -177,7 +177,7 @@ bool TraceWaterfall::configureForTrace(Trace *t)
|
|||
return false;
|
||||
}
|
||||
if(!yAxis.isSupported(xAxis.getType(), getModel().getSource())) {
|
||||
yAxis.set(yDefault, false, true, 0, 1, 1.0);
|
||||
yAxis.set(yDefault, false, true, 0, 1, 10, false);
|
||||
}
|
||||
traceRemovalPending = true;
|
||||
return true;
|
||||
|
|
@ -556,7 +556,7 @@ void TraceWaterfall::traceDataChanged(unsigned int begin, unsigned int end)
|
|||
if(min_x != xAxis.getRangeMin() || max_x != xAxis.getRangeMax()) {
|
||||
resetWaterfall();
|
||||
// adjust axis
|
||||
xAxis.set(xAxis.getType(), xAxis.getLog(), true, min_x, max_x, 0);
|
||||
xAxis.set(xAxis.getType(), xAxis.getLog(), true, min_x, max_x, xAxis.getDivs(), xAxis.getAutoDivs());
|
||||
}
|
||||
}
|
||||
bool YAxisUpdateRequired = false;
|
||||
|
|
@ -593,7 +593,7 @@ void TraceWaterfall::traceDataChanged(unsigned int begin, unsigned int end)
|
|||
}
|
||||
if(yAxis.getAutorange() && !YAxisUpdateRequired && (min != yAxis.getRangeMin() || max != yAxis.getRangeMax())) {
|
||||
// axis scaling needs update due to new trace data
|
||||
yAxis.set(yAxis.getType(), yAxis.getLog(), true, min, max, 0);
|
||||
yAxis.set(yAxis.getType(), yAxis.getLog(), true, min, max, yAxis.getDivs(), yAxis.getAutoDivs());
|
||||
} else if(YAxisUpdateRequired) {
|
||||
updateYAxis();
|
||||
}
|
||||
|
|
@ -619,7 +619,7 @@ void TraceWaterfall::updateYAxis()
|
|||
}
|
||||
}
|
||||
if(max > min) {
|
||||
yAxis.set(yAxis.getType(), yAxis.getLog(), true, min, max, 0);
|
||||
yAxis.set(yAxis.getType(), yAxis.getLog(), true, min, max, yAxis.getDivs(), yAxis.getAutoDivs());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -25,11 +25,11 @@ TraceXYPlot::TraceXYPlot(TraceModel &model, QWidget *parent)
|
|||
xAxisMode = XAxisMode::UseSpan;
|
||||
|
||||
// Setup default axis
|
||||
setYAxis(0, YAxis::Type::Magnitude, false, false, -120, 20, 10);
|
||||
setYAxis(1, YAxis::Type::Phase, false, false, -180, 180, 30);
|
||||
setYAxis(0, YAxis::Type::Magnitude, false, false, -120, 20, 14, true);
|
||||
setYAxis(1, YAxis::Type::Phase, false, false, -180, 180, 12, true);
|
||||
// enable autoscaling and set for full span (no information about actual span available yet)
|
||||
updateSpan(0, 6000000000);
|
||||
setXAxis(XAxis::Type::Frequency, XAxisMode::UseSpan, false, 0, 6000000000, 600000000);
|
||||
setXAxis(XAxis::Type::Frequency, XAxisMode::UseSpan, false, 0, 6000000000, 10, true);
|
||||
initializeTraceInfo();
|
||||
}
|
||||
TraceXYPlot::~TraceXYPlot()
|
||||
|
|
@ -39,7 +39,7 @@ TraceXYPlot::~TraceXYPlot()
|
|||
}
|
||||
}
|
||||
|
||||
void TraceXYPlot::setYAxis(int axis, YAxis::Type type, bool log, bool autorange, double min, double max, double div)
|
||||
void TraceXYPlot::setYAxis(int axis, YAxis::Type type, bool log, bool autorange, double min, double max, unsigned int divs, bool autoDivs)
|
||||
{
|
||||
if(yAxis[axis].getType() != type) {
|
||||
// remove traces that are active but not supported with the new axis type
|
||||
|
|
@ -55,19 +55,19 @@ void TraceXYPlot::setYAxis(int axis, YAxis::Type type, bool log, bool autorange,
|
|||
}
|
||||
} while(erased);
|
||||
}
|
||||
yAxis[axis].set(type, log, autorange, min, max, div);
|
||||
yAxis[axis].set(type, log, autorange, min, max, divs, autoDivs);
|
||||
traceRemovalPending = true;
|
||||
updateContextMenu();
|
||||
replot();
|
||||
}
|
||||
|
||||
void TraceXYPlot::setXAxis(XAxis::Type type, XAxisMode mode, bool log, double min, double max, double div)
|
||||
void TraceXYPlot::setXAxis(XAxis::Type type, XAxisMode mode, bool log, double min, double max, unsigned int divs, bool autoDivs)
|
||||
{
|
||||
bool autorange = false;
|
||||
if(mode == XAxisMode::FitTraces || mode == XAxisMode::UseSpan) {
|
||||
autorange = true;
|
||||
}
|
||||
xAxis.set(type, log, autorange, min, max, div);
|
||||
xAxis.set(type, log, autorange, min, max, divs, autoDivs);
|
||||
xAxisMode = mode;
|
||||
traceRemovalPending = true;
|
||||
updateContextMenu();
|
||||
|
|
@ -101,7 +101,7 @@ void TraceXYPlot::move(const QPoint &vect)
|
|||
// can only move axis in linear mode
|
||||
// calculate amount of movement
|
||||
double distance = xAxis.inverseTransform(vect.x(), 0, plotAreaWidth) - xAxis.getRangeMin();
|
||||
xAxis.set(xAxis.getType(), false, false, xAxis.getRangeMin() - distance, xAxis.getRangeMax() - distance, xAxis.getRangeDiv());
|
||||
xAxis.set(xAxis.getType(), false, false, xAxis.getRangeMin() - distance, xAxis.getRangeMax() - distance, xAxis.getDivs(), xAxis.getAutoDivs());
|
||||
xAxisMode = XAxisMode::Manual;
|
||||
}
|
||||
for(int i=0;i<2;i++) {
|
||||
|
|
@ -109,7 +109,7 @@ void TraceXYPlot::move(const QPoint &vect)
|
|||
// can only move axis in linear mode
|
||||
// calculate amount of movement
|
||||
double distance = yAxis[i].inverseTransform(vect.y(), 0, plotAreaTop - plotAreaBottom) - yAxis[i].getRangeMin();
|
||||
yAxis[i].set(yAxis[i].getType(), false, false, yAxis[i].getRangeMin() - distance, yAxis[i].getRangeMax() - distance, yAxis[i].getRangeDiv());
|
||||
yAxis[i].set(yAxis[i].getType(), false, false, yAxis[i].getRangeMin() - distance, yAxis[i].getRangeMax() - distance, yAxis[i].getDivs(), yAxis[i].getAutoDivs());
|
||||
}
|
||||
}
|
||||
replot();
|
||||
|
|
@ -123,7 +123,7 @@ void TraceXYPlot::zoom(const QPoint ¢er, double factor, bool horizontally, b
|
|||
double cp = xAxis.inverseTransform(center.x(), plotAreaLeft, plotAreaLeft + plotAreaWidth);
|
||||
double min = ((xAxis.getRangeMin() - cp) * factor) + cp;
|
||||
double max = ((xAxis.getRangeMax() - cp) * factor) + cp;
|
||||
xAxis.set(xAxis.getType(), false, false, min, max, xAxis.getRangeDiv() * factor);
|
||||
xAxis.set(xAxis.getType(), false, false, min, max, xAxis.getDivs(), xAxis.getAutoDivs());
|
||||
xAxisMode = XAxisMode::Manual;
|
||||
}
|
||||
for(int i=0;i<2;i++) {
|
||||
|
|
@ -133,7 +133,7 @@ void TraceXYPlot::zoom(const QPoint ¢er, double factor, bool horizontally, b
|
|||
double cp = yAxis[i].inverseTransform(center.y(), plotAreaBottom, plotAreaTop);
|
||||
double min = ((yAxis[i].getRangeMin() - cp) * factor) + cp;
|
||||
double max = ((yAxis[i].getRangeMax() - cp) * factor) + cp;
|
||||
yAxis[i].set(yAxis[i].getType(), false, false, min, max, yAxis[i].getRangeDiv() * factor);
|
||||
yAxis[i].set(yAxis[i].getType(), false, false, min, max, yAxis[i].getDivs(), yAxis[i].getAutoDivs());
|
||||
}
|
||||
}
|
||||
replot();
|
||||
|
|
@ -143,11 +143,11 @@ void TraceXYPlot::setAuto(bool horizontally, bool vertically)
|
|||
{
|
||||
if(horizontally) {
|
||||
xAxisMode = XAxisMode::FitTraces;
|
||||
xAxis.set(xAxis.getType(), xAxis.getLog(), true, xAxis.getRangeMin(), xAxis.getRangeMax(), xAxis.getRangeDiv());
|
||||
xAxis.set(xAxis.getType(), xAxis.getLog(), true, xAxis.getRangeMin(), xAxis.getRangeMax(), xAxis.getDivs(), xAxis.getAutoDivs());
|
||||
}
|
||||
for(int i=0;i<2;i++) {
|
||||
if(vertically && yAxis[i].getType() != YAxis::Type::Disabled) {
|
||||
yAxis[i].set(yAxis[i].getType(), yAxis[i].getLog(), true, yAxis[i].getRangeMin(), yAxis[i].getRangeMax(), yAxis[i].getRangeDiv());
|
||||
yAxis[i].set(yAxis[i].getType(), yAxis[i].getLog(), true, yAxis[i].getRangeMin(), yAxis[i].getRangeMax(), yAxis[i].getDivs(), yAxis[i].getAutoDivs());
|
||||
}
|
||||
}
|
||||
replot();
|
||||
|
|
@ -162,7 +162,8 @@ nlohmann::json TraceXYPlot::toJSON()
|
|||
jX["log"] = xAxis.getLog();
|
||||
jX["min"] = xAxis.getRangeMin();
|
||||
jX["max"] = xAxis.getRangeMax();
|
||||
jX["div"] = xAxis.getRangeDiv();
|
||||
jX["divs"] = xAxis.getDivs();
|
||||
jX["autoDivs"] = xAxis.getAutoDivs();
|
||||
j["XAxis"] = jX;
|
||||
for(unsigned int i=0;i<2;i++) {
|
||||
nlohmann::json jY;
|
||||
|
|
@ -171,7 +172,8 @@ nlohmann::json TraceXYPlot::toJSON()
|
|||
jY["autorange"] = yAxis[i].getAutorange();
|
||||
jY["min"] = yAxis[i].getRangeMin();
|
||||
jY["max"] = yAxis[i].getRangeMax();
|
||||
jY["div"] = yAxis[i].getRangeDiv();
|
||||
jY["divs"] = yAxis[i].getDivs();
|
||||
jY["autoDivs"] = yAxis[i].getAutoDivs();
|
||||
nlohmann::json jtraces;
|
||||
for(auto t : tracesAxis[i]) {
|
||||
jtraces.push_back(t->toHash());
|
||||
|
|
@ -212,9 +214,14 @@ void TraceXYPlot::fromJSON(nlohmann::json j)
|
|||
// auto xlog = jX.value("log", false);
|
||||
auto xmin = jX.value("min", 0.0);
|
||||
auto xmax = jX.value("max", 6000000000.0);
|
||||
auto xdiv = jX.value("div", 600000000.0);
|
||||
auto xdivs = jX.value("divs", 10);
|
||||
// older formats specified the spacing instead of the number of divisions
|
||||
if(jX.contains("div")) {
|
||||
xdivs = (xmax - xmin) / jX.value("div", 600000000.0);
|
||||
}
|
||||
auto xautodivs = jX.value("autoDivs", false);
|
||||
auto xlog = jX.value("log", false);
|
||||
setXAxis(xtype, xmode, xlog, xmin, xmax, xdiv);
|
||||
setXAxis(xtype, xmode, xlog, xmin, xmax, xdivs, xautodivs);
|
||||
nlohmann::json jY[2] = {j["YPrimary"], j["YSecondary"]};
|
||||
for(unsigned int i=0;i<2;i++) {
|
||||
YAxis::Type ytype;
|
||||
|
|
@ -227,8 +234,13 @@ void TraceXYPlot::fromJSON(nlohmann::json j)
|
|||
auto ylog = jY[i].value("log", false);
|
||||
auto ymin = jY[i].value("min", -120.0);
|
||||
auto ymax = jY[i].value("max", 20.0);
|
||||
auto ydiv = jY[i].value("div", 10.0);
|
||||
setYAxis(i, ytype, ylog, yauto, ymin, ymax, ydiv);
|
||||
auto ydivs = jY[i].value("divs", 10);
|
||||
// older formats specified the spacing instead of the number of divisions
|
||||
if(jY[i].contains("div")) {
|
||||
ydivs = (ymax - ymin) / jY[i].value("div", 10);
|
||||
}
|
||||
auto yautodivs = jY[i].value("autoDivs", false);
|
||||
setYAxis(i, ytype, ylog, yauto, ymin, ymax, ydivs, yautodivs);
|
||||
for(unsigned int hash : jY[i]["traces"]) {
|
||||
// attempt to find the traces with this hash
|
||||
bool found = false;
|
||||
|
|
@ -292,21 +304,21 @@ bool TraceXYPlot::configureForTrace(Trace *t)
|
|||
|
||||
switch(t->outputType()) {
|
||||
case Trace::DataType::Frequency:
|
||||
setXAxis(XAxis::Type::Frequency, XAxisMode::FitTraces, false, 0, 1, 0.1);
|
||||
setXAxis(XAxis::Type::Frequency, XAxisMode::FitTraces, false, 0, 1, 10, false);
|
||||
yLeftDefault = YAxis::Type::Magnitude;
|
||||
yRightDefault = YAxis::Type::Phase;
|
||||
break;
|
||||
case Trace::DataType::Time:
|
||||
setXAxis(XAxis::Type::Time, XAxisMode::FitTraces, false, 0, 1, 0.1);
|
||||
setXAxis(XAxis::Type::Time, XAxisMode::FitTraces, false, 0, 1, 10, false);
|
||||
yLeftDefault = YAxis::Type::ImpulseMag;
|
||||
break;
|
||||
case Trace::DataType::Power:
|
||||
setXAxis(XAxis::Type::Power, XAxisMode::FitTraces, false, 0, 1, 0.1);
|
||||
setXAxis(XAxis::Type::Power, XAxisMode::FitTraces, false, 0, 1, 10, false);
|
||||
yLeftDefault = YAxis::Type::Magnitude;
|
||||
yRightDefault = YAxis::Type::Phase;
|
||||
break;
|
||||
case Trace::DataType::TimeZeroSpan:
|
||||
setXAxis(XAxis::Type::TimeZeroSpan, XAxisMode::FitTraces, false, 0, 1, 0.1);
|
||||
setXAxis(XAxis::Type::TimeZeroSpan, XAxisMode::FitTraces, false, 0, 1, 10, false);
|
||||
yLeftDefault = YAxis::Type::Magnitude;
|
||||
yRightDefault = YAxis::Type::Phase;
|
||||
break;
|
||||
|
|
@ -315,10 +327,10 @@ bool TraceXYPlot::configureForTrace(Trace *t)
|
|||
return false;
|
||||
}
|
||||
if(!yAxis[0].isSupported(xAxis.getType(), getModel().getSource())) {
|
||||
setYAxis(0, yLeftDefault, false, true, 0, 1, 1.0);
|
||||
setYAxis(0, yLeftDefault, false, true, 0, 1, 10, false);
|
||||
}
|
||||
if(!yAxis[1].isSupported(xAxis.getType(), getModel().getSource())) {
|
||||
setYAxis(1, yRightDefault, false, true, 0, 1, 1.0);
|
||||
setYAxis(1, yRightDefault, false, true, 0, 1, 10, false);
|
||||
}
|
||||
traceRemovalPending = true;
|
||||
return true;
|
||||
|
|
@ -899,7 +911,7 @@ void TraceXYPlot::updateAxisTicks()
|
|||
}
|
||||
}
|
||||
}
|
||||
xAxis.set(xAxis.getType(), xAxis.getLog(), true, min, max, 0);
|
||||
xAxis.set(xAxis.getType(), xAxis.getLog(), true, min, max, 0, xAxis.getAutoDivs());
|
||||
}
|
||||
|
||||
for(int i=0;i<2;i++) {
|
||||
|
|
@ -981,7 +993,7 @@ void TraceXYPlot::updateAxisTicks()
|
|||
min = 0.1;
|
||||
}
|
||||
}
|
||||
yAxis[i].set(yAxis[i].getType(), yAxis[i].getLog(), true, min, max, 0);
|
||||
yAxis[i].set(yAxis[i].getType(), yAxis[i].getLog(), true, min, max, 0, xAxis.getAutoDivs());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -68,8 +68,8 @@ public:
|
|||
Last,
|
||||
};
|
||||
|
||||
void setYAxis(int axis, YAxis::Type type, bool log, bool autorange, double min, double max, double div);
|
||||
void setXAxis(XAxis::Type type, XAxisMode mode, bool log, double min, double max, double div);
|
||||
void setYAxis(int axis, YAxis::Type type, bool log, bool autorange, double min, double max, unsigned int divs, bool autoDivs);
|
||||
void setXAxis(XAxis::Type type, XAxisMode mode, bool log, double min, double max, unsigned int divs, bool autoDivs);
|
||||
void enableTrace(Trace *t, bool enabled) override;
|
||||
void updateSpan(double min, double max) override;
|
||||
void replot() override;
|
||||
|
|
|
|||
|
|
@ -115,8 +115,8 @@ WaterfallAxisDialog::~WaterfallAxisDialog()
|
|||
void WaterfallAxisDialog::on_buttonBox_accepted()
|
||||
{
|
||||
// set plot values to the ones selected in the dialog
|
||||
plot->xAxis.set(plot->xAxis.getType(), ui->Xlog->isChecked(), true, plot->xAxis.getRangeMin(), plot->xAxis.getRangeMax(), 0);
|
||||
plot->yAxis.set((YAxis::Type) ui->Wtype->currentIndex(), ui->Wlog->isChecked(), ui->Wauto->isChecked(), ui->Wmin->value(), ui->Wmax->value(), 2);
|
||||
plot->xAxis.set(plot->xAxis.getType(), ui->Xlog->isChecked(), true, plot->xAxis.getRangeMin(), plot->xAxis.getRangeMax(), 10, false);
|
||||
plot->yAxis.set((YAxis::Type) ui->Wtype->currentIndex(), ui->Wlog->isChecked(), ui->Wauto->isChecked(), ui->Wmin->value(), ui->Wmax->value(), 2, false);
|
||||
if(ui->Wdir->currentIndex() == 0) {
|
||||
plot->dir = TraceWaterfall::Direction::TopToBottom;
|
||||
} else {
|
||||
|
|
|
|||
|
|
@ -49,85 +49,114 @@ XYplotAxisDialog::XYplotAxisDialog(TraceXYPlot *plot) :
|
|||
}
|
||||
|
||||
// Setup GUI connections
|
||||
connect(ui->Y1type, qOverload<int>(&QComboBox::currentIndexChanged), [=](int index) {
|
||||
ui->Y1log->setEnabled(index != 0);
|
||||
ui->Y1linear->setEnabled(index != 0);
|
||||
ui->Y1auto->setEnabled(index != 0);
|
||||
bool autoRange = ui->Y1auto->isChecked();
|
||||
ui->Y1min->setEnabled(index != 0 && !autoRange);
|
||||
ui->Y1max->setEnabled(index != 0 && !autoRange);
|
||||
ui->Y1divs->setEnabled(index != 0 && !autoRange);
|
||||
auto type = (YAxis::Type) index;
|
||||
QString unit = YAxis::Unit(type);
|
||||
QString prefixes = YAxis::Prefixes(type);
|
||||
ui->Y1min->setUnit(unit);
|
||||
ui->Y1min->setPrefixes(prefixes);
|
||||
ui->Y1max->setUnit(unit);
|
||||
ui->Y1max->setPrefixes(prefixes);
|
||||
ui->Y1divs->setUnit(unit);
|
||||
ui->Y1divs->setPrefixes(prefixes);
|
||||
auto updateYenableState = [](QComboBox *type, QRadioButton *linear, QRadioButton *log, QCheckBox *CBauto, SIUnitEdit *min, SIUnitEdit *max, QSpinBox *divs, QCheckBox *autoDivs) {
|
||||
if(type->currentIndex() == 0) {
|
||||
// axis disabled
|
||||
log->setEnabled(false);
|
||||
linear->setEnabled(false);
|
||||
CBauto->setEnabled(false);
|
||||
} else {
|
||||
// axis enabled
|
||||
log->setEnabled(true);
|
||||
linear->setEnabled(true);
|
||||
CBauto->setEnabled(true);
|
||||
if(CBauto->isChecked()) {
|
||||
// autorange active, other settings disabled
|
||||
min->setEnabled(false);
|
||||
max->setEnabled(false);
|
||||
divs->setEnabled(false);
|
||||
autoDivs->setEnabled(false);
|
||||
} else {
|
||||
min->setEnabled(true);
|
||||
max->setEnabled(true);
|
||||
if(log->isChecked()) {
|
||||
divs->setEnabled(false);
|
||||
autoDivs->setEnabled(false);
|
||||
} else {
|
||||
autoDivs->setEnabled(true);
|
||||
divs->setEnabled(!autoDivs->isChecked());
|
||||
}
|
||||
}
|
||||
}
|
||||
auto t = (YAxis::Type) type->currentIndex();
|
||||
QString unit = YAxis::Unit(t);
|
||||
QString prefixes = YAxis::Prefixes(t);
|
||||
min->setUnit(unit);
|
||||
min->setPrefixes(prefixes);
|
||||
max->setUnit(unit);
|
||||
max->setPrefixes(prefixes);
|
||||
};
|
||||
|
||||
connect(ui->Y1type, qOverload<int>(&QComboBox::currentIndexChanged), [this, updateYenableState](int) {
|
||||
updateYenableState(ui->Y1type, ui->Y1linear, ui->Y1log, ui->Y1auto, ui->Y1min, ui->Y1max, ui->Y1Divs, ui->Y1autoDivs);
|
||||
});
|
||||
connect(ui->Y1auto, &QCheckBox::toggled, [this](bool checked) {
|
||||
ui->Y1min->setEnabled(!checked);
|
||||
ui->Y1max->setEnabled(!checked);
|
||||
ui->Y1divs->setEnabled(!checked && !ui->Y1log->isChecked());
|
||||
connect(ui->Y1auto, &QCheckBox::toggled, [this, updateYenableState](bool) {
|
||||
updateYenableState(ui->Y1type, ui->Y1linear, ui->Y1log, ui->Y1auto, ui->Y1min, ui->Y1max, ui->Y1Divs, ui->Y1autoDivs);
|
||||
});
|
||||
connect(ui->Y1log, &QCheckBox::toggled, [this](bool checked) {
|
||||
ui->Y1divs->setEnabled(!checked && !ui->Y1auto->isChecked());
|
||||
connect(ui->Y1log, &QCheckBox::toggled, [this, updateYenableState](bool) {
|
||||
updateYenableState(ui->Y1type, ui->Y1linear, ui->Y1log, ui->Y1auto, ui->Y1min, ui->Y1max, ui->Y1Divs, ui->Y1autoDivs);
|
||||
});
|
||||
connect(ui->Y1autoDivs, &QCheckBox::toggled, [this, updateYenableState](bool) {
|
||||
updateYenableState(ui->Y1type, ui->Y1linear, ui->Y1log, ui->Y1auto, ui->Y1min, ui->Y1max, ui->Y1Divs, ui->Y1autoDivs);
|
||||
});
|
||||
|
||||
connect(ui->Y2type, qOverload<int>(&QComboBox::currentIndexChanged), [=](int index) {
|
||||
ui->Y2log->setEnabled(index != 0);
|
||||
ui->Y2linear->setEnabled(index != 0);
|
||||
ui->Y2auto->setEnabled(index != 0);
|
||||
bool autoRange = ui->Y2auto->isChecked();
|
||||
ui->Y2min->setEnabled(index != 0 && !autoRange);
|
||||
ui->Y2max->setEnabled(index != 0 && !autoRange);
|
||||
ui->Y2divs->setEnabled(index != 0 && !autoRange);
|
||||
auto type = (YAxis::Type) index;
|
||||
QString unit = YAxis::Unit(type);
|
||||
QString prefixes = YAxis::Prefixes(type);
|
||||
ui->Y2min->setUnit(unit);
|
||||
ui->Y2min->setPrefixes(prefixes);
|
||||
ui->Y2max->setUnit(unit);
|
||||
ui->Y2max->setPrefixes(prefixes);
|
||||
ui->Y2divs->setUnit(unit);
|
||||
ui->Y2divs->setPrefixes(prefixes);
|
||||
connect(ui->Y2type, qOverload<int>(&QComboBox::currentIndexChanged), [this, updateYenableState](int) {
|
||||
updateYenableState(ui->Y2type, ui->Y2linear, ui->Y2log, ui->Y2auto, ui->Y2min, ui->Y2max, ui->Y2Divs, ui->Y2autoDivs);
|
||||
});
|
||||
connect(ui->Y2auto, &QCheckBox::toggled, [this, updateYenableState](bool) {
|
||||
updateYenableState(ui->Y2type, ui->Y2linear, ui->Y2log, ui->Y2auto, ui->Y2min, ui->Y2max, ui->Y2Divs, ui->Y2autoDivs);
|
||||
});
|
||||
connect(ui->Y2log, &QCheckBox::toggled, [this, updateYenableState](bool) {
|
||||
updateYenableState(ui->Y2type, ui->Y2linear, ui->Y2log, ui->Y2auto, ui->Y2min, ui->Y2max, ui->Y2Divs, ui->Y2autoDivs);
|
||||
});
|
||||
connect(ui->Y2autoDivs, &QCheckBox::toggled, [this, updateYenableState](bool) {
|
||||
updateYenableState(ui->Y2type, ui->Y2linear, ui->Y2log, ui->Y2auto, ui->Y2min, ui->Y2max, ui->Y2Divs, ui->Y2autoDivs);
|
||||
});
|
||||
|
||||
connect(ui->Y2auto, &QCheckBox::toggled, [this](bool checked) {
|
||||
ui->Y2min->setEnabled(!checked);
|
||||
ui->Y2max->setEnabled(!checked);
|
||||
ui->Y2divs->setEnabled(!checked && !ui->Y1log->isChecked());
|
||||
});
|
||||
connect(ui->Y2log, &QCheckBox::toggled, [this](bool checked) {
|
||||
ui->Y2divs->setEnabled(!checked && !ui->Y2auto->isChecked());
|
||||
});
|
||||
auto updateXenableState = [](QRadioButton *linear, QRadioButton *log, QCheckBox *CBauto, SIUnitEdit *min, SIUnitEdit *max, QSpinBox *divs, QCheckBox *autoDivs) {
|
||||
log->setEnabled(true);
|
||||
linear->setEnabled(true);
|
||||
CBauto->setEnabled(true);
|
||||
if(CBauto->isChecked()) {
|
||||
// autorange active, other settings disabled
|
||||
min->setEnabled(false);
|
||||
max->setEnabled(false);
|
||||
divs->setEnabled(false);
|
||||
autoDivs->setEnabled(false);
|
||||
} else {
|
||||
min->setEnabled(true);
|
||||
max->setEnabled(true);
|
||||
if(log->isChecked()) {
|
||||
divs->setEnabled(false);
|
||||
autoDivs->setEnabled(false);
|
||||
} else {
|
||||
autoDivs->setEnabled(true);
|
||||
divs->setEnabled(!autoDivs->isChecked());
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
connect(ui->Xauto, &QCheckBox::toggled, [this](bool checked) {
|
||||
ui->Xmin->setEnabled(!checked);
|
||||
ui->Xmax->setEnabled(!checked);
|
||||
ui->Xdivs->setEnabled(!checked && ui->Xlinear->isChecked());
|
||||
ui->Xautomode->setEnabled(checked);
|
||||
connect(ui->Xauto, &QCheckBox::toggled, [this, updateXenableState](bool checked) {
|
||||
updateXenableState(ui->Xlinear, ui->Xlog, ui->Xauto, ui->Xmin, ui->Xmax, ui->XDivs, ui->XautoDivs);
|
||||
});
|
||||
connect(ui->XautoDivs, &QCheckBox::toggled, [this, updateXenableState](bool checked) {
|
||||
updateXenableState(ui->Xlinear, ui->Xlog, ui->Xauto, ui->Xmin, ui->Xmax, ui->XDivs, ui->XautoDivs);
|
||||
});
|
||||
|
||||
ui->XType->setCurrentIndex((int) plot->xAxis.getType());
|
||||
ui->Xmin->setPrefixes("pnum kMG");
|
||||
ui->Xmax->setPrefixes("pnum kMG");
|
||||
ui->Xdivs->setPrefixes("pnum kMG");
|
||||
|
||||
ui->Y1min->setPrefixes("pnum kMG");
|
||||
ui->Y1max->setPrefixes("pnum kMG");
|
||||
ui->Y1divs->setPrefixes("pnum kMG");
|
||||
|
||||
ui->Y2min->setPrefixes("pnum kMG");
|
||||
ui->Y2max->setPrefixes("pnum kMG");
|
||||
ui->Y2divs->setPrefixes("pnum kMG");
|
||||
|
||||
XAxisTypeChanged((int) plot->xAxis.getType());
|
||||
connect(ui->XType, qOverload<int>(&QComboBox::currentIndexChanged), this, &XYplotAxisDialog::XAxisTypeChanged);
|
||||
connect(ui->Xlog, &QCheckBox::toggled, [=](bool checked){
|
||||
ui->Xdivs->setEnabled(!checked && !ui->Xauto->isChecked());
|
||||
updateXenableState(ui->Xlinear, ui->Xlog, ui->Xauto, ui->Xmin, ui->Xmax, ui->XDivs, ui->XautoDivs);
|
||||
});
|
||||
|
||||
// Fill initial values
|
||||
|
|
@ -140,7 +169,8 @@ XYplotAxisDialog::XYplotAxisDialog(TraceXYPlot *plot) :
|
|||
ui->Y1auto->setChecked(plot->yAxis[0].getAutorange());
|
||||
ui->Y1min->setValueQuiet(plot->yAxis[0].getRangeMin());
|
||||
ui->Y1max->setValueQuiet(plot->yAxis[0].getRangeMax());
|
||||
ui->Y1divs->setValueQuiet(plot->yAxis[0].getRangeDiv());
|
||||
ui->Y1Divs->setValue(plot->yAxis[0].getDivs());
|
||||
ui->Y1autoDivs->setChecked(plot->yAxis[0].getAutoDivs());
|
||||
|
||||
ui->Y2type->setCurrentIndex((int) plot->yAxis[1].getType());
|
||||
if(plot->yAxis[1].getLog()) {
|
||||
|
|
@ -151,7 +181,8 @@ XYplotAxisDialog::XYplotAxisDialog(TraceXYPlot *plot) :
|
|||
ui->Y2auto->setChecked(plot->yAxis[1].getAutorange());
|
||||
ui->Y2min->setValueQuiet(plot->yAxis[1].getRangeMin());
|
||||
ui->Y2max->setValueQuiet(plot->yAxis[1].getRangeMax());
|
||||
ui->Y2divs->setValueQuiet(plot->yAxis[1].getRangeDiv());
|
||||
ui->Y2Divs->setValue(plot->yAxis[1].getDivs());
|
||||
ui->Y2autoDivs->setChecked(plot->yAxis[1].getAutoDivs());
|
||||
|
||||
if(plot->xAxis.getLog()) {
|
||||
ui->Xlog->setChecked(true);
|
||||
|
|
@ -166,7 +197,8 @@ XYplotAxisDialog::XYplotAxisDialog(TraceXYPlot *plot) :
|
|||
}
|
||||
ui->Xmin->setValueQuiet(plot->xAxis.getRangeMin());
|
||||
ui->Xmax->setValueQuiet(plot->xAxis.getRangeMax());
|
||||
ui->Xdivs->setValueQuiet(plot->xAxis.getRangeDiv());
|
||||
ui->XDivs->setValue(plot->xAxis.getDivs());
|
||||
ui->XautoDivs->setChecked(plot->xAxis.getAutoDivs());
|
||||
|
||||
// Constant line list handling
|
||||
auto editLine = [&](XYPlotConstantLine *line) {
|
||||
|
|
@ -277,8 +309,8 @@ XYplotAxisDialog::~XYplotAxisDialog()
|
|||
void XYplotAxisDialog::on_buttonBox_accepted()
|
||||
{
|
||||
// set plot values to the ones selected in the dialog
|
||||
plot->setYAxis(0, (YAxis::Type) ui->Y1type->currentIndex(), ui->Y1log->isChecked(), ui->Y1auto->isChecked(), ui->Y1min->value(), ui->Y1max->value(), ui->Y1divs->value());
|
||||
plot->setYAxis(1, (YAxis::Type) ui->Y2type->currentIndex(), ui->Y2log->isChecked(), ui->Y2auto->isChecked(), ui->Y2min->value(), ui->Y2max->value(), ui->Y2divs->value());
|
||||
plot->setYAxis(0, (YAxis::Type) ui->Y1type->currentIndex(), ui->Y1log->isChecked(), ui->Y1auto->isChecked(), ui->Y1min->value(), ui->Y1max->value(), ui->Y1Divs->value(), ui->Y1autoDivs->isChecked());
|
||||
plot->setYAxis(1, (YAxis::Type) ui->Y2type->currentIndex(), ui->Y2log->isChecked(), ui->Y2auto->isChecked(), ui->Y2min->value(), ui->Y2max->value(), ui->Y2Divs->value(), ui->Y2autoDivs->isChecked());
|
||||
TraceXYPlot::XAxisMode mode;
|
||||
if(ui->Xauto->isChecked()) {
|
||||
if(ui->Xautomode->currentIndex() == 0) {
|
||||
|
|
@ -289,7 +321,7 @@ void XYplotAxisDialog::on_buttonBox_accepted()
|
|||
} else {
|
||||
mode = TraceXYPlot::XAxisMode::Manual;
|
||||
}
|
||||
plot->setXAxis((XAxis::Type) ui->XType->currentIndex(), mode, ui->Xlog->isChecked(), ui->Xmin->value(), ui->Xmax->value(), ui->Xdivs->value());
|
||||
plot->setXAxis((XAxis::Type) ui->XType->currentIndex(), mode, ui->Xlog->isChecked(), ui->Xmin->value(), ui->Xmax->value(), ui->XDivs->value(), ui->XautoDivs->isChecked());
|
||||
}
|
||||
|
||||
void XYplotAxisDialog::XAxisTypeChanged(int XAxisIndex)
|
||||
|
|
@ -330,7 +362,6 @@ void XYplotAxisDialog::XAxisTypeChanged(int XAxisIndex)
|
|||
QString unit = XAxis::Unit(type);
|
||||
ui->Xmin->setUnit(unit);
|
||||
ui->Xmax->setUnit(unit);
|
||||
ui->Xdivs->setUnit(unit);
|
||||
}
|
||||
|
||||
std::set<YAxis::Type> XYplotAxisDialog::supportedYAxis(XAxis::Type type)
|
||||
|
|
|
|||
|
|
@ -9,8 +9,8 @@
|
|||
<rect>
|
||||
<x>0</x>
|
||||
<y>0</y>
|
||||
<width>814</width>
|
||||
<height>458</height>
|
||||
<width>810</width>
|
||||
<height>461</height>
|
||||
</rect>
|
||||
</property>
|
||||
<property name="windowTitle">
|
||||
|
|
@ -21,9 +21,9 @@
|
|||
</property>
|
||||
<layout class="QVBoxLayout" name="verticalLayout_5">
|
||||
<item>
|
||||
<layout class="QHBoxLayout" name="horizontalLayout_5">
|
||||
<layout class="QHBoxLayout" name="horizontalLayout_9">
|
||||
<item>
|
||||
<layout class="QVBoxLayout" name="verticalLayout">
|
||||
<layout class="QVBoxLayout" name="verticalLayout_3">
|
||||
<item>
|
||||
<widget class="QLabel" name="label_2">
|
||||
<property name="font">
|
||||
|
|
@ -133,12 +133,27 @@
|
|||
<item row="3" column="0">
|
||||
<widget class="QLabel" name="label_6">
|
||||
<property name="text">
|
||||
<string>Divisions:</string>
|
||||
<string># Divisions:</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="3" column="1">
|
||||
<widget class="SIUnitEdit" name="Y1divs"/>
|
||||
<layout class="QHBoxLayout" name="horizontalLayout_8">
|
||||
<item>
|
||||
<widget class="QSpinBox" name="Y1Divs">
|
||||
<property name="minimum">
|
||||
<number>2</number>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QCheckBox" name="Y1autoDivs">
|
||||
<property name="text">
|
||||
<string>Auto</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
|
|
@ -262,12 +277,27 @@
|
|||
<item row="3" column="0">
|
||||
<widget class="QLabel" name="label_12">
|
||||
<property name="text">
|
||||
<string>Divisions:</string>
|
||||
<string># Divisions:</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="3" column="1">
|
||||
<widget class="SIUnitEdit" name="Y2divs"/>
|
||||
<layout class="QHBoxLayout" name="horizontalLayout_7">
|
||||
<item>
|
||||
<widget class="QSpinBox" name="Y2Divs">
|
||||
<property name="minimum">
|
||||
<number>2</number>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QCheckBox" name="Y2autoDivs">
|
||||
<property name="text">
|
||||
<string>Auto</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
|
|
@ -281,7 +311,7 @@
|
|||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<layout class="QVBoxLayout" name="verticalLayout_3">
|
||||
<layout class="QVBoxLayout" name="verticalLayout">
|
||||
<item>
|
||||
<widget class="QLabel" name="label_13">
|
||||
<property name="sizePolicy">
|
||||
|
|
@ -418,12 +448,27 @@
|
|||
<item row="3" column="0">
|
||||
<widget class="QLabel" name="label_18">
|
||||
<property name="text">
|
||||
<string>Divisions:</string>
|
||||
<string># Divisions:</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="3" column="1">
|
||||
<widget class="SIUnitEdit" name="Xdivs"/>
|
||||
<layout class="QHBoxLayout" name="horizontalLayout_5">
|
||||
<item>
|
||||
<widget class="QSpinBox" name="XDivs">
|
||||
<property name="minimum">
|
||||
<number>2</number>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QCheckBox" name="XautoDivs">
|
||||
<property name="text">
|
||||
<string>Auto</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
|
|
@ -592,8 +637,8 @@
|
|||
</connection>
|
||||
</connections>
|
||||
<buttongroups>
|
||||
<buttongroup name="Y1group"/>
|
||||
<buttongroup name="Xgroup"/>
|
||||
<buttongroup name="Y2group"/>
|
||||
<buttongroup name="Y1group"/>
|
||||
</buttongroups>
|
||||
</ui>
|
||||
|
|
|
|||
|
|
@ -262,6 +262,7 @@ void PreferencesDialog::setInitialGUIState()
|
|||
ui->AcquisitionFullSpanCalibrated->setChecked(p->Acquisition.fullSpanCalibratedRange);
|
||||
ui->AcquisitionLimitTDRCheckbox->setChecked(p->Acquisition.limitDFT);
|
||||
ui->AcquisitionDFTLimitValue->setValue(p->Acquisition.maxDFTrate);
|
||||
ui->AcquisitionGroupDelaySamples->setValue(p->Acquisition.groupDelaySamples);
|
||||
|
||||
ui->GraphsDefaultTransmission->setCurrentText(p->Graphs.defaultGraphs.transmission);
|
||||
ui->GraphsDefaultReflection->setCurrentText(p->Graphs.defaultGraphs.reflection);
|
||||
|
|
@ -299,6 +300,7 @@ void PreferencesDialog::setInitialGUIState()
|
|||
ui->MarkerShowCapacitance->setChecked(p->Marker.defaultBehavior.showCapacitance);
|
||||
ui->MarkerShowInductance->setChecked(p->Marker.defaultBehavior.showInductance);
|
||||
ui->MarkerShowQualityFactor->setChecked(p->Marker.defaultBehavior.showQualityFactor);
|
||||
ui->MarkerShowGroupDelay->setChecked(p->Marker.defaultBehavior.showGroupDelay);
|
||||
ui->MarkerShowNoise->setChecked(p->Marker.defaultBehavior.showNoise);
|
||||
ui->MarkerShowPhasenoise->setChecked(p->Marker.defaultBehavior.showPhasenoise);
|
||||
ui->MarkerShowCenterBandwidth->setChecked(p->Marker.defaultBehavior.showCenterBandwidth);
|
||||
|
|
@ -361,6 +363,7 @@ void PreferencesDialog::updateFromGUI()
|
|||
p->Acquisition.fullSpanCalibratedRange = ui->AcquisitionFullSpanCalibrated->isChecked();
|
||||
p->Acquisition.limitDFT = ui->AcquisitionLimitTDRCheckbox->isChecked();
|
||||
p->Acquisition.maxDFTrate = ui->AcquisitionDFTLimitValue->value();
|
||||
p->Acquisition.groupDelaySamples = ui->AcquisitionGroupDelaySamples->value();
|
||||
|
||||
p->Graphs.defaultGraphs.transmission = ui->GraphsDefaultTransmission->currentText();
|
||||
p->Graphs.defaultGraphs.reflection = ui->GraphsDefaultReflection->currentText();
|
||||
|
|
@ -397,6 +400,7 @@ void PreferencesDialog::updateFromGUI()
|
|||
p->Marker.defaultBehavior.showCapacitance = ui->MarkerShowCapacitance->isChecked();
|
||||
p->Marker.defaultBehavior.showInductance = ui->MarkerShowInductance->isChecked();
|
||||
p->Marker.defaultBehavior.showQualityFactor = ui->MarkerShowQualityFactor->isChecked();
|
||||
p->Marker.defaultBehavior.showGroupDelay = ui->MarkerShowGroupDelay->isChecked();
|
||||
p->Marker.defaultBehavior.showNoise = ui->MarkerShowNoise->isChecked();
|
||||
p->Marker.defaultBehavior.showPhasenoise = ui->MarkerShowPhasenoise->isChecked();
|
||||
p->Marker.defaultBehavior.showCenterBandwidth = ui->MarkerShowCenterBandwidth->isChecked();
|
||||
|
|
|
|||
|
|
@ -108,6 +108,7 @@ public:
|
|||
// Math settings
|
||||
bool limitDFT;
|
||||
double maxDFTrate;
|
||||
int groupDelaySamples;
|
||||
} Acquisition;
|
||||
struct {
|
||||
bool showUnits;
|
||||
|
|
@ -150,7 +151,7 @@ public:
|
|||
struct {
|
||||
struct {
|
||||
bool showDataOnGraphs;
|
||||
bool showdB, showdBm, showdBuV, showdBAngle, showRealImag, showImpedance, showVSWR, showResistance, showCapacitance, showInductance, showQualityFactor;
|
||||
bool showdB, showdBm, showdBuV, showdBAngle, showRealImag, showImpedance, showVSWR, showResistance, showCapacitance, showInductance, showQualityFactor, showGroupDelay;
|
||||
bool showNoise, showPhasenoise, showCenterBandwidth, showCutoff, showInsertionLoss, showTOI, showAvgTone, showAvgModulation, showP1dB, showFlatness, showMaxDeltaNeg, showMaxDeltaPos;
|
||||
} defaultBehavior;
|
||||
bool interpolatePoints;
|
||||
|
|
@ -214,6 +215,7 @@ private:
|
|||
{&Acquisition.fullSpanCalibratedRange, "Acquisition.fullSpanCalibratedRange", false},
|
||||
{&Acquisition.limitDFT, "Acquisition.limitDFT", true},
|
||||
{&Acquisition.maxDFTrate, "Acquisition.maxDFTrate", 1.0},
|
||||
{&Acquisition.groupDelaySamples, "Acquisition.groupDelaySamples", 5},
|
||||
{&Graphs.showUnits, "Graphs.showUnits", true},
|
||||
{&Graphs.Color.background, "Graphs.Color.background", QColor(Qt::black)},
|
||||
{&Graphs.Color.axis, "Graphs.Color.axis", QColor(Qt::white)},
|
||||
|
|
@ -248,6 +250,7 @@ private:
|
|||
{&Marker.defaultBehavior.showCapacitance, "Marker.defaultBehavior.showCapacitance", true},
|
||||
{&Marker.defaultBehavior.showInductance, "Marker.defaultBehavior.showInductance", true},
|
||||
{&Marker.defaultBehavior.showQualityFactor, "Marker.defaultBehavior.showQualityFactor", true},
|
||||
{&Marker.defaultBehavior.showGroupDelay, "Marker.defaultBehavior.showGroupDelay", true},
|
||||
{&Marker.defaultBehavior.showNoise, "Marker.defaultBehavior.showNoise", true},
|
||||
{&Marker.defaultBehavior.showPhasenoise, "Marker.defaultBehavior.showPhasenoise", true},
|
||||
{&Marker.defaultBehavior.showCenterBandwidth, "Marker.defaultBehavior.showCenterBandwidth", true},
|
||||
|
|
|
|||
|
|
@ -93,7 +93,7 @@
|
|||
</size>
|
||||
</property>
|
||||
<property name="currentIndex">
|
||||
<number>1</number>
|
||||
<number>3</number>
|
||||
</property>
|
||||
<widget class="QWidget" name="Startup">
|
||||
<layout class="QHBoxLayout" name="horizontalLayout_4">
|
||||
|
|
@ -107,8 +107,8 @@
|
|||
<rect>
|
||||
<x>0</x>
|
||||
<y>0</y>
|
||||
<width>683</width>
|
||||
<height>897</height>
|
||||
<width>522</width>
|
||||
<height>914</height>
|
||||
</rect>
|
||||
</property>
|
||||
<layout class="QVBoxLayout" name="verticalLayout_13">
|
||||
|
|
@ -829,46 +829,81 @@
|
|||
<property name="title">
|
||||
<string>Math operations</string>
|
||||
</property>
|
||||
<layout class="QHBoxLayout" name="horizontalLayout_6">
|
||||
<layout class="QVBoxLayout" name="verticalLayout_19">
|
||||
<item>
|
||||
<widget class="QCheckBox" name="AcquisitionLimitTDRCheckbox">
|
||||
<property name="text">
|
||||
<string>Limit TDR/DFT to </string>
|
||||
</property>
|
||||
</widget>
|
||||
<layout class="QHBoxLayout" name="horizontalLayout_13">
|
||||
<item>
|
||||
<widget class="QCheckBox" name="AcquisitionLimitTDRCheckbox">
|
||||
<property name="text">
|
||||
<string>Limit TDR/DFT to </string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QDoubleSpinBox" name="AcquisitionDFTLimitValue">
|
||||
<property name="enabled">
|
||||
<bool>false</bool>
|
||||
</property>
|
||||
<property name="minimum">
|
||||
<double>0.100000000000000</double>
|
||||
</property>
|
||||
<property name="maximum">
|
||||
<double>100.000000000000000</double>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QLabel" name="label_30">
|
||||
<property name="text">
|
||||
<string>updates per second</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<spacer name="horizontalSpacer_8">
|
||||
<property name="orientation">
|
||||
<enum>Qt::Horizontal</enum>
|
||||
</property>
|
||||
<property name="sizeHint" stdset="0">
|
||||
<size>
|
||||
<width>40</width>
|
||||
<height>20</height>
|
||||
</size>
|
||||
</property>
|
||||
</spacer>
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QDoubleSpinBox" name="AcquisitionDFTLimitValue">
|
||||
<property name="enabled">
|
||||
<bool>false</bool>
|
||||
</property>
|
||||
<property name="minimum">
|
||||
<double>0.100000000000000</double>
|
||||
</property>
|
||||
<property name="maximum">
|
||||
<double>100.000000000000000</double>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QLabel" name="label_30">
|
||||
<property name="text">
|
||||
<string>updates per second</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<spacer name="horizontalSpacer_8">
|
||||
<property name="orientation">
|
||||
<enum>Qt::Horizontal</enum>
|
||||
</property>
|
||||
<property name="sizeHint" stdset="0">
|
||||
<size>
|
||||
<width>40</width>
|
||||
<height>20</height>
|
||||
</size>
|
||||
</property>
|
||||
</spacer>
|
||||
<layout class="QHBoxLayout" name="horizontalLayout_6">
|
||||
<item>
|
||||
<widget class="QLabel" name="label_31">
|
||||
<property name="text">
|
||||
<string>Number of samples used for group delay calculation: </string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QSpinBox" name="AcquisitionGroupDelaySamples">
|
||||
<property name="minimum">
|
||||
<number>2</number>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<spacer name="horizontalSpacer_9">
|
||||
<property name="orientation">
|
||||
<enum>Qt::Horizontal</enum>
|
||||
</property>
|
||||
<property name="sizeHint" stdset="0">
|
||||
<size>
|
||||
<width>40</width>
|
||||
<height>20</height>
|
||||
</size>
|
||||
</property>
|
||||
</spacer>
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
|
|
@ -1503,6 +1538,13 @@
|
|||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QCheckBox" name="MarkerShowGroupDelay">
|
||||
<property name="text">
|
||||
<string>Group Delay</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
</item>
|
||||
|
|
@ -1737,8 +1779,8 @@
|
|||
<rect>
|
||||
<x>0</x>
|
||||
<y>0</y>
|
||||
<width>697</width>
|
||||
<height>563</height>
|
||||
<width>168</width>
|
||||
<height>127</height>
|
||||
</rect>
|
||||
</property>
|
||||
<layout class="QHBoxLayout" name="horizontalLayout_12">
|
||||
|
|
@ -1827,8 +1869,8 @@
|
|||
<rect>
|
||||
<x>0</x>
|
||||
<y>0</y>
|
||||
<width>697</width>
|
||||
<height>563</height>
|
||||
<width>215</width>
|
||||
<height>168</height>
|
||||
</rect>
|
||||
</property>
|
||||
<layout class="QHBoxLayout" name="horizontalLayout_19">
|
||||
|
|
|
|||
Loading…
Reference in a new issue