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