Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fix digital phosphor effect #123

Merged
merged 1 commit into from
Dec 25, 2017
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
182 changes: 96 additions & 86 deletions openhantek/src/glgenerator.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -11,8 +11,8 @@ GlGenerator::GlGenerator(DsoSettingsScope *scope, DsoSettingsView *view) : setti
const int DIVS_TIME_S2 = (int)DIVS_TIME - 2;
const int DIVS_VOLTAGE_S2 = (int)DIVS_VOLTAGE - 2;
const int vaGrid0Size = (int) ((DIVS_TIME * DIVS_SUB - 2) * DIVS_VOLTAGE_S2 +
(DIVS_VOLTAGE * DIVS_SUB - 2) * DIVS_TIME_S2 -
(DIVS_TIME_S2 * DIVS_VOLTAGE_S2)) * 2;
(DIVS_VOLTAGE * DIVS_SUB - 2) * DIVS_TIME_S2 -
(DIVS_TIME_S2 * DIVS_VOLTAGE_S2)) * 2;

vaGrid[0].resize(vaGrid0Size);
std::vector<GLfloat>::iterator glIterator = vaGrid[0].begin();
Expand Down Expand Up @@ -105,106 +105,116 @@ const std::vector<GLfloat> &GlGenerator::grid(int a) const { return vaGrid[a]; }

bool GlGenerator::isReady() const { return ready; }

GlGenerator::PrePostStartTriggerSamples GlGenerator::computeSoftwareTriggerTY(const DataAnalyzerResult *result)
{
unsigned int preTrigSamples = 0;
unsigned int postTrigSamples = 0;
unsigned int swTriggerStart = 0;
unsigned int channel = settings->trigger.source;

// check trigger point for software trigger
if (settings->trigger.mode != Dso::TRIGGERMODE_SOFTWARE || channel >= settings->physicalChannels)
return PrePostStartTriggerSamples(preTrigSamples, postTrigSamples, swTriggerStart);

// Trigger channel not in use
if (!settings->voltage[channel].used || !result->data(channel) ||
result->data(channel)->voltage.sample.empty())
return PrePostStartTriggerSamples(preTrigSamples, postTrigSamples, swTriggerStart);

double value;
double level = settings->voltage[channel].trigger;
unsigned int sampleCount = result->data(channel)->voltage.sample.size();
double timeDisplay = settings->horizontal.timebase * 10;
double samplesDisplay = timeDisplay * settings->horizontal.samplerate;
if (samplesDisplay >= sampleCount) {
// For sure not enough samples to adjust for jitter.
// Following options exist:
// 1: Decrease sample rate
// 2: Change trigger mode to auto
// 3: Ignore samples
// For now #3 is chosen
timestampDebug(QString("Too few samples to make a steady "
"picture. Decrease sample rate"));
return PrePostStartTriggerSamples(preTrigSamples, postTrigSamples, swTriggerStart);
}
preTrigSamples = (settings->trigger.position * samplesDisplay);
postTrigSamples = sampleCount - (samplesDisplay - preTrigSamples);

const int threshold = 7;
double prev;
bool (*opcmp)(int,int,int);
bool (*smplcmp)(int,int);
if (settings->trigger.slope == Dso::SLOPE_POSITIVE) {
prev = INT_MAX;
opcmp = [](int value, int level, int prev) { return value > level && prev <= level;};
smplcmp = [](int sampleK, int value) { return sampleK >= value;};
} else {
prev = INT_MIN;
opcmp = [](int value, int level, int prev) { return value > level && prev <= level;};
smplcmp = [](int sampleK, int value) { return sampleK < value;};
}

for (unsigned int i = preTrigSamples; i < postTrigSamples; i++) {
value = result->data(channel)->voltage.sample[i];
if (opcmp(value, level, prev)) {
int rising = 0;
for (unsigned int k = i + 1; k < i + 11 && k < sampleCount; k++) {
if (smplcmp(result->data(channel)->voltage.sample[k], value)) { rising++; }
}
if (rising > threshold) {
swTriggerStart = i;
break;
}
}
prev = value;
}
if (swTriggerStart == 0) {
timestampDebug(QString("Trigger not asserted. Data ignored"));
}
return PrePostStartTriggerSamples(preTrigSamples, postTrigSamples, swTriggerStart);
}

void GlGenerator::generateGraphs(const DataAnalyzerResult *result) {

int digitalPhosphorDepth = view->digitalPhosphorDepth;
int digitalPhosphorDepth = view->digitalPhosphor ? view->digitalPhosphorDepth : 1;

// Handle all digital phosphor related list manipulations
for (int mode = Dso::CHANNELMODE_VOLTAGE; mode < Dso::CHANNELMODE_COUNT; ++mode) {
// Adapt the number of graphs
vaChannel[mode].resize(settings->voltage.size());
DrawLinesWithHistoryPerChannel& d = vaChannel[mode];
// Resize to the number of channels
d.resize(settings->voltage.size());

for (unsigned int channel = 0; channel < vaChannel[mode].size(); ++channel) {
DrawLinesWithHistory& drawLinesHistory = d[channel];
// Move the last list element to the front
vaChannel[mode][channel].push_front(std::vector<GLfloat>());
if (digitalPhosphorDepth > 1 && drawLinesHistory.size())
drawLinesHistory.push_front(drawLinesHistory.back());

// Resize lists for vector array to fit the digital phosphor depth
vaChannel[mode][channel].resize(digitalPhosphorDepth);
drawLinesHistory.resize(digitalPhosphorDepth);
}
}

ready = true;

unsigned int preTrigSamples = 0;
unsigned int postTrigSamples = 0;
unsigned preTrigSamples;
unsigned postTrigSamples;
unsigned swTriggerStart;
switch (settings->horizontal.format) {
case Dso::GRAPHFORMAT_TY: {
unsigned int swTriggerStart = 0;
// check trigger point for software trigger
if (settings->trigger.mode == Dso::TRIGGERMODE_SOFTWARE && settings->trigger.source <= 1) {
unsigned int channel = settings->trigger.source;
if (settings->voltage[channel].used && result->data(channel) &&
!result->data(channel)->voltage.sample.empty()) {
double value;
double level = settings->voltage[channel].trigger;
unsigned int sampleCount = result->data(channel)->voltage.sample.size();
double timeDisplay = settings->horizontal.timebase * 10;
double samplesDisplay = timeDisplay * settings->horizontal.samplerate;
if (samplesDisplay >= sampleCount) {
// For sure not enough samples to adjust for jitter.
// Following options exist:
// 1: Decrease sample rate
// 2: Change trigger mode to auto
// 3: Ignore samples
// For now #3 is chosen
timestampDebug(QString("Too few samples to make a steady "
"picture. Decrease sample rate"));
return;
}
preTrigSamples = (settings->trigger.position * samplesDisplay);
postTrigSamples = sampleCount - (samplesDisplay - preTrigSamples);

if (settings->trigger.slope == Dso::SLOPE_POSITIVE) {
double prev = INT_MAX;
for (unsigned int i = preTrigSamples; i < postTrigSamples; i++) {
value = result->data(channel)->voltage.sample[i];
if (value > level && prev <= level) {
int rising = 0;
for (unsigned int k = i + 1; k < i + 11 && k < sampleCount; k++) {
if (result->data(channel)->voltage.sample[k] >= value) { rising++; }
}
if (rising > 7) {
swTriggerStart = i;
break;
}
}
prev = value;
}
} else if (settings->trigger.slope == Dso::SLOPE_NEGATIVE) {
double prev = INT_MIN;
for (unsigned int i = preTrigSamples; i < postTrigSamples; i++) {
value = result->data(channel)->voltage.sample[i];
if (value < level && prev >= level) {
int falling = 0;
for (unsigned int k = i + 1; k < i + 11 && k < sampleCount; k++) {
if (result->data(channel)->voltage.sample[k] < value) { falling++; }
}
if (falling > 7) {
swTriggerStart = i;
break;
}
}
prev = value;
}
}
}
if (swTriggerStart == 0) {
timestampDebug(QString("Trigger not asserted. Data ignored"));
return;
}
}
case Dso::GRAPHFORMAT_TY:
std::tie(preTrigSamples, postTrigSamples, swTriggerStart) = computeSoftwareTriggerTY(result);

// Add graphs for channels
for (int mode = Dso::CHANNELMODE_VOLTAGE; mode < Dso::CHANNELMODE_COUNT; ++mode) {
for (int channel = 0; channel < (int)settings->voltage.size(); ++channel) {
// Check if this channel is used and available at the data analyzer
if (((mode == Dso::CHANNELMODE_VOLTAGE) ? settings->voltage[channel].used
: settings->spectrum[channel].used) &&
result->data(channel) && !result->data(channel)->voltage.sample.empty()) {
: settings->spectrum[channel].used) &&
result->data(channel) && !result->data(channel)->voltage.sample.empty()) {
// Check if the sample count has changed
size_t sampleCount = (mode == Dso::CHANNELMODE_VOLTAGE)
? result->data(channel)->voltage.sample.size()
: result->data(channel)->spectrum.sample.size();
? result->data(channel)->voltage.sample.size()
: result->data(channel)->spectrum.sample.size();
if (mode == Dso::CHANNELMODE_VOLTAGE) sampleCount -= (swTriggerStart - preTrigSamples);
size_t neededSize = sampleCount * 2;

Expand All @@ -227,12 +237,12 @@ void GlGenerator::generateGraphs(const DataAnalyzerResult *result) {
horizontalFactor = result->data(channel)->voltage.interval / settings->horizontal.timebase;
else
horizontalFactor =
result->data(channel)->spectrum.interval / settings->horizontal.frequencybase;
result->data(channel)->spectrum.interval / settings->horizontal.frequencybase;

// Fill vector array
if (mode == Dso::CHANNELMODE_VOLTAGE) {
std::vector<double>::const_iterator dataIterator =
result->data(channel)->voltage.sample.begin();
result->data(channel)->voltage.sample.begin();
const double gain = settings->voltage[channel].gain;
const double offset = settings->voltage[channel].offset;
const double invert = settings->voltage[channel].inverted ? -1.0 : 1.0;
Expand All @@ -245,7 +255,7 @@ void GlGenerator::generateGraphs(const DataAnalyzerResult *result) {
}
} else {
std::vector<double>::const_iterator dataIterator =
result->data(channel)->spectrum.sample.begin();
result->data(channel)->spectrum.sample.begin();
const double magnitude = settings->spectrum[channel].magnitude;
const double offset = settings->spectrum[channel].offset;

Expand All @@ -261,31 +271,31 @@ void GlGenerator::generateGraphs(const DataAnalyzerResult *result) {
}
}
}
} break;
break;

case Dso::GRAPHFORMAT_XY:
for (int channel = 0; channel < settings->voltage.size(); ++channel) {
// For even channel numbers check if this channel is used and this and the
// following channel are available at the data analyzer
if (channel % 2 == 0 && channel + 1 < settings->voltage.size() && settings->voltage[channel].used &&
result->data(channel) && !result->data(channel)->voltage.sample.empty() && result->data(channel + 1) &&
!result->data(channel + 1)->voltage.sample.empty()) {
result->data(channel) && !result->data(channel)->voltage.sample.empty() && result->data(channel + 1) &&
!result->data(channel + 1)->voltage.sample.empty()) {
// Check if the sample count has changed
const unsigned sampleCount = qMin(result->data(channel)->voltage.sample.size(),
result->data(channel + 1)->voltage.sample.size());
const unsigned neededSize = sampleCount * 2;
for (unsigned index = 0; index < (unsigned)digitalPhosphorDepth; ++index) {
if (vaChannel[Dso::CHANNELMODE_VOLTAGE][(size_t)channel][index].size() != neededSize)
vaChannel[Dso::CHANNELMODE_VOLTAGE][(size_t)channel][index]
.clear(); // Something was changed, drop old traces
.clear(); // Something was changed, drop old traces
}

// Set size directly to avoid reallocations
vaChannel[Dso::CHANNELMODE_VOLTAGE][(size_t)channel].front().resize(neededSize);

// Iterator to data for direct access
std::vector<GLfloat>::iterator glIterator =
vaChannel[Dso::CHANNELMODE_VOLTAGE][channel].front().begin();
vaChannel[Dso::CHANNELMODE_VOLTAGE][channel].front().begin();

// Fill vector array
unsigned int xChannel = channel;
Expand Down
8 changes: 7 additions & 1 deletion openhantek/src/glgenerator.h
Original file line number Diff line number Diff line change
Expand Up @@ -30,9 +30,15 @@ class GlGenerator : public QObject {
bool isReady() const;

private:
typedef std::tuple<unsigned,unsigned,unsigned> PrePostStartTriggerSamples;
typedef std::vector<GLfloat> DrawLines;
typedef std::deque<DrawLines> DrawLinesWithHistory;
typedef std::vector<DrawLinesWithHistory> DrawLinesWithHistoryPerChannel;
DrawLinesWithHistoryPerChannel vaChannel[Dso::CHANNELMODE_COUNT];

PrePostStartTriggerSamples computeSoftwareTriggerTY(const DataAnalyzerResult *result);
DsoSettingsScope *settings;
DsoSettingsView *view;
std::vector<std::deque<std::vector<GLfloat>>> vaChannel[Dso::CHANNELMODE_COUNT];
std::vector<GLfloat> vaGrid[3];
bool ready = false;
signals:
Expand Down
17 changes: 9 additions & 8 deletions openhantek/src/glscope.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,8 @@ void GlScope::paintGL() {
glClear(GL_COLOR_BUFFER_BIT);
glLineWidth(1);

if (settings->view.digitalPhosphorDepth > 0 && generator->isReady()) { drawGraph(); }
int digitalPhosphorDepth = settings->view.digitalPhosphor ? settings->view.digitalPhosphorDepth : 1;
if (generator->isReady()) { drawGraph(digitalPhosphorDepth); }

if (!this->zoomed) {
// Draw vertical lines at marker positions
Expand Down Expand Up @@ -126,7 +127,7 @@ void GlScope::drawGraphDepth(int mode, int channel, int index) {
generator->channel(mode, channel, index).size() / 2);
}

void GlScope::drawGraph() {
void GlScope::drawGraph(int digitalPhosphorDepth) {
if (settings->view.antialiasing) {
glEnable(GL_POINT_SMOOTH);
glEnable(GL_LINE_SMOOTH);
Expand All @@ -142,11 +143,11 @@ void GlScope::drawGraph() {
}

// Values we need for the fading of the digital phosphor
if ((int)fadingFactor.size() != settings->view.digitalPhosphorDepth) {
fadingFactor.resize((size_t)settings->view.digitalPhosphorDepth);
if ((int)fadingFactor.size() != digitalPhosphorDepth) {
fadingFactor.resize((size_t)digitalPhosphorDepth);
fadingFactor[0] = 100;
double fadingRatio = pow(10.0, 2.0 / settings->view.digitalPhosphorDepth);
for (size_t index = 1; index < (size_t)settings->view.digitalPhosphorDepth; ++index)
double fadingRatio = pow(10.0, 2.0 / digitalPhosphorDepth);
for (size_t index = 1; index < (size_t)digitalPhosphorDepth; ++index)
fadingFactor[index] = fadingFactor[index - 1] * fadingRatio;
}

Expand All @@ -158,7 +159,7 @@ void GlScope::drawGraph() {
if (!channelUsed(mode, channel)) continue;

// Draw graph for all available depths
for (int index = settings->view.digitalPhosphorDepth - 1; index >= 0; index--) {
for (int index = digitalPhosphorDepth - 1; index >= 0; index--) {
drawGraphDepth(mode, channel, index);
}
}
Expand All @@ -169,7 +170,7 @@ void GlScope::drawGraph() {
// Real and virtual channels
for (int channel = 0; channel < settings->scope.voltage.size() - 1; channel += 2) {
if (settings->scope.voltage[channel].used) {
for (int index = settings->view.digitalPhosphorDepth - 1; index >= 0; index--) {
for (int index = digitalPhosphorDepth - 1; index >= 0; index--) {
drawGraphDepth(Dso::CHANNELMODE_VOLTAGE, channel, index);
}
}
Expand Down
2 changes: 1 addition & 1 deletion openhantek/src/glscope.h
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,7 @@ class GlScope : public GL_WIDGET_CLASS {

void drawGrid();
void drawGraphDepth(int mode, int channel, int index);
void drawGraph();
void drawGraph(int digitalPhosphorDepth);
bool channelUsed(int mode, int channel);

private:
Expand Down