CSI-DSP  Version 1.0.0
CSI DSP Software Library
函数
最小均方 (LMS) 滤波器

函数

void csky_lms_f32 (const csky_lms_instance_f32 *S, float32_t *pSrc, float32_t *pRef, float32_t *pOut, float32_t *pErr, uint32_t blockSize)
 浮点LMS滤波器处理函数 更多...
 
void csky_lms_init_f32 (csky_lms_instance_f32 *S, uint16_t numTaps, float32_t *pCoeffs, float32_t *pState, float32_t mu, uint32_t blockSize)
 浮点LMS滤波器初始化函数 更多...
 
void csky_lms_init_q15 (csky_lms_instance_q15 *S, uint16_t numTaps, q15_t *pCoeffs, q15_t *pState, q15_t mu, uint32_t blockSize, uint32_t postShift)
 Q15 LMS滤波器初始化函数 更多...
 
void csky_lms_init_q31 (csky_lms_instance_q31 *S, uint16_t numTaps, q31_t *pCoeffs, q31_t *pState, q31_t mu, uint32_t blockSize, uint32_t postShift)
 Q31 LMS滤波器初始化函数 更多...
 
void csky_lms_q15 (const csky_lms_instance_q15 *S, q15_t *pSrc, q15_t *pRef, q15_t *pOut, q15_t *pErr, uint32_t blockSize)
 Q15 LMS滤波器处理函数 更多...
 
void csky_lms_q31 (const csky_lms_instance_q31 *S, q31_t *pSrc, q31_t *pRef, q31_t *pOut, q31_t *pErr, uint32_t blockSize)
 Q31 LMS滤波器处理函数 更多...
 

简要说明

LMS 滤波器是一类自适应滤波器,使用的是一种梯度下降的算法,根据瞬时误差更新滤波器的系数, 达到“学习”一种未知的转换方式目的。

自适应滤波器常应用在通信系统,均衡器,和噪声去除。

CSI DSP 库内的LMS滤波器函数支持 Q15, Q31和浮点数据类型。

库内也有归一化 LMS 滤波器,归一化LMS滤波器系数自适应与输入信号的电平无关。

一个LMS滤波器包括以下两个部分:

LMS 滤波器有两个输入信号。一个是接受的输入信号,另一个是参考的输入信号, 输出两个信号,一个是FIR滤波器的输出信号,另一个是与参考输入相比的误差信号。 滤波器根据输出和参考输入之间的差值更新系数, 直到FIR滤波器的FIR滤波器的输出跟参考输入相符。 误差通过滤波器的调解倾向于0。

LMS.gif
最小均方滤波器结构

函数以块为单位处理数据,每次调用滤波器函数处理 blockSize 个样本。 pSrc 指向输入信号, pRef 指向参考信号, pOut 指向输出信号和 pErr 指向误差信号。 所有的数组都包括 blockSize 个值。

函数以块为单位操作。 滤波器内部系数 b[n] 以样本为单位更新。

算法:
输出信号 y[n] 通过标准FIR滤波器计算:
     y[n] = b[0] * x[n] + b[1] * x[n-1] + b[2] * x[n-2] + ...+ b[numTaps-1] * x[n-numTaps+1]
 
误差信号等于参考信号 d[n] 和滤波器输出的差值:
     e[n] = d[n] - y[n].
 
计算每个误差信号的每个样本后,滤波器系数 b[k] 以样本为单位更新:
     b[k] = b[k] + e[n] * mu * x[n-k],  for k=0, 1, ..., numTaps-1
 
其中 mu 是步进大小,控制系数收敛速率。
接口中, pCoeffs 指向系数数组,大小是 numTaps. 系数保存的顺序如下:
    {b[numTaps-1], b[numTaps-2], b[N-2], ..., b[1], b[0]}
 
pState 指向状态数组,数组大小是 numTaps + blockSize - 1. 样本在状态缓存中的保存顺序是:
    {x[n-numTaps+1], x[n-numTaps], x[n-numTaps-1], x[n-numTaps-2]....x[0], x[1], ..., x[blockSize-1]}
 
注意:状态缓存的长度超过了系数数组 blockSize-1 个样本. 增长的状态缓存长度可以用来取代传统FIR滤波器使用的循环寻址,从而显著提高速度。 状态变量在每块数据处理后更新。
结构体实例
滤波器的系数和状态变量都保存在数据结构的实例中。 每个滤波器都必须有一个单独的结构体实例。 系数数组可能可以在几个实例之间共享,但是状态变量数组不能共享。 为支持的3种数据类型分别提供了不同的结构体实例声明。
初始化函数
为每种支持的数据类型都提供了一个相应的初始化函数。 初始化函数处理以下操作:
  • 设置内部结构体字段的值
  • 清零状态缓存中的值 如果手动初始化,而不调用初始化函数,需要指定结构体实例的以下字段: numTaps, pCoeffs, mu, postShift (f32不需要), pState. pState中的所有值置0.
是否使用初始化函数是可选的。 但是,使用了初始化函数,则不能将结构体实例放在常量数据段。 要将结构体实例放在常量数据段,则必须手动初始化结构体实例。 在静态初始化之前,要确保状态缓存中的值已经清零。 下面的代码,为3种不同的滤波器,静态的初始化了结构体实例。
    csky_lms_instance_f32 S = {numTaps, pState, pCoeffs, mu};
    csky_lms_instance_q31 S = {numTaps, pState, pCoeffs, mu, postShift};
    csky_lms_instance_q15 S = {numTaps, pState, pCoeffs, mu, postShift};
 
其中 numTaps 是滤波器系数的数量; pState 是状态缓存的地址; pCoeffs 是系数缓存的地址; mu 是步进大小; postShift 是系数的移位数.
定点行为:
使用Q15和Q31版本的LMS滤波器函数需要注意。 下列问题必须考虑:
  • 系数缩放
  • 溢出和饱和
系数缩放:
滤波器系数表示为一个小数值,被限制在范围 [-1 +1)之间。 定点函数有一个附加的缩放参数 postShift。 滤波器的输出累加器是一个可移位的寄存器,结果移动 postShift 位。 基本上就是将滤波器系数缩放 2^postShift , 允许将滤波器的系数扩展到超过范围 [+1 -1)postShift 的值根据用户系统模型期望的增益设定。
溢出和饱和:
Q15和Q31版本的溢出和饱和分别描述在各个函数各自的文档部分。

函数说明

void csky_lms_f32 ( const csky_lms_instance_f32 S,
float32_t pSrc,
float32_t pRef,
float32_t pOut,
float32_t pErr,
uint32_t  blockSize 
)

这个函数操作浮点类型的数据

参数
[in]*S指向浮点LMS滤波器结构体实例
[in]*pSrc指向输入数据块
[in]*pRef指向参考数据块
[out]*pOut指向输出数据块
[out]*pErr指向误差数据块
[in]blockSize处理的样本的数量
返回
none.
void csky_lms_init_f32 ( csky_lms_instance_f32 S,
uint16_t  numTaps,
float32_t pCoeffs,
float32_t pState,
float32_t  mu,
uint32_t  blockSize 
)
参数
[in]*S指向浮点LMS滤波器结构体实例
[in]numTaps滤波器系数的数量
[in]*pCoeffs指向系数缓存
[in]*pState指向状态缓存
[in]mu控制滤波器系数更新的步进大小
[in]blockSize处理的样本数量
返回
none.
描述说明:
pCoeffs 指向滤波器系数的数组,保存的顺序如下:
   {b[numTaps-1], b[numTaps-2], b[N-2], ..., b[1], b[0]}
初始化滤波器系数作为自适应滤波器的起始点 pState 指向一个长度为 numTaps+blockSize-1 样本数组, 其中 blockSize 是处理的输入样本数量,传入函数 csky_lms_f32().
void csky_lms_init_q15 ( csky_lms_instance_q15 S,
uint16_t  numTaps,
q15_t pCoeffs,
q15_t pState,
q15_t  mu,
uint32_t  blockSize,
uint32_t  postShift 
)
参数
[in]*S指向Q15 LMS滤波器结构体实例
[in]numTaps滤波器系数的数量
[in]*pCoeffs指向参数缓存
[in]*pState指向状态缓存
[in]mu控制滤波器系数更新的步进大小
[in]blockSize处理的样本数量
[in]postShift系数的移位数
返回
none.
描述说明:
pCoeffs 指向滤波器系数保存的数组,保存的顺序如下:
   {b[numTaps-1], b[numTaps-2], b[N-2], ..., b[1], b[0]}
初始化的滤波器系数被看做自适应滤波器的起始点。 pState 指向状态变量数组,数组大小是 numTaps+blockSize-1 , 其中 blockSize 是处理的输入样本的数量, 传入 csky_lms_q15().
void csky_lms_init_q31 ( csky_lms_instance_q31 S,
uint16_t  numTaps,
q31_t pCoeffs,
q31_t pState,
q31_t  mu,
uint32_t  blockSize,
uint32_t  postShift 
)
参数
[in]*S指向Q31 LMS滤波器结构体实例
[in]numTaps滤波器系数的数量
[in]*pCoeffs指向参数缓存
[in]*pState指向状态缓存
[in]mu控制滤波器系数更新的步进大小
[in]blockSize处理的样本数量
[in]postShift系数的移位数
返回
none.
描述说明:
pCoeffs 指向滤波器系数保存的数组,保存的顺序如下:
   {b[numTaps-1], b[numTaps-2], b[N-2], ..., b[1], b[0]}
初始化的滤波器系数被看做自适应滤波器的起始点。 pState 指向状态变量数组,数组大小是 numTaps+blockSize-1, 其中 blockSize是处理的输入样本的数量,传入 csky_lms_q31().
void csky_lms_q15 ( const csky_lms_instance_q15 S,
q15_t pSrc,
q15_t pRef,
q15_t pOut,
q15_t pErr,
uint32_t  blockSize 
)
参数
[in]*S指向Q15 LMS滤波器结构体实例
[in]*pSrc指向输入数据块
[in]*pRef指向参考数据块
[out]*pOut指向输出数据块
[out]*pErr指向误差数据块
[in]blockSize处理的样本的数量
返回
none.
缩放和溢出行为:
函数实现使用了一个内部64位累加器。 系数和状态变量都表示为1.15格式。 中间乘法生成2.30格式的结果,结果在34.30格式的64位累加器累加。 因为有33位保护位,所以不会有溢出的风险。同时还可以保存所有的中间乘法结果的精度。 最后,34.30格式的丢弃低15位截断为34.15,然后饱和生成1.15格式的结果。
这个滤波器中,滤波器系数会根据样本更新,并且系数更新是饱和的。
void csky_lms_q31 ( const csky_lms_instance_q31 S,
q31_t pSrc,
q31_t pRef,
q31_t pOut,
q31_t pErr,
uint32_t  blockSize 
)
参数
[in]*S指向Q31 LMS滤波器结构体实例
[in]*pSrc指向输入数据块
[in]*pRef指向参考数据块
[out]*pOut指向输出数据块
[out]*pErr指向误差数据块
[in]blockSize处理的样本的数量
返回
none.
缩放和溢出行为:
函数实现使用了一个内部64位累加器。 累加器是2.62格式,并且维持了中间乘法结果的所有精度,但是只有一个保护位。 为了防止溢出,输入信号必须缩小 log2(numTaps) 位. 参考信号不应该缩小。 在所有的乘累加处理后,2.62格式累加器右移,然后饱和生成1.31最后的结果 输出信号和错误信号是 1.31 格式.
这个滤波器中,滤波器系数会根据样本更新,并且系数更新是饱和的。