将 2 的补码转换为整数并计算 rms 值
Convert 2's complement to integer and calculate rms value
有人在 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 值。
我的问题是,
- 我是否正确地进行了数据位操作?
- 是否需要将数据样本从 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 的平方根来计算 rms 值。
然后,20 * log10(rms) 给我相应的分贝值。
rmsValue = peak2peakValue / sqrt2;
DB_Val = 20 * log10(rmsValue);
- 上面的代码是否处理了您提到的“偏移量”?
- 我还没有找到一个测试计划来验证计算出的分贝值,但我是否正确计算了分贝值?
2' 补码部分看起来应该可以工作,但它不必要地复杂,因为常规整数是使用 2' 补码表示的(除非您使用的是一些非常奇特的硬件)。你可以简单地这样做:
signed int signedInputVal = (signed int)inputVal;
signedInputVal >>= 14;
这将为您提供 -(2^17) 到 (2^17-1) 范围内的值。
看起来你的所有样本值都接近 -6800,所以我认为这是你需要考虑的偏移量。
(这不包括 RMS 部分,它在您具有正确的带符号整数值之后出现)
有人在 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 值。
我的问题是,
- 我是否正确地进行了数据位操作?
- 是否需要将数据样本从 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 的平方根来计算 rms 值。 然后,20 * log10(rms) 给我相应的分贝值。
rmsValue = peak2peakValue / sqrt2;
DB_Val = 20 * log10(rmsValue);
- 上面的代码是否处理了您提到的“偏移量”?
- 我还没有找到一个测试计划来验证计算出的分贝值,但我是否正确计算了分贝值?
2' 补码部分看起来应该可以工作,但它不必要地复杂,因为常规整数是使用 2' 补码表示的(除非您使用的是一些非常奇特的硬件)。你可以简单地这样做:
signed int signedInputVal = (signed int)inputVal;
signedInputVal >>= 14;
这将为您提供 -(2^17) 到 (2^17-1) 范围内的值。
看起来你的所有样本值都接近 -6800,所以我认为这是你需要考虑的偏移量。
(这不包括 RMS 部分,它在您具有正确的带符号整数值之后出现)