如何在 C# 中计算波信号的混响时间

Posted

技术标签:

【中文标题】如何在 C# 中计算波信号的混响时间【英文标题】:How to calculate the reverberation time of a wave signal in C# 【发布时间】:2012-12-23 22:50:40 【问题描述】:

我正在尝试用 C# 开发一个控制台应用程序,它使用 WAV 文件作为输入。应用程序应该按顺序做几件事,如下所示。首先是完整的代码:

class Program

static List<double> points = new List<double>();
static double maxValue = 0;
static double minValue = 1;
static int num = 0;
static int num2 = 0;
static List<double> values = new List<double>();
private static object akima;
static void Main(string[] args)

    string[] fileLines = File.ReadAllLines(args[0]);
    int count = 0;
    foreach (string fileLine in fileLines)
    
        if (!fileLine.Contains(";"))
        
            string processLine = fileLine.Trim();
            processLine = Regex.Replace(processLine, @"\s+", " ");
            if (Environment.OSVersion.Platform == PlatformID.Win32NT)
            
                processLine = processLine.Replace(".", ",");
            
            string[] dataParts = processLine.Split(Char.Parse(" "));
            points.Add(double.Parse(dataParts[0]));
            double value = Math.Pow(double.Parse(dataParts[1]), 2);
            if (value > maxValue)
            
                maxValue = value;
                num = count;
            
            values.Add(value);
        
        count++;
    
    for (int i = num; i < values.Count; i++)
    
        if (values[i] < minValue)
        
            minValue = values[i];
            num2 = i;
        
    
    Console.WriteLine(num + " " + num2);
    int between = num2 - num;
    points = points.GetRange(num, between);
    values = values.GetRange(num, between);
    List<double> defVal = new List<double>();
    List<double> defValPoints = new List<double>();
    alglib.spline1dinterpolant c;
    alglib.spline1dbuildakima(points.ToArray(), values.ToArray(), out c);
    double baseInt = alglib.spline1dintegrate(c, points[points.Count - 1]);
    List<double> defETC = new List<double>();
    for (int i = 0; i < points.Count; i += 10)
    
        double toVal = points[i];
        defETC.Add(10 * Math.Log10(values[i]));
        defVal.Add(10 * Math.Log10((baseInt - alglib.spline1dintegrate(c, toVal)) / baseInt));
        defValPoints.Add(points[i]);
    
    WriteDoubleArrayToFile(defValPoints.ToArray(), defVal.ToArray(), "test.dat");
    WriteDoubleArrayToFile(defValPoints.ToArray(), defETC.ToArray(), "etc.dat");
    int end = 0;
    for (int i = 0; i < points.Count; i++)
    
        if (defVal[i] < -10)
        
            end = i;
            break;
        
    
    //Console.WriteLine(num + " " + end);
    int beginEDT = num;
    int endEDT = num + end;
    double timeBetween = (defValPoints[endEDT] - defValPoints[beginEDT]) * 6;
    Console.WriteLine(timeBetween);
    for (int i = 0; i < points.Count; i++)
    

    
    Console.ReadLine();

static void WriteDoubleArrayToFile(double[] points, double[] values, string filename)
    
        string[] defStr = new string[values.Length];
        for (int i = 0; i < values.Length; i++)
        
        defStr[i] = String.Format("0,101,25", points[i], values[i]);
        
        File.WriteAllLines(filename, defStr);
    

    从 WAV 文件中提取十进制/浮点/双精度值 从提取的数据创建一个数组 创建一个能量时间曲线,以类似分贝的方式显示噪音/声音的衰减 根据第 3 步中创建的 ETC 创建衰减曲线 根据此衰减曲线计算早期衰减时间 (EDT)、T15/T20 和 RT60。 在标准输出中显示这些混响时间。

目前,我的过程已经完成了一半。我会解释我做了什么:

    我使用 Sox 将音频文件转换为带有数字的 .dat 文件 我使用 C# 创建了一个数组,方法是简单地拆分上面文件中的每一行并将时间放入 TimesArray 并将这些点的值放入 ValuesArray。 我正在通过 GNUPlot 显示一个图形,使用这个函数处理的数据:10 * Math.Log10(values[i]); (其中 i 是 for 循环中迭代 ValuesArray 中所有项目的迭代整数) 这是我开始陷入困境的地方。我的意思是,在这一步中,我使用来自 Alglib 的 Akima Spline 函数来整合一条线。我通过这个数学计算使用 Schroeder 积分(反向)来做到这一点: 10 * Math.Log10((baseInt - alglib.spline1dintegrate(c, toVal)) / baseInt); (其中 baseInt 是计算为完整曲线的基础积分的值,因此我计算了反向施罗德积分的底部部分。c 是使用函数 alglib.spline1dbuildakima 时可用的 spline1dinterpolant,它将 timeArray 作为 x值,valueArray 作为 y 值,c 作为向外 spline1dinterpolant。toval 是点数组中的 x 值。使用 for 循环选择特定值。)从这些新保存的值中,我想创建一个插值线并从该行计算 RT60,但我不知道该怎么做。 试过了,没有真正奏效。 和上面一样,我没有真正的价值要展示。

我现在很困惑,因为我不确定这是否是正确的方法。如果有人能告诉我如何在 C# 中以快速响应的方式计算混响时间,我会很高兴听到。这样做的方式可能和我现在的完全不同,没关系,告诉我!

【问题讨论】:

一个有趣的问题。你在找数学吗?一种实现数学的方法?还有什么? 我没有给你答案,但你的问题非常令人困惑。这可能就是你挣扎的原因。首先要提出一个简单明了(尽可能清晰!)的问题。你需要做什么?你在哪里卡住了?您是否了解需要使用什么数学或算法,或者您是否对它的 c-sharp 实现感到厌烦?我敢打赌,当你提出一个清晰的问题时,你可以自己解决它...... 请尝试将信号处理代码与您的文件 IO 代码隔离开来。然后使用非常简单的硬编码输入(如脉冲或阶跃函数)测试信号处理部分。 【参考方案1】:

也许你需要以不同的方式处理这个问题:

    从基础数学开始。找出这些函数的数学公式。 使用简单的数学函数并手动计算(在 excel 或 matlab 中)应该是什么值(所有这些东西 ETC、DC、EDC、T15、T20、RT60) (一个函数,如您需要的最小点数的正弦波) 然后编写一个单独的程序以在 C# 中评估每一项,并验证您的结果与 excel/matlab 的一致性。

在 C# 中,可能将数据存储在一个类中,然后传递给每个方法进行计算。

你的主要功能应该是这样的:

main()

data = new Data();

//1, 2: 
extract_data(data, filename);

//3: 
energy_time_curve(data)

//...4, 5

//6: 
display_results(data);



【讨论】:

以上是关于如何在 C# 中计算波信号的混响时间的主要内容,如果未能解决你的问题,请参考以下文章

方波,正弦波,三角波信号是如何产生的

正弦信号怎么变成方波信号,需要怎么处理?

用小波分析法除去音频信号的噪声

如何将正弦信号转换成同频率方波信号

信号转换 | 如何将正弦波转换成方波?

如何讲正弦波转化为方波?频率不变。