Commit db4f8ba0b7b2bcc9ee7f41c96b597cdda56acacc
Committed by
David Gräff
1 parent
4a1617f4
Fix digital phosphor effect
Showing
4 changed files
with
113 additions
and
96 deletions
openhantek/src/glgenerator.cpp
| ... | ... | @@ -11,8 +11,8 @@ GlGenerator::GlGenerator(DsoSettingsScope *scope, DsoSettingsView *view) : setti |
| 11 | 11 | const int DIVS_TIME_S2 = (int)DIVS_TIME - 2; |
| 12 | 12 | const int DIVS_VOLTAGE_S2 = (int)DIVS_VOLTAGE - 2; |
| 13 | 13 | const int vaGrid0Size = (int) ((DIVS_TIME * DIVS_SUB - 2) * DIVS_VOLTAGE_S2 + |
| 14 | - (DIVS_VOLTAGE * DIVS_SUB - 2) * DIVS_TIME_S2 - | |
| 15 | - (DIVS_TIME_S2 * DIVS_VOLTAGE_S2)) * 2; | |
| 14 | + (DIVS_VOLTAGE * DIVS_SUB - 2) * DIVS_TIME_S2 - | |
| 15 | + (DIVS_TIME_S2 * DIVS_VOLTAGE_S2)) * 2; | |
| 16 | 16 | |
| 17 | 17 | vaGrid[0].resize(vaGrid0Size); |
| 18 | 18 | std::vector<GLfloat>::iterator glIterator = vaGrid[0].begin(); |
| ... | ... | @@ -105,106 +105,116 @@ const std::vector<GLfloat> &GlGenerator::grid(int a) const { return vaGrid[a]; } |
| 105 | 105 | |
| 106 | 106 | bool GlGenerator::isReady() const { return ready; } |
| 107 | 107 | |
| 108 | +GlGenerator::PrePostStartTriggerSamples GlGenerator::computeSoftwareTriggerTY(const DataAnalyzerResult *result) | |
| 109 | +{ | |
| 110 | + unsigned int preTrigSamples = 0; | |
| 111 | + unsigned int postTrigSamples = 0; | |
| 112 | + unsigned int swTriggerStart = 0; | |
| 113 | + unsigned int channel = settings->trigger.source; | |
| 114 | + | |
| 115 | + // check trigger point for software trigger | |
| 116 | + if (settings->trigger.mode != Dso::TRIGGERMODE_SOFTWARE || channel >= settings->physicalChannels) | |
| 117 | + return PrePostStartTriggerSamples(preTrigSamples, postTrigSamples, swTriggerStart); | |
| 118 | + | |
| 119 | + // Trigger channel not in use | |
| 120 | + if (!settings->voltage[channel].used || !result->data(channel) || | |
| 121 | + result->data(channel)->voltage.sample.empty()) | |
| 122 | + return PrePostStartTriggerSamples(preTrigSamples, postTrigSamples, swTriggerStart); | |
| 123 | + | |
| 124 | + double value; | |
| 125 | + double level = settings->voltage[channel].trigger; | |
| 126 | + unsigned int sampleCount = result->data(channel)->voltage.sample.size(); | |
| 127 | + double timeDisplay = settings->horizontal.timebase * 10; | |
| 128 | + double samplesDisplay = timeDisplay * settings->horizontal.samplerate; | |
| 129 | + if (samplesDisplay >= sampleCount) { | |
| 130 | + // For sure not enough samples to adjust for jitter. | |
| 131 | + // Following options exist: | |
| 132 | + // 1: Decrease sample rate | |
| 133 | + // 2: Change trigger mode to auto | |
| 134 | + // 3: Ignore samples | |
| 135 | + // For now #3 is chosen | |
| 136 | + timestampDebug(QString("Too few samples to make a steady " | |
| 137 | + "picture. Decrease sample rate")); | |
| 138 | + return PrePostStartTriggerSamples(preTrigSamples, postTrigSamples, swTriggerStart); | |
| 139 | + } | |
| 140 | + preTrigSamples = (settings->trigger.position * samplesDisplay); | |
| 141 | + postTrigSamples = sampleCount - (samplesDisplay - preTrigSamples); | |
| 142 | + | |
| 143 | + const int threshold = 7; | |
| 144 | + double prev; | |
| 145 | + bool (*opcmp)(int,int,int); | |
| 146 | + bool (*smplcmp)(int,int); | |
| 147 | + if (settings->trigger.slope == Dso::SLOPE_POSITIVE) { | |
| 148 | + prev = INT_MAX; | |
| 149 | + opcmp = [](int value, int level, int prev) { return value > level && prev <= level;}; | |
| 150 | + smplcmp = [](int sampleK, int value) { return sampleK >= value;}; | |
| 151 | + } else { | |
| 152 | + prev = INT_MIN; | |
| 153 | + opcmp = [](int value, int level, int prev) { return value > level && prev <= level;}; | |
| 154 | + smplcmp = [](int sampleK, int value) { return sampleK < value;}; | |
| 155 | + } | |
| 156 | + | |
| 157 | + for (unsigned int i = preTrigSamples; i < postTrigSamples; i++) { | |
| 158 | + value = result->data(channel)->voltage.sample[i]; | |
| 159 | + if (opcmp(value, level, prev)) { | |
| 160 | + int rising = 0; | |
| 161 | + for (unsigned int k = i + 1; k < i + 11 && k < sampleCount; k++) { | |
| 162 | + if (smplcmp(result->data(channel)->voltage.sample[k], value)) { rising++; } | |
| 163 | + } | |
| 164 | + if (rising > threshold) { | |
| 165 | + swTriggerStart = i; | |
| 166 | + break; | |
| 167 | + } | |
| 168 | + } | |
| 169 | + prev = value; | |
| 170 | + } | |
| 171 | + if (swTriggerStart == 0) { | |
| 172 | + timestampDebug(QString("Trigger not asserted. Data ignored")); | |
| 173 | + } | |
| 174 | + return PrePostStartTriggerSamples(preTrigSamples, postTrigSamples, swTriggerStart); | |
| 175 | +} | |
| 176 | + | |
| 108 | 177 | void GlGenerator::generateGraphs(const DataAnalyzerResult *result) { |
| 109 | 178 | |
| 110 | - int digitalPhosphorDepth = view->digitalPhosphorDepth; | |
| 179 | + int digitalPhosphorDepth = view->digitalPhosphor ? view->digitalPhosphorDepth : 1; | |
| 111 | 180 | |
| 112 | 181 | // Handle all digital phosphor related list manipulations |
| 113 | 182 | for (int mode = Dso::CHANNELMODE_VOLTAGE; mode < Dso::CHANNELMODE_COUNT; ++mode) { |
| 114 | - // Adapt the number of graphs | |
| 115 | - vaChannel[mode].resize(settings->voltage.size()); | |
| 183 | + DrawLinesWithHistoryPerChannel& d = vaChannel[mode]; | |
| 184 | + // Resize to the number of channels | |
| 185 | + d.resize(settings->voltage.size()); | |
| 116 | 186 | |
| 117 | 187 | for (unsigned int channel = 0; channel < vaChannel[mode].size(); ++channel) { |
| 188 | + DrawLinesWithHistory& drawLinesHistory = d[channel]; | |
| 118 | 189 | // Move the last list element to the front |
| 119 | - vaChannel[mode][channel].push_front(std::vector<GLfloat>()); | |
| 190 | + if (digitalPhosphorDepth > 1 && drawLinesHistory.size()) | |
| 191 | + drawLinesHistory.push_front(drawLinesHistory.back()); | |
| 120 | 192 | |
| 121 | 193 | // Resize lists for vector array to fit the digital phosphor depth |
| 122 | - vaChannel[mode][channel].resize(digitalPhosphorDepth); | |
| 194 | + drawLinesHistory.resize(digitalPhosphorDepth); | |
| 123 | 195 | } |
| 124 | 196 | } |
| 125 | 197 | |
| 126 | 198 | ready = true; |
| 127 | 199 | |
| 128 | - unsigned int preTrigSamples = 0; | |
| 129 | - unsigned int postTrigSamples = 0; | |
| 200 | + unsigned preTrigSamples; | |
| 201 | + unsigned postTrigSamples; | |
| 202 | + unsigned swTriggerStart; | |
| 130 | 203 | switch (settings->horizontal.format) { |
| 131 | - case Dso::GRAPHFORMAT_TY: { | |
| 132 | - unsigned int swTriggerStart = 0; | |
| 133 | - // check trigger point for software trigger | |
| 134 | - if (settings->trigger.mode == Dso::TRIGGERMODE_SOFTWARE && settings->trigger.source <= 1) { | |
| 135 | - unsigned int channel = settings->trigger.source; | |
| 136 | - if (settings->voltage[channel].used && result->data(channel) && | |
| 137 | - !result->data(channel)->voltage.sample.empty()) { | |
| 138 | - double value; | |
| 139 | - double level = settings->voltage[channel].trigger; | |
| 140 | - unsigned int sampleCount = result->data(channel)->voltage.sample.size(); | |
| 141 | - double timeDisplay = settings->horizontal.timebase * 10; | |
| 142 | - double samplesDisplay = timeDisplay * settings->horizontal.samplerate; | |
| 143 | - if (samplesDisplay >= sampleCount) { | |
| 144 | - // For sure not enough samples to adjust for jitter. | |
| 145 | - // Following options exist: | |
| 146 | - // 1: Decrease sample rate | |
| 147 | - // 2: Change trigger mode to auto | |
| 148 | - // 3: Ignore samples | |
| 149 | - // For now #3 is chosen | |
| 150 | - timestampDebug(QString("Too few samples to make a steady " | |
| 151 | - "picture. Decrease sample rate")); | |
| 152 | - return; | |
| 153 | - } | |
| 154 | - preTrigSamples = (settings->trigger.position * samplesDisplay); | |
| 155 | - postTrigSamples = sampleCount - (samplesDisplay - preTrigSamples); | |
| 156 | - | |
| 157 | - if (settings->trigger.slope == Dso::SLOPE_POSITIVE) { | |
| 158 | - double prev = INT_MAX; | |
| 159 | - for (unsigned int i = preTrigSamples; i < postTrigSamples; i++) { | |
| 160 | - value = result->data(channel)->voltage.sample[i]; | |
| 161 | - if (value > level && prev <= level) { | |
| 162 | - int rising = 0; | |
| 163 | - for (unsigned int k = i + 1; k < i + 11 && k < sampleCount; k++) { | |
| 164 | - if (result->data(channel)->voltage.sample[k] >= value) { rising++; } | |
| 165 | - } | |
| 166 | - if (rising > 7) { | |
| 167 | - swTriggerStart = i; | |
| 168 | - break; | |
| 169 | - } | |
| 170 | - } | |
| 171 | - prev = value; | |
| 172 | - } | |
| 173 | - } else if (settings->trigger.slope == Dso::SLOPE_NEGATIVE) { | |
| 174 | - double prev = INT_MIN; | |
| 175 | - for (unsigned int i = preTrigSamples; i < postTrigSamples; i++) { | |
| 176 | - value = result->data(channel)->voltage.sample[i]; | |
| 177 | - if (value < level && prev >= level) { | |
| 178 | - int falling = 0; | |
| 179 | - for (unsigned int k = i + 1; k < i + 11 && k < sampleCount; k++) { | |
| 180 | - if (result->data(channel)->voltage.sample[k] < value) { falling++; } | |
| 181 | - } | |
| 182 | - if (falling > 7) { | |
| 183 | - swTriggerStart = i; | |
| 184 | - break; | |
| 185 | - } | |
| 186 | - } | |
| 187 | - prev = value; | |
| 188 | - } | |
| 189 | - } | |
| 190 | - } | |
| 191 | - if (swTriggerStart == 0) { | |
| 192 | - timestampDebug(QString("Trigger not asserted. Data ignored")); | |
| 193 | - return; | |
| 194 | - } | |
| 195 | - } | |
| 204 | + case Dso::GRAPHFORMAT_TY: | |
| 205 | + std::tie(preTrigSamples, postTrigSamples, swTriggerStart) = computeSoftwareTriggerTY(result); | |
| 196 | 206 | |
| 197 | 207 | // Add graphs for channels |
| 198 | 208 | for (int mode = Dso::CHANNELMODE_VOLTAGE; mode < Dso::CHANNELMODE_COUNT; ++mode) { |
| 199 | 209 | for (int channel = 0; channel < (int)settings->voltage.size(); ++channel) { |
| 200 | 210 | // Check if this channel is used and available at the data analyzer |
| 201 | 211 | if (((mode == Dso::CHANNELMODE_VOLTAGE) ? settings->voltage[channel].used |
| 202 | - : settings->spectrum[channel].used) && | |
| 203 | - result->data(channel) && !result->data(channel)->voltage.sample.empty()) { | |
| 212 | + : settings->spectrum[channel].used) && | |
| 213 | + result->data(channel) && !result->data(channel)->voltage.sample.empty()) { | |
| 204 | 214 | // Check if the sample count has changed |
| 205 | 215 | size_t sampleCount = (mode == Dso::CHANNELMODE_VOLTAGE) |
| 206 | - ? result->data(channel)->voltage.sample.size() | |
| 207 | - : result->data(channel)->spectrum.sample.size(); | |
| 216 | + ? result->data(channel)->voltage.sample.size() | |
| 217 | + : result->data(channel)->spectrum.sample.size(); | |
| 208 | 218 | if (mode == Dso::CHANNELMODE_VOLTAGE) sampleCount -= (swTriggerStart - preTrigSamples); |
| 209 | 219 | size_t neededSize = sampleCount * 2; |
| 210 | 220 | |
| ... | ... | @@ -227,12 +237,12 @@ void GlGenerator::generateGraphs(const DataAnalyzerResult *result) { |
| 227 | 237 | horizontalFactor = result->data(channel)->voltage.interval / settings->horizontal.timebase; |
| 228 | 238 | else |
| 229 | 239 | horizontalFactor = |
| 230 | - result->data(channel)->spectrum.interval / settings->horizontal.frequencybase; | |
| 240 | + result->data(channel)->spectrum.interval / settings->horizontal.frequencybase; | |
| 231 | 241 | |
| 232 | 242 | // Fill vector array |
| 233 | 243 | if (mode == Dso::CHANNELMODE_VOLTAGE) { |
| 234 | 244 | std::vector<double>::const_iterator dataIterator = |
| 235 | - result->data(channel)->voltage.sample.begin(); | |
| 245 | + result->data(channel)->voltage.sample.begin(); | |
| 236 | 246 | const double gain = settings->voltage[channel].gain; |
| 237 | 247 | const double offset = settings->voltage[channel].offset; |
| 238 | 248 | const double invert = settings->voltage[channel].inverted ? -1.0 : 1.0; |
| ... | ... | @@ -245,7 +255,7 @@ void GlGenerator::generateGraphs(const DataAnalyzerResult *result) { |
| 245 | 255 | } |
| 246 | 256 | } else { |
| 247 | 257 | std::vector<double>::const_iterator dataIterator = |
| 248 | - result->data(channel)->spectrum.sample.begin(); | |
| 258 | + result->data(channel)->spectrum.sample.begin(); | |
| 249 | 259 | const double magnitude = settings->spectrum[channel].magnitude; |
| 250 | 260 | const double offset = settings->spectrum[channel].offset; |
| 251 | 261 | |
| ... | ... | @@ -261,15 +271,15 @@ void GlGenerator::generateGraphs(const DataAnalyzerResult *result) { |
| 261 | 271 | } |
| 262 | 272 | } |
| 263 | 273 | } |
| 264 | - } break; | |
| 274 | + break; | |
| 265 | 275 | |
| 266 | 276 | case Dso::GRAPHFORMAT_XY: |
| 267 | 277 | for (int channel = 0; channel < settings->voltage.size(); ++channel) { |
| 268 | 278 | // For even channel numbers check if this channel is used and this and the |
| 269 | 279 | // following channel are available at the data analyzer |
| 270 | 280 | if (channel % 2 == 0 && channel + 1 < settings->voltage.size() && settings->voltage[channel].used && |
| 271 | - result->data(channel) && !result->data(channel)->voltage.sample.empty() && result->data(channel + 1) && | |
| 272 | - !result->data(channel + 1)->voltage.sample.empty()) { | |
| 281 | + result->data(channel) && !result->data(channel)->voltage.sample.empty() && result->data(channel + 1) && | |
| 282 | + !result->data(channel + 1)->voltage.sample.empty()) { | |
| 273 | 283 | // Check if the sample count has changed |
| 274 | 284 | const unsigned sampleCount = qMin(result->data(channel)->voltage.sample.size(), |
| 275 | 285 | result->data(channel + 1)->voltage.sample.size()); |
| ... | ... | @@ -277,7 +287,7 @@ void GlGenerator::generateGraphs(const DataAnalyzerResult *result) { |
| 277 | 287 | for (unsigned index = 0; index < (unsigned)digitalPhosphorDepth; ++index) { |
| 278 | 288 | if (vaChannel[Dso::CHANNELMODE_VOLTAGE][(size_t)channel][index].size() != neededSize) |
| 279 | 289 | vaChannel[Dso::CHANNELMODE_VOLTAGE][(size_t)channel][index] |
| 280 | - .clear(); // Something was changed, drop old traces | |
| 290 | + .clear(); // Something was changed, drop old traces | |
| 281 | 291 | } |
| 282 | 292 | |
| 283 | 293 | // Set size directly to avoid reallocations |
| ... | ... | @@ -285,7 +295,7 @@ void GlGenerator::generateGraphs(const DataAnalyzerResult *result) { |
| 285 | 295 | |
| 286 | 296 | // Iterator to data for direct access |
| 287 | 297 | std::vector<GLfloat>::iterator glIterator = |
| 288 | - vaChannel[Dso::CHANNELMODE_VOLTAGE][channel].front().begin(); | |
| 298 | + vaChannel[Dso::CHANNELMODE_VOLTAGE][channel].front().begin(); | |
| 289 | 299 | |
| 290 | 300 | // Fill vector array |
| 291 | 301 | unsigned int xChannel = channel; | ... | ... |
openhantek/src/glgenerator.h
| ... | ... | @@ -30,9 +30,15 @@ class GlGenerator : public QObject { |
| 30 | 30 | bool isReady() const; |
| 31 | 31 | |
| 32 | 32 | private: |
| 33 | + typedef std::tuple<unsigned,unsigned,unsigned> PrePostStartTriggerSamples; | |
| 34 | + typedef std::vector<GLfloat> DrawLines; | |
| 35 | + typedef std::deque<DrawLines> DrawLinesWithHistory; | |
| 36 | + typedef std::vector<DrawLinesWithHistory> DrawLinesWithHistoryPerChannel; | |
| 37 | + DrawLinesWithHistoryPerChannel vaChannel[Dso::CHANNELMODE_COUNT]; | |
| 38 | + | |
| 39 | + PrePostStartTriggerSamples computeSoftwareTriggerTY(const DataAnalyzerResult *result); | |
| 33 | 40 | DsoSettingsScope *settings; |
| 34 | 41 | DsoSettingsView *view; |
| 35 | - std::vector<std::deque<std::vector<GLfloat>>> vaChannel[Dso::CHANNELMODE_COUNT]; | |
| 36 | 42 | std::vector<GLfloat> vaGrid[3]; |
| 37 | 43 | bool ready = false; |
| 38 | 44 | signals: | ... | ... |
openhantek/src/glscope.cpp
| ... | ... | @@ -37,7 +37,8 @@ void GlScope::paintGL() { |
| 37 | 37 | glClear(GL_COLOR_BUFFER_BIT); |
| 38 | 38 | glLineWidth(1); |
| 39 | 39 | |
| 40 | - if (settings->view.digitalPhosphorDepth > 0 && generator->isReady()) { drawGraph(); } | |
| 40 | + int digitalPhosphorDepth = settings->view.digitalPhosphor ? settings->view.digitalPhosphorDepth : 1; | |
| 41 | + if (generator->isReady()) { drawGraph(digitalPhosphorDepth); } | |
| 41 | 42 | |
| 42 | 43 | if (!this->zoomed) { |
| 43 | 44 | // Draw vertical lines at marker positions |
| ... | ... | @@ -126,7 +127,7 @@ void GlScope::drawGraphDepth(int mode, int channel, int index) { |
| 126 | 127 | generator->channel(mode, channel, index).size() / 2); |
| 127 | 128 | } |
| 128 | 129 | |
| 129 | -void GlScope::drawGraph() { | |
| 130 | +void GlScope::drawGraph(int digitalPhosphorDepth) { | |
| 130 | 131 | if (settings->view.antialiasing) { |
| 131 | 132 | glEnable(GL_POINT_SMOOTH); |
| 132 | 133 | glEnable(GL_LINE_SMOOTH); |
| ... | ... | @@ -142,11 +143,11 @@ void GlScope::drawGraph() { |
| 142 | 143 | } |
| 143 | 144 | |
| 144 | 145 | // Values we need for the fading of the digital phosphor |
| 145 | - if ((int)fadingFactor.size() != settings->view.digitalPhosphorDepth) { | |
| 146 | - fadingFactor.resize((size_t)settings->view.digitalPhosphorDepth); | |
| 146 | + if ((int)fadingFactor.size() != digitalPhosphorDepth) { | |
| 147 | + fadingFactor.resize((size_t)digitalPhosphorDepth); | |
| 147 | 148 | fadingFactor[0] = 100; |
| 148 | - double fadingRatio = pow(10.0, 2.0 / settings->view.digitalPhosphorDepth); | |
| 149 | - for (size_t index = 1; index < (size_t)settings->view.digitalPhosphorDepth; ++index) | |
| 149 | + double fadingRatio = pow(10.0, 2.0 / digitalPhosphorDepth); | |
| 150 | + for (size_t index = 1; index < (size_t)digitalPhosphorDepth; ++index) | |
| 150 | 151 | fadingFactor[index] = fadingFactor[index - 1] * fadingRatio; |
| 151 | 152 | } |
| 152 | 153 | |
| ... | ... | @@ -158,7 +159,7 @@ void GlScope::drawGraph() { |
| 158 | 159 | if (!channelUsed(mode, channel)) continue; |
| 159 | 160 | |
| 160 | 161 | // Draw graph for all available depths |
| 161 | - for (int index = settings->view.digitalPhosphorDepth - 1; index >= 0; index--) { | |
| 162 | + for (int index = digitalPhosphorDepth - 1; index >= 0; index--) { | |
| 162 | 163 | drawGraphDepth(mode, channel, index); |
| 163 | 164 | } |
| 164 | 165 | } |
| ... | ... | @@ -169,7 +170,7 @@ void GlScope::drawGraph() { |
| 169 | 170 | // Real and virtual channels |
| 170 | 171 | for (int channel = 0; channel < settings->scope.voltage.size() - 1; channel += 2) { |
| 171 | 172 | if (settings->scope.voltage[channel].used) { |
| 172 | - for (int index = settings->view.digitalPhosphorDepth - 1; index >= 0; index--) { | |
| 173 | + for (int index = digitalPhosphorDepth - 1; index >= 0; index--) { | |
| 173 | 174 | drawGraphDepth(Dso::CHANNELMODE_VOLTAGE, channel, index); |
| 174 | 175 | } |
| 175 | 176 | } | ... | ... |
openhantek/src/glscope.h
| ... | ... | @@ -39,7 +39,7 @@ class GlScope : public GL_WIDGET_CLASS { |
| 39 | 39 | |
| 40 | 40 | void drawGrid(); |
| 41 | 41 | void drawGraphDepth(int mode, int channel, int index); |
| 42 | - void drawGraph(); | |
| 42 | + void drawGraph(int digitalPhosphorDepth); | |
| 43 | 43 | bool channelUsed(int mode, int channel); |
| 44 | 44 | |
| 45 | 45 | private: | ... | ... |