~arcachofo/simulide/1.1.0

« back to all changes in this revision

Viewing changes to src/gui/circuitwidget/components/meters/oscopechannel.cpp

  • Committer: arcachofo
  • Date: 2021-01-01 14:23:42 UTC
  • Revision ID: arcachofo@simulide.com-20210101142342-ozfljnll44g5lbl3
Initial Commit 0.5.15-RC3

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/***************************************************************************
 
2
 *   Copyright (C) 2020 by santiago González                               *
 
3
 *   santigoro@gmail.com                                                   *
 
4
 *                                                                         *
 
5
 *   This program is free software; you can redistribute it and/or modify  *
 
6
 *   it under the terms of the GNU General Public License as published by  *
 
7
 *   the Free Software Foundation; either version 3 of the License, or     *
 
8
 *   (at your option) any later version.                                   *
 
9
 *                                                                         *
 
10
 *   This program is distributed in the hope that it will be useful,       *
 
11
 *   but WITHOUT ANY WARRANTY; without even the implied warranty of        *
 
12
 *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the         *
 
13
 *   GNU General Public License for more details.                          *
 
14
 *                                                                         *
 
15
 *   You should have received a copy of the GNU General Public License     *
 
16
 *   along with this program; if not, see <http://www.gnu.org/licenses/>.  *
 
17
 *                                                                         *
 
18
 ***************************************************************************/
 
19
 
 
20
#include "oscopechannel.h"
 
21
#include "plotbase.h"
 
22
#include "simulator.h"
 
23
 
 
24
OscopeChannel::OscopeChannel( QString id )
 
25
             : DataChannel( id )
 
26
{
 
27
    m_filter = 0.1;
 
28
 
 
29
    m_trigger = 2;
 
30
 
 
31
    m_hTick = 1;
 
32
    m_vTick = 1;
 
33
    m_Vpos  = 0;
 
34
 
 
35
    m_points = &m_pointsA;
 
36
}
 
37
OscopeChannel::~OscopeChannel()  { }
 
38
 
 
39
void OscopeChannel::initialize()
 
40
{
 
41
    //qDebug() <<"OscopeChannel::resetState";
 
42
    m_reading  = true;
 
43
    m_rising   = false;
 
44
    m_falling  = false;
 
45
    m_runEvent = false;
 
46
    m_chCondFlag = false;
 
47
 
 
48
    m_period = 0;
 
49
    m_risEdge = 0;
 
50
    m_nCycles = 0;
 
51
    m_totalP = 0;
 
52
    m_numMax = 0;
 
53
    m_lastMax = 0;
 
54
    m_ampli = 0;
 
55
    m_maxVal =-1e12;
 
56
    m_minVal = 1e12;
 
57
    m_dispMax = 5;
 
58
    m_dispMin =-5;
 
59
 
 
60
    m_lastValue = 0;
 
61
    m_bufferCounter = 0;
 
62
 
 
63
    m_hTick = 1e9;
 
64
    m_vTick = 1;
 
65
    m_Vpos = 0;
 
66
    m_freq = 0;
 
67
 
 
68
    m_stepsPerS = 1e12;
 
69
 
 
70
    m_pointsA.clear();
 
71
    m_pointsB.clear();
 
72
 
 
73
    //DataChannel::updateStep();
 
74
    m_dataPlotW->m_data1Label[m_channel]->setText( "---" );
 
75
    m_dataPlotW->m_data2Label[m_channel]->setText( "---" );
 
76
    m_dataPlotW->m_display->update();
 
77
}
 
78
 
 
79
void OscopeChannel::runEvent()
 
80
{
 
81
    if( !m_runEvent ) return;
 
82
    voltChanged();
 
83
    Simulator::self()->addEvent( m_hTick/20, this );
 
84
}
 
85
 
 
86
void OscopeChannel::updateStep()
 
87
{
 
88
    if( m_connected )
 
89
    {
 
90
        uint64_t simTime = Simulator::self()->circTime();
 
91
 
 
92
        if( !m_reading ) // There is data set ready to display
 
93
        {
 
94
            m_reading = true;
 
95
            m_dataPlotW->m_display->setData( m_channel, m_points );
 
96
 
 
97
            if( m_points == &m_pointsA ) m_points = &m_pointsB;
 
98
            else                         m_points = &m_pointsA;
 
99
 
 
100
            m_dataPlotW->m_display->update();
 
101
        }
 
102
 
 
103
        if( m_numMax > 1 )  // Got enought maximums to calculate Freq
 
104
        {
 
105
            m_freq = 1e12/((double)m_totalP/(double)(m_numMax-1));
 
106
            m_totalP  = 0;
 
107
            m_numMax  = 0;
 
108
        }
 
109
 
 
110
        if( m_period > 10 )  // We have a wave
 
111
        {
 
112
            if( m_numMax > 1 )
 
113
            {
 
114
                uint64_t stepsPF = Simulator::self()->circuitRate()*1e6;
 
115
                uint64_t lost = m_period*2;
 
116
                if( lost < stepsPF ) lost = stepsPF*2;
 
117
 
 
118
                if( simTime-m_lastMax > lost ) // Wave lost
 
119
                {
 
120
                    m_freq    = 0;
 
121
                    m_period  = 0;
 
122
                    m_risEdge = 0;
 
123
                    m_nCycles = 0;
 
124
                    m_totalP  = 0;
 
125
                    m_numMax  = 0;
 
126
                    m_lastMax = 0;
 
127
                    m_ampli   = 0;
 
128
                    //m_dispMax = 5;
 
129
                    //m_dispMin =-5;
 
130
                    m_maxVal  = -1e12;
 
131
                    m_minVal  = 1e12;
 
132
                }
 
133
            }
 
134
        }
 
135
        else if( !m_runEvent ) // No wave, then read voltages in runEvent
 
136
        {
 
137
            if( !m_dataPlotW->m_paOnCond )
 
138
            {
 
139
                m_runEvent = true;
 
140
                Simulator::self()->addEvent( m_hTick/20, this );
 
141
            }
 
142
            //voltChanged();
 
143
        }
 
144
        if( m_ampli > 1e-6 ) m_dataPlotW->m_display->setMaxMin( m_channel, m_dispMax, m_dispMin );
 
145
 
 
146
        double freq = m_freq;
 
147
 
 
148
        int Fdecs = 2;
 
149
        QString unit = "  Hz";
 
150
 
 
151
        if( freq > 999 )
 
152
        {
 
153
            freq /= 1e3; unit = " KHz";
 
154
            if( freq > 999 ) { freq /= 1e3; unit = " MHz"; }
 
155
        }
 
156
        if     ( freq < 10 )  Fdecs = 4;
 
157
        else if( freq < 100 ) Fdecs = 3;
 
158
        m_dataPlotW->m_data1Label[m_channel]->setText( " "+QString::number( freq, 'f', Fdecs )+unit );
 
159
 
 
160
        unit = " V";
 
161
        double val = m_ampli;
 
162
 
 
163
        if( val < 1 )
 
164
        {
 
165
            unit = " mV";
 
166
            val *= 1e3;
 
167
        }
 
168
        int Vdecimals = 0;
 
169
        if     ( val < 10 )  Vdecimals = 2;
 
170
        else if( val < 100 ) Vdecimals = 1;
 
171
        m_dataPlotW->m_data2Label[m_channel]->setText( "Amp "+QString::number( val,'f', Vdecimals )+unit );
 
172
 
 
173
        DataChannel::updateStep();
 
174
    }
 
175
}
 
176
 
 
177
void OscopeChannel::voltChanged()
 
178
{
 
179
    uint64_t simTime = Simulator::self()->circTime();
 
180
 
 
181
    double data = m_ePin[0]->getVolt() + m_ePin[1]->getVolt();
 
182
 
 
183
    if( data > m_maxVal ) m_maxVal = data;
 
184
    if( data < m_minVal ) m_minVal = data;
 
185
 
 
186
    if( ++m_bufferCounter >= m_buffer.size() ) m_bufferCounter = 0;
 
187
    m_buffer[m_bufferCounter] = data;
 
188
    uint64_t time = simTime;
 
189
    m_time[m_bufferCounter] = time;
 
190
 
 
191
    double delta = data-m_lastValue;
 
192
 
 
193
    if( delta > 0 )               // Rising
 
194
    {
 
195
        if( delta > m_filter )
 
196
        {
 
197
            if( m_falling && !m_rising )     // Min To Rising
 
198
            {
 
199
                if( m_numMax > 0 ) m_totalP += simTime-m_lastMax;
 
200
                m_lastMax = simTime;
 
201
 
 
202
                m_numMax++;
 
203
                m_nCycles++;
 
204
                m_falling = false;
 
205
 
 
206
                if( m_dataPlotW->m_paOnCond )
 
207
                {
 
208
                    if( (m_chCond == Rising) || (m_chCond == High) ) // Pause on Rising or High
 
209
                    {
 
210
                        m_chCondFlag = true;
 
211
                        m_dataPlotW->m_plotB->pauseOnCond();
 
212
                        if( m_chCond == Rising ) m_chCondFlag = false;
 
213
                    }
 
214
                    else if( m_chCond == Low ) m_chCondFlag = false;
 
215
                }
 
216
            }
 
217
            else if( m_dataPlotW->m_paOnCond )
 
218
            {
 
219
                if( m_chCond == Rising ) m_chCondFlag = false;
 
220
            }
 
221
            m_rising = true;
 
222
            m_lastValue = data;
 
223
        }
 
224
        if( m_nCycles > 1 )     // Wait for a full wave
 
225
        {
 
226
            m_ampli = m_maxVal-m_minVal;
 
227
            double mid = m_minVal + m_ampli/2;
 
228
 
 
229
            if( data >= mid )            // Rising edge
 
230
            {
 
231
                m_dispMax = m_maxVal;
 
232
                m_dispMin = m_minVal;
 
233
                m_maxVal  = -1e12;
 
234
                m_minVal  = 1e12;
 
235
                m_nCycles--;
 
236
 
 
237
                if( m_risEdge > 0 ) m_period = simTime-m_risEdge; // period = this_edge_time - last_edge_time
 
238
                m_risEdge = simTime;
 
239
 
 
240
                if( m_period > 10 )
 
241
                {
 
242
                    m_runEvent = false;
 
243
                    if( m_dataPlotW->m_auto == m_channel )
 
244
                    {
 
245
                        m_Vpos = 0;
 
246
                        m_vTick = m_ampli/10;
 
247
                        if     ( m_vTick > 1000 )  m_vTick = 1000;
 
248
                        else if( m_vTick < 0.001 ) m_vTick = 0.001;
 
249
 
 
250
                        m_hTick = abs( (double)m_period/5 );
 
251
                        if( m_hTick < 1 ) m_hTick = 1;
 
252
                    }
 
253
                }
 
254
            }
 
255
        }
 
256
    }
 
257
    else if( delta < -m_filter )         // Falling
 
258
    {
 
259
        if( m_rising && !m_falling )    // Max Found
 
260
        {
 
261
            m_rising = false;
 
262
 
 
263
            if( m_dataPlotW->m_paOnCond )
 
264
            {
 
265
                if( (m_chCond == Falling) || (m_chCond == Low) ) // Pause on Falling or Low
 
266
                {
 
267
                    m_chCondFlag = true;
 
268
                    m_dataPlotW->m_plotB->pauseOnCond();
 
269
                    if( m_chCond == Falling ) m_chCondFlag = false;
 
270
                }
 
271
                else if( m_chCond == High ) m_chCondFlag = false;
 
272
            }
 
273
        }
 
274
        else if( m_dataPlotW->m_paOnCond )
 
275
        {
 
276
            if( m_chCond == Falling ) m_chCondFlag = false;
 
277
        }
 
278
        m_falling = true;
 
279
        m_lastValue = data;
 
280
    }
 
281
    if( m_dataPlotW->m_paOnCond ) return;
 
282
    if( m_reading )
 
283
    {
 
284
        if( m_trigger < 2  ) // We want wave
 
285
        {
 
286
            if( m_trigger == m_channel ) // We drive trigger
 
287
            {
 
288
                if( m_period > 10 )  // We have wave
 
289
                    m_dataPlotW->m_plotB->fetchData( m_channel, m_risEdge );
 
290
                else             //  We don't have a wave, trigger just now
 
291
                    m_dataPlotW->m_plotB->fetchData( m_channel, time );
 
292
            }
 
293
        }
 
294
        else            // Free running
 
295
        {
 
296
            fetchData( m_channel, time );
 
297
        }
 
298
    }
 
299
}
 
300
 
 
301
void OscopeChannel::fetchData( int ch, uint64_t edge )
 
302
{
 
303
    //if( m_trigger && ch != m_channel ) return; // we have our own trigger
 
304
    if( !m_reading ) return;
 
305
 
 
306
    uint64_t period = m_period;
 
307
    if( m_period <= 10 ) period = m_hTick/20;
 
308
    if( m_dataPlotW->m_paOnCond ) period = m_hTick/20;// Pause on Condition
 
309
 
 
310
    uint64_t timeFrame = m_hTick*10;
 
311
    uint64_t nCycles = timeFrame/period;
 
312
    if( timeFrame%period ) nCycles++;
 
313
    if( nCycles%2 ) nCycles++;
 
314
 
 
315
    uint64_t orig = edge-nCycles*period/2-timeFrame/2;
 
316
    uint64_t origAbs = edge-(nCycles+1)*period;
 
317
 
 
318
    if( m_dataPlotW->m_paOnCond ) // Pause on Condition
 
319
    {
 
320
        uint64_t size = edge-origAbs;
 
321
        if( size < m_dataSize )
 
322
        {
 
323
            if( edge < m_dataSize) origAbs = 0;
 
324
            else                   origAbs = edge - m_dataSize;
 
325
        }
 
326
    }
 
327
    int pos = m_bufferCounter;
 
328
    uint64_t timeAbs;
 
329
    int64_t  time;
 
330
    m_points->clear();
 
331
 
 
332
    m_points->prepend( QPointF( edge-orig, m_buffer[pos] )); // First poit at current time
 
333
 
 
334
    for( int i=0; i<m_buffer.size(); ++i ) // Read Backwards
 
335
    {
 
336
        timeAbs = m_time.at(pos);
 
337
        time = timeAbs-orig;
 
338
        m_points->prepend( QPointF( time, m_buffer[pos] ));
 
339
        if( timeAbs < origAbs ) break; // End of data
 
340
 
 
341
        pos--;
 
342
        if( pos < 0 ) pos += m_buffer.size();
 
343
    }
 
344
    //m_dataPlotW->m_display->setXFrame( m_channel, timeFrame );
 
345
 
 
346
    m_reading = false;
 
347
}