mirror of
https://github.com/f4exb/sdrangel.git
synced 2025-02-03 09:44:01 -05:00
DSD demod: highpass filtering for audio completed
This commit is contained in:
parent
e1d7ada5dd
commit
2145eeb7b6
@ -70,6 +70,7 @@ public:
|
||||
void setAudioGain(float gain) { m_decoder.setAudioGain(gain); }
|
||||
void setBaudRate(int baudRate);
|
||||
void setSymbolPLLLock(bool pllLock) { m_decoder.setSymbolPLLLock(pllLock); }
|
||||
void useHPMbelib(bool useHP) { m_decoder.useHPMbelib(useHP); }
|
||||
|
||||
private:
|
||||
DSDcc::DSDDecoder m_decoder;
|
||||
|
@ -215,6 +215,7 @@ void DSDDemod::feed(const SampleVector::const_iterator& begin, const SampleVecto
|
||||
m_dsdDecoder.getMbeRateIndex(),
|
||||
m_settings.m_volume * 10.0,
|
||||
m_settings.m_tdmaStereo ? 1 : 3, // left or both channels
|
||||
m_settings.m_highPassFilter,
|
||||
&m_audioFifo1);
|
||||
}
|
||||
|
||||
@ -230,6 +231,7 @@ void DSDDemod::feed(const SampleVector::const_iterator& begin, const SampleVecto
|
||||
m_dsdDecoder.getMbeRateIndex(),
|
||||
m_settings.m_volume * 10.0,
|
||||
m_settings.m_tdmaStereo ? 2 : 3, // right or both channels
|
||||
m_settings.m_highPassFilter,
|
||||
&m_audioFifo2);
|
||||
}
|
||||
|
||||
@ -375,6 +377,7 @@ bool DSDDemod::handleMessage(const Message& cmd)
|
||||
<< " m_udpCopyAudio: " << m_settings.m_udpCopyAudio
|
||||
<< " m_udpAddress: " << m_settings.m_udpAddress
|
||||
<< " m_udpPort: " << m_settings.m_udpPort
|
||||
<< " m_highPassFilter: "<< m_settings.m_highPassFilter
|
||||
<< " force: " << cfg.getForce();
|
||||
|
||||
return true;
|
||||
@ -467,6 +470,11 @@ void DSDDemod::applySettings(DSDDemodSettings& settings, bool force)
|
||||
m_audioFifo2.setCopyToUDP(settings.m_slot2On && !settings.m_slot1On && settings.m_udpCopyAudio);
|
||||
}
|
||||
|
||||
if ((settings.m_highPassFilter != m_settings.m_highPassFilter) || force)
|
||||
{
|
||||
m_dsdDecoder.useHPMbelib(settings.m_highPassFilter);
|
||||
}
|
||||
|
||||
m_settings = settings;
|
||||
}
|
||||
|
||||
|
@ -196,6 +196,12 @@ void DSDDemodGUI::on_audioMute_toggled(bool checked)
|
||||
applySettings();
|
||||
}
|
||||
|
||||
void DSDDemodGUI::on_highPassFilter_toggled(bool checked)
|
||||
{
|
||||
m_settings.m_highPassFilter = checked;
|
||||
applySettings();
|
||||
}
|
||||
|
||||
void DSDDemodGUI::on_symbolPLLLock_toggled(bool checked)
|
||||
{
|
||||
if (checked) {
|
||||
|
@ -124,6 +124,7 @@ private slots:
|
||||
void on_fmDeviation_valueChanged(int value);
|
||||
void on_squelchGate_valueChanged(int value);
|
||||
void on_squelch_valueChanged(int value);
|
||||
void on_highPassFilter_toggled(bool checked);
|
||||
void on_audioMute_toggled(bool checked);
|
||||
void on_symbolPLLLock_toggled(bool checked);
|
||||
void on_udpOutput_toggled(bool checked);
|
||||
|
@ -584,7 +584,7 @@
|
||||
<widget class="QLabel" name="volumeText">
|
||||
<property name="minimumSize">
|
||||
<size>
|
||||
<width>0</width>
|
||||
<width>30</width>
|
||||
<height>0</height>
|
||||
</size>
|
||||
</property>
|
||||
@ -598,7 +598,7 @@
|
||||
<string>Sound volume</string>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>2.0</string>
|
||||
<string>10.0</string>
|
||||
</property>
|
||||
<property name="alignment">
|
||||
<set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
|
||||
@ -828,7 +828,7 @@
|
||||
<item>
|
||||
<widget class="ButtonSwitch" name="highPassFilter">
|
||||
<property name="toolTip">
|
||||
<string>Toggle audio high pass filter for mbelib (>300 Hz)</string>
|
||||
<string>Toggle audio high pass filter</string>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string/>
|
||||
|
@ -134,8 +134,6 @@ void FileSourceGui::handleInputMessages()
|
||||
|
||||
while ((message = m_inputMessageQueue.pop()) != 0)
|
||||
{
|
||||
qDebug("FileSourceGui::handleInputMessages: message: %s", message->getIdentifier());
|
||||
|
||||
if (DSPSignalNotification::match(*message))
|
||||
{
|
||||
DSPSignalNotification* notif = (DSPSignalNotification*) message;
|
||||
|
@ -231,9 +231,15 @@ void DSPEngine::getDVSerialNames(std::vector<std::string>& deviceNames __attribu
|
||||
#endif
|
||||
|
||||
#ifdef DSD_USE_SERIALDV
|
||||
void DSPEngine::pushMbeFrame(const unsigned char *mbeFrame, int mbeRateIndex, int mbeVolumeIndex, unsigned char channels, AudioFifo *audioFifo)
|
||||
void DSPEngine::pushMbeFrame(
|
||||
const unsigned char *mbeFrame,
|
||||
int mbeRateIndex,
|
||||
int mbeVolumeIndex,
|
||||
unsigned char channels,
|
||||
bool useHP,
|
||||
AudioFifo *audioFifo)
|
||||
{
|
||||
m_dvSerialEngine.pushMbeFrame(mbeFrame, mbeRateIndex, mbeVolumeIndex, channels, audioFifo);
|
||||
m_dvSerialEngine.pushMbeFrame(mbeFrame, mbeRateIndex, mbeVolumeIndex, channels, useHP, audioFifo);
|
||||
}
|
||||
#else
|
||||
void DSPEngine::pushMbeFrame(
|
||||
@ -241,6 +247,7 @@ void DSPEngine::pushMbeFrame(
|
||||
int mbeRateIndex __attribute((unused)),
|
||||
int mbeVolumeIndex __attribute((unused)),
|
||||
unsigned char channels __attribute((unused)),
|
||||
bool useHP __attribute((unused)),
|
||||
AudioFifo *audioFifo __attribute((unused)))
|
||||
{}
|
||||
#endif
|
||||
|
@ -78,7 +78,13 @@ public:
|
||||
bool hasDVSerialSupport();
|
||||
void setDVSerialSupport(bool support);
|
||||
void getDVSerialNames(std::vector<std::string>& deviceNames);
|
||||
void pushMbeFrame(const unsigned char *mbeFrame, int mbeRateIndex, int mbeVolumeIndex, unsigned char channels, AudioFifo *audioFifo);
|
||||
void pushMbeFrame(
|
||||
const unsigned char *mbeFrame,
|
||||
int mbeRateIndex,
|
||||
int mbeVolumeIndex,
|
||||
unsigned char channels,
|
||||
bool useHP,
|
||||
AudioFifo *audioFifo);
|
||||
|
||||
const QTimer& getMasterTimer() const { return m_masterTimer; }
|
||||
|
||||
|
@ -247,7 +247,13 @@ void DVSerialEngine::getDevicesNames(std::vector<std::string>& deviceNames)
|
||||
}
|
||||
}
|
||||
|
||||
void DVSerialEngine::pushMbeFrame(const unsigned char *mbeFrame, int mbeRateIndex, int mbeVolumeIndex, unsigned char channels, AudioFifo *audioFifo)
|
||||
void DVSerialEngine::pushMbeFrame(
|
||||
const unsigned char *mbeFrame,
|
||||
int mbeRateIndex,
|
||||
int mbeVolumeIndex,
|
||||
unsigned char channels,
|
||||
bool useLP,
|
||||
AudioFifo *audioFifo)
|
||||
{
|
||||
std::vector<DVSerialController>::iterator it = m_controllers.begin();
|
||||
std::vector<DVSerialController>::iterator itAvail = m_controllers.end();
|
||||
@ -258,7 +264,7 @@ void DVSerialEngine::pushMbeFrame(const unsigned char *mbeFrame, int mbeRateInde
|
||||
{
|
||||
if (it->worker->hasFifo(audioFifo))
|
||||
{
|
||||
it->worker->pushMbeFrame(mbeFrame, mbeRateIndex, mbeVolumeIndex, channels, audioFifo);
|
||||
it->worker->pushMbeFrame(mbeFrame, mbeRateIndex, mbeVolumeIndex, channels, useLP, audioFifo);
|
||||
done = true;
|
||||
}
|
||||
else if (it->worker->isAvailable())
|
||||
@ -276,7 +282,7 @@ void DVSerialEngine::pushMbeFrame(const unsigned char *mbeFrame, int mbeRateInde
|
||||
int wNum = itAvail - m_controllers.begin();
|
||||
|
||||
qDebug("DVSerialEngine::pushMbeFrame: push %p on empty queue %d", audioFifo, wNum);
|
||||
itAvail->worker->pushMbeFrame(mbeFrame, mbeRateIndex, mbeVolumeIndex, channels, audioFifo);
|
||||
itAvail->worker->pushMbeFrame(mbeFrame, mbeRateIndex, mbeVolumeIndex, channels, useLP, audioFifo);
|
||||
}
|
||||
else
|
||||
{
|
||||
|
@ -41,7 +41,13 @@ public:
|
||||
int getNbDevices() const { return m_controllers.size(); }
|
||||
void getDevicesNames(std::vector<std::string>& devicesNames);
|
||||
|
||||
void pushMbeFrame(const unsigned char *mbeFrame, int mbeRateIndex, int mbeVolumeIndex, unsigned char channels, AudioFifo *audioFifo);
|
||||
void pushMbeFrame(
|
||||
const unsigned char *mbeFrame,
|
||||
int mbeRateIndex,
|
||||
int mbeVolumeIndex,
|
||||
unsigned char channels,
|
||||
bool useHP,
|
||||
AudioFifo *audioFifo);
|
||||
|
||||
private:
|
||||
struct DVSerialController
|
||||
|
@ -81,6 +81,8 @@ void DVSerialWorker::handleInputMessages()
|
||||
MsgMbeDecode *decodeMsg = (MsgMbeDecode *) message;
|
||||
int dBVolume = (decodeMsg->getVolumeIndex() - 30) / 2;
|
||||
|
||||
m_upsampleFilter.useHP(decodeMsg->getUseHP());
|
||||
|
||||
if (m_dvController.decode(m_dvAudioSamples, decodeMsg->getMbeFrame(), decodeMsg->getMbeRate(), dBVolume))
|
||||
{
|
||||
upsample6(m_dvAudioSamples, SerialDV::MBE_AUDIO_BLOCK_SIZE, decodeMsg->getChannels());
|
||||
@ -111,10 +113,12 @@ void DVSerialWorker::handleInputMessages()
|
||||
void DVSerialWorker::pushMbeFrame(const unsigned char *mbeFrame,
|
||||
int mbeRateIndex,
|
||||
int mbeVolumeIndex,
|
||||
unsigned char channels, AudioFifo *audioFifo)
|
||||
unsigned char channels,
|
||||
bool useHP,
|
||||
AudioFifo *audioFifo)
|
||||
{
|
||||
m_audioFifo = audioFifo;
|
||||
m_inputMessageQueue.push(MsgMbeDecode::create(mbeFrame, mbeRateIndex, mbeVolumeIndex, channels, audioFifo));
|
||||
m_inputMessageQueue.push(MsgMbeDecode::create(mbeFrame, mbeRateIndex, mbeVolumeIndex, channels, useHP, audioFifo));
|
||||
}
|
||||
|
||||
bool DVSerialWorker::isAvailable()
|
||||
|
@ -54,11 +54,18 @@ public:
|
||||
SerialDV::DVRate getMbeRate() const { return m_mbeRate; }
|
||||
int getVolumeIndex() const { return m_volumeIndex; }
|
||||
unsigned char getChannels() const { return m_channels % 4; }
|
||||
bool getUseHP() const { return m_useHP; }
|
||||
AudioFifo *getAudioFifo() { return m_audioFifo; }
|
||||
|
||||
static MsgMbeDecode* create(const unsigned char *mbeFrame, int mbeRateIndex, int volumeIndex, unsigned char channels, AudioFifo *audioFifo)
|
||||
static MsgMbeDecode* create(
|
||||
const unsigned char *mbeFrame,
|
||||
int mbeRateIndex,
|
||||
int volumeIndex,
|
||||
unsigned char channels,
|
||||
bool useHP,
|
||||
AudioFifo *audioFifo)
|
||||
{
|
||||
return new MsgMbeDecode(mbeFrame, (SerialDV::DVRate) mbeRateIndex, volumeIndex, channels, audioFifo);
|
||||
return new MsgMbeDecode(mbeFrame, (SerialDV::DVRate) mbeRateIndex, volumeIndex, channels, useHP, audioFifo);
|
||||
}
|
||||
|
||||
private:
|
||||
@ -66,17 +73,20 @@ public:
|
||||
SerialDV::DVRate m_mbeRate;
|
||||
int m_volumeIndex;
|
||||
unsigned char m_channels;
|
||||
bool m_useHP;
|
||||
AudioFifo *m_audioFifo;
|
||||
|
||||
MsgMbeDecode(const unsigned char *mbeFrame,
|
||||
SerialDV::DVRate mbeRate,
|
||||
int volumeIndex,
|
||||
unsigned char channels,
|
||||
bool useHP,
|
||||
AudioFifo *audioFifo) :
|
||||
Message(),
|
||||
m_mbeRate(mbeRate),
|
||||
m_volumeIndex(volumeIndex),
|
||||
m_channels(channels),
|
||||
m_useHP(useHP),
|
||||
m_audioFifo(audioFifo)
|
||||
{
|
||||
memcpy((void *) m_mbeFrame, (const void *) mbeFrame, SerialDV::DVController::getNbMbeBytes(m_mbeRate));
|
||||
@ -90,6 +100,7 @@ public:
|
||||
int mbeRateIndex,
|
||||
int mbeVolumeIndex,
|
||||
unsigned char channels,
|
||||
bool useHP,
|
||||
AudioFifo *audioFifo);
|
||||
|
||||
bool open(const std::string& serialDevice);
|
||||
|
@ -17,40 +17,23 @@
|
||||
|
||||
#include "filtermbe.h"
|
||||
|
||||
const float MBEAudioInterpolatorFilter::m_a0 = 3.869430E-02;
|
||||
const float MBEAudioInterpolatorFilter::m_a1 = 7.738860E-02;
|
||||
const float MBEAudioInterpolatorFilter::m_a2 = 3.869430E-02;
|
||||
const float MBEAudioInterpolatorFilter::m_b1 = 1.392667E+00;
|
||||
const float MBEAudioInterpolatorFilter::m_b2 = -5.474446E-01;
|
||||
const float MBEAudioInterpolatorFilter::m_lpa[3] = {1.0, 1.392667E+00, -5.474446E-01};
|
||||
const float MBEAudioInterpolatorFilter::m_lpb[3] = {3.869430E-02, 7.738860E-02, 3.869430E-02};
|
||||
|
||||
MBEAudioInterpolatorFilter::MBEAudioInterpolatorFilter()
|
||||
const float MBEAudioInterpolatorFilter::m_hpa[3] = {1.000000e+00, 1.911437E+00, -9.155749E-01};
|
||||
const float MBEAudioInterpolatorFilter::m_hpb[3] = {9.567529E-01, -1.913506E+00, 9.567529E-01};
|
||||
|
||||
MBEAudioInterpolatorFilter::MBEAudioInterpolatorFilter() :
|
||||
m_filterLP(m_lpa, m_lpb),
|
||||
m_filterHP(m_hpa, m_hpb),
|
||||
m_useHP(false)
|
||||
{
|
||||
init();
|
||||
}
|
||||
|
||||
MBEAudioInterpolatorFilter::~MBEAudioInterpolatorFilter()
|
||||
{}
|
||||
|
||||
void MBEAudioInterpolatorFilter::init()
|
||||
float MBEAudioInterpolatorFilter::run(const float& sample)
|
||||
{
|
||||
m_x[0] = 0.0f;
|
||||
m_x[1] = 0.0f;
|
||||
m_y[0] = 0.0f;
|
||||
m_y[1] = 0.0f;
|
||||
return m_useHP ? m_filterLP.run(m_filterHP.run(sample)) : m_filterLP.run(sample);
|
||||
}
|
||||
|
||||
float MBEAudioInterpolatorFilter::run(float sample)
|
||||
{
|
||||
float y = m_a0*sample + m_a1*m_x[0] + m_a2*m_x[1] + m_b1*m_y[0] + m_b2*m_y[1]; // this is y[n]
|
||||
|
||||
m_x[1] = m_x[0];
|
||||
m_x[0] = sample;
|
||||
|
||||
m_y[1] = m_y[0];
|
||||
m_y[0] = y;
|
||||
|
||||
return y;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
@ -19,35 +19,61 @@
|
||||
#define SDRBASE_DSP_FILTERMBE_H_
|
||||
|
||||
/**
|
||||
* This is a 2 pole lowpass Chebyshev (recursive) filter at fc=0.075 using coefficients found in table 20-1 of
|
||||
* http://www.analog.com/media/en/technical-documentation/dsp-book/dsp_book_Ch20.pdf
|
||||
* Uses the generic IIR filter internally
|
||||
*
|
||||
* Low pass / High pass:
|
||||
*
|
||||
* This is a 2 pole Chebyshev (recursive) filter using coefficients found in table 20-1 (low pass)
|
||||
* or table 20-2 (high pass) of http://www.analog.com/media/en/technical-documentation/dsp-book/dsp_book_Ch20.pdf
|
||||
*
|
||||
* For low pass fc = 0.075
|
||||
* For high oass fc = 0.01
|
||||
*
|
||||
* Convention taken here exchanges A and B coefficients as shown in this image:
|
||||
* https://cdn.mikroe.com/ebooks/img/8/2016/02/digital-filter-design-chapter-03-image-2-9.gif
|
||||
* So A applies to Y and B to X
|
||||
*
|
||||
* At the interpolated sampling frequency of 48 kHz the -3 dB corner is at 48 * .075 = 3.6 kHz which is perfect for voice
|
||||
* The high pass has a 3 dB corner of 48 * 0.01 = 0.48 kHz
|
||||
*
|
||||
* a0= 3.869430E-02
|
||||
* a1= 7.738860E-02 b1= 1.392667E+00
|
||||
* a2= 3.869430E-02 b2= -5.474446E-01
|
||||
* Low pass:
|
||||
*
|
||||
* b0 = 3.869430E-02 (a0 = 1.0)
|
||||
* b1 = 7.738860E-02 a1 = 1.392667E+00
|
||||
* b2 = 3.869430E-02 a2 = -5.474446E-01
|
||||
*
|
||||
* High pass:
|
||||
*
|
||||
* b0 = 9.567529E-01 (a0 = 1.0)
|
||||
* b1 = -1.913506E+00 a1 = 1.911437E+00
|
||||
* b2 = 9.567529E-01 a2 = -9.155749E-01
|
||||
*
|
||||
* given x[n] is the new input sample and y[n] the returned output sample:
|
||||
*
|
||||
* y[n] = a0*x[n] + a1*x[n] + a2*x[n] + b1*y[n-1] + b2*y[n-2]
|
||||
* y[n] = b0*x[n] + b1*x[n] + b2*x[n] + a1*y[n-1] + a2*y[n-2]
|
||||
*
|
||||
* This one works directly with floats
|
||||
*
|
||||
*
|
||||
*/
|
||||
|
||||
#include "iirfilter.h"
|
||||
|
||||
class MBEAudioInterpolatorFilter
|
||||
{
|
||||
public:
|
||||
MBEAudioInterpolatorFilter();
|
||||
~MBEAudioInterpolatorFilter();
|
||||
|
||||
void init();
|
||||
float run(float sample);
|
||||
void useHP(bool useHP) { m_useHP = useHP; }
|
||||
float run(const float& sample);
|
||||
|
||||
private:
|
||||
float m_x[2];
|
||||
float m_y[2];
|
||||
static const float m_a0, m_a1, m_a2, m_b1, m_b2;
|
||||
IIRFilter<float, 2> m_filterLP;
|
||||
IIRFilter<float, 2> m_filterHP;
|
||||
bool m_useHP;
|
||||
static const float m_lpa[3], m_lpb[3]; // low pass coefficients
|
||||
static const float m_hpa[3], m_hpb[3]; // band pass coefficients
|
||||
};
|
||||
|
||||
|
||||
|
@ -15,10 +15,16 @@
|
||||
// along with this program. If not, see <http://www.gnu.org/licenses/>. //
|
||||
///////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
/**
|
||||
* IIR filter
|
||||
* See: https://cdn.mikroe.com/ebooks/img/8/2016/02/digital-filter-design-chapter-03-image-2-9.gif
|
||||
*/
|
||||
|
||||
#ifndef SDRBASE_DSP_IIRFILTER_H_
|
||||
#define SDRBASE_DSP_IIRFILTER_H_
|
||||
|
||||
#include <stdint.h>
|
||||
#include <string.h>
|
||||
#include <assert.h>
|
||||
|
||||
template <typename Type, uint32_t Order> class IIRFilter
|
||||
@ -26,7 +32,8 @@ template <typename Type, uint32_t Order> class IIRFilter
|
||||
public:
|
||||
IIRFilter(const Type *a, const Type *b);
|
||||
~IIRFilter();
|
||||
Type run(Type sample);
|
||||
void setCoeffs(const Type *a, const Type *b);
|
||||
Type run(const Type& sample);
|
||||
|
||||
private:
|
||||
Type *m_a;
|
||||
@ -40,7 +47,8 @@ template <typename Type> class IIRFilter<Type, 2>
|
||||
public:
|
||||
IIRFilter(const Type *a, const Type *b);
|
||||
~IIRFilter();
|
||||
Type run(Type sample);
|
||||
void setCoeffs(const Type *a, const Type *b);
|
||||
Type run(const Type& sample);
|
||||
|
||||
private:
|
||||
Type m_a[3];
|
||||
@ -59,14 +67,7 @@ IIRFilter<Type, Order>::IIRFilter(const Type *a, const Type *b)
|
||||
m_x = new Type[Order];
|
||||
m_y = new Type[Order];
|
||||
|
||||
memcpy(m_a, a, (Order+1)*sizeof(Type));
|
||||
memcpy(m_b, b, (Order+1)*sizeof(Type));
|
||||
|
||||
for (int i = 0; i < Order; i++)
|
||||
{
|
||||
m_x[i] = 0;
|
||||
m_y[i] = 0;
|
||||
}
|
||||
setCoeffs(a, b);
|
||||
}
|
||||
|
||||
template <typename Type, uint32_t Order>
|
||||
@ -79,30 +80,47 @@ IIRFilter<Type, Order>::~IIRFilter()
|
||||
}
|
||||
|
||||
template <typename Type, uint32_t Order>
|
||||
Type IIRFilter<Type, Order>::run(Type sample)
|
||||
void IIRFilter<Type, Order>::setCoeffs(const Type *a, const Type *b)
|
||||
{
|
||||
Type y = m_a[0] * sample;
|
||||
memcpy(m_a, b, (Order+1)*sizeof(Type));
|
||||
memcpy(m_b, a, (Order+1)*sizeof(Type));
|
||||
|
||||
for (int i = 0; i < Order; i++)
|
||||
for (uint32_t i = 0; i < Order; i++)
|
||||
{
|
||||
y += m_a[i+1] * m_x[i] + m_b[i+1] * m_y[i];
|
||||
m_x[i] = 0;
|
||||
m_y[i] = 0;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
template <typename Type, uint32_t Order>
|
||||
Type IIRFilter<Type, Order>::run(const Type& sample)
|
||||
{
|
||||
Type y = m_b[0] * sample;
|
||||
|
||||
for (uint32_t i = Order; i > 0; i--)
|
||||
{
|
||||
y += m_b[i] * m_x[i-1] + m_a[i] * m_y[i-1];
|
||||
|
||||
if (i > 1) // shift
|
||||
{
|
||||
m_x[i-1] = m_x[i-2];
|
||||
m_y[i-1] = m_y[i-2];
|
||||
}
|
||||
}
|
||||
|
||||
// last shift
|
||||
m_x[0] = sample;
|
||||
m_y[0] = y;
|
||||
|
||||
memcpy(&m_x[1], &m_x[0], (Order-1)*sizeof(Type));
|
||||
return y;
|
||||
}
|
||||
|
||||
|
||||
template <typename Type>
|
||||
IIRFilter<Type, 2>::IIRFilter(const Type *a, const Type *b)
|
||||
{
|
||||
m_a[0] = a[0];
|
||||
m_a[1] = a[1];
|
||||
m_a[2] = a[2];
|
||||
m_b[0] = b[0];
|
||||
m_b[1] = b[1];
|
||||
m_b[2] = b[2];
|
||||
setCoeffs(a, b);
|
||||
}
|
||||
|
||||
template <typename Type>
|
||||
@ -111,9 +129,24 @@ IIRFilter<Type, 2>::~IIRFilter()
|
||||
}
|
||||
|
||||
template <typename Type>
|
||||
Type IIRFilter<Type, 2>::run(Type sample)
|
||||
void IIRFilter<Type, 2>::setCoeffs(const Type *a, const Type *b)
|
||||
{
|
||||
Type y = m_a[0]*sample + m_a[1]*m_x[0] + m_a[2]*m_x[1] + m_b[1]*m_y[0] + m_b[2]*m_y[1]; // this is y[n]
|
||||
m_a[0] = a[0];
|
||||
m_a[1] = a[1];
|
||||
m_a[2] = a[2];
|
||||
m_b[0] = b[0];
|
||||
m_b[1] = b[1];
|
||||
m_b[2] = b[2];
|
||||
m_x[0] = 0;
|
||||
m_x[1] = 0;
|
||||
m_y[0] = 0;
|
||||
m_y[1] = 0;
|
||||
}
|
||||
|
||||
template <typename Type>
|
||||
Type IIRFilter<Type, 2>::run(const Type& sample)
|
||||
{
|
||||
Type y = m_b[0]*sample + m_b[1]*m_x[0] + m_b[2]*m_x[1] + m_a[1]*m_y[0] + m_a[2]*m_y[1]; // this is y[n]
|
||||
|
||||
m_x[1] = m_x[0];
|
||||
m_x[0] = sample;
|
||||
|
Loading…
Reference in New Issue
Block a user