IQMath定点数运算库性能测试

基本信息

单片机:GD32F303RC,运行主频:120MHz,SRAM:48KB,Flash:256KB,带单精度FPU
编译环境:ARMCC 5.06 update6 (build750)

由于iq数的底层数据类型是4字节的int32_t因此_iq30 ~ _iq1 尽管表示的精度不同,但是运算速度是相同的。下列测试使用_iq15作为被测数据类型,能表示的范围从-65536到65535.999969483,精度是0.000030518/LSB。

测试代码

声明数组变量用于存储两个操作数向量和一个结果向量

#define CONST_PI_VAL 3.1415926f

#define VECTOR_SIZE  1000

static _iq15 ResultVector[VECTOR_SIZE];
static _iq15 VectorA[VECTOR_SIZE];
static _iq15 VectorB[VECTOR_SIZE];

static float ResultVectorF[VECTOR_SIZE];
static float VectorAF[VECTOR_SIZE];
static float VectorBF[VECTOR_SIZE];

测试数组的初始化,_IQ15(1.0221f)这种IQ立即数在编译时就已确定,因此VectorA[index] = _IQ15(1.0221f) * index; 等效于两个32位数据相乘,数组初始化不计入测试时间。

static void BenchmarkVectorIQArrayInit(void) {
    unsigned int index = 0u;
    for(index = 0; index < VECTOR_SIZE; index++) {
        VectorA[index] = _IQ15(1.0221f) * index;
        VectorB[index] = _IQ15(2.127f) * index;
        ResultVector[index] = 0;
    }
}

static void BenchmarkVectorFloatArrayInit(void) {
    unsigned int index = 0u;
    for(index = 0; index < VECTOR_SIZE; index++) {
        VectorAF[index] = 1.0221f * index;
        VectorBF[index] = 2.127f * index;
        ResultVectorF[index] = 0.0f;
    }
}

IQ数累加和浮点数累加

static void VectorIQAdd(_iq15 *vectorA, _iq15 *vectorB, _iq15 *result) {
    unsigned int index = 0u;
    for(index = 0; index < VECTOR_SIZE; index++) {
        result[index] = vectorA[index]+ vectorB[index];
    }
}

static void VectorFloatAdd(float *vectorA, float *vectorB, float *result) {
    unsigned int index = 0u;
    for(index = 0; index < VECTOR_SIZE; index++) {
        result[index] = vectorA[index] + vectorB[index];
    }
}

IQ数相乘和浮点数相乘

static void VectorIQMultiply(_iq15 *vectorA, _iq15 *vectorB, _iq15 *result) {
    unsigned int index = 0u;
    for(index = 0; index < VECTOR_SIZE; index++) {
        result[index] = _IQ15mpy(vectorA[index], vectorB[index]);
    }
}

static void VectorFloatMultiply(float *vectorA, float *vectorB, float *result ) {
    unsigned int index = 0u;
    for(index = 0; index < VECTOR_SIZE; index++){
        result[index] = vectorA[index] * vectorB[index];
    }
}

IQ数除法和浮点数除法

static void VectorIQDiv(_iq15 *vectorA, _iq15 *vectorB, _iq15 *result) {
    unsigned int index = 0u;
    for(index = 0; index < VECTOR_SIZE; index++) {
        result[index] = _IQ15div(vectorA[index], vectorB[index]);
    }
}

static void VectorFloatDiv(float *vectorA, float *vectorB, float *result) {
    unsigned int index = 0u;
    for(index = 0; index < VECTOR_SIZE; index++) {
        result[index] = vectorA[index] / vectorB[index];
    }
}

IQ数乘加和浮点数乘加,y=kx+b

static void VectorIQScale(_iq15 *vectorA, _iq15 *vectorB, _iq15 *result) {
    unsigned int index = 0u;
    for(index = 0; index < VECTOR_SIZE; index++) {
        result[index] = _IQ15mpy(vectorA[index], _IQ15(CONST_PI_VAL));
        result[index] += vectorB[index];
    }
}

static void VectorFloatScale(float *vectorA, float *vectorB, float *result) {
    unsigned int index = 0u;
    for(index = 0; index < VECTOR_SIZE; index++) {
        result[index] = (vectorA[index] * CONST_PI_VAL) + vectorB[index];
    }
}

性能测试使用Cortex-m4自带的32位DWT计数器,计数频率和CPU主频相同。

static void hw_dwt_init(void) {
    // DWT timer enable
    CoreDebug->DEMCR = 0x1000000;
    // clear Cycle Count Register
    DWT->CYCCNT = 0x0;
    // enable  Data Watchpoint and Trace Register
    DWT->CTRL = 0x1;
}

测试代码模板,由于测试代码执行时间较短,不用考虑DWT计数器溢出问题。

    start = DWT->CYCCNT;
    // 此处运行测试代码
    end = DWT->CYCCNT;
    diff = end - start;
    rt_kprintf("elapse:%d\n", diff);

测试结果

IQ数和单精度软浮点数对比,单片机未开启FPU,代码优化等级-O3,计算次数1000。
image
image
image

DWT计数原始数据:120MHz

数据类型 加法 乘法 除法 乘加
iq15 11006 41007 155487 49006
软浮点 64454 57436 240989 116753

DWT换算时间:微秒

数据类型 加法 乘法 除法 乘加
iq15 91.716 341.725 1295.725 408.383
软浮点 537.116 478.633 2008.2416 972.9416

IQ数和单精度硬浮点数对比,单片机开启单精度FPU,代码优化等级-O3,计算次数1000。
image
image
image

DWT计数原始数据:120MHz

数据类型 加法 乘法 除法 乘加
iq15 11006 41007 155454 49006
硬浮点 17007 17007 30007 19039

DWT换算时间:微秒

数据类型 加法 乘法 除法 乘加
iq15 91.716 341.725 1,295.45 408.383
硬浮点 141.725 141.725 250.0583 158.6583

总结

IQ数相比软浮点数性能提升

加法 乘法 除法 乘加
提升百分比 82.92% 28.604% 35.47% 58.02%

IQ数相比硬浮点数性能提升(下降)

加法 乘法 除法 乘加
提升/下降百分比 35.28% -58.52% -80.697% -61.149%

在单片机有浮点数加速单元的情况下,开启浮点数协处理器CP10,并且打开编译器的硬浮点代码生成,乘法和除法直接使用float数据类型进行计算的速度是最快的;而IQ定点数只在加法和减法有优势,由于IQ定点数可以和浮点数相互转换,某些精度和值范围确定的场合可以结合两者使用。但我认为性能提升有限或者没有,毕竟调用函数__IQNtoF将IQ定点数转成浮点数也需要代码执行时间,定点数加减计算+转换为浮点数的总时间不一点比直接浮点数加减来的快。

在没有FPU的单片机,例如不带FPU的Cortex-M4,Cortex-M0/M0p,ARM9等内核,使用IQMathlib提供的定点数替代软浮点数会带来性能的提升。

即使是精心优化的软件代码也难以敌过硬件加速器带来的性能提升,有浮点数运算需求尽量选择带FPU的单片机。

资料下载

本例程用到的iqmath定点库源码:
https://files.cnblogs.com/files/blogs/575121/iqmath.zip
iqmath在线用户指南
https://software-dl.ti.com/msp430/esd/MSPM0-SDK/1_10_01_05/docs/chinese/middleware/iqmath/doc_guide/doc_guide-srcs/Users_Guide_CN.html
https://software-dl.ti.com/msp430/esd/MSPM0-SDK/1_10_01_05/docs/chinese/middleware/iqmath/doxygen/api_guide/html/index.html

posted @ 2024-04-03 22:59  Yanye  阅读(111)  评论(0编辑  收藏  举报