kopia lustrzana https://github.com/f4exb/sdrangel
WFM modulator: fixed RF bandwidth issue
rodzic
b626cf67e6
commit
f91b0382e5
|
@ -59,9 +59,13 @@ WFMMod::WFMMod() :
|
|||
m_config.m_audioSampleRate = DSPEngine::instance()->getAudioSampleRate();
|
||||
|
||||
m_rfFilter = new fftfilt(-62500.0 / 384000.0, 62500.0 / 384000.0, m_rfFilterFFTLength);
|
||||
m_rfFilterBuffer = new Complex[m_rfFilterFFTLength];
|
||||
memset(m_rfFilterBuffer, 0, sizeof(Complex)*(m_rfFilterFFTLength));
|
||||
m_rfFilterBufferIndex = 0;
|
||||
|
||||
apply();
|
||||
|
||||
|
||||
m_audioBuffer.resize(1<<14);
|
||||
m_audioBufferFill = 0;
|
||||
|
||||
|
@ -70,6 +74,7 @@ WFMMod::WFMMod() :
|
|||
m_magsq = 0.0;
|
||||
|
||||
m_toneNco.setFreq(1000.0, m_config.m_audioSampleRate);
|
||||
m_toneNcoRF.setFreq(1000.0, m_config.m_outputSampleRate);
|
||||
DSPEngine::instance()->addAudioSource(&m_audioFifo);
|
||||
|
||||
// CW keyer
|
||||
|
@ -82,6 +87,7 @@ WFMMod::WFMMod() :
|
|||
WFMMod::~WFMMod()
|
||||
{
|
||||
delete m_rfFilter;
|
||||
delete[] m_rfFilterBuffer;
|
||||
DSPEngine::instance()->removeAudioSource(&m_audioFifo);
|
||||
}
|
||||
|
||||
|
@ -109,9 +115,13 @@ void WFMMod::pull(Sample& sample)
|
|||
|
||||
Complex ci, ri;
|
||||
Real t;
|
||||
fftfilt::cmplx *rf;
|
||||
int rf_out;
|
||||
|
||||
m_settingsMutex.lock();
|
||||
|
||||
if ((m_afInput == WFMModInputFile) || (m_afInput == WFMModInputAudio) || (m_afInput == WFMModInputCWTone))
|
||||
{
|
||||
if (m_interpolator.interpolate(&m_interpolatorDistanceRemain, m_modSample, &ri))
|
||||
{
|
||||
pullAF(m_modSample);
|
||||
|
@ -120,14 +130,28 @@ void WFMMod::pull(Sample& sample)
|
|||
}
|
||||
|
||||
m_interpolatorDistanceRemain += m_interpolatorDistance;
|
||||
}
|
||||
else
|
||||
{
|
||||
pullAF(ri);
|
||||
}
|
||||
|
||||
m_modPhasor += (m_running.m_fmDeviation / (float) m_running.m_outputSampleRate) * ri.real() * M_PI;
|
||||
ci.real(cos(m_modPhasor) * 29204.0f); // -1 dB
|
||||
ci.imag(sin(m_modPhasor) * 29204.0f);
|
||||
|
||||
// RF filtering is unnecessary
|
||||
// RF filtering
|
||||
rf_out = m_rfFilter->runFilt(ci, &rf);
|
||||
|
||||
ci *= m_carrierNco.nextIQ(); // shift to carrier frequency
|
||||
if (rf_out > 0)
|
||||
{
|
||||
memcpy((void *) m_rfFilterBuffer, (const void *) rf, rf_out*sizeof(Complex));
|
||||
m_rfFilterBufferIndex = 0;
|
||||
|
||||
}
|
||||
|
||||
ci = m_rfFilterBuffer[m_rfFilterBufferIndex] * m_carrierNco.nextIQ(); // shift to carrier frequency
|
||||
m_rfFilterBufferIndex++;
|
||||
|
||||
m_settingsMutex.unlock();
|
||||
|
||||
|
@ -158,7 +182,7 @@ void WFMMod::pullAF(Complex& sample)
|
|||
switch (m_afInput)
|
||||
{
|
||||
case WFMModInputTone:
|
||||
sample.real(m_toneNco.next() * m_running.m_volumeFactor);
|
||||
sample.real(m_toneNcoRF.next() * m_running.m_volumeFactor);
|
||||
sample.imag(0.0f);
|
||||
break;
|
||||
case WFMModInputFile:
|
||||
|
@ -390,6 +414,14 @@ void WFMMod::apply()
|
|||
m_settingsMutex.unlock();
|
||||
}
|
||||
|
||||
if ((m_config.m_toneFrequency != m_running.m_toneFrequency) ||
|
||||
(m_config.m_outputSampleRate != m_running.m_outputSampleRate))
|
||||
{
|
||||
m_settingsMutex.lock();
|
||||
m_toneNcoRF.setFreq(m_config.m_toneFrequency, m_config.m_outputSampleRate);
|
||||
m_settingsMutex.unlock();
|
||||
}
|
||||
|
||||
if (m_config.m_audioSampleRate != m_running.m_audioSampleRate)
|
||||
{
|
||||
m_cwKeyer.setSampleRate(m_config.m_audioSampleRate);
|
||||
|
|
|
@ -310,14 +310,18 @@ private:
|
|||
|
||||
NCO m_carrierNco;
|
||||
NCOF m_toneNco;
|
||||
NCOF m_toneNcoRF;
|
||||
float m_modPhasor; //!< baseband modulator phasor
|
||||
Complex m_modSample;
|
||||
Interpolator m_interpolator;
|
||||
Real m_interpolatorDistance;
|
||||
Real m_interpolatorDistanceRemain;
|
||||
bool m_interpolatorConsumed;
|
||||
|
||||
fftfilt* m_rfFilter;
|
||||
static const int m_rfFilterFFTLength;
|
||||
fftfilt::cmplx *m_rfFilterBuffer;
|
||||
int m_rfFilterBufferIndex;
|
||||
|
||||
Real m_magsq;
|
||||
MovingAverage<Real> m_movingAverage;
|
||||
|
|
|
@ -40,6 +40,16 @@ const int WFMModGUI::m_rfBW[] = {
|
|||
};
|
||||
const int WFMModGUI::m_nbRfBW = 14;
|
||||
|
||||
int WFMModGUI::requiredBW(int rfBW)
|
||||
{
|
||||
if (rfBW <= 48000)
|
||||
return 48000;
|
||||
else if (rfBW < 100000)
|
||||
return 96000;
|
||||
else
|
||||
return 384000;
|
||||
}
|
||||
|
||||
WFMModGUI* WFMModGUI::create(PluginAPI* pluginAPI, DeviceSinkAPI *deviceAPI)
|
||||
{
|
||||
WFMModGUI* gui = new WFMModGUI(pluginAPI, deviceAPI);
|
||||
|
@ -430,7 +440,7 @@ void WFMModGUI::applySettings()
|
|||
setTitleColor(m_channelMarker.getColor());
|
||||
|
||||
m_channelizer->configure(m_channelizer->getInputMessageQueue(),
|
||||
48000,
|
||||
requiredBW(m_rfBW[ui->rfBW->currentIndex()]),
|
||||
m_channelMarker.getCenterFrequency());
|
||||
|
||||
ui->deltaFrequency->setValue(abs(m_channelMarker.getCenterFrequency()));
|
||||
|
|
|
@ -109,6 +109,7 @@ private:
|
|||
explicit WFMModGUI(PluginAPI* pluginAPI, DeviceSinkAPI *deviceAPI, QWidget* parent = NULL);
|
||||
virtual ~WFMModGUI();
|
||||
|
||||
int requiredBW(int rfBW);
|
||||
void blockApplySettings(bool block);
|
||||
void applySettings();
|
||||
void updateWithStreamData();
|
||||
|
|
|
@ -56,16 +56,7 @@
|
|||
<property name="spacing">
|
||||
<number>3</number>
|
||||
</property>
|
||||
<property name="leftMargin">
|
||||
<number>2</number>
|
||||
</property>
|
||||
<property name="topMargin">
|
||||
<number>2</number>
|
||||
</property>
|
||||
<property name="rightMargin">
|
||||
<number>2</number>
|
||||
</property>
|
||||
<property name="bottomMargin">
|
||||
<property name="margin">
|
||||
<number>2</number>
|
||||
</property>
|
||||
<item>
|
||||
|
@ -455,7 +446,7 @@
|
|||
<number>10</number>
|
||||
</property>
|
||||
<property name="maximum">
|
||||
<number>250</number>
|
||||
<number>1000</number>
|
||||
</property>
|
||||
<property name="pageStep">
|
||||
<number>1</number>
|
||||
|
|
Ładowanie…
Reference in New Issue