在嵌入式中如何对对数log函数加速

1. 概述

        对数由于其卓越的性能在工程中应用广泛,特别是无线通信中经常会需要计算对数的情况,虽然相关的开发语言(如C语言)已经内置了对应计算的函数,但对于一些性能要求较高的场景,需要对计算对数的时间性能进行跨数量级提升,以下就针对嵌入式平台提供数种优化手段。

验证环境如下:

MCU型号:STM32F407

主频配置:16MHz

2. 原生log函数有多耗时

HAL_GPIO_WritePin(GPIOA, GPIO_PIN_6, GPIO_PIN_RESET);
td=log10(t++);
HAL_GPIO_WritePin(GPIOA, GPIO_PIN_6, GPIO_PIN_SET);
HAL_Delay(100);

        通过示波器测量其IO的脉冲宽度log函数略约为:210us,log耗时较长,跳转到log函数的有文件声明,如下:

        发现其log10函数使用了双精度浮点,也会导致log函数的耗时过长,在精度满足下可以使用单精度降低log耗时,翻阅math.h文件发现log10f采用了单精度,如下:

3. 使用log10f方案

        将log10函数替换为log10f函数,如下:

HAL_GPIO_WritePin(GPIOA, GPIO_PIN_6, GPIO_PIN_RESET);
td=log10f(t++);
HAL_GPIO_WritePin(GPIOA, GPIO_PIN_6, GPIO_PIN_SET);
HAL_Delay(100);

        通过示波器测量其IO的脉冲宽度log函数略约为:103us,相对与log10耗时下降了1倍左右。另外log10f采用了单精度浮点,那么开启硬件单精度浮点应该进一步加速。

4. 使用log10f+硬件浮点方案

        在log10f基础上配置开启硬件浮点运算,在keil上开启方式如下:

        在STM32CubeIDE开启方式如下:        开启后重新测试log10f耗时:17.8us,相对与纯软件log10f耗时下降了6倍左右。

5. 使用查表方案

        对于一些MCU或者SOC不支持硬件浮点功能,使用上面的解决方案优化效果有限,这时在精度要求不高情况下就可以使用查表方案这种空间换取时间策略来优化耗时。首先log函数是一种单调递减函数,且递减速度下降极快,如下图所示:

        基于以上情况就可以使用分段的y=b来拟合y=log10(x),其中自变量x越大那么拟合效果就会越好。对于如何拟合?这里面有两个关键点,一是确认在相关表达式log值域范围,二是要确定好在相关表达式中log的值域分辨率,在这两者都被确定好后就可以生成两个表,生成如下:

import numpy as np

Y=np.arange(-1,10,1)#值域及其分辨率
X=10**Y #对应定义域

xstr="log10_x={"
for v in X:
    xstr += "%f,"%v
xstr += "}"

Y=Y*10
Y=Y.astype(int)
ystr="log10_y={"
for v in Y:
    ystr += "%d,"%v
ystr += "}"
print(xstr)
print(ystr)

        使用生成表来加速log函数计算,由于这是一个有序的表可以使用二分查找来进一步加速,最终耗时约10us左右。

6. 总结

        log函数在工程会频繁使用,对于要加速这一计算过程情况,根据使用不用条件有不用的方法,对于有单精度硬件浮点的MCU可以直接开发浮点单元+使用logf类函数可以达到速度与性能的最佳状态,对于不包含浮点硬件模块,在精度或者分辨率满足的情况下可以基于log函数的特性使用查表法达到一个较好的时间性能。

 

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值