将2的补数转换为整数并计算均方根值

时间:2018-11-20 13:58:55

标签: c bit-manipulation twos-complement

Need fastest way to convert 2's complement to decimal in C上也提出了类似的问题,但我无法用它来获得答案,所以发布此...

我有32位数据来自音频传感器,格式如下: 数据格式是I2S,24位,2的补码,MSB在前。数据精度为18位;未使用的位为零。

没有任何音频输入,我就能从传感器读取以下数据:-

  • 0xFA578000
  • 0xFA8AC000
  • 0xFA85C000
  • 0xFA828000
  • 0xFA800000
  • 0xFA7E4000
  • 0xFA7D0000
  • 0xFA7BC000

以此类推...

我需要使用这些数据样本来计算其RMS值,然后进一步使用该RMS值来计算分贝(20 * log(rms))。

这是我的注释代码:-

//I have 32-bits, with data in the most-significant 24 bits.

inputVal &= 0xFFFFFF00;    //Mask the least significant 8 bits.

inputVal = inputVal >> 8;  //Data is shifted to least 24 bits. 24th bit is the sign bit.

inputVal &= 0x00FFFFC0;  //Mask the least 6 bits, since data precision is 18 bits.

//So, I have got 24-bit data with masked 6 lsb bits. 24th bit is sign bit.

//Converting from 2's complement.
const int negative = (inputVal & (1 << 23)) != 0;
int nativeInt;

if (negative)
    nativeInt = inputVal | ~((1 << 24) - 1);
else
    nativeInt = inputVal;

return (nativeInt * nativeInt);   //Returning the squared value to calculate RMS

在此之后,我求平方值之和的平均值,并计算其根值,以获得RMS值。

我的问题是

  1. 我是否正确进行数据位操作?
  2. 是否有必要将数据样本从2的补数转换为整数以计算其RMS值?

***************************************************第2部分*********************************************** ******

继续@Johnny Johansson的回答:-

您的所有样本值似乎都接近-6800,因此我认为这是您需要考虑的偏移量。

为标准化样本集,我计算了样本集的平均值,并将其从样本集中的每个值中减去。

然后,我从样本集中找到了最大值和最小值,并计算了峰峰值。

// I have the sample set, get the mean
float meanval = 0;
for (int i=0; i <actualNumberOfSamples ; i++)
{
    meanval += samples[i];
}
meanval /= actualNumberOfSamples;
printf("Average is: %f\n", meanval);

// subtract it from all samples to get a 'normalized' output
for (int i = 0; i < actualNumberOfSamples; i++)
{
    samples[i] -= meanval;
}

// find the 'peak to peak' max
float minsample = 100000;
float maxsample = -100000;
float peakToPeakMax = 0.0;
for (int i = 0; i < actualNumberOfSamples; i++)
{
    minsample = fmin(minsample, samples[i]);
    maxsample = fmax(maxsample, samples[i]);
}
peakToPeakMax = (maxsample - minsample);
printf("The peak-to-peak maximum value is: %f\n", peakToPeakMax);

(这不包括RMS部分,在您拥有正确的带符号整数值之后出现)

现在,我通过将峰峰值除以2的平方根来计算均方根值。 然后,20 * log10(rms)给我相应的分贝值。

rmsValue = peak2peakValue / sqrt2;

DB_Val = 20 * log10(rmsValue);
  1. 上面的代码是否照顾了您提到的“偏移量”?
  2. 我还没有找到一个测试计划来验证计算出的分贝,但是我是否在数学上正确计算了分贝值?

1 个答案:

答案 0 :(得分:0)

2'补码部分似乎应该工作,但它不必要地复杂,因为使用2'补码表示常规整数(除非您使用某些非常特殊的硬件)。您可以简单地这样做:

signed int signedInputVal = (signed int)inputVal;
signedInputVal >>= 14;

这将为您提供-(2 ^ 17)到(2 ^ 17-1)范围内的值。

似乎所有样本值都接近-6800,所以我认为这是您需要考虑的偏移量。

(这不包括RMS部分,该部分在您拥有正确的带符号整数值之后出现)