目录
1. Q/S表示法的数值范围
2. 定点化加减法计算规则
2.1 防溢出处理
3. 定点化乘法计算规则
3.1 推算
4. 定点化除法计算规则
4.1 推算
5. 程序代码中如何确定Q值
6. 浮点转定点计算示例
1. Q/S表示法的数值范围
Q表示法 |
S表示法 |
数的范围 |
Q15 |
S0.15 |
-1≤X≤0.9999695 |
Q14 |
S1.14 |
-2≤X≤1.9999390 |
Q13 |
S2.13 |
-4≤X≤3.9998779 |
Q12 |
S3.12 |
-8≤X≤7.9997559 |
Q11 |
S4.11 |
-16≤X≤15.9995117 |
Q10 |
S5.10 |
-32≤X≤31.9990234 |
Q9 |
S6.9 |
-64≤X≤63.9980469 |
Q8 |
S7.8 |
-128≤X≤127.9960938 |
Q7 |
S8.7 |
-256≤X≤255.9921875 |
Q6 |
S9.6 |
-512≤X≤511.9804375 |
Q5 |
S10.5 |
-1024≤X≤1023.96875 |
Q4 |
S11.4 |
-2048≤X≤2047.9375 |
Q3 |
S12.3 |
-4096≤X≤4095.875 |
Q2 |
S13.2 |
-8192≤X≤8191.75 |
Q1 |
S14.1 |
-16384≤X≤16383.5 |
Q0 |
S15.0 |
-32768≤X≤32767 |
注:
2. 定点化加减法计算规则
加减法,首先要做的是对标,也就是Q值相同才能进行加减法。
(1)加法
如果两个参与运算的加数Q值不同,则首先要进行小数点的调整,数学表达式推算:
故定点加法的伪代码描述如下:
Int x,y,z; Long temp; Temp=y<<(Qx-Qy); Temp=x+temp; If(Qx≥Qz) z=(int)(temp>>( Qx- Qz)) else if(Qx≤Qz) z=(int)(temp<<( Qz- Qx)) else |
示例代码:
#include <stdio.h>
#include <stdlib.h>
#define Q15 32768.0
#define Q13 8192.0
int main()
{
float x=0.5;
float y=3.1; //结果3.6-->Q13
short x_Qx=(short)(x*Q15+0.5);
short y_Qx=(short)(y*Q13+0.5);
short z_Q13;
// printf("%d\n", x_Qx);
// printf("%d\n", y_Qx);
long temp;
temp=y_Qx<<2;
temp=temp+x_Qx;
z_Q13=(int)(temp>>2);
printf("res:%f\n", z_Q13/Q13);
return 0;
}
结果:res:3.599976
(2)减法
代码示例
#include <stdio.h>
#include <stdlib.h>
#define Q15 32768.0
#define Q13 8192.0
int main()
{
float x=3.0;
float y=3.1; //结果x-y=-0.1-->Q15
short x_Qx=(short)(x*Q13+0.5);
short y_Qx=(short)(y*Q13+0.5);
short z_Q15;
// printf("%d\n", x_Qx);
// printf("%d\n", y_Qx);
long temp;
temp=x_Qx-y_Qx; //
z_Q15=(int)(temp<<2);
printf("res:%f\n", z_Q15/Q15);
return 0;
}
结果:res:-0.099976
2.1 防溢出处理
整型数进行加减运算的时候,如果得到的结果超出范围:-32768≤X≤32767,即[8000H-7FFFH]
则称之为上溢或者下溢。
(1)下溢:
x=32766, y=3,x和y均从浮点数转换而来,假设它们是同一个Q值,进行加法操作后,结果为:32769,假设这里的数值都是16bit的,那么32769的补码就是:
1000000000000001
计算机将该值取出时,会把它当成一个负数(最高位符号位为1):除去符号位,其余位减1得到:0000 0000 0000 000
再取反,得到:1111 1111 1111 111,为-32767d
所以,若将该数加上1,并不是32770,而是-32766。
测试代码:
#include <stdio.h> #include <stdlib.h> int main() { short x=32766; short y=3; short z=x+y; printf("z=%d\n", z); return 0; } |
结果:z=-32767
(2)上溢
设x=15000,y=20000,则求和后z=x+y=35000 > 32767,如果结果超出16bit的表示范围,则保留32bit的结果(转成32bit数进行运算)。
首先,进行定标(16bit):Qx=1, Qy=0, Qz=0
定点加法先定标,y向x对齐:long temp=y<<1=20000<<1=40000
进行加法:temp=temp+(x<<1);//相当于两个加数同时左移
最后,结果:temp=temp>>1; //Qx>Qz
测试代码:
#include <stdio.h> #include <stdlib.h> int main() { short x=15000, y=20000; int temp, z; temp=(y<<1); temp=(x<<1)+temp; z=temp>>1; printf("z=%d\n", z); return 0; } |
结果:z=35000
结果超范围,则两个加数同时左移,最后同时右移,结果不在用16bit来存储,而是32bit。伪代码如下:
Int x,y; Long temp, z; Temp=y<<(Qx-Qy); //假设Qx>Qy,y向x对标,y就要左移操作(上文数学表达式推算)。 Temp=x+temp; If(Qx≥Qz) z=(int)(temp>>( Qx- Qz)) else if(Qx≤Qz) z=(int)(temp<<( Qz- Qx)) else |
另一种做法是,保持16bit的运算(虽然对结果进行了检查):
#include <stdio.h> #include <stdlib.h> #include <stdint.h> int16_t Q16_add_sat(int16_t a, int16_t b) { int16_t result; int32_t tmp; tmp = (int32_t)a + (int32_t)b; if (tmp > 0x7FFF) tmp = 0x7FFF; if (tmp < -1 * 0x8000) tmp = -1 * 0x8000; result = (int16_t)tmp; return result; } int main() { short x=15000, y=20000; // int temp, z; // temp=(y<<1); // temp=(x<<1)+temp; // z=temp>>1; // printf("z=%d\n", z); printf("z=%d\n", q_add_sat(x,y)); return 0; } |
结果:z=32767,精度严重恶化。
修改如下:
int32_t Q16_add_sat(int16_t a, int16_t b) { int32_t result; result = (a<<1) + (b<<1); result = (result>>1); return result; } int main() { short x=15000, y=20000; // int temp, z; // temp=(y<<1); // temp=(x<<1)+temp; // z=temp>>1; // printf("z=%d\n", z); printf("z=%d\n", Q16_add_sat(x,y)); return 0; } |
3. 定点化乘法计算规则
3.1 推算
所以,定点乘法伪代码如下:
Int x,y,z; Long temp; Temp=long(x); z=(temp*y)>>(); |
测试代码:
#include <stdio.h> #include <stdlib.h> #include <stdint.h> #define Q10 1024.0 #define Q9 512.0 #define Q5 32.0 int main() { float x=18.4, y=36.8; long temp; short x_Q16=x*Q10; short y_Q16=y*Q9; short res; temp=x_Q16*y_Q16; res=temp>>(10+9-5); printf("res=%d, %f\n", res, res/32.0); return 0; } |
结果:res=21666, 677.062500
4. 定点化除法计算规则
4.1 推算
测试代码:
#include <stdio.h> #include <stdlib.h> #include <stdint.h> #define Q15 32768.0 #define Q10 1024.0 #define Q9 512.0 #define Q5 32.0 int main() { float x=18.4, y=36.8; long temp; short x_Q16=x*Q10; short y_Q16=y*Q9; short res; //Q15 temp=(x_Q16<<(15-10+9)); res=temp/y_Q16; printf("res=%d, %f\n", res, res/Q15); return 0; } |
结果:res=16384, 0.500000
5. 程序代码中如何确定Q值
6. 浮点转定点计算示例
示例1:混合计算
计算1.78x0.6+2.43
代码:
#include <stdio.h> #include <stdlib.h> #define Q13_a (0.35*8192.0) #define Q13_b (2.7*8192.0) #define Q13_c (1.43*8192.0) void main() { int a,b,c,d,f; long result; a=(int)Q13_a; b=(int)Q13_b; c=(int)Q13_c; result=(long)(a*b); d=(result>>13); f=d+c; printf("result:%f\n", f/8192.0); } |
示例2:汉明窗的计算文章来源:https://www.toymoban.com/news/detail-626660.html
示例3:FIR低通滤波实现文章来源地址https://www.toymoban.com/news/detail-626660.html
到了这里,关于DSP定点数的计算规则和示例的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!