第2C部分:使用VPU加速
与第2B部分一样,第2C部分使用定点算术实现了FIR滤波器。
在第2B部分中,我们调用了int32_dot()来计算内积。虽然int32_dot()比我们在C中编写的编译器生成的内积要快得多,但int32_dot()仍然只使用了xcore设备的标量算术单元。
第2C部分将int32_dot()替换为对vect_s32_dot()的调用,这是来自lib_xcore_math的库函数之一,它使用VPU来进行计算。
我们将看到使用VPU可以显著提高速度。
来自lib_xcore_math
本阶段使用了lib_xcore_math中的以下操作:
实现
在本部分中,filter_task()、rx_frame()和tx_frame()与第2A部分和第2B部分中的相同。
src/part2C/part2C.c
// 将滤波器应用于产生单个输出样本
q1_31 filter_sample(
const q1_31 sample_history[TAP_COUNT])
{
// 与滤波器系数关联的指数
const exponent_t coef_exp = -28;
// 与输入信号关联的指数
const exponent_t input_exp = -31;
// 与输出信号关联的指数
const exponent_t output_exp = input_exp;
// 与累加器关联的指数
const exponent_t acc_exp = input_exp + coef_exp + 30;
// 为了实现正确的输出指数,对滤波器的累加器应用算术右移位
const right_shift_t acc_shr = output_exp - acc_exp;
// 使用lib_xcore_math中的优化函数计算样本历史和滤波器系数之间的64位内积
int64_t acc = vect_s32_dot(&sample_history[0],
&filter_coef[0],
TAP_COUNT,
0,
0);
// 应用右移位操作,将位深度降至32位
return ashr64(acc,
acc_shr);
}
vect_s32_dot()与int32_dot()有一个重要的区别,我们需要考虑到这一点。
C_API
int64_t vect_s32_dot(
const int32_t b[],
const int32_t c[],
const unsigned length,
const right_shift_t b_shr,
const right_shift_t c_shr);
int32_dot()的输出是两个int32_t向量的直接内积,而vect_s32_dot()在硬件上有一些额外的操作,一些是由硬件强制要求的,一些是为了块浮点运算而需要的。