我有两个WAV音轨我想分别在+ 10,+ 8,+ 6,+ 4和0db的SNR下播放
SNR(db)公式= 20 log(信号有效值/ rms噪声)
为此,我需要使用C#语言计算和设置音轨的SNR。我终于想出了这个解决方案,感谢人们,并希望验证它。
这是我做的:
public void play(int required_snr)
{
WaveFileReader signal = new WaveFileReader(@"E:\signal.wav"),
noise = new WaveFileReader(@"E:\noise.wav");
int signal_length = (int)signal.Length, noise_length = (int)noise.Length, i;
byte[] signal_sample = new byte[signal_length], noise_sample = new byte[noise_length];
int signal_read = signal.Read(signal_sample, 0, signal_length) / 2, noise_read = noise.Read(noise_sample, 0, noise_length) / 2;
float[] sample_arr = new float[signal_read], noise_arr = new float[noise_read];
float sum = 0;
for (i = 0; i < sample_arr.Length; i++)
{
sample_arr[i] = (float)BitConverter.ToInt16(signal_sample, i * 2) / 32768f;
sum += (sample_arr[i] * sample_arr[i]);
}
float rms_signal = (float)Math.Sqrt((sum / sample_arr.Length));
sum = 0;
for (i = 0; i < noise_arr.Length; i++)
{
noise_arr[i] = (float)BitConverter.ToInt16(noise_sample, i * 2) / 32768f;
sum += (noise_arr[i] * noise_arr[i]);
}
float rms_noise = (float)Math.Sqrt((sum / noise_arr.Length));
float snr_db = (float)Math.Round(20 * Math.Log10(rms_signal / rms_noise), 1);
float factor = (float)Math.Pow(10, (required_snr - snr_db) / 20);
rms_noise = 0;
for (i = 0; i < noise_arr.Length; i++)
{
noise_arr[i] = noise_arr[i] / factor;
rms_noise += (noise_arr[i] * noise_arr[i]);
}
rms_noise = (float)Math.Sqrt((rms_noise / noise_arr.Length));
snr_db = (float)Math.Round(20 * Math.Log10(rms_signal / rms_noise), 1);
using (WaveFileWriter writer = new WaveFileWriter(@"E:\aw4.wav", noise.WaveFormat))
{
for (i = 0; i < noise_arr.Length; i++)
writer.WriteSample(noise_arr[i]);
}
WaveFileReader reader = new WaveFileReader(@"E:\aw4.wav");
WaveOut waveOut = new WaveOut();
waveOut.Init(reader);
waveOut.Play();
WaveFileReader si = new WaveFileReader(@"E:\signal.wav");
WaveOut o = new WaveOut();
o.Init(si);
o.Play();
}
这段代码是否正确? 我是DSP中的菜鸟,所以我不知道。 但我确实听到并感觉到噪音音量水平的变化随着我将所需的SNR从10降低到0而增加。
答案 0 :(得分:0)
您希望生成具有定义的信噪比(SNR)的音频信号。这意味着你有两个音频信号,一个是信号,另一个是 noise 。
以下所有操作都可以通过直接样本(int)操作,将样本乘以因子或添加两个样本来完成。
首先,您必须测量两个信号的RMS(均方根)水平。这是(顾名思义)所有平方样本均值的根,表示为分贝值:
db = 20*Log10(amplitude)
假设您的信号为30 dB且噪声为20 dB,则信噪比为30-20 = 10dB。
如果您需要更好的SNR,您必须放大信号或削弱噪音。
通过将所有样本乘以常数因子来放大。 (注意不要过载,即产生的样本对于允许的整数范围来说太大)
factor = exp10(db/20);
最后,添加两个信号以获得具有所需SNR的组合信号。
<小时/> 的修改
信噪比可以通过两种方式计算:
snr1 = 20 * log10(rms_signal / rms_noise)
或使用log(分贝)值:
snr2 = db_signal - db_noise
这两个是等价的。
这里是更详细的步骤,用于从两个音轨产生具有定义的SNR的混合信号。
Method1线性计算
计算两个信号的线性均方根:
rms := sqrt ( sum(x*x) / num(x) )
x是音轨的所有样本(通常是int16)。
6dB的SNR相当于exp10(6/20)= 2.0
的线性比因此,如果您发现两个信号的平均幅度(均方根)为160
,则您需要将信号乘以2或除以噪声 by two。这将导致两个均方根值为160和80,这使您的预期信噪比为2.0(线性)或6.0 dB。
方法2对数计算
首先如上所述计算线性均方根(导致信号= 160,噪声= 160)
该rms值的第二个分贝分贝,导致信号= 40 dB噪声= 40dB
因此当前SNR为40-40 = 0dB,两个部分具有相同的功率。
要达到6dB的SNR,您必须将噪声分量降低6dB。
这样做的因素是exp10(6.0 / 20.0)= 2.0
所以你必须将你的噪音信号除以2.0。
这将为噪声信号提供80的线性均方根值。
所以最后你的SNR = 20.0 * log10(160/80)= 6.0
<小时/> 的修改
修改噪声信号后,必须混合信号和噪声:
for(...) mix[i] = signal[i] + noise[i];
这将导致具有所需SNR的噪声信号。