mirror of
https://github.com/f4exb/sdrangel.git
synced 2024-11-22 08:04:49 -05:00
Audio Input: quarter sample rate heterodyne for mono signals
This commit is contained in:
parent
6e3add76e3
commit
9cdcfeef70
@ -287,6 +287,7 @@ void AudioInput::applySettings(const AudioInputSettings& settings, bool force, b
|
||||
if ((m_settings.m_iqMapping != settings.m_iqMapping) || force)
|
||||
{
|
||||
reverseAPIKeys.append("iqMapping");
|
||||
forwardChange = true;
|
||||
|
||||
if (m_worker) {
|
||||
m_worker->setIQMapping(settings.m_iqMapping);
|
||||
@ -306,7 +307,11 @@ void AudioInput::applySettings(const AudioInputSettings& settings, bool force, b
|
||||
|
||||
if (forwardChange)
|
||||
{
|
||||
DSPSignalNotification *notif = new DSPSignalNotification(m_settings.m_sampleRate/(1<<m_settings.m_log2Decim), 0);
|
||||
qint64 dF =
|
||||
((m_settings.m_iqMapping == AudioInputSettings::IQMapping::L) ||
|
||||
(m_settings.m_iqMapping == AudioInputSettings::IQMapping::R)) ?
|
||||
m_settings.m_sampleRate / 4 : 0;
|
||||
DSPSignalNotification *notif = new DSPSignalNotification(m_settings.m_sampleRate/(1<<m_settings.m_log2Decim), dF);
|
||||
m_deviceAPI->getDeviceEngineInputMessageQueue()->push(notif);
|
||||
}
|
||||
}
|
||||
|
@ -37,7 +37,8 @@ AudioInputGui::AudioInputGui(DeviceUISet *deviceUISet, QWidget* parent) :
|
||||
m_deviceUISet(deviceUISet),
|
||||
m_forceSettings(true),
|
||||
m_settings(),
|
||||
m_sampleSource(NULL)
|
||||
m_sampleSource(nullptr),
|
||||
m_centerFrequency(0)
|
||||
{
|
||||
m_sampleSource = (AudioInput*) m_deviceUISet->m_deviceAPI->getSampleSource();
|
||||
|
||||
@ -130,6 +131,7 @@ void AudioInputGui::handleInputMessages()
|
||||
{
|
||||
DSPSignalNotification* notif = (DSPSignalNotification*) message;
|
||||
m_sampleRate = notif->getSampleRate();
|
||||
m_centerFrequency = notif->getCenterFrequency();
|
||||
qDebug("AudioInputGui::handleInputMessages: DSPSignalNotification: SampleRate: %d", notif->getSampleRate());
|
||||
updateSampleRateAndFrequency();
|
||||
|
||||
@ -160,7 +162,7 @@ void AudioInputGui::updateSampleRateAndFrequency()
|
||||
*/
|
||||
{
|
||||
m_deviceUISet->getSpectrum()->setSampleRate(m_sampleRate);
|
||||
m_deviceUISet->getSpectrum()->setCenterFrequency(0);
|
||||
m_deviceUISet->getSpectrum()->setCenterFrequency(m_centerFrequency);
|
||||
m_deviceUISet->getSpectrum()->setSsbSpectrum(false);
|
||||
m_deviceUISet->getSpectrum()->setLsbDisplay(false);
|
||||
}
|
||||
|
@ -57,6 +57,7 @@ private:
|
||||
QTimer m_updateTimer;
|
||||
DeviceSampleSource* m_sampleSource;
|
||||
int m_sampleRate;
|
||||
qint64 m_centerFrequency;
|
||||
|
||||
MessageQueue m_inputMessageQueue;
|
||||
|
||||
|
@ -210,6 +210,13 @@
|
||||
</property>
|
||||
</spacer>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QLabel" name="decimLabel">
|
||||
<property name="text">
|
||||
<string>Dec</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QComboBox" name="decim">
|
||||
<property name="maximumSize">
|
||||
@ -243,13 +250,6 @@
|
||||
</item>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QLabel" name="decimLabel">
|
||||
<property name="text">
|
||||
<string>Dec</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
<item>
|
||||
@ -336,12 +336,12 @@
|
||||
</property>
|
||||
<item>
|
||||
<property name="text">
|
||||
<string>I=L, Q=0</string>
|
||||
<string>Mono L</string>
|
||||
</property>
|
||||
</item>
|
||||
<item>
|
||||
<property name="text">
|
||||
<string>I=R, Q=0</string>
|
||||
<string>Mono R</string>
|
||||
</property>
|
||||
</item>
|
||||
<item>
|
||||
|
@ -33,7 +33,8 @@ AudioInputWorker::AudioInputWorker(SampleSinkFifo* sampleFifo, AudioFifo *fifo,
|
||||
m_log2Decim(0),
|
||||
m_iqMapping(AudioInputSettings::IQMapping::L),
|
||||
m_convertBuffer(m_convBufSamples),
|
||||
m_sampleFifo(sampleFifo)
|
||||
m_sampleFifo(sampleFifo),
|
||||
m_quNCOPhase(0)
|
||||
{
|
||||
}
|
||||
|
||||
@ -56,20 +57,40 @@ void AudioInputWorker::stopWork()
|
||||
void AudioInputWorker::workIQ(unsigned int nbRead)
|
||||
{
|
||||
// Map between left and right audio channels and IQ channels
|
||||
if (m_iqMapping == AudioInputSettings::IQMapping::L)
|
||||
{
|
||||
for (uint32_t i = 0; i < nbRead; i++)
|
||||
m_buf[i*2+1] = 0;
|
||||
}
|
||||
else if (m_iqMapping == AudioInputSettings::IQMapping::R)
|
||||
if ((m_iqMapping == AudioInputSettings::IQMapping::L) || // mono
|
||||
(m_iqMapping == AudioInputSettings::IQMapping::R))
|
||||
{
|
||||
for (uint32_t i = 0; i < nbRead; i++)
|
||||
{
|
||||
m_buf[i*2] = m_buf[i*2+1];
|
||||
m_buf[i*2+1] = 0;
|
||||
qint16 r = m_buf[i*2 + (m_iqMapping == AudioInputSettings::IQMapping::R ? 1 : 0)]; // real sample
|
||||
|
||||
if (m_quNCOPhase == 0) // 0
|
||||
{
|
||||
m_buf[i*2] = r; // 1
|
||||
m_buf[i*2+1] = 0; // 0
|
||||
m_quNCOPhase = 1; // next phase
|
||||
}
|
||||
else if (m_quNCOPhase == 1) // -pi/2
|
||||
{
|
||||
m_buf[i*2] = 0; // 0
|
||||
m_buf[i*2+1] = -r; // -1
|
||||
m_quNCOPhase = 2; // next phase
|
||||
}
|
||||
else if (m_quNCOPhase == 2) // pi or -pi
|
||||
{
|
||||
m_buf[i*2] = -r; // -1
|
||||
m_buf[i*2+1] = 0; // 0
|
||||
m_quNCOPhase = 3; // next phase
|
||||
}
|
||||
else if (m_quNCOPhase == 3) // pi/2
|
||||
{
|
||||
m_buf[i*2] = 0; // 0
|
||||
m_buf[i*2+1] = r; // 1
|
||||
m_quNCOPhase = 0; // next phase
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (m_iqMapping == AudioInputSettings::IQMapping::LR)
|
||||
else if (m_iqMapping == AudioInputSettings::IQMapping::LR) // stereo - reverse
|
||||
{
|
||||
for (uint32_t i = 0; i < nbRead; i++)
|
||||
{
|
||||
@ -79,30 +100,35 @@ void AudioInputWorker::workIQ(unsigned int nbRead)
|
||||
}
|
||||
}
|
||||
|
||||
decimate(m_buf, nbRead);
|
||||
}
|
||||
|
||||
void AudioInputWorker::decimate(qint16 *buf, unsigned int nbRead)
|
||||
{
|
||||
SampleVector::iterator it = m_convertBuffer.begin();
|
||||
|
||||
switch (m_log2Decim)
|
||||
{
|
||||
case 0:
|
||||
m_decimatorsIQ.decimate1(&it, m_buf, 2*nbRead);
|
||||
m_decimatorsIQ.decimate1(&it, buf, 2*nbRead);
|
||||
break;
|
||||
case 1:
|
||||
m_decimatorsIQ.decimate2_cen(&it, m_buf, 2*nbRead);
|
||||
m_decimatorsIQ.decimate2_cen(&it, buf, 2*nbRead);
|
||||
break;
|
||||
case 2:
|
||||
m_decimatorsIQ.decimate4_cen(&it, m_buf, 2*nbRead);
|
||||
m_decimatorsIQ.decimate4_cen(&it, buf, 2*nbRead);
|
||||
break;
|
||||
case 3:
|
||||
m_decimatorsIQ.decimate8_cen(&it, m_buf, 2*nbRead);
|
||||
m_decimatorsIQ.decimate8_cen(&it, buf, 2*nbRead);
|
||||
break;
|
||||
case 4:
|
||||
m_decimatorsIQ.decimate16_cen(&it, m_buf, 2*nbRead);
|
||||
m_decimatorsIQ.decimate16_cen(&it, buf, 2*nbRead);
|
||||
break;
|
||||
case 5:
|
||||
m_decimatorsIQ.decimate32_cen(&it, m_buf, 2*nbRead);
|
||||
m_decimatorsIQ.decimate32_cen(&it, buf, 2*nbRead);
|
||||
break;
|
||||
case 6:
|
||||
m_decimatorsIQ.decimate64_cen(&it, m_buf, 2*nbRead);
|
||||
m_decimatorsIQ.decimate64_cen(&it, buf, 2*nbRead);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
|
@ -51,8 +51,10 @@ private:
|
||||
SampleVector m_convertBuffer;
|
||||
SampleSinkFifo* m_sampleFifo;
|
||||
Decimators<qint32, qint16, SDR_RX_SAMP_SZ, 16, true> m_decimatorsIQ;
|
||||
int m_quNCOPhase; //!< Quarter sample rate pseudo NCO phase index (0, 90, 180, 270)
|
||||
|
||||
void workIQ(unsigned int nbRead);
|
||||
void decimate(qint16 *buf, unsigned int nbRead);
|
||||
|
||||
private slots:
|
||||
void handleAudio();
|
||||
|
@ -38,9 +38,9 @@ A control to set the input volume. This is not supported by all input audio devi
|
||||
|
||||
<h3>7: Channel Map</h3>
|
||||
|
||||
This controls how the left and right stereo audio channels map on to the IQ channels.
|
||||
This controls how the left and right audio channels map on to the IQ channels.
|
||||
|
||||
* I=L, Q=0 - The left audio channel is driven to the I channel. The Q channel is set to 0.
|
||||
* I=R, Q=0 - The right audio channel is driven to the I channel. The Q channel is set to 0.
|
||||
* I=L, Q=R - The left audio channel is driven to the I channel. The right audio channel is driven to the Q channel.
|
||||
* I=R, Q=L - The right audio channel is driven to the I channel. The left audio channel is driven to the Q channel.
|
||||
* Mono L - Real samples are taken from the left audio channel and are heterodyned by the fourth of the sample rate (fs/4) to obtain complex samples. Therefore the spectrum of the complex baseband is centered at the fourth of the sample rate (fs/4). As per Nyquist rule only a bandwidth of half of the sample rate (fs/2) is available for real signals. Frequencies outside the [0, fs/2] interval are artefacts and can be eliminated by decimating by a factor of 2.
|
||||
* Mono R - Same as above but takes the right audio channel for the real signal.
|
||||
* I=L, Q=R - The left audio channel is driven to the I channel. The right audio channel is driven to the Q channel for a complex (analytic signal)input.
|
||||
* I=R, Q=L - The right audio channel is driven to the I channel. The left audio channel is driven to the Q channel for a complex (analytic signal)input.
|
||||
|
Loading…
Reference in New Issue
Block a user