mirror of
https://github.com/f4exb/sdrangel.git
synced 2024-12-23 01:55:48 -05:00
FreeDV demod: fixed filters
This commit is contained in:
parent
6c3536e0a0
commit
7759f9cebc
@ -49,8 +49,8 @@ const QString FreeDVDemod::m_channelId = "FreeDVDemod";
|
||||
FreeDVDemod::FreeDVDemod(DeviceSourceAPI *deviceAPI) :
|
||||
ChannelSinkAPI(m_channelIdURI),
|
||||
m_deviceAPI(deviceAPI),
|
||||
m_hiCutoff(5000),
|
||||
m_lowCutoff(300),
|
||||
m_hiCutoff(6000),
|
||||
m_lowCutoff(0),
|
||||
m_volume(2),
|
||||
m_spanLog2(3),
|
||||
m_sum(0),
|
||||
@ -97,7 +97,7 @@ FreeDVDemod::FreeDVDemod(DeviceSourceAPI *deviceAPI) :
|
||||
m_agc.setClampMax(SDR_RX_SCALED/100.0);
|
||||
m_agc.setClamping(m_agcClamping);
|
||||
|
||||
SSBFilter = new fftfilt(m_lowCutoff / m_audioSampleRate, m_hiCutoff / m_audioSampleRate, ssbFftLen);
|
||||
SSBFilter = new fftfilt(m_lowCutoff / m_modemSampleRate, m_hiCutoff / m_modemSampleRate, ssbFftLen);
|
||||
|
||||
applyChannelSettings(m_inputSampleRate, m_inputFrequencyOffset, true);
|
||||
applySettings(m_settings, true);
|
||||
@ -320,7 +320,7 @@ bool FreeDVDemod::handleMessage(const Message& cmd)
|
||||
|
||||
void FreeDVDemod::pushSampleToDV(int16_t sample)
|
||||
{
|
||||
qint16 speechSample, audioSample;
|
||||
qint16 audioSample;
|
||||
|
||||
if (m_iModem == m_nin)
|
||||
{
|
||||
@ -328,9 +328,7 @@ void FreeDVDemod::pushSampleToDV(int16_t sample)
|
||||
|
||||
for (int i = 0; i < nout; i++)
|
||||
{
|
||||
speechSample = (qint16)(m_speechOut[i] * m_volume);
|
||||
|
||||
while (!m_audioResampler.upSample(speechSample, audioSample)) {
|
||||
while (!m_audioResampler.upSample(m_speechOut[i], audioSample)) {
|
||||
pushSampleToAudio(audioSample);
|
||||
}
|
||||
|
||||
@ -346,8 +344,8 @@ void FreeDVDemod::pushSampleToDV(int16_t sample)
|
||||
|
||||
void FreeDVDemod::pushSampleToAudio(int16_t sample)
|
||||
{
|
||||
m_audioBuffer[m_audioBufferFill].l = sample;
|
||||
m_audioBuffer[m_audioBufferFill].r = sample;
|
||||
m_audioBuffer[m_audioBufferFill].l = sample * m_volume;
|
||||
m_audioBuffer[m_audioBufferFill].r = sample * m_volume;
|
||||
++m_audioBufferFill;
|
||||
|
||||
if (m_audioBufferFill >= m_audioBuffer.size())
|
||||
@ -379,7 +377,7 @@ void FreeDVDemod::applyChannelSettings(int inputSampleRate, int inputFrequencyOf
|
||||
m_settingsMutex.lock();
|
||||
m_interpolator.create(16, inputSampleRate, m_hiCutoff * 1.5f, 2.0f);
|
||||
m_interpolatorDistanceRemain = 0;
|
||||
m_interpolatorDistance = (Real) inputSampleRate / (Real) m_audioSampleRate;
|
||||
m_interpolatorDistance = (Real) inputSampleRate / (Real) m_modemSampleRate;
|
||||
m_settingsMutex.unlock();
|
||||
}
|
||||
|
||||
@ -394,7 +392,7 @@ void FreeDVDemod::applyAudioSampleRate(int sampleRate)
|
||||
m_settingsMutex.lock();
|
||||
m_audioFifo.setSize(sampleRate);
|
||||
m_audioResampler.setDecimation(sampleRate / m_speechSampleRate);
|
||||
m_audioResampler.setAudioFilters(sampleRate, m_speechSampleRate, 250, 3300);
|
||||
m_audioResampler.setAudioFilters(sampleRate, sampleRate, 250, 3300, 4.0f);
|
||||
m_settingsMutex.unlock();
|
||||
|
||||
m_audioSampleRate = sampleRate;
|
||||
@ -415,15 +413,17 @@ void FreeDVDemod::applyFreeDVMode(FreeDVDemodSettings::FreeDVMode mode)
|
||||
modemSampleRate, m_settings.m_inputFrequencyOffset);
|
||||
m_inputMessageQueue.push(channelConfigMsg);
|
||||
|
||||
m_interpolator.create(16, m_inputSampleRate, m_hiCutoff * 1.5f, 2.0f);
|
||||
m_interpolatorDistanceRemain = 0;
|
||||
//m_interpolatorConsumed = false;
|
||||
m_interpolatorDistance = (Real) m_inputSampleRate / (Real) modemSampleRate;
|
||||
|
||||
m_interpolator.create(16, m_inputSampleRate, m_hiCutoff * 1.5f, 2.0f);
|
||||
SSBFilter->create_filter(m_lowCutoff / (float) modemSampleRate, m_hiCutoff / (float) modemSampleRate);
|
||||
|
||||
int agcNbSamples = (modemSampleRate / 1000) * (1<<m_settings.m_agcTimeLog2);
|
||||
int agcThresholdGate = (modemSampleRate / 1000) * m_settings.m_agcThresholdGate; // ms
|
||||
|
||||
m_modemSampleRate = modemSampleRate;
|
||||
|
||||
if (m_agcNbSamples != agcNbSamples)
|
||||
{
|
||||
m_agc.resize(agcNbSamples, agcNbSamples/2, agcTarget);
|
||||
@ -437,8 +437,6 @@ void FreeDVDemod::applyFreeDVMode(FreeDVDemodSettings::FreeDVMode mode)
|
||||
m_agcThresholdGate = agcThresholdGate;
|
||||
}
|
||||
|
||||
m_modemSampleRate = modemSampleRate;
|
||||
|
||||
if (getMessageQueueToGUI())
|
||||
{
|
||||
DSPConfigureAudio *cfg = new DSPConfigureAudio(m_modemSampleRate);
|
||||
@ -583,10 +581,10 @@ void FreeDVDemod::applySettings(const FreeDVDemodSettings& settings, bool force)
|
||||
(m_settings.m_agcThresholdGate != settings.m_agcThresholdGate) ||
|
||||
(m_settings.m_agcClamping != settings.m_agcClamping) || force)
|
||||
{
|
||||
int agcNbSamples = (m_audioSampleRate / 1000) * (1<<settings.m_agcTimeLog2);
|
||||
int agcNbSamples = (m_modemSampleRate / 1000) * (1<<settings.m_agcTimeLog2);
|
||||
m_agc.setThresholdEnable(settings.m_agcPowerThreshold != -FreeDVDemodSettings::m_minPowerThresholdDB);
|
||||
double agcPowerThreshold = CalcDb::powerFromdB(settings.m_agcPowerThreshold) * (SDR_RX_SCALED*SDR_RX_SCALED);
|
||||
int agcThresholdGate = (m_audioSampleRate / 1000) * settings.m_agcThresholdGate; // ms
|
||||
int agcThresholdGate = (m_modemSampleRate / 1000) * settings.m_agcThresholdGate; // ms
|
||||
bool agcClamping = settings.m_agcClamping;
|
||||
|
||||
if (m_agcNbSamples != agcNbSamples)
|
||||
@ -752,7 +750,7 @@ int FreeDVDemod::webapiSettingsPutPatch(
|
||||
if (frequencyOffsetChanged)
|
||||
{
|
||||
MsgConfigureChannelizer* channelConfigMsg = MsgConfigureChannelizer::create(
|
||||
m_audioSampleRate, settings.m_inputFrequencyOffset);
|
||||
m_modemSampleRate, settings.m_inputFrequencyOffset);
|
||||
m_inputMessageQueue.push(channelConfigMsg);
|
||||
}
|
||||
|
||||
|
@ -38,23 +38,23 @@ AudioFilter::~AudioFilter()
|
||||
{}
|
||||
|
||||
|
||||
void AudioFilter::setDecimFilters(int srHigh, int srLow, float fcHigh, float fcLow)
|
||||
void AudioFilter::setDecimFilters(int srHigh, int srLow, float fcHigh, float fcLow, float fgain)
|
||||
{
|
||||
double fcNormHigh = fcHigh / srHigh;
|
||||
double fcNormLow = fcLow / srLow;
|
||||
|
||||
calculate2(false, fcNormHigh, m_lpva, m_lpvb);
|
||||
calculate2(true, fcNormLow, m_hpva, m_hpvb);
|
||||
calculate2(false, fcNormHigh, m_lpva, m_lpvb, fgain);
|
||||
calculate2(true, fcNormLow, m_hpva, m_hpvb, fgain);
|
||||
|
||||
m_filterLP.setCoeffs(m_lpva, m_lpvb);
|
||||
m_filterHP.setCoeffs(m_hpva, m_hpvb);
|
||||
}
|
||||
|
||||
void AudioFilter::calculate2(bool highPass, double fc, float *va, float *vb)
|
||||
void AudioFilter::calculate2(bool highPass, double fc, float *va, float *vb, float fgain)
|
||||
{
|
||||
double a[22], b[22];
|
||||
|
||||
cheby(highPass, fc, 0.5, 2, a, b); // low-pass, 0.5% ripple, 2 pole filter
|
||||
cheby(highPass, fc, 0.5, 2, a, b, fgain); // low-pass, 0.5% ripple, 2 pole filter
|
||||
|
||||
// Copy to the 2-pole filter coefficients
|
||||
for (int i=0; i<3; i++) {
|
||||
@ -79,7 +79,7 @@ void AudioFilter::calculate2(bool highPass, double fc, float *va, float *vb)
|
||||
* Adapted from BASIC program in table 20-4 of
|
||||
* https://www.analog.com/media/en/technical-documentation/dsp-book/dsp_book_Ch20.pdf
|
||||
*/
|
||||
void AudioFilter::cheby(bool highPass, double fc, float pr, int np, double *a, double *b)
|
||||
void AudioFilter::cheby(bool highPass, double fc, float pr, int np, double *a, double *b, float fgain)
|
||||
{
|
||||
double a0, a1, a2, b1, b2;
|
||||
double ta[22], tb[22];
|
||||
@ -135,6 +135,7 @@ void AudioFilter::cheby(bool highPass, double fc, float pr, int np, double *a, d
|
||||
}
|
||||
|
||||
double gain = sa/(1.0 -sb);
|
||||
gain /= fgain;
|
||||
|
||||
for (int i=0; i<20; i++) {
|
||||
a[i] /= gain;
|
||||
|
@ -47,14 +47,14 @@ public:
|
||||
|
||||
void useHP(bool useHP) { m_useHP = useHP; }
|
||||
bool usesHP() const { return m_useHP; }
|
||||
void setDecimFilters(int srHigh, int srLow, float fcHigh, float fcLow);
|
||||
void setDecimFilters(int srHigh, int srLow, float fcHigh, float fcLow, float gain = 1.0f);
|
||||
float run(const float& sample);
|
||||
float runHP(const float& sample);
|
||||
float runLP(const float& sample);
|
||||
|
||||
private:
|
||||
void calculate2(bool highPass, double fc, float *a, float *b); // two pole Chebyshev calculation
|
||||
void cheby(bool highPass, double fc, float pr, int np, double *a, double *b);
|
||||
void calculate2(bool highPass, double fc, float *a, float *b, float fgain); // two pole Chebyshev calculation
|
||||
void cheby(bool highPass, double fc, float pr, int np, double *a, double *b, float fgain);
|
||||
void cheby_sub(bool highPass, double fc, float pr, int np, int stage,
|
||||
double& a0, double& a1, double& a2, double& b1, double& b2);
|
||||
|
||||
|
@ -30,7 +30,7 @@ void AudioResampler::setDecimation(uint32_t decimation)
|
||||
m_decimation = decimation == 0 ? 1 : decimation;
|
||||
}
|
||||
|
||||
void AudioResampler::setAudioFilters(int srHigh, int srLow, int fcLow, int fcHigh)
|
||||
void AudioResampler::setAudioFilters(int srHigh, int srLow, int fcLow, int fcHigh, float gain)
|
||||
{
|
||||
srHigh = (srHigh <= 100 ? 100 : srHigh);
|
||||
srLow = (srLow <= 0 ? 1 : srLow);
|
||||
@ -40,7 +40,7 @@ void AudioResampler::setAudioFilters(int srHigh, int srLow, int fcLow, int fcHig
|
||||
fcHigh = fcHigh < 100 ? 100 : fcHigh;
|
||||
fcLow = fcLow > fcHigh - 100 ? fcHigh - 100 : fcLow;
|
||||
|
||||
m_audioFilter.setDecimFilters(srHigh, srLow, fcHigh, fcLow);
|
||||
m_audioFilter.setDecimFilters(srHigh, srLow, fcHigh, fcLow, gain);
|
||||
}
|
||||
|
||||
bool AudioResampler::downSample(qint16 sampleIn, qint16& sampleOut)
|
||||
|
@ -29,7 +29,7 @@ public:
|
||||
|
||||
void setDecimation(uint32_t decimation);
|
||||
uint32_t getDecimation() const { return m_decimation; }
|
||||
void setAudioFilters(int srHigh, int srLow, int fcLow, int fcHigh);
|
||||
void setAudioFilters(int srHigh, int srLow, int fcLow, int fcHigh, float gain=1.0f);
|
||||
bool downSample(qint16 sampleIn, qint16& sampleOut);
|
||||
bool upSample(qint16 sampleIn, qint16& sampleOut);
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user