DSP 知识点

一.计算机中有符号整数的取值范围

计算机中基本数据类型共有4类8种,分别为整数、浮点数、字符型、布尔型。这次只谈论整型

有符号整数在计算机中分别占有一个字节(8位),2个字节(16位),四个字节(32位),8个字节(64位)
整数类型有:byte short int long

一个字节(byte)的有符号整数的取值范围
在这里插入图片描述
范围是 -128至127.
根据补码的几条规定即可推出上述结论:
1 若二进制每位全为0,则表示数0
2 若最高位(即符号位)为0,表示正数
3 若最高位为1, 表示是负数,而该负数的绝对值是多少呢?将每个二进制位(包括符号位)取反加1,得到一个二进制数,将该数看成无符号数,其值就是上述负数的绝对值。

例如,二进制的 10000000 的最高位为1, 所以它表示的是负数。是负的多少呢?我们将其八位全部取反,得到01111111, 然后加1,得到10000000. 将该数看作无符号数,值为128, 故计算机中的10000000表示的是-128

最高位(即符号位)为1的8位有符号数有128个,故可表示128个负数;最高位为0的8位有符号数有128个,但全0的那个表示数0,所以总共只能表示127个正整数。

两个字节(short)为16位
在这里插入图片描述四个字节(int)32位
在这里插入图片描述
八个字节(long)64位
在这里插入图片描述
二.原码和补码之间的相互转化
补码是一种计算机中用于表示有符号整数的方式,它允许使用相同的二进制加法操作来处理有符号数的加法和减法,简化了计算机的设计。

补码转换为原码(从补码得到实际数值):
如果补码的最高位(符号位)是0,那么它表示的是一个正数,原码就是补码本身。
如果补码的最高位是1,那么它表示的是一个负数,原码可以通过以下步骤得到:
先对补码除符号位外的其他位进行按位取反(位反转)。
然后给反转后的数加1。
原码转换为补码(将实际数值转换为补码以便在计算机中表示):
如果原码表示的是一个正数,补码就是原码本身。
如果原码表示的是一个负数,补码可以通过以下步骤得到:
先对原码的绝对值部分进行按位取反。
然后给反转后的数加1。
举例
假设我们有一个8位的系统,我们要转换 -5 的原码为补码。

-5 的原码(考虑到符号位)是 1000 0101。
取绝对值 5 的二进制表示(不包括符号位):0000 0101。
按位取反(除符号位外):1111 1010。
加1得到补码:1111 1011。
因此,-5 在8位系统中的补码是 1111 1011。

反过来,如果我们要将补码 1111 1011 转换为原码:

补码 1111 1011 的最高位是1,因此它是负数的补码。
除去最高位,取反得到:0000 0100。
加1得到绝对值:0000 0101。
添加符号位得到原码:1000 0101。
这样我们就得到了 -5 的原码 1000 0101。

三.负数左移和右移的运算规则

负数左移和右移的运算规则
负数在计算机中的表示通常使用补码形式。补码是一位符号位跟随原码的位表示,对于负数而言,最高位(最左边的位)是1。在位运算中,无论是左移还是右移,都需要考虑到这一点。12

负数右移的规则:

当负数进行右移操作时,为了保持其负数的特性,需要在二进制表示的右侧补上1。这样,即使经过多次右移,仍然能够保持负数的状态。如果一直右移,最终会变成-1,即所有位都为1的情况。

负数左移的规则:

当负数进行左移操作时,与正整数左移相同,右侧补0。在左移过程中,负数的符号位(最左边的位)保持不变,即始终为1。如果一直左移,最终会变成0,因为所有位都移出并补0。
总结:

负数右移时,右侧补1,以保持其负数的状态。多次右移后,结果为-1。
负数左移时,右侧补0。多次左移后,结果为0。

四.STM32中DSP的负数移位运算

typedef   signed          char int8_t;
typedef int8_t q7_t;
q7_t  pSrcA3 = 0x86;
q7_t  pDst3;

arm_shift_q7(&pSrcA3, 3, &pDst3, 1);
printf("arm_shift_q7 = %2x\r\n", pDst3);

输出结果:arm_shift_q7 = ffffff80
输出结果:arm_shift_q7 = -128
为什么输出结果为:ffffff80
这是因为pSrcA3类型为有符号整型范围为-128-127,而pSrcA3 = 0x86=134,134已经超过了127,所以这个值为负数,由于在单片机中负数是以补码的形式存在的,所以0x86即为负数的补码,0x86=0b1000 0110将此补码转换为原码,去掉最高位取反即为0b0111 1001,再加上1为0111 1010,添加符号位即为0b1111 1010,即为负数-122。
arm_shift_q7(&pSrcA3, 3, &pDst3, 1);函数是将pSrcA3数据左移三位,由于0x86=0b1000 0110,左移三位后即为0b0011 0000,由于负数的最小值为-128,饱和运算后即为-128。

typedef   signed          char int8_t;
typedef int8_t q7_t;
q7_t  pSrcA3 = 0xF6;
q7_t  pDst3;

arm_shift_q7(&pSrcA3, 3, &pDst3, 1);
printf("arm_shift_q7 = %2x\r\n", pDst3);

输出结果:arm_shift_q7 = ffffffb0
输出结果:arm_shift_q7 = -80
为什么输出结果为:ffffffb0
这是因为pSrcA3类型为有符号整型范围为-128-127,而pSrcA3 =0xF6=0b1111 0110,由于最高位为1,所以这个数为负数,由于在单片机中负数是以补码的形式存在的,所以0xF6即为负数的补码,将补码转换为原码,去掉最高位取反即为0b0000 1001,再加上1为0b0000 1010,添加符号位0b1000 1010,即为负数-10。

arm_shift_q7(&pSrcA3, 3, &pDst3, 1);函数是将pSrcA3数据左移三位,由于0xF6=0b1111 0110,左移三位后即为0b1011 0000,将补码转换为原码,去掉最高位取反即为0b0100 1111,再加上1为0101 0000,添加符号位即为1101 0000,即为负数-80。

typedef   signed short     int int16_t;
typedef int16_t q15_t;
q15_t  pSrcA2 = 0x8866; 
q15_t  pDst2;

arm_shift_q15(&pSrcA2, -3, &pDst2, 1);
printf("arm_shift_q15 = %4x\r\n", pDst2);

输出结果:arm_shift_q15 = fffff10c
为什么会输出fffff10c
这是因为pSrcA2类型为有符号整型范围为-32,768-32767,而pSrcA2=0x8866=34918,已经超过了32767,所以这个数为负数,0x8866即为这个数的补码,0x8866=0b1000 1000 0110 0110,最高位为1,所以这个数为负数,由于在单片机中负数是以补码的形式存在的,所以0x8866即为负数的补码,将补码转换为原码,去掉最高位取反即为0b0111 0111 1001 1001,再加上1为0b0111 0111 1001 1010,添加符号位,即为负数-30618。

arm_shift_q15(&pSrcA2, -3, &pDst2, 1);函数是将pSrcA2数据右移三位(因为为-3,有负号即代表右移),由于0x8866=0b1000 1000 0110 0110,右移三位,由于负数右移时,右侧补1,以保持其负数的状态,所以右移后0b111 1 0001 0000 1100=0xF10C。

五.STM32中DSP比例因子的计算规则

主要用于实现数据的比例放大和缩小,浮点数据公式描述如下:
pDst[n] = pSrc[n] * scale, 0 <= n < blockSize.
如果是 Q31, Q15, Q7 格式的数据,公式描述如下:
pDst[n] = (pSrc[n] * scaleFract) << shift, 0 <= n < blockSize.

typedef   signed short     int int16_t;
typedef int16_t q15_t;
q15_t  pSrcA2[5] = {0x6fff,1,1,1,1};  
q15_t  scale2 = 0x6fff;  
q15_t  pDst2[5];   

scale2 += 1;
arm_scale_q15(pSrcA2, scale2, 0, pDst2, 5);
printf("arm_scale_q15 = %x\r\n", pDst2[0]);
printf("arm_scale_q15 = %x\r\n", pDst2[1]);

输出结果:arm_scale_q15 = 61ff
输出结果:arm_scale_q15 = 0
为什么是这样的输出结果了?
由于定点数的比例因子计算公式为:pDst[n] = (pSrc[n] * scaleFract) << shift,所以在这里先计算scaleFract的值
scale2=scale2+1=0x6fff+1=0x7000
在第一组数据中pSrcA2[0]=0x6fff,(0x6fff * 0x7000)<<0.
转换为定点数的乘法运算,先转换为浮点数的计算,(0x6fff * 0x7000)/(0x8000 * 0x8000)=(2867128672)/(3276832768)=822054912/1073741824=0.765598297119140625。
再将计算之后的浮点数换算为定点数:0.765598297119140625 * 32768=25087.125=0x61FF。

在第二组数据中pSrcA2[1]=1,(1* 0x7000)<<0.
转换为定点数的乘法运算,先转换为浮点数的计算,(1 * 0x7000)/(0x8000 * 0x8000)=(128672)/(3276832768)=28672/1073741824=0.000026702880859375
由于q15数据类型最小的浮点数精度为:1/32768=0.000030517578125,而0.000026702880859375 < 0.000030517578125,即小于最小的精度,故近似于0。0*32768=0,所以结果为0。

typedef   signed          char int8_t;
typedef int8_t q7_t;
q7_t  pSrcA3[5] = {0x70,1,1,1,1}; 
q7_t  scale3 = 0x6f;  
q7_t pDst3[5];

scale3 += 1;
arm_scale_q7(pSrcA3, scale3, 0, pDst3, 5);
printf("arm_scale_q7 = %x\r\n", pDst3[0]);

输出结果:arm_scale_q7 = 62
为什么会输出这样的结果?
由于定点数的比例因子计算公式为:pDst[n] = (pSrc[n] * scaleFract) << shift,所以在这里先计算scaleFract的值
scale3=scale3+1=0x6f+1=0x70
在第一组数据中:(0x70 * 0x70) << 0
转换为定点数的乘法运算,先转换为浮点数的计算,(0x70 * 0x70)/(0x80 * 0x80)=12544/16384=0.765625,再将计算之后的浮点数换算为定点数:0.765625 * 128=98=0x62。

六.STM32中DSP的平方根(Sqrt)计算规则

arm_sqrt_q31(1000, &pOut1);
printf("arm_sqrt_q31 = %d\r\n", pOut1);

输出结果:arm_sqrt_q31 = 1465429

为什么输出的结果为1465429。
这里in的输入范围是0x00000000 到 0x7FFFFFFF,转化成浮点数范围就是[0 +1),这是因为将0x7FFFFFFF转换为浮点数即为0x7FFFFFFF/0x8000 0000=2147483647/2147483648=0.9999999995343387126922607421875,四舍五入之后即为1。

arm_sqrt_q31(1000, &pOut1),定点数为1000,将此定点数转换为浮点数,1000/2147483648=0.0000004656612873077392578125。利用计算器对0.0000004656612873077392578125求平方根之后结果为6.82393791961605742312369894022e-4。之后再将6.82393791961605742312369894022e-4转换为定点数6.82393791961605742312369894022e-4 * 2147483648=1465429.5097342621754387160555397。所以输出的结果为1465429。

arm_sqrt_q15(1000, &pOut);
printf("arm_sqrt_q15 = %d\r\n", pOut);

输出结果:arm_sqrt_q15 = 5724

为什么输出的结果为5724
参数范围 0x0000 到 0x7FFF( 转化成浮点数范围就是[0 +1))。

arm_sqrt_q15(1000, &pOut);定点数为1000,将此定点数转换为浮点数,1000/32768=0.030517578125,利用计算器对0.030517578125求平方根之后结果为0.17469281074217107003196669286963,之后再将0.17469281074217107003196669286963转换为定点数0.17469281074217107003196669286963 * 32768=5724.334022399461622807484591952,所以输出结果为5724。

七.STM32中DSP的标准偏差计算规则

标准偏差计算公式
Result = sqrt((sumOfSquares – sum^2 / blockSize) / (blockSize - 1))
其中:
sumOfSquares = pSrc[0] * pSrc[0] + pSrc[1] * pSrc[1] + … + pSrc[blockSize-1] *
pSrc[blockSize-1]
sum = pSrc[0] + pSrc[1] + pSrc[2] + … + pSrc[blockSize-1]

typedef float float32_t;
float32_t pSrc3[2] = {0.6557f, 0.0357f};
float32_t pResult3;

arm_std_f32(pSrc3, 2, &pResult3);
printf("arm_std_f32 : pResult3 = %f\r\n", pResult3);

输出结果:arm_std_f32 : pResult3 = 0.438406
为什么结果为:0.438406
sumOfSquares=0.6557f * 0.6557f + 0.0357f * 0.0357f = 0.42994249 + 0.00127449 = 0.43121698
sum=0.6557f + 0.0357f = 0.6914
sum^2=0.6914 ^ 2 = 0.47803396
sum^2 / 2 = 0.47803396 / 2 = 0.23901698
sqrt((sumOfSquares – sum^2 / blockSize) / (blockSize - 1)) =sqrt ( (0.43121698 - 0.23901698) / (2-1) ) = sqrt (0.1922 / 1) = 0.43840620433565946512852350450501。

标准差的数据计算方式规则
例如上面的一组数据0.6557f, 0.0357f,一共是两个数据
(1).先求出这两个数据的平均值:(0.6557f + 0.0357f) / 2 = 0.3457
(2).根据计算出的平均值,求出这两个数据分别和平均值的差值的平方,将平方求和:
(0.6557 - 0.3457) * (0.6557 - 0.3457) + (0.0357 - 0.3457) * (0.0357 - 0.3457) = 0.0961 + 0.0961 = 0.1922
(3).由于一共是两个数据:0.1922 / (2 - 1) = 0.1922,这样计算出来的即为方差。
(4).由于标准差的平方即为方差,所以将方差开根号即为标准差:0.1922开根号即为0.4384。

八.STM32中DSP的均方根计算规则

Result = sqrt(((pSrc[0] * pSrc[0] + pSrc[1] * pSrc[1] + … + pSrc[blockSize-1] *
pSrc[blockSize-1]) / blockSize));

typedef float float32_t;
float32_t pSrc3[2] = {0.7060f, 0.0318f};
float32_t pResult3;

arm_rms_f32(pSrc3, 2, &pResult3);
printf("arm_rms_f32 : pResult3 = %f\r\n", pResult3);

输出结果:arm_rms_f32 : pResult3 = 0.499724

0.7060 * 0.7060 + 0.0318 * 0.0318 = 0.498436 + 0.00101124=0.49944724
0.49944724 / 2 = 0.24972362
sqrt(0.24972362) = 0.49972354357184333085643235839603,所以输出结果为:0.499724

九.STM32中DSP的方差计算规则

标准差和方差的关系:标准差的平方即为方差

float32_t pSrc3[2] = {0.4387f, 0.3816f};
float32_t pResult3;

arm_var_f32(pSrc3, 2, &pResult3);
printf("arm_var_f32 : pResult3 = %f\r\n", pResult3);

输出结果:arm_var_f32 : pResult3 = 0.001630

计算数组中元素的总和:0.4387 + 0.3816 = 0.8203
计算数组中总的元素的平均值:0.8203 / 2 = 0.41015

计算数组中每个元素和平均值的差值:0.4387 - 0.41015=0.02855
计算数组中每个元素和平均值的差值:0.3816 - 0.41015=-0.02855

计算差值的平方累加和:0.02855 * 0.02855 + (-0.02855 * -0.02855) = 0.0008151025+0.0008151025=0.001630205
计算平方累加和求平均:由于一共2个数据,所以:0.001630205 / (2 - 1) = 0.001630205
所以输出结果为:0.001630

十.STM32中浮点数转换为定点数的计算规则

浮点数转 Q31 公式描述:
pDst[n] = (q31_t)(pSrc[n] * 2147483648); 0 <= n < blockSize。
浮点数转 Q15 公式描述:
pDst[n] = (q15_t)(pSrc[n] * 32768); 0 <= n < blockSize
浮点数转 Q7 公式描述:
pDst[n] = (q7_t)(pSrc[n] * 128); 0 <= n < blockSize

float32_t pSrc[10] = {0.6557,  0.0357,  0.8491,  0.9340, 0.6787,  0.7577,  0.7431,  0.3922,  0.6555,  0.1712};
uint32_t pIndex;
q15_t pDst2[10];

arm_float_to_q15(pSrc, pDst2, 10);
for(pIndex = 0; pIndex < 10; pIndex++)
{
	printf("arm_float_to_q15: pDst1[%d] = %d\r\n", pIndex, pDst2[pIndex]);
}

输出结果:
arm_float_to_q15: pDst1[0] = 21485
arm_float_to_q15: pDst1[1] = 1169
arm_float_to_q15: pDst1[2] = 27823
arm_float_to_q15: pDst1[3] = 30605
arm_float_to_q15: pDst1[4] = 22239
arm_float_to_q15: pDst1[5] = 24828
arm_float_to_q15: pDst1[6] = 24349
arm_float_to_q15: pDst1[7] = 12851
arm_float_to_q15: pDst1[8] = 21479
arm_float_to_q15: pDst1[9] = 5609

arm_float_to_q15(pSrc, pDst2, 10);由于q15的范围为:-32768-32767,0.6557 * 32768 = 21485.9776,所以输出结果为:21485

十一.STM32中DSP的复数共轭运算( ComplexConj)

计算规则
for(n=0; n<numSamples; n++)
{
pDst[(2n)+0)] = pSrc[(2n)+0]; // 实部
pDst[(2n)+1)] = -pSrc[(2n)+1]; // 虚部
}
用代数式来表示a+bi的共轭就是a-bi

uint8_t i;
float32_t pSrc[10] = {1.1f, 1.1f, 2.1f, 2.1f, 3.1f, 3.1f, 4.1f, 4.1f, 5.1f, 5.1f};
float32_t pDst[10];

arm_cmplx_conj_f32(pSrc, pDst, 5);
for(i = 0; i < 5; i++)
{
	printf("pSrc[%d] = %f %fj    pDst[%d] = %f %fj\r\n", i,  pSrc[2*i], pSrc[2*i+1], i, pDst[2*i], pDst[2*i+1]);
}

输出结果:
pSrc[0] = 1.100000 1.100000j pDst[0] = 1.100000 -1.100000j
pSrc[1] = 2.100000 2.100000j pDst[1] = 2.100000 -2.100000j
pSrc[2] = 3.100000 3.100000j pDst[2] = 3.100000 -3.100000j
pSrc[3] = 4.100000 4.100000j pDst[3] = 4.100000 -4.100000j
pSrc[4] = 5.100000 5.100000j pDst[4] = 5.100000 -5.100000j

  • 7
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值