Improve display of eye diagram
This commit is contained in:
parent
ee3c6274ad
commit
b9b501bd00
@ -321,8 +321,7 @@ void TDRThread::run()
|
||||
|
||||
Fft::transform(frequencyDomain, true);
|
||||
|
||||
tdr.data.clear();
|
||||
tdr.data.resize(fft_bins);
|
||||
tdr.data.resize(fft_bins, TraceMath::Data());
|
||||
|
||||
for(unsigned int i = 0;i<fft_bins;i++) {
|
||||
tdr.data[i].x = fs * i;
|
||||
|
@ -53,6 +53,7 @@ public:
|
||||
|
||||
class Data {
|
||||
public:
|
||||
Data() : x(){}
|
||||
double x;
|
||||
std::complex<double> y;
|
||||
};
|
||||
|
@ -405,6 +405,20 @@
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="2" column="0">
|
||||
<widget class="QLabel" name="label_10">
|
||||
<property name="text">
|
||||
<string>Trace blurring:</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="2" column="1">
|
||||
<widget class="QSpinBox" name="traceBlurring">
|
||||
<property name="maximum">
|
||||
<number>20</number>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
</item>
|
||||
|
@ -34,7 +34,8 @@ EyeDiagramPlot::EyeDiagramPlot(TraceModel &model, QWidget *parent)
|
||||
jitter(0.0000000001),
|
||||
linearEdge(true),
|
||||
patternbits(9),
|
||||
cycles(200)
|
||||
cycles(200),
|
||||
traceBlurring(2)
|
||||
{
|
||||
plotAreaTop = 0;
|
||||
plotAreaLeft = 0;
|
||||
@ -179,6 +180,7 @@ void EyeDiagramPlot::fromJSON(nlohmann::json j)
|
||||
patternbits = j.value("patternBits", patternbits);
|
||||
cycles = j.value("cycles", cycles);
|
||||
xSamples = j.value("xSamples", xSamples);
|
||||
traceBlurring = j.value("traceBlurring", traceBlurring);
|
||||
|
||||
for(unsigned int hash : j["traces"]) {
|
||||
// attempt to find the traces with this hash
|
||||
@ -231,6 +233,7 @@ nlohmann::json EyeDiagramPlot::toJSON()
|
||||
j["patternBits"] = patternbits;
|
||||
j["cycles"] = cycles;
|
||||
j["xSamples"] = xSamples;
|
||||
j["traceBlurring"] = traceBlurring;
|
||||
return j;
|
||||
}
|
||||
|
||||
@ -308,6 +311,7 @@ void EyeDiagramPlot::axisSetupDialog()
|
||||
|
||||
ui->displayedCycles->setValue(cycles);
|
||||
ui->pointsPerCycle->setValue(xSamples);
|
||||
ui->traceBlurring->setValue(traceBlurring);
|
||||
|
||||
connect(ui->Xauto, &QCheckBox::toggled, [=](bool checked) {
|
||||
ui->Xmin->setEnabled(!checked);
|
||||
@ -345,6 +349,7 @@ void EyeDiagramPlot::axisSetupDialog()
|
||||
|
||||
cycles = ui->displayedCycles->value();
|
||||
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());
|
||||
@ -547,6 +552,9 @@ void EyeDiagramPlot::draw(QPainter &p)
|
||||
|
||||
if(displayData->size() >= 2) {
|
||||
std::lock_guard<std::mutex> guard(bufferSwitchMutex);
|
||||
if((*displayData)[0].y[0] == 0.0 && (*displayData)[0].y[1] == 0.0) {
|
||||
qDebug() << "detected null data, displaydata:" << displayData;
|
||||
}
|
||||
unsigned int pxWidth = plotAreaWidth;
|
||||
unsigned int pxHeight = plotAreaBottom - plotAreaTop;
|
||||
std::vector<std::vector<unsigned int>> bitmap;
|
||||
@ -555,7 +563,7 @@ void EyeDiagramPlot::draw(QPainter &p)
|
||||
y.resize(pxHeight, 0);
|
||||
}
|
||||
unsigned int highestIntensity = 0;
|
||||
unsigned int numTraces = (*displayData)[0].y.size();
|
||||
unsigned int numTraces = (*displayData)[displayData->size()-1].y.size();
|
||||
|
||||
auto addLine = [&](int x0, int y0, int x1, int y1, bool skipFirst = true) {
|
||||
bool first = true;
|
||||
@ -564,13 +572,19 @@ void EyeDiagramPlot::draw(QPainter &p)
|
||||
first = false;
|
||||
return;
|
||||
}
|
||||
if(x < 0 || x >= (int) pxWidth || y < 0 || y >= (int) pxHeight) {
|
||||
return;
|
||||
}
|
||||
auto &bin = bitmap[x][y];
|
||||
bin++;
|
||||
if(bin > highestIntensity) {
|
||||
highestIntensity = bin;
|
||||
for(int i=-traceBlurring;i<=traceBlurring;i++) {
|
||||
for(int j=-traceBlurring;j<=traceBlurring;j++) {
|
||||
if(i*i+j*j <= traceBlurring*traceBlurring) {
|
||||
if(x+i < 0 || x+i >= (int) pxWidth || y+j < 0 || y+j >= (int) pxHeight) {
|
||||
return;
|
||||
}
|
||||
auto &bin = bitmap[x+i][y+j];
|
||||
bin++;
|
||||
if(bin > highestIntensity) {
|
||||
highestIntensity = bin;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
@ -588,7 +602,7 @@ void EyeDiagramPlot::draw(QPainter &p)
|
||||
};
|
||||
|
||||
// Assemble the bitmap
|
||||
for(unsigned int i=1;i<xSamples;i++) {
|
||||
for(unsigned int i=1;i<displayData->size();i++) {
|
||||
int x0 = xAxis.transform((*displayData)[i-1].x, 0, pxWidth);
|
||||
int x1 = xAxis.transform((*displayData)[i].x, 0, pxWidth);
|
||||
if((x0 < 0 && x1 < 0) || (x0 >= (int) pxWidth && x1 >= (int) pxWidth)) {
|
||||
@ -602,19 +616,46 @@ void EyeDiagramPlot::draw(QPainter &p)
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Only a small amount of pixels will have a lot of traces of top of each other.
|
||||
* This would result in using mostly the colder colors in the intensity grading.
|
||||
*
|
||||
* Generate a histogram of pixel usage and create an adjustment curve to evenly
|
||||
* distribute all intensity colors
|
||||
*/
|
||||
unsigned int hist[highestIntensity+1];
|
||||
memset(hist, 0, sizeof(hist));
|
||||
unsigned long total = 0;
|
||||
for(unsigned int i=1;i<pxWidth;i++) {
|
||||
for(unsigned int j=0;j<pxHeight;j++) {
|
||||
hist[bitmap[i][j]]++;
|
||||
total++;
|
||||
}
|
||||
}
|
||||
unsigned int sum = 0;
|
||||
double correctedCurve[highestIntensity+1];
|
||||
correctedCurve[0] = 0.0;
|
||||
total -= hist[0];
|
||||
for(unsigned int i=1;i<=highestIntensity;i++) {
|
||||
sum += hist[i];
|
||||
correctedCurve[i] = pow((double) sum / total, 2); // not totally even distribution, x^2 seems to look better
|
||||
}
|
||||
|
||||
// draw the bitmap
|
||||
pen = QPen();
|
||||
pen.setCosmetic(true);
|
||||
for(unsigned int i=1;i<pxWidth;i++) {
|
||||
for(unsigned int j=0;j<pxHeight;j++) {
|
||||
if(bitmap[i][j] > 0) {
|
||||
double value = (double) bitmap[i][j] / highestIntensity;
|
||||
double value = correctedCurve[bitmap[i][j]];
|
||||
pen.setColor(Util::getIntensityGradeColor(value));
|
||||
p.setPen(pen);
|
||||
p.drawPoint(plotAreaLeft + i + 1, plotAreaTop + j + 1);
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
qDebug() << "Empty eye data, displaydata:" << displayData;
|
||||
}
|
||||
if(dropPending) {
|
||||
p.setOpacity(0.5);
|
||||
@ -627,7 +668,7 @@ void EyeDiagramPlot::draw(QPainter &p)
|
||||
p.setFont(font);
|
||||
p.setOpacity(1.0);
|
||||
p.setPen(Qt::white);
|
||||
auto text = "Drop here to add\n" + dropTrace->name() + "\nto waterfall plot";
|
||||
auto text = "Drop here to add\n" + dropTrace->name() + "\nto eye diagram";
|
||||
p.drawText(plotRect, Qt::AlignCenter, text);
|
||||
}
|
||||
}
|
||||
@ -720,6 +761,7 @@ void EyeDiagramPlot::updateThread(unsigned int xSamples)
|
||||
std::vector<std::complex<double>> inVec(xSamples * (cycles + 1), 0.0); // needs to calculate one more cycle than required for the display (settling)
|
||||
|
||||
// resize working buffer
|
||||
qDebug() << "Clearing old eye data, calcData:" << calcData;
|
||||
calcData->clear();
|
||||
calcData->resize(xSamples);
|
||||
for(auto& s : *calcData) {
|
||||
@ -879,12 +921,12 @@ void EyeDiagramPlot::updateThread(unsigned int xSamples)
|
||||
|
||||
// fill data from outVec
|
||||
for(unsigned int i=0;i<xSamples;i++) {
|
||||
(*calcData)[i].x = i * timestep;
|
||||
(*calcData).at(i).x = i * timestep;
|
||||
}
|
||||
for(unsigned int i=xSamples;i<inVec.size();i++) {
|
||||
unsigned int x = i % xSamples;
|
||||
unsigned int y = i / xSamples;
|
||||
(*calcData)[x].y[y] = outVec[i].real();
|
||||
unsigned int y = i / xSamples - 1;
|
||||
(*calcData).at(x).y.at(y) = outVec[i].real();
|
||||
}
|
||||
|
||||
qDebug() << "Eye calculation: Convolution done";
|
||||
@ -892,9 +934,14 @@ void EyeDiagramPlot::updateThread(unsigned int xSamples)
|
||||
{
|
||||
std::lock_guard<std::mutex> guard(bufferSwitchMutex);
|
||||
// switch buffers
|
||||
qDebug() << "Switching diplay buffers, calcData:" << calcData;
|
||||
auto buf = displayData;
|
||||
displayData = calcData;
|
||||
calcData = buf;
|
||||
if((*displayData)[0].y[0] == 0.0 && (*displayData)[0].y[1] == 0.0) {
|
||||
qDebug() << "detected null after eye calculation";
|
||||
}
|
||||
qDebug() << "Buffer switch complete, displayData:" << displayData;
|
||||
}
|
||||
|
||||
setStatus("Eye calculation complete");
|
||||
|
@ -91,6 +91,7 @@ private:
|
||||
bool linearEdge;
|
||||
unsigned int patternbits;
|
||||
unsigned int cycles;
|
||||
int traceBlurring;
|
||||
|
||||
int plotAreaLeft, plotAreaWidth, plotAreaBottom, plotAreaTop;
|
||||
|
||||
|
@ -1,327 +0,0 @@
|
||||
{
|
||||
"Modes": [
|
||||
{
|
||||
"name": "Vector Network Analyzer",
|
||||
"settings": {
|
||||
"de-embedding": null,
|
||||
"de-embedding_enabled": false,
|
||||
"markers": null,
|
||||
"sweep": {
|
||||
"IFBW": 10000.0,
|
||||
"frequency": {
|
||||
"log": false,
|
||||
"power": -10.0,
|
||||
"start": 1000000.0,
|
||||
"stop": 6000000000.0
|
||||
},
|
||||
"points": 501,
|
||||
"power": {
|
||||
"frequency": 1000000000.0,
|
||||
"start": -30.0,
|
||||
"stop": -15.0
|
||||
},
|
||||
"single": false,
|
||||
"type": "Frequency"
|
||||
},
|
||||
"tiles": {
|
||||
"orientation": "vertical",
|
||||
"sizes": [
|
||||
373,
|
||||
372
|
||||
],
|
||||
"split": true,
|
||||
"tile1": {
|
||||
"orientation": "horizontal",
|
||||
"sizes": [
|
||||
797,
|
||||
796
|
||||
],
|
||||
"split": true,
|
||||
"tile1": {
|
||||
"plot": "smithchart",
|
||||
"plotsettings": {
|
||||
"Z0": 50.0,
|
||||
"constantLines": null,
|
||||
"edge_reflection": 1.0,
|
||||
"frequency_override": false,
|
||||
"limit_to_edge": true,
|
||||
"limit_to_span": true,
|
||||
"offset_axis_x": 0.0,
|
||||
"override_max": 6000000000.0,
|
||||
"override_min": 0.0,
|
||||
"traces": [
|
||||
753243053
|
||||
]
|
||||
},
|
||||
"split": false
|
||||
},
|
||||
"tile2": {
|
||||
"plot": "EyeDiagram",
|
||||
"plotsettings": {
|
||||
"XAxis": {
|
||||
"autorange": false,
|
||||
"div": 7.62939453125e-09,
|
||||
"max": 5.653089396158854e-08,
|
||||
"min": -1.9763051350911456e-08
|
||||
},
|
||||
"YAxis": {
|
||||
"autorange": false,
|
||||
"div": 0.3814697265625,
|
||||
"max": 2.9595544473356057,
|
||||
"min": -2.381021724539393
|
||||
},
|
||||
"bitPerSymbol": 1,
|
||||
"cycles": 200,
|
||||
"datarate": 100000000.0,
|
||||
"falltime": 1e-09,
|
||||
"highlevel": 1.0,
|
||||
"jitter": 1e-10,
|
||||
"linearEdge": true,
|
||||
"lowlevel": 0.0,
|
||||
"noise": 0.01,
|
||||
"patternBits": 9,
|
||||
"risetime": 1e-09,
|
||||
"traces": [
|
||||
3153058534
|
||||
],
|
||||
"xSamples": 200
|
||||
},
|
||||
"split": false
|
||||
}
|
||||
},
|
||||
"tile2": {
|
||||
"orientation": "horizontal",
|
||||
"sizes": [
|
||||
797,
|
||||
796
|
||||
],
|
||||
"split": true,
|
||||
"tile1": {
|
||||
"plot": "EyeDiagram",
|
||||
"plotsettings": {
|
||||
"XAxis": {
|
||||
"autorange": true,
|
||||
"div": 1e-07,
|
||||
"max": 1e-06,
|
||||
"min": 0.0
|
||||
},
|
||||
"YAxis": {
|
||||
"autorange": true,
|
||||
"div": 0.1,
|
||||
"max": 1.2,
|
||||
"min": -0.2
|
||||
},
|
||||
"bitPerSymbol": 2,
|
||||
"cycles": 200,
|
||||
"datarate": 2000000.0,
|
||||
"falltime": 1e-09,
|
||||
"highlevel": 1.0,
|
||||
"jitter": 4e-10,
|
||||
"linearEdge": true,
|
||||
"lowlevel": 0.0,
|
||||
"noise": 0.03,
|
||||
"patternBits": 9,
|
||||
"risetime": 1e-09,
|
||||
"traces": [
|
||||
2663219575
|
||||
],
|
||||
"xSamples": 200
|
||||
},
|
||||
"split": false
|
||||
},
|
||||
"tile2": {
|
||||
"plot": "smithchart",
|
||||
"plotsettings": {
|
||||
"Z0": 50.0,
|
||||
"constantLines": null,
|
||||
"edge_reflection": 1.0,
|
||||
"frequency_override": false,
|
||||
"limit_to_edge": true,
|
||||
"limit_to_span": true,
|
||||
"offset_axis_x": 0.0,
|
||||
"override_max": 6000000000.0,
|
||||
"override_min": 0.0,
|
||||
"traces": [
|
||||
1360958916
|
||||
]
|
||||
},
|
||||
"split": false
|
||||
}
|
||||
}
|
||||
},
|
||||
"traces": [
|
||||
{
|
||||
"color": "#ffff00",
|
||||
"hash": 753243053,
|
||||
"livetype": 0,
|
||||
"math": null,
|
||||
"math_enabled": false,
|
||||
"name": "S11",
|
||||
"parameter": "S11",
|
||||
"paused": false,
|
||||
"reflection": true,
|
||||
"type": "Live",
|
||||
"velocityFactor": 0.66,
|
||||
"visible": true
|
||||
},
|
||||
{
|
||||
"color": "#0000ff",
|
||||
"hash": 3153058534,
|
||||
"livetype": 0,
|
||||
"math": null,
|
||||
"math_enabled": false,
|
||||
"name": "S12",
|
||||
"parameter": "S12",
|
||||
"paused": false,
|
||||
"reflection": false,
|
||||
"type": "Live",
|
||||
"velocityFactor": 0.66,
|
||||
"visible": true
|
||||
},
|
||||
{
|
||||
"color": "#00ff00",
|
||||
"hash": 2663219575,
|
||||
"livetype": 0,
|
||||
"math": null,
|
||||
"math_enabled": false,
|
||||
"name": "S21",
|
||||
"parameter": "S21",
|
||||
"paused": false,
|
||||
"reflection": false,
|
||||
"type": "Live",
|
||||
"velocityFactor": 0.66,
|
||||
"visible": true
|
||||
},
|
||||
{
|
||||
"color": "#ff0000",
|
||||
"hash": 1360958916,
|
||||
"livetype": 0,
|
||||
"math": null,
|
||||
"math_enabled": false,
|
||||
"name": "S22",
|
||||
"parameter": "S22",
|
||||
"paused": false,
|
||||
"reflection": true,
|
||||
"type": "Live",
|
||||
"velocityFactor": 0.66,
|
||||
"visible": true
|
||||
}
|
||||
]
|
||||
},
|
||||
"type": "Vector Network Analyzer"
|
||||
},
|
||||
{
|
||||
"name": "Signal Generator",
|
||||
"settings": {
|
||||
"frequency": 1000000000.0,
|
||||
"port": 0,
|
||||
"power": 0.0,
|
||||
"sweep": {
|
||||
"dwell": 1.0,
|
||||
"enabled": false,
|
||||
"span": 0.0,
|
||||
"steps": 100.0
|
||||
}
|
||||
},
|
||||
"type": "Signal Generator"
|
||||
},
|
||||
{
|
||||
"name": "Spectrum Analyzer",
|
||||
"settings": {
|
||||
"markers": null,
|
||||
"sweep": {
|
||||
"acquisition": {
|
||||
"RBW": 100.0,
|
||||
"detector": "+Peak",
|
||||
"signal ID": true,
|
||||
"window": "Kaiser"
|
||||
},
|
||||
"frequency": {
|
||||
"start": 999975000.0,
|
||||
"stop": 1000025000.0
|
||||
},
|
||||
"single": false,
|
||||
"trackingGenerator": {
|
||||
"enabled": false,
|
||||
"offset": 0.0,
|
||||
"port": 1,
|
||||
"power": -20.0
|
||||
}
|
||||
},
|
||||
"tiles": {
|
||||
"plot": "XY-plot",
|
||||
"plotsettings": {
|
||||
"XAxis": {
|
||||
"div": 5000.0,
|
||||
"log": false,
|
||||
"max": 1000025000.0,
|
||||
"min": 999975000.0,
|
||||
"mode": "Use Span",
|
||||
"type": "Frequency"
|
||||
},
|
||||
"YPrimary": {
|
||||
"autorange": false,
|
||||
"div": 10.0,
|
||||
"log": false,
|
||||
"max": 0.0,
|
||||
"min": -120.0,
|
||||
"traces": [
|
||||
3115643686,
|
||||
1375490686
|
||||
],
|
||||
"type": "Magnitude"
|
||||
},
|
||||
"YSecondary": {
|
||||
"autorange": true,
|
||||
"div": 0.0,
|
||||
"log": false,
|
||||
"max": 1.0,
|
||||
"min": -1.0,
|
||||
"traces": null,
|
||||
"type": "Disabled"
|
||||
},
|
||||
"limitLines": null
|
||||
},
|
||||
"split": false
|
||||
},
|
||||
"traces": [
|
||||
{
|
||||
"color": "#ffff00",
|
||||
"hash": 1375490686,
|
||||
"livetype": 0,
|
||||
"math": null,
|
||||
"math_enabled": false,
|
||||
"name": "PORT1",
|
||||
"parameter": "PORT1",
|
||||
"paused": false,
|
||||
"reflection": false,
|
||||
"type": "Live",
|
||||
"velocityFactor": 0.66,
|
||||
"visible": true
|
||||
},
|
||||
{
|
||||
"color": "#0000ff",
|
||||
"hash": 3115643686,
|
||||
"livetype": 0,
|
||||
"math": null,
|
||||
"math_enabled": false,
|
||||
"name": "PORT2",
|
||||
"parameter": "PORT2",
|
||||
"paused": false,
|
||||
"reflection": false,
|
||||
"type": "Live",
|
||||
"velocityFactor": 0.66,
|
||||
"visible": true
|
||||
}
|
||||
]
|
||||
},
|
||||
"type": "Spectrum Analyzer"
|
||||
}
|
||||
],
|
||||
"Reference": {
|
||||
"Mode": "Internal",
|
||||
"Output": "Off"
|
||||
},
|
||||
"activeMode": "Vector Network Analyzer",
|
||||
"version": "1.5.0-alpha.1-329f4487e"
|
||||
}
|
Loading…
Reference in New Issue
Block a user