Skip to main content
欢迎来到PAWPAW技术文档网站了解更多信息

第4C部分:XMath滤波器生成脚本

第4B部分中,使用了lib_xcore_math的数字滤波器API来实现FIR滤波器。第4C部分也使用了FIR滤波器API,但是间接地使用。

除了数字滤波器API外,lib_xcore_math还提供了一组用于将现有的浮点系数数字滤波器转换为与xcore兼容形式的Python脚本,甚至生成可以直接编译到应用程序中的代码。

特别是对于本示例,使用了gen_fir_filter_s32.py脚本,并使用coef.csv作为输入,生成了userFilter.cuserFilter.h。该脚本生成了一个带有名称的滤波器,生成的API中的函数名基于滤波器名称。在本例中,调用脚本时指定的滤波器名称为"userFilter"。

使用这些脚本生成的滤波器分配和管理自己的内存,因此API调用非常简单。

来自lib_xcore_math

本阶段不直接调用lib_xcore_math中的任何函数,但使用了gen_fir_filter_s32.py滤波器转换脚本。

生成滤波器

本阶段使用的userFilter.cuserFilter.h是作为本教程的便利而提供的。您可以使用gen_fir_filter_s32.py自行生成这些文件。这将需要安装有numpy的Python 3。

> python gen_fir_filter_s32.py -h
usage: gen_fir_filter_s32.py [-h] [--taps TAPS] [--out-dir OUT_DIR] [--input-headroom INPUT_HEADROOM] [--output-headroom OUTPUT_HEADROOM]
filter_name filter_coefficients

该脚本需要两个参数:滤波器的名称filter_name,以及包含滤波器系数的.csv文件的路径。滤波器系数必须是浮点值,系数之间用逗号和/或空格分隔。系数的顺序是b[0]b[1]b[2]等。

要生成滤波器,请从工作区根目录开始:

cd xmath_walkthrough/src/stage11
python ../../lib_xcore_math/lib_xcore_math/script/gen_fir_filter_s32.py --taps 1024 userFilter coef.csv

输出应类似于以下内容:

workspace/xmath_walkthrough/src/part4C> python ../../lib_xcore_math/lib_xcore_math/script/gen_fir_filter_s32.py --taps 1024 userFilter coef.csv
Filter tap count: 1024
Files to be written:
./userFilter.h
./userFilter.c

--taps选项用于确保转换后的滤波器具有预期的滤波器系数数量。

实现

第4C部分中的rx_frame()tx_frame()第4B部分中的相同。第4C部分还包括两个额外的文件userFilter.huserFilter.c,这些文件是由滤波器转换脚本生成的。这些文件被设计为不透明的,但非常简单,所以可以随意查看。

src/part4C/part4C.c
/**
* This is the thread entry point for the hardware thread which will actually
* be applying the FIR filter.
*
* `c_audio` is the channel over which PCM audio data is exchanged with tile[0].
*/
void filter_task(
chanend_t c_audio)
{
// This buffer is where input/output samples will be placed.
int32_t sample_buffer[FRAME_SIZE] = {0};

// Initialize userFilter. userFilter allocates and manages its own buffers and
// filter object, so no buffer needs to be supplied.
userFilter_init();

// If userFilter_exp_diff is not 0, the results will be wrong.
assert(userFilter_exp_diff == 0);

// Loop forever
while(1) {

// Read in a new frame
rx_frame(&sample_buffer[0],
c_audio);

// Compute FRAME_SIZE output samples.
for(int s = 0; s < FRAME_SIZE; s++){
timer_start(TIMING_SAMPLE);
// userFilter() is the generated function to add a new input sample and get
// back the filtered result.
sample_buffer[s] = userFilter(sample_buffer[s]);
timer_stop(TIMING_SAMPLE);
}

// Send out the processed frame
tx_frame(c_audio,
&sample_buffer[0]);
}
}

我们可以看到,这只是第10阶段filter_task()的简化版本。在这里,我们不需要手动声明状态并显式初始化filter_fir_s32_t对象,而是调用生成的函数userFilter_init()(来自userFilter.h)来为我们初始化所有内容。然后,我们不再调用filter_fir_s32()来获取新的输出样本,而是使用我们的新输入样本调用userFilter()

结果

时间

时间类型测量时间
每个滤波器系数4.81 ns
每个输出样本4920.95 ns
每帧1311088.12 ns

输出波形

第4C部分输出