OpenEdv-开源电子网

 找回密码
 立即注册
正点原子全套STM32/Linux/FPGA开发资料,上千讲STM32视频教程免费下载...
查看: 596|回复: 3

GD32长数组平均数算法优化,平均数计算耗时对比

[复制链接]

8

主题

32

帖子

0

精华

中级会员

Rank: 3Rank: 3

积分
222
金钱
222
注册时间
2020-7-6
在线时间
54 小时
发表于 2024-9-28 20:32:18 | 显示全部楼层 |阅读模式
本帖最后由 akes 于 2024-9-28 20:34 编辑

做好功能但没有人能分享,憋得慌就来写一下文章,也期待能有更好的方法出现。
项目需要1Khz的ADC采集,希望滤波做好,用的ADC+DMA采集控制采样频率在约1Mhz采集到1Kb的数组里,每一毫秒进行一次平均数计算,且不关注这个采集要求其他功能如何分时,只看这个算法耗时,通常来说程序是这样的
unsigned short adc_arr[1024];
unsigned short ave_cal()
{
        unsigned short* p = adc_arr;
        unsigned short* end = adc_arr + 1024;
        uint32_t total_num = 0;
        uint32_t total_num2 = 0;
        p = adc_arr;
        while(p != end){
                total_num+=*p;
                p++;
        }
        total_num>>=10;//右移1等效于除2,右移10等效于除1024
        return total_num;
}

这个函数在GD32F103的108MHz工作频率下运行耗时134us
每次循环就加一个数,看起来循环太多次了,一次循环多几个数如何?下面这个是我找到的最合适单次循环相加数,单次计算时间来到了72us
unsigned short adc_arr[1024];
unsigned short ave_cal()
{
        unsigned short* p = adc_arr;
        unsigned short* end = adc_arr + 1024;
        uint32_t total_num = 0;
        while(p != end){
                total_num+=(*p+*(p+1)+*(p+2)+*(p+3)+*(p+4)+*(p+5)+*(p+6)+*(p+7));
                total_num+=(*(p+8)+*(p+9)+*(p+10)+*(p+11)+*(p+12)+*(p+13)+*(p+14)+*(p+15));
                p+=16;
        }
        total_num>>=10;//右移1等效于除2,右移10等效于除1024
        return total_num;
}
后来我想到ADC值是12位的,最大4095,用的16bit的数组存储,最大65535,而GD32的cpu是32位的,有没有什么把这些资源全都利用上?
确实有,可以用一个32bit的指针操作数组,每次相加实际上是运行两次16bit的加法,拆分的话,因为这里数据是12bit的,如果每次都是4095那么最多能加到16次,第17次就会溢出,所以第16次做拆分最合适
unsigned short adc_arr[1024];
unsigned short ave_cal()
{
        unsigned int* u32p = (void*)adc_arr;
        unsigned int* u32end = (void*)(adc_arr + 1024);
        uint32_t total_num = 0;
        uint32_t total_num2 = 0;
        while(u32p != u32end){
                //把两个u16当成一个u32相加16次后做分离,计算时间为34us
                total_num2+=(*(u32p)+*(u32p+1)+*(u32p+2)+*(u32p+3));//单次相加四个数字速度最快
                total_num2+=(*(u32p+4)+*(u32p+5)+*(u32p+6)+*(u32p+7));
                total_num2+=(*(u32p+8)+*(u32p+9)+*(u32p+10)+*(u32p+11));
                total_num2+=(*(u32p+12)+*(u32p+13)+*(u32p+14)+*(u32p+15));
                total_num += ((total_num2&0xffff)+(total_num2>>16));
                total_num2 = 0;
                u32p+=16;
        }
        total_num>>=10;//右移1等效于除2,右移10等效于除1024
        return total_num;
}
运行耗时缩小到了34us ,得意
以前我那IMX6ull做 SPI framebuffer驱动的时候就出现了64位循环拷贝数组比32位拷贝数组快得多的事,于是就有了这个想法


正点原子逻辑分析仪DL16劲爆上市
回复

使用道具 举报

10

主题

3280

帖子

1

精华

论坛元老

Rank: 8Rank: 8

积分
8182
金钱
8182
注册时间
2020-5-11
在线时间
3694 小时
发表于 2024-9-29 09:24:03 | 显示全部楼层
QQ图片20210717101417.png
不错不错,有《让你的软件飞起来》的风格。


专治疑难杂症
回复 支持 反对

使用道具 举报

22

主题

2251

帖子

0

精华

论坛元老

Rank: 8Rank: 8

积分
4471
金钱
4471
注册时间
2013-4-22
在线时间
335 小时
发表于 2024-10-6 17:36:12 | 显示全部楼层
循环拆分法
回复 支持 反对

使用道具 举报

11

主题

2103

帖子

0

精华

论坛元老

Rank: 8Rank: 8

积分
4584
金钱
4584
注册时间
2015-1-10
在线时间
573 小时
发表于 2024-10-8 16:38:05 | 显示全部楼层
学习了
回复 支持 反对

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则



关闭

原子哥极力推荐上一条 /2 下一条

正点原子公众号

QQ|手机版|OpenEdv-开源电子网 ( 粤ICP备12000418号-1 )

GMT+8, 2024-11-22 06:51

Powered by OpenEdv-开源电子网

© 2001-2030 OpenEdv-开源电子网

快速回复 返回顶部 返回列表