Merge pull request #939 from srcejon/radio_clock_waveform

Radio Clock: Send multiple streams to scope
pull/941/head
Edouard Griffiths 2021-06-25 16:20:29 +02:00 zatwierdzone przez GitHub
commit 5eff1c7bb4
Nie znaleziono w bazie danych klucza dla tego podpisu
ID klucza GPG: 4AEE18F83AFDEB23
7 zmienionych plików z 40 dodań i 224 usunięć

Wyświetl plik

@ -176,18 +176,6 @@ void RadioClockGUI::on_timezone_currentIndexChanged(int index)
applySettings();
}
void RadioClockGUI::on_channel1_currentIndexChanged(int index)
{
m_settings.m_scopeCh1 = index;
applySettings();
}
void RadioClockGUI::on_channel2_currentIndexChanged(int index)
{
m_settings.m_scopeCh2 = index;
applySettings();
}
void RadioClockGUI::onWidgetRolled(QWidget* widget, bool rollDown)
{
(void) widget;
@ -259,10 +247,11 @@ RadioClockGUI::RadioClockGUI(PluginAPI* pluginAPI, DeviceUISet *deviceUISet, Bas
m_scopeVis = m_radioClock->getScopeSink();
m_scopeVis->setGLScope(ui->glScope);
m_scopeVis->setNbStreams(1);
m_scopeVis->setNbStreams(7);
m_scopeVis->setLiveRate(1000);
ui->glScope->connectTimer(MainCore::instance()->getMasterTimer());
ui->scopeGUI->setBuddies(m_scopeVis->getInputMessageQueue(), m_scopeVis, ui->glScope);
ui->scopeGUI->setStreams(QStringList({"IQ", "MagSq", "TH", "FM", "Data", "Samp", "GotMM"}));
ui->status->setText("Looking for minute marker");
@ -342,9 +331,6 @@ void RadioClockGUI::displaySettings()
displayStreamIndex();
ui->channel1->setCurrentIndex(m_settings.m_scopeCh1);
ui->channel2->setCurrentIndex(m_settings.m_scopeCh2);
blockApplySettings(false);
}

Wyświetl plik

@ -89,8 +89,6 @@ private slots:
void on_threshold_valueChanged(int value);
void on_modulation_currentIndexChanged(int index);
void on_timezone_currentIndexChanged(int index);
void on_channel1_currentIndexChanged(int index);
void on_channel2_currentIndexChanged(int index);
void onWidgetRolled(QWidget* widget, bool rollDown);
void onMenuDialogCalled(const QPoint& p);
void handleInputMessages();

Wyświetl plik

@ -586,136 +586,6 @@
<property name="bottomMargin">
<number>3</number>
</property>
<item>
<layout class="QHBoxLayout" name="scopelLayout">
<item>
<widget class="QLabel" name="channel1Label">
<property name="text">
<string>Real</string>
</property>
</widget>
</item>
<item>
<widget class="QComboBox" name="channel1">
<property name="sizePolicy">
<sizepolicy hsizetype="Expanding" vsizetype="Fixed">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="toolTip">
<string>Signal to feed to scope as stream 0 real data</string>
</property>
<item>
<property name="text">
<string>I</string>
</property>
</item>
<item>
<property name="text">
<string>Mag Sq</string>
</property>
</item>
<item>
<property name="text">
<string>Mag Sq LPF</string>
</property>
</item>
<item>
<property name="text">
<string>Threshold</string>
</property>
</item>
<item>
<property name="text">
<string>FM demod LPF</string>
</property>
</item>
<item>
<property name="text">
<string>Data</string>
</property>
</item>
<item>
<property name="text">
<string>Sample</string>
</property>
</item>
<item>
<property name="text">
<string>Got minute marker</string>
</property>
</item>
</widget>
</item>
<item>
<widget class="QLabel" name="channel2Label">
<property name="sizePolicy">
<sizepolicy hsizetype="Preferred" vsizetype="Preferred">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="text">
<string>Imag</string>
</property>
</widget>
</item>
<item>
<widget class="QComboBox" name="channel2">
<property name="sizePolicy">
<sizepolicy hsizetype="Expanding" vsizetype="Fixed">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="toolTip">
<string>Signal to feed to scope as stream 0 imag data</string>
</property>
<item>
<property name="text">
<string>Q</string>
</property>
</item>
<item>
<property name="text">
<string>Mag Sq</string>
</property>
</item>
<item>
<property name="text">
<string>Mag Sq LPF</string>
</property>
</item>
<item>
<property name="text">
<string>Threshold</string>
</property>
</item>
<item>
<property name="text">
<string>FM Demod LPF</string>
</property>
</item>
<item>
<property name="text">
<string>Data</string>
</property>
</item>
<item>
<property name="text">
<string>Sample</string>
</property>
</item>
<item>
<property name="text">
<string>Got minute marker</string>
</property>
</item>
</widget>
</item>
</layout>
</item>
<item>
<widget class="GLScope" name="glScope" native="true">
<property name="minimumSize">
@ -778,8 +648,6 @@
<tabstop>timezone</tabstop>
<tabstop>date</tabstop>
<tabstop>time</tabstop>
<tabstop>channel1</tabstop>
<tabstop>channel2</tabstop>
</tabstops>
<resources>
<include location="../../../sdrgui/resources/res.qrc"/>

Wyświetl plik

@ -37,8 +37,6 @@ void RadioClockSettings::resetToDefaults()
m_threshold = 5;
m_modulation = MSF;
m_timezone = BROADCAST;
m_scopeCh1 = 2;
m_scopeCh2 = 3;
m_rgbColor = QColor(102, 0, 0).rgb();
m_title = "Radio Clock";
m_streamIndex = 0;
@ -58,8 +56,6 @@ QByteArray RadioClockSettings::serialize() const
s.writeFloat(4, m_threshold);
s.writeS32(5, (int)m_modulation);
s.writeS32(6, (int)m_timezone);
s.writeS32(10, m_scopeCh1);
s.writeS32(11, m_scopeCh2);
s.writeU32(12, m_rgbColor);
s.writeString(13, m_title);
if (m_channelMarker) {
@ -97,8 +93,6 @@ bool RadioClockSettings::deserialize(const QByteArray& data)
d.readFloat(4, &m_threshold, 30);
d.readS32(5, (int *)&m_modulation, DCF77);
d.readS32(6, (int *)&m_timezone, BROADCAST);
d.readS32(10, &m_scopeCh1, 2);
d.readS32(11, &m_scopeCh2, 3);
d.readU32(12, &m_rgbColor, QColor(102, 0, 0).rgb());
d.readString(13, &m_title, "Radio Clock");
d.readBlob(14, &bytetmp);

Wyświetl plik

@ -41,8 +41,6 @@ struct RadioClockSettings
LOCAL,
UTC
} m_timezone;
int m_scopeCh1;
int m_scopeCh2;
quint32 m_rgbColor;
QString m_title;

Wyświetl plik

@ -66,14 +66,22 @@ void RadioClockSink::sampleToScope(Complex sample)
{
if (m_scopeSink)
{
Real r = std::real(sample) * SDR_RX_SCALEF;
Real i = std::imag(sample) * SDR_RX_SCALEF;
SampleVector m_sampleBuffer1;
m_sampleBuffer1.push_back(Sample(r, i));
std::vector<SampleVector::const_iterator> vbegin;
vbegin.push_back(m_sampleBuffer1.begin());
m_scopeSink->feed(vbegin, m_sampleBuffer1.end() - m_sampleBuffer1.begin());
m_sampleBuffer1.clear();
ComplexVector m_sampleBuffer[7];
m_sampleBuffer[0].push_back(sample);
m_sampleBuffer[1].push_back(Complex(m_magsq, 0.0f));
m_sampleBuffer[2].push_back(Complex(m_threshold, 0.0f));
m_sampleBuffer[3].push_back(Complex(m_fmDemodMovingAverage.asDouble(), 0.0f));
m_sampleBuffer[4].push_back(Complex(m_data, 0.0f));
m_sampleBuffer[5].push_back(Complex(m_sample, 0.0f));
m_sampleBuffer[6].push_back(Complex(m_gotMinuteMarker, 0.0f));
std::vector<ComplexVector::const_iterator> vbegin;
for (int i = 0; i < 7; i++) {
vbegin.push_back(m_sampleBuffer[i].begin());
}
m_scopeSink->feed(vbegin, m_sampleBuffer[0].end() - m_sampleBuffer[0].begin());
for (int i = 0; i < 7; i++) {
m_sampleBuffer[i].clear();
}
}
}
@ -596,63 +604,8 @@ void RadioClockSink::processOneSample(Complex &ci)
msf60();
}
// Select signals to feed to scope
Complex scopeSample;
switch (m_settings.m_scopeCh1)
{
case 0:
scopeSample.real(ci.real() / SDR_RX_SCALEF);
break;
case 1:
scopeSample.real(magsq * 1e6);
break;
case 2:
scopeSample.real(m_magsq * 1e6);
break;
case 3:
scopeSample.real(m_threshold * 1e6);
break;
case 4:
scopeSample.real(m_fmDemodMovingAverage.asDouble());
break;
case 5:
scopeSample.real(m_data);
break;
case 6:
scopeSample.real(m_sample);
break;
case 7:
scopeSample.real(m_gotMinuteMarker);
break;
}
switch (m_settings.m_scopeCh2)
{
case 0:
scopeSample.imag(ci.imag() / SDR_RX_SCALEF);
break;
case 1:
scopeSample.imag(magsq * 1e6);
break;
case 2:
scopeSample.imag(m_magsq * 1e6);
break;
case 3:
scopeSample.imag(m_threshold * 1e6);
break;
case 4:
scopeSample.imag(m_fmDemodMovingAverage.asDouble());
break;
case 5:
scopeSample.imag(m_data);
break;
case 6:
scopeSample.imag(m_sample);
break;
case 7:
scopeSample.imag(m_gotMinuteMarker);
break;
}
sampleToScope(scopeSample);
// Feed signals to scope
sampleToScope(Complex(re, im));
}
void RadioClockSink::applyChannelSettings(int channelSampleRate, int channelFrequencyOffset, bool force)

Wyświetl plik

@ -12,7 +12,7 @@ If you'd like other transmitters to be supported (such as WWVB), please upload a
Typically, it will take two minutes before the time is able to be displayed (up to one minute to find the minute marker, then another minute to receive the timecode).
Although the atomic clocks used to transmit the timecode are extremely accurate, propagation, SDR data transfer and demodulation delays limit accuracy of the displayed time to around 1 second.
Although the atomic clocks used to transmit the timecode are extremely accurate, propagation, SDR data transfer and demodulation delays limit accuracy of the displayed time to around 1 second.
<h2>Interface</h2>
@ -76,3 +76,22 @@ Displays the demodulator status. This can be:
The date and time fields are only valid when the status indicates OK.
If while in the OK state several second markers are not detected, the status will return to Looking for minute marker.
<h3>Waveforms</h3>
The scope shows how various variables within the demodulator vary with time. These can be used to help debug operation of the demodulator.
The signals available include:
- IQ - IQ data at channel sample rate (1kHz).
- MagSq - Magnitude squared (power) of received signal after being filtered with a moving average filter.
- TH - Current threshold, which is moving average of MagSq - TH setting.
- FM - Output of FM demodulator for TDF demodulator only.
- Data - Demodulated data. For MSF/DCF77, this data=MagSq>TH.
- Samp - Indicates when data is sampled (either for the second marker or for a timecode data bit).
- GotMM - Indicates whether the minute marker has been received. Cleared when synchronization to second marker is lost.
As an example of how this can be used, we can plot the MagSq as X and the calculated TH as Y, which can help to set the value of the
TH setting to an approproate level.
![Radio clock plugin GUI](../../../doc/img/RadioClock_waveforms.png)