1
0
mirror of https://github.com/f4exb/sdrangel.git synced 2026-08-14 15:33:34 -04:00

XTRX: make clock gen setting consistent

This commit is contained in:
f4exb
2019-01-04 04:45:52 +01:00
parent e3069d3a69
commit 733f3d4ba4
15 changed files with 307 additions and 127 deletions
+12 -8
View File
@@ -2,6 +2,8 @@
<h2>Introduction</h2>
&#9888; Support is experimental and for Linux only. You have to compile it from source.
This input sample source plugin gets its samples from a [XTRX device](https://xtrx.io).
XTRX is a 2x2 MIMO device so it has two receiving channels that can run concurrently. To activate the second channel when the first is already active just open a new source tab in the main window (Devices -> Add source device) and select the same LimeSDR device. You may need to change frequency back and forth in case reception is not working properly.
@@ -30,12 +32,12 @@ This is the center frequency of reception in kHz.
<h4>1.2: Start/Stop</h4>
Device start / stop button.
Device start / stop button.
- Blue triangle icon: device is ready and can be started
- Green square icon: device is running and can be stopped
- Magenta (or pink) square icon: an error occurred. In the case the device was accidentally disconnected you may click on the icon to stop, plug back in, check the source on the sampling devices control panel and start again.
<h4>1.3: Record</h4>
Record baseband I/Q stream toggle button
@@ -48,7 +50,7 @@ This is the sample rate at which the ADC runs in kS/s (k) or MS/s (M) before har
<h4>1.5: Stream sample rate</h4>
Baseband I/Q sample rate in kS/s. This is the device to host sample rate (5) divided by the software decimation factor (4).
Baseband I/Q sample rate in kS/s. This is the device to host sample rate (5) divided by the software decimation factor (4).
<h4>1.6: Channel number</h4>
@@ -68,7 +70,7 @@ Use this button to activate/deactivate the TSP NCO. The LMS7002M chip has an ind
This is the frequency shift applied when the NCO is engaged thus the actual LO frequency is the center frequency of reception minus this value. Use the thumbwheels to adjust frequency as done with the LO (1.1). Pressing shift simultaneously moves digit by 5 and pressing control moves it by 2. The boundaries are dynamically calculated from the LO center frequency, sample rate and hardware decimation factor.
&#9758; In the LMS7002M TSP block the NCO sits before the decimator (see Fig.14 of the [datasheet](http://www.limemicro.com/wp-content/uploads/2015/09/LMS7002M-Data-Sheet-v2.8.0.pdf) p.7) so it runs at the actual ADC rate. Hence the NCO limits are calculated as +/- half the device to host sample rate multiplied by the hardware decimation factor. For example with a 4 MS/s device to host sample rate (5) and a hardware decimation of 16 (3) you have +/- 32 MHz span around the LO for the NCO. In this example you can tune all HF frequencies with the center frequency set at its lowest (30 MHz).
&#9758; In the LMS7002M TSP block the NCO sits before the decimator (see Fig.14 of the [datasheet](http://www.limemicro.com/wp-content/uploads/2015/09/LMS7002M-Data-Sheet-v2.8.0.pdf) p.7) so it runs at the actual ADC rate. Hence the NCO limits are calculated as +/- half the device to host sample rate multiplied by the hardware decimation factor. For example with a 4 MS/s device to host sample rate (5) and a hardware decimation of 16 (3) you have +/- 32 MHz span around the LO for the NCO. In this example you can tune all HF frequencies with the center frequency set at its lowest (30 MHz).
<h4>2.3: DC component auto correction</h4>
@@ -97,16 +99,18 @@ Use this checkbox to enable or disable the external clock input
<h5>2.6.3: Confirm changes</h5>
Use the "OK" button to confirm your changes
<h5>2.6.4: Dismiss changes</h5>
Use the "Cancel" button to dismiss your changes
<h3>3: LMS7002M hardware decimation factor</h3>
The TSP block in the LMS7002M hardware has a decimation chain that acts on both Rx channels. It is composed of 5 halfband decimation stages and therefore can achieve decimation between 1 (no decimation) and 32 in increasing powers of 2: 1, 2, 4, 8, 16, 32.
Thus the actual sample rate of the ADC is the stream sample rate (5) multiplied by this factor.
Thus the actual sample rate of the ADC is the stream sample rate (5) multiplied by this factor.
The first position in the combo is marked as "A". This is because decimation by 1 is not implemented and instead an automatic decimation factor is applied. The ADC rate display is updated automatically and siblings are updated with the actual ADC and hardware decimation factor.
<h3>4: Software decimation factor</h3>
@@ -158,7 +162,7 @@ Use this combo box to select the antenna input:
- **Lo**: Selects the low frequency input (700 to 900 MHz nominally)
- **Hi**: Selects the high frequency input (2 to 2.6 GHz)
<h3>10: Stream status indicator</h3>
This label turns green when status can be obtained from the current stream. Usually this means that the stream is up and running but not necessarily streaming data. The various status elements appear next on the same line (12)
+76 -21
View File
@@ -42,6 +42,7 @@
MESSAGE_CLASS_DEFINITION(XTRXInput::MsgConfigureXTRX, Message)
MESSAGE_CLASS_DEFINITION(XTRXInput::MsgGetStreamInfo, Message)
MESSAGE_CLASS_DEFINITION(XTRXInput::MsgGetDeviceInfo, Message)
MESSAGE_CLASS_DEFINITION(XTRXInput::MsgReportClockGenChange, Message)
MESSAGE_CLASS_DEFINITION(XTRXInput::MsgReportStreamInfo, Message)
MESSAGE_CLASS_DEFINITION(XTRXInput::MsgFileRecord, Message)
MESSAGE_CLASS_DEFINITION(XTRXInput::MsgStartStop, Message)
@@ -507,9 +508,45 @@ const QString& XTRXInput::getDeviceDescription() const
int XTRXInput::getSampleRate() const
{
double rate = m_settings.m_devSampleRate;
if (m_deviceShared.m_dev) {
rate = m_deviceShared.m_dev->getActualInputRate();
}
return (int)((rate / (1<<m_settings.m_log2SoftDecim)));
}
uint32_t XTRXInput::getDevSampleRate() const
{
uint32_t devSampleRate = m_settings.m_devSampleRate;
if (m_deviceShared.m_dev) {
devSampleRate = m_deviceShared.m_dev->getActualInputRate();
}
return devSampleRate;
}
uint32_t XTRXInput::getLog2HardDecim() const
{
uint32_t log2HardDecim = m_settings.m_log2HardDecim;
if (m_deviceShared.m_dev && (m_deviceShared.m_dev->getActualInputRate() != 0.0)) {
log2HardDecim = log2(m_deviceShared.m_dev->getClockGen() / m_deviceShared.m_dev->getActualInputRate() / 4);
}
return log2HardDecim;
}
double XTRXInput::getClockGen() const
{
if (m_deviceShared.m_dev) {
return m_deviceShared.m_dev->getClockGen();
} else {
return 0.0;
}
}
quint64 XTRXInput::getCenterFrequency() const
{
return m_settings.m_centerFrequency + (m_settings.m_ncoEnable ? m_settings.m_ncoFrequency : 0);
@@ -588,12 +625,12 @@ bool XTRXInput::handleMessage(const Message& message)
}
else
{
m_settings.m_devSampleRate = m_deviceShared.m_inputRate;
m_settings.m_log2HardDecim = log2(m_deviceShared.m_masterRate / m_deviceShared.m_inputRate / 4);
m_settings.m_devSampleRate = m_deviceShared.m_dev->getActualInputRate();
m_settings.m_log2HardDecim = getLog2HardDecim();
qDebug() << "XTRXInput::handleMessage: MsgReportBuddyChange:"
<< " host_Hz: " << m_deviceShared.m_inputRate
<< " rf_Hz: " << m_deviceShared.m_masterRate / 4
<< " host_Hz: " << m_deviceShared.m_dev->getActualInputRate()
<< " adc_Hz: " << m_deviceShared.m_dev->getClockGen() / 4
<< " m_log2HardDecim: " << m_settings.m_log2HardDecim;
}
@@ -1057,9 +1094,9 @@ bool XTRXInput::applySettings(const XTRXInputSettings& settings, bool force, boo
double master = (settings.m_log2HardDecim == 0) ? 0 : (settings.m_devSampleRate * 4 * (1 << settings.m_log2HardDecim));
if (m_deviceShared.set_samplerate(settings.m_devSampleRate,
master, //(settings.m_devSampleRate<<settings.m_log2HardDecim)*4,
false) < 0)
if (m_deviceShared.m_dev->set_samplerate(settings.m_devSampleRate,
master, //(settings.m_devSampleRate<<settings.m_log2HardDecim)*4,
false) < 0)
{
qCritical("XTRXInput::applySettings: could not set sample rate to %f with oversampling of %d",
settings.m_devSampleRate,
@@ -1069,10 +1106,11 @@ bool XTRXInput::applySettings(const XTRXInputSettings& settings, bool force, boo
{
doChangeFreq = true;
forceNCOFrequency = true;
forwardChangeAllDSP = true;
qDebug("XTRXInput::applySettings: sample rate set to %f with oversampling of %d",
settings.m_devSampleRate,
1<<settings.m_log2HardDecim);
m_deviceShared.m_dev->getActualInputRate(),
1 << getLog2HardDecim());
}
resumeTxThread();
@@ -1162,11 +1200,15 @@ bool XTRXInput::applySettings(const XTRXInputSettings& settings, bool force, boo
int ncoShift = m_settings.m_ncoEnable ? m_settings.m_ncoFrequency : 0;
// send to self first
DSPSignalNotification *notif = new DSPSignalNotification(
m_settings.m_devSampleRate/(1<<m_settings.m_log2SoftDecim),
m_settings.m_centerFrequency + ncoShift);
DSPSignalNotification *notif = new DSPSignalNotification(getSampleRate(), m_settings.m_centerFrequency + ncoShift);
m_deviceAPI->getDeviceEngineInputMessageQueue()->push(notif);
if (getMessageQueueToGUI())
{
MsgReportClockGenChange *report = MsgReportClockGenChange::create();
getMessageQueueToGUI()->push(report);
}
// send to source buddies
const std::vector<DeviceSourceAPI*>& sourceBuddies = m_deviceAPI->getSourceBuddies();
std::vector<DeviceSourceAPI*>::const_iterator itSource = sourceBuddies.begin();
@@ -1174,7 +1216,7 @@ bool XTRXInput::applySettings(const XTRXInputSettings& settings, bool force, boo
for (; itSource != sourceBuddies.end(); ++itSource)
{
DeviceXTRXShared::MsgReportBuddyChange *report = DeviceXTRXShared::MsgReportBuddyChange::create(
m_settings.m_devSampleRate, m_settings.m_log2HardDecim, m_settings.m_centerFrequency, true);
getDevSampleRate(), getLog2HardDecim(), m_settings.m_centerFrequency, true);
(*itSource)->getSampleSourceInputMessageQueue()->push(report);
}
@@ -1185,7 +1227,7 @@ bool XTRXInput::applySettings(const XTRXInputSettings& settings, bool force, boo
for (; itSink != sinkBuddies.end(); ++itSink)
{
DeviceXTRXShared::MsgReportBuddyChange *report = DeviceXTRXShared::MsgReportBuddyChange::create(
m_settings.m_devSampleRate, m_settings.m_log2HardDecim, m_settings.m_centerFrequency, true);
getDevSampleRate(), getLog2HardDecim(), m_settings.m_centerFrequency, true);
(*itSink)->getSampleSinkInputMessageQueue()->push(report);
}
}
@@ -1193,13 +1235,18 @@ bool XTRXInput::applySettings(const XTRXInputSettings& settings, bool force, boo
{
qDebug("XTRXInput::applySettings: forward change to Rx buddies");
int sampleRate = m_settings.m_devSampleRate/(1<<m_settings.m_log2SoftDecim);
int ncoShift = m_settings.m_ncoEnable ? m_settings.m_ncoFrequency : 0;
// send to self first
DSPSignalNotification *notif = new DSPSignalNotification(sampleRate, m_settings.m_centerFrequency + ncoShift);
DSPSignalNotification *notif = new DSPSignalNotification(getSampleRate(), m_settings.m_centerFrequency + ncoShift);
m_deviceAPI->getDeviceEngineInputMessageQueue()->push(notif);
if (getMessageQueueToGUI())
{
MsgReportClockGenChange *report = MsgReportClockGenChange::create();
getMessageQueueToGUI()->push(report);
}
// send to source buddies
const std::vector<DeviceSourceAPI*>& sourceBuddies = m_deviceAPI->getSourceBuddies();
std::vector<DeviceSourceAPI*>::const_iterator itSource = sourceBuddies.begin();
@@ -1207,7 +1254,7 @@ bool XTRXInput::applySettings(const XTRXInputSettings& settings, bool force, boo
for (; itSource != sourceBuddies.end(); ++itSource)
{
DeviceXTRXShared::MsgReportBuddyChange *report = DeviceXTRXShared::MsgReportBuddyChange::create(
m_settings.m_devSampleRate, m_settings.m_log2HardDecim, m_settings.m_centerFrequency, true);
getDevSampleRate(), getLog2HardDecim(), m_settings.m_centerFrequency, true);
(*itSource)->getSampleSourceInputMessageQueue()->push(report);
}
}
@@ -1215,11 +1262,17 @@ bool XTRXInput::applySettings(const XTRXInputSettings& settings, bool force, boo
{
qDebug("XTRXInput::applySettings: forward change to self only");
int sampleRate = m_settings.m_devSampleRate/(1<<m_settings.m_log2SoftDecim);
int ncoShift = m_settings.m_ncoEnable ? m_settings.m_ncoFrequency : 0;
DSPSignalNotification *notif = new DSPSignalNotification(sampleRate, m_settings.m_centerFrequency + ncoShift);
DSPSignalNotification *notif = new DSPSignalNotification(getSampleRate(), m_settings.m_centerFrequency + ncoShift);
m_fileSink->handleMessage(*notif); // forward to file sink
m_deviceAPI->getDeviceEngineInputMessageQueue()->push(notif);
if (getMessageQueueToGUI())
{
MsgReportClockGenChange *report = MsgReportClockGenChange::create();
getMessageQueueToGUI()->push(report);
}
}
if (forwardClockSource)
@@ -1248,8 +1301,10 @@ bool XTRXInput::applySettings(const XTRXInputSettings& settings, bool force, boo
}
qDebug() << "XTRXInput::applySettings: center freq: " << m_settings.m_centerFrequency << " Hz"
<< " device stream sample rate: " << m_settings.m_devSampleRate << "S/s"
<< " sample rate with soft decimation: " << m_settings.m_devSampleRate/(1<<m_settings.m_log2SoftDecim) << "S/s"
<< " device stream sample rate: " << getDevSampleRate() << "S/s"
<< " sample rate with soft decimation: " << getSampleRate() << "S/s"
<< " m_devSampleRate: " << m_settings.m_devSampleRate
<< " m_log2SoftDecim: " << m_settings.m_log2SoftDecim
<< " m_gain: " << m_settings.m_gain
<< " m_lpfBW: " << m_settings.m_lpfBW
<< " m_ncoEnable: " << m_settings.m_ncoEnable
@@ -91,6 +91,21 @@ public:
{ }
};
class MsgReportClockGenChange : public Message {
MESSAGE_CLASS_DECLARATION
public:
static MsgReportClockGenChange* create()
{
return new MsgReportClockGenChange();
}
private:
MsgReportClockGenChange() :
Message()
{ }
};
class MsgReportStreamInfo : public Message {
MESSAGE_CLASS_DECLARATION
@@ -190,6 +205,9 @@ public:
virtual void setMessageQueueToGUI(MessageQueue *queue) { m_guiMessageQueue = queue; }
virtual const QString& getDeviceDescription() const;
virtual int getSampleRate() const;
uint32_t getDevSampleRate() const;
uint32_t getLog2HardDecim() const;
double getClockGen() const;
virtual quint64 getCenterFrequency() const;
virtual void setCenterFrequency(qint64 centerFrequency);
@@ -170,6 +170,16 @@ bool XTRXInputGUI::handleMessage(const Message& message)
return true;
}
else if (XTRXInput::MsgReportClockGenChange::match(message))
{
m_settings.m_devSampleRate = m_XTRXInput->getDevSampleRate();
blockApplySettings(true);
displaySettings();
blockApplySettings(false);
return true;
}
else if (XTRXInput::MsgReportStreamInfo::match(message))
{
XTRXInput::MsgReportStreamInfo& report = (XTRXInput::MsgReportStreamInfo&) message;
@@ -245,7 +255,7 @@ void XTRXInputGUI::handleInputMessages()
void XTRXInputGUI::updateADCRate()
{
uint32_t adcRate = m_settings.m_devSampleRate * (1<<m_settings.m_log2HardDecim);
uint32_t adcRate = m_XTRXInput->getClockGen() / 4;
if (adcRate < 100000000) {
ui->adcRateLabel->setText(tr("%1k").arg(QString::number(adcRate / 1000.0f, 'g', 5)));
@@ -29,7 +29,7 @@
</font>
</property>
<property name="windowTitle">
<string>LimeSDR Input</string>
<string>XTRX Input</string>
</property>
<layout class="QVBoxLayout" name="verticalLayout">
<property name="spacing">
@@ -363,7 +363,7 @@
</property>
<item>
<property name="text">
<string>1</string>
<string>A</string>
</property>
</item>
<item>