一.介绍
前段时间接到一个项目:侦听调频广播,实现频谱、瀑布图显示,话音播放、存储及语音时域图绘制。其中,话音播放时感觉其噪声很大,必须对其降噪。在C#网上搜索了很多关于C#降噪的,没搜到。利用MATLAB编写降噪函数,并生成dll,但是发现调用Matlab的dll挺耗时的,所以不采用这种方式。于是我仿MATLAB降噪的函数,写出了C#版降噪函数。播放的话音明显实现了,但是其中有一个bug,就是降噪后会有哒哒哒的声音,找了好久没找到原因。如果能找出bug的兄弟,望告知一下。
二.代码
1.低通滤波函数
// 说明:MATLAB转C#函数
private double[,] Lowpass_T(Int16[] Indata, int Len)
{
//定义滤波结果的数组,为二位数组,Len行,1列
double[,] Filterdata = new double[Len, 1];
int LowpassLen = 67;
//滤波器系数
double[] LowpassBuf_1 = new double[] {
-0.0002297245116924, -0.001272528501084, -0.003334224714919, -0.006360776347928,
- 0.009289045067669, -0.01048313976472, -0.008492643648294, -0.003258372951239,
0.003268094048695, 0.007734987474474, 0.007277665725254, 0.001653277578148,
- 0.005926998028789, -0.01029359540466, -0.007644782129877, 0.001353382650881,
0.01111257398261, 0.01429420479649, 0.007026067120628, -0.007359476125338,
- 0.01926144120085, -0.01876047817833, -0.003187318370228, 0.01905162190054,
0.03211612756329, 0.02284966783339, -0.008518122931876, -0.04454921689637,
- 0.05771153561822, -0.02573624712695, 0.05336790092737, 0.1561693966912,
0.2429077783893, 0.2767802107121, 0.2429077783893, 0.1561693966912,
0.05336790092737, -0.02573624712695, -0.05771153561822, -0.04454921689637,
- 0.008518122931876, 0.02284966783339, 0.03211612756329, 0.01905162190054,
- 0.003187318370228, -0.01876047817833, -0.01926144120085, -0.007359476125338,
0.007026067120628, 0.01429420479649, 0.01111257398261, 0.001353382650881,
- 0.007644782129877, -0.01029359540466, -0.005926998028789, 0.001653277578148,
0.007277665725254, 0.007734987474474, 0.003268094048695, -0.003258372951239,
- 0.008492643648294, -0.01048313976472, -0.009289045067669, -0.006360776347928,
- 0.003334224714919, -0.001272528501084, -0.0002297245116924
};
//将滤波系数LowpassBuf_1转化为二位数组
double[,] LowpassBuf = new double[LowpassBuf_1.Length, 1];
for (int i = 0; i < LowpassBuf_1.Length; i++)
{
LowpassBuf[i, 0] = LowpassBuf_1[i];
}
//创建缓存变量
Int16[] m_pData = new Int16[Len];
//计算滤波
for (int k = 0; k < Len; k++)
{
for (int i = LowpassLen - 1; i > 0; i--)
{
m_pData[i] = m_pData[i - 1];
}
m_pData[0] = Indata[k];
double Temp = 0;
for (int i = 0; i < LowpassLen; i++)
{
Temp = Temp + LowpassBuf[i, 0] * m_pData[i] * 2;
}
//保存为Len行1列的数组
Filterdata[k, 0] = Temp;
}
return Filterdata;
}
2.降噪函数
// 说明:MATLAB转C#函数
private double[] NoiseReduction_T(Int16[] Indata, int Len, int Thre)
{
// 定义返回数组,和输入数据长度等长
double[] Outdata = new double[Len];
// 滤波器
double[,] Filterdata = Lowpass_T(Indata, Len);
// 设置窗口长度
int Win = 256;
for (int i = 0; i < Len / Win; i++)
{
//将数据按Win长度分段处理
double[] Windata = new double[Win];
for (int m = 0; m < Win; m++)
{
Windata[m] = Filterdata[i * Win + m, 0];
}
int sum = 0;
//判断每个Win长度数据中小于阈值Thre的数据个数
for (int j = 0; j < Win; j++)
{
if (Windata[j] < Thre)
{
sum = sum + 1;
}
}
// 如果大于250个 则认定为噪声 并对这段Win长度数据归零 如果不是噪声 往后延续15段保证声音连续
if (sum > 250)
{
for (int m = 0; m < Win; m++)
{
Filterdata[i * Win + m, 0] = 0;
}
}
else
{
i = i + 15;
}
}
for (int i = 0; i < Len; i++)
{
Outdata[i] = Filterdata[i, 0];
}
return Outdata;
}
3.降噪处理函数
// 自定义函数:降噪处理
public byte[] DeNoise(byte[] sData, int nLen, int Fs, int Thre)
{
// 长度:8192
byte[] result = new byte[nLen];
// 长度:4096
Int16[] buffer_s = new Int16[nLen / 2];
for (int i = 0; i < buffer_s.Length; i++)
{
// 两个字节转为short(低位在前,高位在后)
buffer_s[i] = BitConverter.ToInt16(new byte[] {sData[2 * i], sData[2 * i + 1] }, 0);
}
// 降噪处理:输入(长度:4096)
Int16[] array_In = buffer_s;
// 降噪处理:输出(长度:4096)
double[] array_Out = NoiseReduction_T(array_In, buffer_s.Length, Thre);
// 取出最后一个值(即索引为4096的值)
for (int i = 0; i < array_Out.Length - 1; i++)
{
sbyte[] tmp = TypeCast(array_Out[i]);
result[i * 2] = (byte)tmp[0]; // 低位在前
result[i * 2 + 1] = (byte)tmp[1]; // 高位在后
}
return result;
}
4.调用降噪处理函数
//降噪
byte[] bytesDst = bytesSrc;
bytesDst = m_NoiseReduct.DeNoise(bytesSrc, bytesSrc.Length, 31500, m_nThresholdDeNoise);