partial eye diagram implementation
This commit is contained in:
parent
9a198217b8
commit
c7a99af820
@ -33,6 +33,7 @@ HEADERS += \
|
|||||||
SpectrumAnalyzer/spectrumanalyzer.h \
|
SpectrumAnalyzer/spectrumanalyzer.h \
|
||||||
SpectrumAnalyzer/tracewidgetsa.h \
|
SpectrumAnalyzer/tracewidgetsa.h \
|
||||||
Tools/eseries.h \
|
Tools/eseries.h \
|
||||||
|
Tools/eyediagramdialog.h \
|
||||||
Tools/impedancematchdialog.h \
|
Tools/impedancematchdialog.h \
|
||||||
Tools/parameters.h \
|
Tools/parameters.h \
|
||||||
Traces/Marker/marker.h \
|
Traces/Marker/marker.h \
|
||||||
@ -112,6 +113,7 @@ HEADERS += \
|
|||||||
Traces/waterfallaxisdialog.h \
|
Traces/waterfallaxisdialog.h \
|
||||||
Traces/xyplotaxisdialog.h \
|
Traces/xyplotaxisdialog.h \
|
||||||
Traces/tracepolarchart.h \
|
Traces/tracepolarchart.h \
|
||||||
|
Util/prbs.h \
|
||||||
Util/qpointervariant.h \
|
Util/qpointervariant.h \
|
||||||
Util/util.h \
|
Util/util.h \
|
||||||
Util/app_common.h \
|
Util/app_common.h \
|
||||||
@ -175,6 +177,7 @@ SOURCES += \
|
|||||||
SpectrumAnalyzer/spectrumanalyzer.cpp \
|
SpectrumAnalyzer/spectrumanalyzer.cpp \
|
||||||
SpectrumAnalyzer/tracewidgetsa.cpp \
|
SpectrumAnalyzer/tracewidgetsa.cpp \
|
||||||
Tools/eseries.cpp \
|
Tools/eseries.cpp \
|
||||||
|
Tools/eyediagramdialog.cpp \
|
||||||
Tools/impedancematchdialog.cpp \
|
Tools/impedancematchdialog.cpp \
|
||||||
Tools/parameters.cpp \
|
Tools/parameters.cpp \
|
||||||
Traces/Marker/marker.cpp \
|
Traces/Marker/marker.cpp \
|
||||||
@ -243,6 +246,7 @@ SOURCES += \
|
|||||||
Traces/tracepolar.cpp \
|
Traces/tracepolar.cpp \
|
||||||
Traces/waterfallaxisdialog.cpp \
|
Traces/waterfallaxisdialog.cpp \
|
||||||
Traces/xyplotaxisdialog.cpp \
|
Traces/xyplotaxisdialog.cpp \
|
||||||
|
Util/prbs.cpp \
|
||||||
Util/util.cpp \
|
Util/util.cpp \
|
||||||
VNA/Deembedding/deembedding.cpp \
|
VNA/Deembedding/deembedding.cpp \
|
||||||
VNA/Deembedding/deembeddingdialog.cpp \
|
VNA/Deembedding/deembeddingdialog.cpp \
|
||||||
@ -301,6 +305,7 @@ FORMS += \
|
|||||||
Device/firmwareupdatedialog.ui \
|
Device/firmwareupdatedialog.ui \
|
||||||
Device/manualcontroldialog.ui \
|
Device/manualcontroldialog.ui \
|
||||||
Generator/signalgenwidget.ui \
|
Generator/signalgenwidget.ui \
|
||||||
|
Tools/eyediagramdialog.ui \
|
||||||
Tools/impedancematchdialog.ui \
|
Tools/impedancematchdialog.ui \
|
||||||
Traces/Marker/markerwidget.ui \
|
Traces/Marker/markerwidget.ui \
|
||||||
Traces/Math/dftdialog.ui \
|
Traces/Math/dftdialog.ui \
|
||||||
@ -343,7 +348,7 @@ RESOURCES += \
|
|||||||
icons.qrc \
|
icons.qrc \
|
||||||
resources/librevna.qrc
|
resources/librevna.qrc
|
||||||
|
|
||||||
QMAKE_CXXFLAGS += -Wno-deprecated -Wno-deprecated-declarations
|
QMAKE_CXXFLAGS += -Wno-deprecated -Wno-deprecated-declarations -Wno-deprecated-copy
|
||||||
|
|
||||||
CONFIG += c++17
|
CONFIG += c++17
|
||||||
REVISION = $$system(git rev-parse HEAD)
|
REVISION = $$system(git rev-parse HEAD)
|
||||||
|
File diff suppressed because it is too large
Load Diff
412
Software/PC_Application/LibreVNA-GUI/Tools/eyediagramdialog.cpp
Normal file
412
Software/PC_Application/LibreVNA-GUI/Tools/eyediagramdialog.cpp
Normal file
@ -0,0 +1,412 @@
|
|||||||
|
#include "eyediagramdialog.h"
|
||||||
|
#include "ui_eyediagramdialog.h"
|
||||||
|
#include "Util/prbs.h"
|
||||||
|
#include "Traces/Math/tdr.h"
|
||||||
|
#include "Util/util.h"
|
||||||
|
#include "preferences.h"
|
||||||
|
#include "Traces/fftcomplex.h"
|
||||||
|
|
||||||
|
#include <random>
|
||||||
|
#include <thread>
|
||||||
|
#include <chrono>
|
||||||
|
|
||||||
|
#include <QPainter>
|
||||||
|
|
||||||
|
using namespace std::chrono_literals;
|
||||||
|
|
||||||
|
EyeDiagramDialog::EyeDiagramDialog(TraceModel &model) :
|
||||||
|
QDialog(nullptr),
|
||||||
|
ui(new Ui::EyeDiagramDialog)
|
||||||
|
{
|
||||||
|
ui->setupUi(this);
|
||||||
|
|
||||||
|
workingBuffer = &eyeBuffer[0];
|
||||||
|
finishedBuffer = &eyeBuffer[1];
|
||||||
|
|
||||||
|
updating = false;
|
||||||
|
|
||||||
|
trace = nullptr;
|
||||||
|
ui->update->setEnabled(false);
|
||||||
|
|
||||||
|
ui->datarate->setUnit("bps");
|
||||||
|
ui->datarate->setPrefixes(" kMG");
|
||||||
|
ui->datarate->setPrecision(3);
|
||||||
|
|
||||||
|
ui->risetime->setUnit("s");
|
||||||
|
ui->risetime->setPrefixes("pnum ");
|
||||||
|
ui->risetime->setPrecision(3);
|
||||||
|
|
||||||
|
ui->falltime->setUnit("s");
|
||||||
|
ui->falltime->setPrefixes("pnum ");
|
||||||
|
ui->falltime->setPrecision(3);
|
||||||
|
|
||||||
|
ui->highLevel->setUnit("V");
|
||||||
|
ui->highLevel->setPrefixes("m ");
|
||||||
|
ui->highLevel->setPrecision(3);
|
||||||
|
|
||||||
|
ui->lowLevel->setUnit("V");
|
||||||
|
ui->lowLevel->setPrefixes("m ");
|
||||||
|
ui->lowLevel->setPrecision(3);
|
||||||
|
|
||||||
|
ui->noise->setUnit("V");
|
||||||
|
ui->noise->setPrefixes("um ");
|
||||||
|
ui->noise->setPrecision(3);
|
||||||
|
|
||||||
|
ui->jitter->setUnit("s");
|
||||||
|
ui->jitter->setPrefixes("pnum ");
|
||||||
|
ui->jitter->setPrecision(3);
|
||||||
|
|
||||||
|
ui->datarate->setValue(100000000);
|
||||||
|
ui->risetime->setValue(0.000000001);
|
||||||
|
ui->falltime->setValue(0.000000001);
|
||||||
|
ui->highLevel->setValue(1);
|
||||||
|
ui->lowLevel->setValue(0);
|
||||||
|
ui->noise->setValue(0.01);
|
||||||
|
ui->jitter->setValue(0.0000000001);
|
||||||
|
|
||||||
|
ui->displayedCycles->setValue(200);
|
||||||
|
|
||||||
|
ui->widget->setDialog(this);
|
||||||
|
|
||||||
|
connect(this, &EyeDiagramDialog::updatePercent, ui->progress, &QProgressBar::setValue, Qt::QueuedConnection);
|
||||||
|
connect(ui->update, &QPushButton::clicked, this, &EyeDiagramDialog::triggerUpdate);
|
||||||
|
connect(this, &EyeDiagramDialog::updateDone, ui->widget, qOverload<>(&QWidget::update));
|
||||||
|
|
||||||
|
connect(ui->traceSelector, qOverload<int>(&QComboBox::currentIndexChanged), [=](){
|
||||||
|
trace = qvariant_cast<Trace*>(ui->traceSelector->itemData(ui->traceSelector->currentIndex()));
|
||||||
|
ui->update->setEnabled(true);
|
||||||
|
});
|
||||||
|
|
||||||
|
// find applicable traces
|
||||||
|
for(auto t : model.getTraces()) {
|
||||||
|
if(t->getDataType() != Trace::DataType::Frequency) {
|
||||||
|
// wrong domain
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if(t->isReflection()) {
|
||||||
|
// can't work with reflection measurements
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if(t->numSamples() < 100) {
|
||||||
|
// not enough samples
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
auto start = t->getSample(0).x;
|
||||||
|
auto stop = t->getSample(t->numSamples() - 1).x;
|
||||||
|
if(stop - start < start * 100) {
|
||||||
|
// span/start is not suitable for step response TDR
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
// can use this trace
|
||||||
|
ui->traceSelector->addItem(t->name(), QVariant::fromValue<Trace*>(t));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
EyeDiagramDialog::~EyeDiagramDialog()
|
||||||
|
{
|
||||||
|
delete ui;
|
||||||
|
}
|
||||||
|
|
||||||
|
double EyeDiagramDialog::getIntensity(unsigned int x, unsigned int y)
|
||||||
|
{
|
||||||
|
if(finishedBuffer->size() > x) {
|
||||||
|
if((*finishedBuffer)[x].size() > y) {
|
||||||
|
return (*finishedBuffer)[x][y];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return std::numeric_limits<double>::quiet_NaN();
|
||||||
|
}
|
||||||
|
|
||||||
|
bool EyeDiagramDialog::triggerUpdate()
|
||||||
|
{
|
||||||
|
update(ui->widget->width(), ui->widget->height());
|
||||||
|
}
|
||||||
|
|
||||||
|
bool EyeDiagramDialog::update(unsigned int width, unsigned int height)
|
||||||
|
{
|
||||||
|
if(updating) {
|
||||||
|
// already updating, can't start again
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
updating = true;
|
||||||
|
new std::thread(&EyeDiagramDialog::updateThread, this, width, height);
|
||||||
|
}
|
||||||
|
|
||||||
|
void EyeDiagramDialog::updateThread(unsigned int width, unsigned int height)
|
||||||
|
{
|
||||||
|
emit updatePercent(0);
|
||||||
|
if(!trace) {
|
||||||
|
updating = false;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
qDebug() << "Starting eye diagram calculation";
|
||||||
|
|
||||||
|
auto datarate = ui->datarate->value();
|
||||||
|
auto highlevel = ui->highLevel->value();
|
||||||
|
auto lowlevel = ui->lowLevel->value();
|
||||||
|
auto risetime = ui->risetime->value();
|
||||||
|
auto falltime = ui->falltime->value();
|
||||||
|
auto noise = ui->noise->value();
|
||||||
|
auto jitter = ui->jitter->value();
|
||||||
|
unsigned int patternbits = ui->patternLength->currentIndex() + 2;
|
||||||
|
unsigned int cycles = ui->displayedCycles->value() + 1; // first cycle will not be displayed
|
||||||
|
|
||||||
|
// sanity check values
|
||||||
|
// TODO
|
||||||
|
|
||||||
|
qDebug() << "Eye calculation: input values okay";
|
||||||
|
|
||||||
|
// resize working buffer
|
||||||
|
workingBuffer->clear();
|
||||||
|
workingBuffer->resize(width);
|
||||||
|
for(auto& y : *workingBuffer) {
|
||||||
|
y.resize(height, 0.0);
|
||||||
|
}
|
||||||
|
|
||||||
|
// calculate timestep
|
||||||
|
double displayedTime = 2 * 1.0/datarate; // always showing two bit periods
|
||||||
|
double timestep = displayedTime / (width);
|
||||||
|
|
||||||
|
auto prbs = new PRBS(patternbits);
|
||||||
|
|
||||||
|
bool currentBit = prbs->next();
|
||||||
|
bool nextBit = prbs->next();
|
||||||
|
|
||||||
|
// initialize random generator
|
||||||
|
std::random_device rd1;
|
||||||
|
std::mt19937 mt_noise(rd1());
|
||||||
|
std::normal_distribution<> dist_noise(0, noise);
|
||||||
|
|
||||||
|
std::random_device rd2;
|
||||||
|
std::mt19937 mt_jitter(rd2());
|
||||||
|
std::normal_distribution<> dist_jitter(0, jitter);
|
||||||
|
|
||||||
|
// reserve vector for input data
|
||||||
|
std::vector<double> input(width * cycles, 0.0);
|
||||||
|
|
||||||
|
unsigned int bitcnt = 1;
|
||||||
|
double transitionTime = -10; // assume that we start with a settled input, last transition was "long" ago
|
||||||
|
for(unsigned int i=0;i<input.size();i++) {
|
||||||
|
double time = i*timestep;
|
||||||
|
double voltage;
|
||||||
|
if(time >= transitionTime) {
|
||||||
|
// currently within a bit transition
|
||||||
|
double edgeTime = 0;
|
||||||
|
if(!currentBit && nextBit) {
|
||||||
|
edgeTime = risetime;
|
||||||
|
} else if(currentBit && !nextBit) {
|
||||||
|
edgeTime = falltime;
|
||||||
|
}
|
||||||
|
if(time >= transitionTime + edgeTime) {
|
||||||
|
// bit transition settled
|
||||||
|
voltage = nextBit ? highlevel : lowlevel;
|
||||||
|
// move on to the next bit
|
||||||
|
currentBit = nextBit;
|
||||||
|
nextBit = prbs->next();
|
||||||
|
transitionTime = bitcnt * 1.0 / datarate + dist_jitter(mt_jitter);
|
||||||
|
bitcnt++;
|
||||||
|
} else {
|
||||||
|
// still within rise or fall time
|
||||||
|
double timeSinceEdge = time - transitionTime;
|
||||||
|
double edgeRatio = timeSinceEdge / edgeTime;
|
||||||
|
double from = currentBit ? highlevel : lowlevel;
|
||||||
|
double to = nextBit ? highlevel : lowlevel;
|
||||||
|
voltage = from * (1.0 - edgeRatio) + to * edgeRatio;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
// still before the next edge
|
||||||
|
voltage = currentBit ? highlevel : lowlevel;
|
||||||
|
}
|
||||||
|
voltage += dist_noise(mt_noise);
|
||||||
|
input[i] = voltage;
|
||||||
|
}
|
||||||
|
|
||||||
|
// input voltage vector fully assembled
|
||||||
|
qDebug() << "Eye calculation: input data generated";
|
||||||
|
|
||||||
|
// calculate impulse response of trace
|
||||||
|
auto tdr = new Math::TDR();
|
||||||
|
// default configuration of TDR is lowpass with automatic DC, which is exactly what we need
|
||||||
|
|
||||||
|
// TDR calculation happens in background thread, need to wait for emitted signal
|
||||||
|
volatile bool TDRdone = false;
|
||||||
|
|
||||||
|
double eyeTimeShift = 0;
|
||||||
|
|
||||||
|
std::vector<double> convolutionData;
|
||||||
|
auto conn = connect(tdr, &Math::TDR::outputSamplesChanged, [&](){
|
||||||
|
if(!TDRdone) {
|
||||||
|
// determine how long the impulse response is
|
||||||
|
auto samples = tdr->numSamples();
|
||||||
|
auto length = tdr->getSample(samples - 1).x;
|
||||||
|
|
||||||
|
// determine average delay
|
||||||
|
auto total_step = tdr->getStepResponse(samples - 1);
|
||||||
|
for(unsigned int i=0;i<samples;i++) {
|
||||||
|
auto step = tdr->getStepResponse(i);
|
||||||
|
if(abs(total_step - step) <= abs(step)) {
|
||||||
|
// mid point reached
|
||||||
|
eyeTimeShift = tdr->getSample(i).x;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
auto scale = timestep / (length / (samples - 1));
|
||||||
|
unsigned long convolutedSize = length / timestep;
|
||||||
|
if(convolutedSize > input.size()) {
|
||||||
|
// impulse response is longer than what we display, truncate
|
||||||
|
convolutedSize = input.size();
|
||||||
|
}
|
||||||
|
convolutionData.resize(convolutedSize);
|
||||||
|
for(unsigned long i=0;i<convolutedSize;i++) {
|
||||||
|
auto x = i*timestep;
|
||||||
|
convolutionData[i] = tdr->getInterpolatedSample(x).y.real() * scale;
|
||||||
|
}
|
||||||
|
TDRdone = true;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
// assigning the trace starts the TDR calculation
|
||||||
|
tdr->assignInput(trace);
|
||||||
|
|
||||||
|
// wait for the TDR calculation to be done
|
||||||
|
while(!TDRdone) {
|
||||||
|
std::this_thread::sleep_for(20ms);
|
||||||
|
};
|
||||||
|
disconnect(conn);
|
||||||
|
delete tdr;
|
||||||
|
|
||||||
|
eyeTimeShift += (risetime + falltime) / 4;
|
||||||
|
eyeTimeShift += 0.5 / datarate;
|
||||||
|
int eyeXshift = eyeTimeShift / timestep;
|
||||||
|
|
||||||
|
qDebug() << "Eye calculation: TDR calculation done";
|
||||||
|
|
||||||
|
// calculate voltage at top and bottom of diagram for y binning to pixels
|
||||||
|
auto eyeRange = highlevel - lowlevel;
|
||||||
|
auto topValue = highlevel + eyeRange * yOverrange;
|
||||||
|
auto bottomValue = lowlevel - eyeRange * yOverrange;
|
||||||
|
|
||||||
|
unsigned int highestIntensity = 0;
|
||||||
|
|
||||||
|
qDebug() << "Convolve via FFT start";
|
||||||
|
std::vector<std::complex<double>> inVec;
|
||||||
|
std::vector<std::complex<double>> impulseVec;
|
||||||
|
std::vector<std::complex<double>> outVec;
|
||||||
|
for(auto i : input) {
|
||||||
|
inVec.push_back(i);
|
||||||
|
}
|
||||||
|
for(auto i : convolutionData) {
|
||||||
|
impulseVec.push_back(i);
|
||||||
|
}
|
||||||
|
impulseVec.resize(inVec.size(), 0.0);
|
||||||
|
outVec.resize(inVec.size());
|
||||||
|
Fft::convolve(inVec, impulseVec, outVec);
|
||||||
|
qDebug() << "Convolve via FFT stop";
|
||||||
|
|
||||||
|
auto addLine = [&](int x0, int y0, int x1, int y1, bool skipFirst = true) {
|
||||||
|
bool first = true;
|
||||||
|
auto putpixel = [&](int x, int y) {
|
||||||
|
if(skipFirst && first) {
|
||||||
|
first = false;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if(x < 0 || x >= width || y < 0 || y >= height) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
auto &bin = (*workingBuffer)[x][y];
|
||||||
|
bin++;
|
||||||
|
if(bin > highestIntensity) {
|
||||||
|
highestIntensity = bin;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
int dx = abs (x1 - x0), sx = x0 < x1 ? 1 : -1;
|
||||||
|
int dy = -abs (y1 - y0), sy = y0 < y1 ? 1 : -1;
|
||||||
|
int err = dx + dy, e2; /* error value e_xy */
|
||||||
|
|
||||||
|
for (;;){ /* loop */
|
||||||
|
putpixel (x0,y0);
|
||||||
|
if (x0 == x1 && y0 == y1) break;
|
||||||
|
e2 = 2 * err;
|
||||||
|
if (e2 >= dy) { err += dy; x0 += sx; } /* e_xy+e_x > 0 */
|
||||||
|
if (e2 <= dx) { err += dx; y0 += sy; } /* e_xy+e_y < 0 */
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
// got the input data and the convolution data, calculate output
|
||||||
|
int lastyBin;
|
||||||
|
for(unsigned int i=width;i<input.size();i++) {
|
||||||
|
// double voltage = 0;
|
||||||
|
// for(unsigned j=0;j<convolutionData.size();j++) {
|
||||||
|
// double inputValue = i >= j ? input[i-j] : input[0];
|
||||||
|
// voltage += convolutionData[j] * inputValue;
|
||||||
|
// }
|
||||||
|
double voltage = outVec[i].real();
|
||||||
|
int yBin = Util::Scale<double>(voltage, bottomValue, topValue, height-1, 0);
|
||||||
|
// increment pixel bin
|
||||||
|
if(yBin < 0) {
|
||||||
|
yBin = 0;
|
||||||
|
} else if(yBin >= height) {
|
||||||
|
yBin = height - 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
auto xlast = (i-1-eyeXshift)%width;
|
||||||
|
auto xnow = (i-eyeXshift)%width;
|
||||||
|
if(xnow > xlast && i > width) {
|
||||||
|
addLine(xlast, lastyBin, xnow, yBin, xlast > 0);
|
||||||
|
}
|
||||||
|
lastyBin = yBin;
|
||||||
|
emit updatePercent(100 * i / input.size());
|
||||||
|
}
|
||||||
|
|
||||||
|
qDebug() << "Eye calculation: Convolution done";
|
||||||
|
|
||||||
|
// normalize intensity
|
||||||
|
for(auto &y : *workingBuffer) {
|
||||||
|
for(auto &v : y) {
|
||||||
|
v /= highestIntensity;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
emit updatePercent(100);
|
||||||
|
// switch buffers
|
||||||
|
auto buf = finishedBuffer;
|
||||||
|
finishedBuffer = workingBuffer;
|
||||||
|
workingBuffer = buf;
|
||||||
|
updating = false;
|
||||||
|
emit updateDone();
|
||||||
|
}
|
||||||
|
|
||||||
|
EyeDiagramPlot::EyeDiagramPlot(QDialog *dialog)
|
||||||
|
{
|
||||||
|
Q_UNUSED(dialog)
|
||||||
|
}
|
||||||
|
|
||||||
|
void EyeDiagramPlot::setDialog(EyeDiagramDialog *dialog)
|
||||||
|
{
|
||||||
|
this->dialog = dialog;
|
||||||
|
}
|
||||||
|
|
||||||
|
void EyeDiagramPlot::paintEvent(QPaintEvent *event)
|
||||||
|
{
|
||||||
|
auto &pref = Preferences::getInstance();
|
||||||
|
QPainter p(this);
|
||||||
|
p.setBackground(QBrush(pref.Graphs.Color.background));
|
||||||
|
p.fillRect(0, 0, width(), height(), QBrush(pref.Graphs.Color.background));
|
||||||
|
if(!dialog) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
for(unsigned int i=0;i<width();i++) {
|
||||||
|
for(unsigned int j=0;j<height();j++) {
|
||||||
|
auto value = dialog->getIntensity(i, j);
|
||||||
|
if(isnan(value) || value == 0) {
|
||||||
|
// do not paint, just leave the background shining through
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
auto pen = QPen(Util::getIntensityGradeColor(value));
|
||||||
|
pen.setCosmetic(true);
|
||||||
|
p.setPen(pen);
|
||||||
|
p.drawPoint(i, j);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,66 @@
|
|||||||
|
#ifndef EYEDIAGRAMDIALOG_H
|
||||||
|
#define EYEDIAGRAMDIALOG_H
|
||||||
|
|
||||||
|
#include "Traces/tracemodel.h"
|
||||||
|
|
||||||
|
#include <vector>
|
||||||
|
|
||||||
|
#include <QDialog>
|
||||||
|
|
||||||
|
namespace Ui {
|
||||||
|
class EyeDiagramDialog;
|
||||||
|
}
|
||||||
|
|
||||||
|
class EyeDiagramDialog;
|
||||||
|
|
||||||
|
class EyeDiagramPlot : public QWidget
|
||||||
|
{
|
||||||
|
Q_OBJECT
|
||||||
|
public:
|
||||||
|
EyeDiagramPlot(QDialog *dialog);
|
||||||
|
|
||||||
|
void setDialog(EyeDiagramDialog *dialog);
|
||||||
|
|
||||||
|
private:
|
||||||
|
void paintEvent(QPaintEvent *event) override;
|
||||||
|
|
||||||
|
EyeDiagramDialog *dialog;
|
||||||
|
};
|
||||||
|
|
||||||
|
class EyeDiagramDialog : public QDialog
|
||||||
|
{
|
||||||
|
Q_OBJECT
|
||||||
|
|
||||||
|
public:
|
||||||
|
explicit EyeDiagramDialog(TraceModel &model);
|
||||||
|
~EyeDiagramDialog();
|
||||||
|
|
||||||
|
double getIntensity(unsigned int x, unsigned int y);
|
||||||
|
|
||||||
|
public slots:
|
||||||
|
bool triggerUpdate();
|
||||||
|
bool update(unsigned int width, unsigned int height);
|
||||||
|
|
||||||
|
signals:
|
||||||
|
void updateDone();
|
||||||
|
|
||||||
|
private:
|
||||||
|
signals:
|
||||||
|
void updatePercent(int percent);
|
||||||
|
|
||||||
|
private:
|
||||||
|
static constexpr double yOverrange = 0.2;
|
||||||
|
void updateThread(unsigned int width, unsigned int height);
|
||||||
|
|
||||||
|
Ui::EyeDiagramDialog *ui;
|
||||||
|
|
||||||
|
Trace *trace;
|
||||||
|
|
||||||
|
std::vector<std::vector<double>> eyeBuffer[2];
|
||||||
|
std::vector<std::vector<double>> *workingBuffer;
|
||||||
|
std::vector<std::vector<double>> *finishedBuffer;
|
||||||
|
|
||||||
|
bool updating;
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif // EYEDIAGRAMDIALOG_H
|
264
Software/PC_Application/LibreVNA-GUI/Tools/eyediagramdialog.ui
Normal file
264
Software/PC_Application/LibreVNA-GUI/Tools/eyediagramdialog.ui
Normal file
@ -0,0 +1,264 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<ui version="4.0">
|
||||||
|
<class>EyeDiagramDialog</class>
|
||||||
|
<widget class="QDialog" name="EyeDiagramDialog">
|
||||||
|
<property name="geometry">
|
||||||
|
<rect>
|
||||||
|
<x>0</x>
|
||||||
|
<y>0</y>
|
||||||
|
<width>909</width>
|
||||||
|
<height>544</height>
|
||||||
|
</rect>
|
||||||
|
</property>
|
||||||
|
<property name="windowTitle">
|
||||||
|
<string>Eye Diagram</string>
|
||||||
|
</property>
|
||||||
|
<property name="modal">
|
||||||
|
<bool>true</bool>
|
||||||
|
</property>
|
||||||
|
<layout class="QHBoxLayout" name="horizontalLayout" stretch="0,1">
|
||||||
|
<item>
|
||||||
|
<layout class="QVBoxLayout" name="verticalLayout_2">
|
||||||
|
<item>
|
||||||
|
<widget class="QGroupBox" name="groupBox_3">
|
||||||
|
<property name="title">
|
||||||
|
<string>Trace Selection</string>
|
||||||
|
</property>
|
||||||
|
<layout class="QFormLayout" name="formLayout_3">
|
||||||
|
<item row="0" column="0">
|
||||||
|
<widget class="QLabel" name="label_11">
|
||||||
|
<property name="text">
|
||||||
|
<string>Transmission line trace:</string>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item row="0" column="1">
|
||||||
|
<widget class="QComboBox" name="traceSelector"/>
|
||||||
|
</item>
|
||||||
|
</layout>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
<widget class="QGroupBox" name="groupBox">
|
||||||
|
<property name="title">
|
||||||
|
<string>Input Datastream Configuration</string>
|
||||||
|
</property>
|
||||||
|
<layout class="QFormLayout" name="formLayout">
|
||||||
|
<item row="0" column="0">
|
||||||
|
<widget class="QLabel" name="label">
|
||||||
|
<property name="text">
|
||||||
|
<string>Data rate:</string>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item row="0" column="1">
|
||||||
|
<widget class="SIUnitEdit" name="datarate"/>
|
||||||
|
</item>
|
||||||
|
<item row="1" column="0">
|
||||||
|
<widget class="QLabel" name="label_2">
|
||||||
|
<property name="text">
|
||||||
|
<string>Rise time:</string>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item row="1" column="1">
|
||||||
|
<widget class="SIUnitEdit" name="risetime"/>
|
||||||
|
</item>
|
||||||
|
<item row="2" column="0">
|
||||||
|
<widget class="QLabel" name="label_3">
|
||||||
|
<property name="text">
|
||||||
|
<string>Fall time:</string>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item row="2" column="1">
|
||||||
|
<widget class="SIUnitEdit" name="falltime"/>
|
||||||
|
</item>
|
||||||
|
<item row="3" column="0">
|
||||||
|
<widget class="QLabel" name="label_4">
|
||||||
|
<property name="text">
|
||||||
|
<string>High level:</string>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item row="3" column="1">
|
||||||
|
<widget class="SIUnitEdit" name="highLevel"/>
|
||||||
|
</item>
|
||||||
|
<item row="4" column="0">
|
||||||
|
<widget class="QLabel" name="label_5">
|
||||||
|
<property name="text">
|
||||||
|
<string>Low level:</string>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item row="4" column="1">
|
||||||
|
<widget class="SIUnitEdit" name="lowLevel"/>
|
||||||
|
</item>
|
||||||
|
<item row="5" column="0">
|
||||||
|
<widget class="QLabel" name="label_6">
|
||||||
|
<property name="text">
|
||||||
|
<string>Noise (RMS):</string>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item row="5" column="1">
|
||||||
|
<widget class="SIUnitEdit" name="noise"/>
|
||||||
|
</item>
|
||||||
|
<item row="6" column="0">
|
||||||
|
<widget class="QLabel" name="label_7">
|
||||||
|
<property name="text">
|
||||||
|
<string>Jitter (RMS):</string>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item row="6" column="1">
|
||||||
|
<widget class="SIUnitEdit" name="jitter"/>
|
||||||
|
</item>
|
||||||
|
<item row="7" column="0">
|
||||||
|
<widget class="QLabel" name="label_8">
|
||||||
|
<property name="text">
|
||||||
|
<string>Pattern length:</string>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item row="7" column="1">
|
||||||
|
<widget class="QComboBox" name="patternLength">
|
||||||
|
<property name="currentIndex">
|
||||||
|
<number>7</number>
|
||||||
|
</property>
|
||||||
|
<item>
|
||||||
|
<property name="text">
|
||||||
|
<string>3</string>
|
||||||
|
</property>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
<property name="text">
|
||||||
|
<string>7</string>
|
||||||
|
</property>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
<property name="text">
|
||||||
|
<string>15</string>
|
||||||
|
</property>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
<property name="text">
|
||||||
|
<string>31</string>
|
||||||
|
</property>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
<property name="text">
|
||||||
|
<string>63</string>
|
||||||
|
</property>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
<property name="text">
|
||||||
|
<string>127</string>
|
||||||
|
</property>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
<property name="text">
|
||||||
|
<string>255</string>
|
||||||
|
</property>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
<property name="text">
|
||||||
|
<string>511</string>
|
||||||
|
</property>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
<property name="text">
|
||||||
|
<string>1023</string>
|
||||||
|
</property>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
<property name="text">
|
||||||
|
<string>2047</string>
|
||||||
|
</property>
|
||||||
|
</item>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
</layout>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
<widget class="QGroupBox" name="groupBox_2">
|
||||||
|
<property name="title">
|
||||||
|
<string>Eye Calculation</string>
|
||||||
|
</property>
|
||||||
|
<layout class="QVBoxLayout" name="verticalLayout">
|
||||||
|
<item>
|
||||||
|
<layout class="QFormLayout" name="formLayout_2">
|
||||||
|
<item row="0" column="0">
|
||||||
|
<widget class="QLabel" name="label_9">
|
||||||
|
<property name="text">
|
||||||
|
<string>Displayed cycles:</string>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item row="0" column="1">
|
||||||
|
<widget class="QSpinBox" name="displayedCycles">
|
||||||
|
<property name="minimum">
|
||||||
|
<number>1</number>
|
||||||
|
</property>
|
||||||
|
<property name="maximum">
|
||||||
|
<number>1000</number>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item row="1" column="0">
|
||||||
|
<widget class="QLabel" name="label_10">
|
||||||
|
<property name="text">
|
||||||
|
<string>Update when trace changes:</string>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item row="1" column="1">
|
||||||
|
<widget class="QCheckBox" name="updateOnTraceChange">
|
||||||
|
<property name="text">
|
||||||
|
<string/>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
</layout>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
<widget class="QPushButton" name="update">
|
||||||
|
<property name="text">
|
||||||
|
<string>Update</string>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
<widget class="QProgressBar" name="progress">
|
||||||
|
<property name="value">
|
||||||
|
<number>0</number>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
</layout>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
</layout>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
<widget class="EyeDiagramPlot" name="widget" native="true"/>
|
||||||
|
</item>
|
||||||
|
</layout>
|
||||||
|
</widget>
|
||||||
|
<customwidgets>
|
||||||
|
<customwidget>
|
||||||
|
<class>SIUnitEdit</class>
|
||||||
|
<extends>QLineEdit</extends>
|
||||||
|
<header>CustomWidgets/siunitedit.h</header>
|
||||||
|
</customwidget>
|
||||||
|
<customwidget>
|
||||||
|
<class>EyeDiagramPlot</class>
|
||||||
|
<extends>QWidget</extends>
|
||||||
|
<header>Tools/eyediagramdialog.h</header>
|
||||||
|
<container>1</container>
|
||||||
|
</customwidget>
|
||||||
|
</customwidgets>
|
||||||
|
<resources/>
|
||||||
|
<connections/>
|
||||||
|
</ui>
|
@ -450,8 +450,8 @@
|
|||||||
</connection>
|
</connection>
|
||||||
</connections>
|
</connections>
|
||||||
<buttongroups>
|
<buttongroups>
|
||||||
|
<buttongroup name="lGroup"/>
|
||||||
<buttongroup name="zGroup"/>
|
<buttongroup name="zGroup"/>
|
||||||
<buttongroup name="cGroup"/>
|
<buttongroup name="cGroup"/>
|
||||||
<buttongroup name="lGroup"/>
|
|
||||||
</buttongroups>
|
</buttongroups>
|
||||||
</ui>
|
</ui>
|
||||||
|
@ -16,7 +16,7 @@ class TDRThread : public QThread
|
|||||||
Q_OBJECT
|
Q_OBJECT
|
||||||
public:
|
public:
|
||||||
TDRThread(TDR &tdr);
|
TDRThread(TDR &tdr);
|
||||||
~TDRThread(){};
|
~TDRThread(){}
|
||||||
private:
|
private:
|
||||||
void run() override;
|
void run() override;
|
||||||
TDR &tdr;
|
TDR &tdr;
|
||||||
@ -38,7 +38,7 @@ public:
|
|||||||
|
|
||||||
virtual nlohmann::json toJSON() override;
|
virtual nlohmann::json toJSON() override;
|
||||||
virtual void fromJSON(nlohmann::json j) override;
|
virtual void fromJSON(nlohmann::json j) override;
|
||||||
Type getType() override {return Type::TDR;};
|
Type getType() override {return Type::TDR;}
|
||||||
|
|
||||||
enum class Mode {
|
enum class Mode {
|
||||||
Lowpass,
|
Lowpass,
|
||||||
|
@ -101,13 +101,13 @@ public:
|
|||||||
// indicate whether this function produces time or frequency domain data
|
// indicate whether this function produces time or frequency domain data
|
||||||
virtual DataType outputType(DataType inputType) = 0;
|
virtual DataType outputType(DataType inputType) = 0;
|
||||||
virtual QString description() = 0;
|
virtual QString description() = 0;
|
||||||
virtual void edit(){};
|
virtual void edit(){}
|
||||||
|
|
||||||
void removeInput();
|
void removeInput();
|
||||||
void assignInput(TraceMath *input);
|
void assignInput(TraceMath *input);
|
||||||
|
|
||||||
DataType getDataType() const;
|
DataType getDataType() const;
|
||||||
std::vector<Data>& rData() { return data;};
|
std::vector<Data>& rData() { return data;}
|
||||||
Status getStatus() const;
|
Status getStatus() const;
|
||||||
QString getStatusDescription() const;
|
QString getStatusDescription() const;
|
||||||
virtual Type getType() = 0;
|
virtual Type getType() = 0;
|
||||||
@ -119,7 +119,7 @@ public:
|
|||||||
|
|
||||||
public slots:
|
public slots:
|
||||||
// some values of the input data have changed, begin/end determine which sample(s) has changed
|
// some values of the input data have changed, begin/end determine which sample(s) has changed
|
||||||
virtual void inputSamplesChanged(unsigned int begin, unsigned int end){Q_UNUSED(begin) Q_UNUSED(end)};
|
virtual void inputSamplesChanged(unsigned int begin, unsigned int end){Q_UNUSED(begin) Q_UNUSED(end)}
|
||||||
|
|
||||||
void inputTypeChanged(DataType type);
|
void inputTypeChanged(DataType type);
|
||||||
|
|
||||||
|
@ -241,7 +241,7 @@ void TraceWaterfall::draw(QPainter &p)
|
|||||||
}
|
}
|
||||||
p.drawRect(legendRect);
|
p.drawRect(legendRect);
|
||||||
for(int i=plotAreaTop + 1;i<plotAreaBottom;i++) {
|
for(int i=plotAreaTop + 1;i<plotAreaBottom;i++) {
|
||||||
auto color = getColor(Util::Scale<double>(i, plotAreaTop, plotAreaBottom, 1.0, 0.0));
|
auto color = Util::getIntensityGradeColor(Util::Scale<double>(i, plotAreaTop, plotAreaBottom, 1.0, 0.0));
|
||||||
p.setPen(QColor(color));
|
p.setPen(QColor(color));
|
||||||
pen.setCosmetic(true);
|
pen.setCosmetic(true);
|
||||||
p.drawLine(legendRect.x()+1, i, legendRect.x()+legendRect.width()-1, i);
|
p.drawLine(legendRect.x()+1, i, legendRect.x()+legendRect.width()-1, i);
|
||||||
@ -387,7 +387,7 @@ void TraceWaterfall::draw(QPainter &p)
|
|||||||
}
|
}
|
||||||
x_stop = xAxis.transform(x_stop, plotAreaLeft, plotAreaLeft + plotAreaWidth);
|
x_stop = xAxis.transform(x_stop, plotAreaLeft, plotAreaLeft + plotAreaWidth);
|
||||||
auto y = yAxis.sampleToCoordinate(sweep[s]);
|
auto y = yAxis.sampleToCoordinate(sweep[s]);
|
||||||
auto color = getColor(yAxis.transform(y, 0.0, 1.0));
|
auto color = Util::getIntensityGradeColor(yAxis.transform(y, 0.0, 1.0));
|
||||||
auto rect = QRect(round(x_start), ytop, round(x_stop - x_start) + 1, ybottom - ytop + 1);
|
auto rect = QRect(round(x_start), ytop, round(x_stop - x_start) + 1, ybottom - ytop + 1);
|
||||||
p.fillRect(rect, QBrush(color));
|
p.fillRect(rect, QBrush(color));
|
||||||
}
|
}
|
||||||
@ -569,19 +569,6 @@ void TraceWaterfall::updateYAxis()
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
QColor TraceWaterfall::getColor(double scale)
|
|
||||||
{
|
|
||||||
if(scale < 0.0) {
|
|
||||||
return Qt::black;
|
|
||||||
} else if(scale > 1.0) {
|
|
||||||
return Qt::white;
|
|
||||||
} else if(scale >= 0.0 && scale <= 1.0) {
|
|
||||||
return QColor::fromHsv(Util::Scale<double>(scale, 0.0, 1.0, 240, 0), 255, 255);
|
|
||||||
} else {
|
|
||||||
return Qt::black;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
QString TraceWaterfall::AlignmentToString(Alignment a)
|
QString TraceWaterfall::AlignmentToString(Alignment a)
|
||||||
{
|
{
|
||||||
switch(a) {
|
switch(a) {
|
||||||
|
@ -44,9 +44,6 @@ protected slots:
|
|||||||
private slots:
|
private slots:
|
||||||
void updateYAxis();
|
void updateYAxis();
|
||||||
private:
|
private:
|
||||||
// color scale, input value from 0.0 to 1.0
|
|
||||||
QColor getColor(double scale);
|
|
||||||
|
|
||||||
enum class Direction {
|
enum class Direction {
|
||||||
TopToBottom,
|
TopToBottom,
|
||||||
BottomToTop,
|
BottomToTop,
|
||||||
|
43
Software/PC_Application/LibreVNA-GUI/Util/prbs.cpp
Normal file
43
Software/PC_Application/LibreVNA-GUI/Util/prbs.cpp
Normal file
@ -0,0 +1,43 @@
|
|||||||
|
#include "prbs.h"
|
||||||
|
|
||||||
|
#include <array>
|
||||||
|
|
||||||
|
PRBS::PRBS(unsigned int bits)
|
||||||
|
{
|
||||||
|
this->bits = bits;
|
||||||
|
|
||||||
|
// from https://www.eetimes.com/tutorial-linear-feedback-shift-registers-lfsrs-part-1/
|
||||||
|
const std::array<unsigned int, 12> polynoms = {{
|
||||||
|
0x00000000,
|
||||||
|
0x00000000,
|
||||||
|
0x00000003,
|
||||||
|
0x00000005,
|
||||||
|
0x00000009,
|
||||||
|
0x00000012,
|
||||||
|
0x00000021,
|
||||||
|
0x00000041,
|
||||||
|
0x0000008E,
|
||||||
|
0x00000108,
|
||||||
|
0x00000204,
|
||||||
|
0x00000402,
|
||||||
|
}};
|
||||||
|
if(bits < 2 || bits >= polynoms.size()) {
|
||||||
|
throw std::runtime_error("Bit size not supported");
|
||||||
|
}
|
||||||
|
polynom = polynoms[bits];
|
||||||
|
shiftReg = 0xFFFFFFFF;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool PRBS::next()
|
||||||
|
{
|
||||||
|
bool newbit = false;
|
||||||
|
unsigned int mask = 0x01;
|
||||||
|
for(unsigned int i=0;i<bits;i++) {
|
||||||
|
if(polynom & mask & shiftReg) {
|
||||||
|
newbit = !newbit;
|
||||||
|
}
|
||||||
|
mask <<= 1;
|
||||||
|
}
|
||||||
|
shiftReg = (shiftReg << 1) | (newbit ? 0x01 : 0x00);
|
||||||
|
return newbit;
|
||||||
|
}
|
18
Software/PC_Application/LibreVNA-GUI/Util/prbs.h
Normal file
18
Software/PC_Application/LibreVNA-GUI/Util/prbs.h
Normal file
@ -0,0 +1,18 @@
|
|||||||
|
#ifndef PRBS_H
|
||||||
|
#define PRBS_H
|
||||||
|
|
||||||
|
|
||||||
|
class PRBS
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
PRBS(unsigned int bits);
|
||||||
|
|
||||||
|
bool next();
|
||||||
|
|
||||||
|
private:
|
||||||
|
unsigned int bits;
|
||||||
|
unsigned int shiftReg;
|
||||||
|
unsigned int polynom;
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif // PRBS_H
|
@ -188,3 +188,16 @@ std::complex<double> Util::addTransmissionLine(std::complex<double> termination_
|
|||||||
|
|
||||||
return Gamma_i;
|
return Gamma_i;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
QColor Util::getIntensityGradeColor(double intensity)
|
||||||
|
{
|
||||||
|
if(intensity < 0.0) {
|
||||||
|
return Qt::black;
|
||||||
|
} else if(intensity > 1.0) {
|
||||||
|
return Qt::white;
|
||||||
|
} else if(intensity >= 0.0 && intensity <= 1.0) {
|
||||||
|
return QColor::fromHsv(Util::Scale<double>(intensity, 0.0, 1.0, 240, 0), 255, 255);
|
||||||
|
} else {
|
||||||
|
return Qt::black;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@ -88,6 +88,9 @@ namespace Util {
|
|||||||
result1 = (-b + root) / (T(2) * a);
|
result1 = (-b + root) / (T(2) * a);
|
||||||
result2 = (-b - root) / (T(2) * a);
|
result2 = (-b - root) / (T(2) * a);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// intensity color scale, input value from 0.0 to 1.0
|
||||||
|
QColor getIntensityGradeColor(double intensity);
|
||||||
}
|
}
|
||||||
|
|
||||||
#endif // UTILH_H
|
#endif // UTILH_H
|
||||||
|
@ -12,6 +12,7 @@
|
|||||||
#include "CustomWidgets/siunitedit.h"
|
#include "CustomWidgets/siunitedit.h"
|
||||||
#include "Traces/Marker/markerwidget.h"
|
#include "Traces/Marker/markerwidget.h"
|
||||||
#include "Tools/impedancematchdialog.h"
|
#include "Tools/impedancematchdialog.h"
|
||||||
|
#include "Tools/eyediagramdialog.h"
|
||||||
#include "ui_main.h"
|
#include "ui_main.h"
|
||||||
#include "Device/firmwareupdatedialog.h"
|
#include "Device/firmwareupdatedialog.h"
|
||||||
#include "preferences.h"
|
#include "preferences.h"
|
||||||
@ -182,6 +183,8 @@ VNA::VNA(AppWindow *window, QString name)
|
|||||||
actions.insert(toolsMenu->menuAction());
|
actions.insert(toolsMenu->menuAction());
|
||||||
auto impedanceMatching = toolsMenu->addAction("Impedance Matching");
|
auto impedanceMatching = toolsMenu->addAction("Impedance Matching");
|
||||||
connect(impedanceMatching, &QAction::triggered, this, &VNA::StartImpedanceMatching);
|
connect(impedanceMatching, &QAction::triggered, this, &VNA::StartImpedanceMatching);
|
||||||
|
auto eyeDiagram = toolsMenu->addAction("Eye Diagram");
|
||||||
|
connect(eyeDiagram, &QAction::triggered, this, &VNA::StartEyeDiagram);
|
||||||
|
|
||||||
defaultCalMenu = new QMenu("Default Calibration", window);
|
defaultCalMenu = new QMenu("Default Calibration", window);
|
||||||
assignDefaultCal = defaultCalMenu->addAction("Assign...");
|
assignDefaultCal = defaultCalMenu->addAction("Assign...");
|
||||||
@ -952,6 +955,14 @@ void VNA::StartImpedanceMatching()
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void VNA::StartEyeDiagram()
|
||||||
|
{
|
||||||
|
auto dialog = new EyeDiagramDialog(traceModel);
|
||||||
|
if(AppWindow::showGUI()) {
|
||||||
|
dialog->show();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
void VNA::SetSweepType(SweepType sw)
|
void VNA::SetSweepType(SweepType sw)
|
||||||
{
|
{
|
||||||
|
@ -81,6 +81,7 @@ public slots:
|
|||||||
private slots:
|
private slots:
|
||||||
void NewDatapoint(VirtualDevice::VNAMeasurement m);
|
void NewDatapoint(VirtualDevice::VNAMeasurement m);
|
||||||
void StartImpedanceMatching();
|
void StartImpedanceMatching();
|
||||||
|
void StartEyeDiagram();
|
||||||
// Sweep control
|
// Sweep control
|
||||||
void SetSweepType(SweepType sw);
|
void SetSweepType(SweepType sw);
|
||||||
void SetStartFreq(double freq);
|
void SetStartFreq(double freq);
|
||||||
|
@ -40,6 +40,7 @@ SOURCES += \
|
|||||||
../LibreVNA-GUI/SpectrumAnalyzer/spectrumanalyzer.cpp \
|
../LibreVNA-GUI/SpectrumAnalyzer/spectrumanalyzer.cpp \
|
||||||
../LibreVNA-GUI/SpectrumAnalyzer/tracewidgetsa.cpp \
|
../LibreVNA-GUI/SpectrumAnalyzer/tracewidgetsa.cpp \
|
||||||
../LibreVNA-GUI/Tools/eseries.cpp \
|
../LibreVNA-GUI/Tools/eseries.cpp \
|
||||||
|
../LibreVNA-GUI/Tools/eyediagramdialog.cpp \
|
||||||
../LibreVNA-GUI/Tools/impedancematchdialog.cpp \
|
../LibreVNA-GUI/Tools/impedancematchdialog.cpp \
|
||||||
../LibreVNA-GUI/Tools/parameters.cpp \
|
../LibreVNA-GUI/Tools/parameters.cpp \
|
||||||
../LibreVNA-GUI/Traces/Marker/marker.cpp \
|
../LibreVNA-GUI/Traces/Marker/marker.cpp \
|
||||||
@ -108,6 +109,7 @@ SOURCES += \
|
|||||||
../LibreVNA-GUI/Traces/tracexyplot.cpp \
|
../LibreVNA-GUI/Traces/tracexyplot.cpp \
|
||||||
../LibreVNA-GUI/Traces/waterfallaxisdialog.cpp \
|
../LibreVNA-GUI/Traces/waterfallaxisdialog.cpp \
|
||||||
../LibreVNA-GUI/Traces/xyplotaxisdialog.cpp \
|
../LibreVNA-GUI/Traces/xyplotaxisdialog.cpp \
|
||||||
|
../LibreVNA-GUI/Util/prbs.cpp \
|
||||||
../LibreVNA-GUI/Util/util.cpp \
|
../LibreVNA-GUI/Util/util.cpp \
|
||||||
../LibreVNA-GUI/VNA/Deembedding/deembedding.cpp \
|
../LibreVNA-GUI/VNA/Deembedding/deembedding.cpp \
|
||||||
../LibreVNA-GUI/VNA/Deembedding/deembeddingdialog.cpp \
|
../LibreVNA-GUI/VNA/Deembedding/deembeddingdialog.cpp \
|
||||||
@ -201,6 +203,7 @@ HEADERS += \
|
|||||||
../LibreVNA-GUI/SpectrumAnalyzer/spectrumanalyzer.h \
|
../LibreVNA-GUI/SpectrumAnalyzer/spectrumanalyzer.h \
|
||||||
../LibreVNA-GUI/SpectrumAnalyzer/tracewidgetsa.h \
|
../LibreVNA-GUI/SpectrumAnalyzer/tracewidgetsa.h \
|
||||||
../LibreVNA-GUI/Tools/eseries.h \
|
../LibreVNA-GUI/Tools/eseries.h \
|
||||||
|
../LibreVNA-GUI/Tools/eyediagramdialog.h \
|
||||||
../LibreVNA-GUI/Tools/impedancematchdialog.h \
|
../LibreVNA-GUI/Tools/impedancematchdialog.h \
|
||||||
../LibreVNA-GUI/Tools/parameters.h \
|
../LibreVNA-GUI/Tools/parameters.h \
|
||||||
../LibreVNA-GUI/Traces/Marker/marker.h \
|
../LibreVNA-GUI/Traces/Marker/marker.h \
|
||||||
@ -280,6 +283,7 @@ HEADERS += \
|
|||||||
../LibreVNA-GUI/Traces/tracexyplot.h \
|
../LibreVNA-GUI/Traces/tracexyplot.h \
|
||||||
../LibreVNA-GUI/Traces/waterfallaxisdialog.h \
|
../LibreVNA-GUI/Traces/waterfallaxisdialog.h \
|
||||||
../LibreVNA-GUI/Traces/xyplotaxisdialog.h \
|
../LibreVNA-GUI/Traces/xyplotaxisdialog.h \
|
||||||
|
../LibreVNA-GUI/Util/prbs.h \
|
||||||
../LibreVNA-GUI/Util/util.h \
|
../LibreVNA-GUI/Util/util.h \
|
||||||
../LibreVNA-GUI/VNA/Deembedding/deembedding.h \
|
../LibreVNA-GUI/VNA/Deembedding/deembedding.h \
|
||||||
../LibreVNA-GUI/VNA/Deembedding/deembeddingdialog.h \
|
../LibreVNA-GUI/VNA/Deembedding/deembeddingdialog.h \
|
||||||
@ -339,6 +343,7 @@ FORMS += \
|
|||||||
../LibreVNA-GUI/Device/firmwareupdatedialog.ui \
|
../LibreVNA-GUI/Device/firmwareupdatedialog.ui \
|
||||||
../LibreVNA-GUI/Device/manualcontroldialog.ui \
|
../LibreVNA-GUI/Device/manualcontroldialog.ui \
|
||||||
../LibreVNA-GUI/Generator/signalgenwidget.ui \
|
../LibreVNA-GUI/Generator/signalgenwidget.ui \
|
||||||
|
../LibreVNA-GUI/Tools/eyediagramdialog.ui \
|
||||||
../LibreVNA-GUI/Tools/impedancematchdialog.ui \
|
../LibreVNA-GUI/Tools/impedancematchdialog.ui \
|
||||||
../LibreVNA-GUI/Traces/Marker/markerwidget.ui \
|
../LibreVNA-GUI/Traces/Marker/markerwidget.ui \
|
||||||
../LibreVNA-GUI/Traces/Math/dftdialog.ui \
|
../LibreVNA-GUI/Traces/Math/dftdialog.ui \
|
||||||
|
Loading…
Reference in New Issue
Block a user