基本資訊
微控制器:GD32F303RC,執行主頻:120MHz,SRAM:48KB,Flash:256KB
編譯環境: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。
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。
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定點數可以和浮點數相互轉換)
在沒有FPU的微控制器,例如不帶FPU的Cortex-M4,Cortex-M0,ARM9等核心,使用IQMathlib提供的定點數替代軟浮點數會帶來效能的提升。
即使是精心最佳化的軟體程式碼也難以敵過硬體加速器帶來的效能提升,有浮點數運算需求儘量選擇帶FPU的微控制器。