将 Apple 开发人员文档中的 Mel Spectrogram 示例扩展到录制样本而不是现场麦克风的情况

问题描述 投票:0回答:0

我在 Apple Developer 的文档示例之上构建,称为 Computing the Mel Spectrum Using Linear Algebra。我的目标是扩展此示例,以便能够将其应用于从现场麦克风录制的样本。具体来说,我通过以下方式使用此示例中的子例程:

while(i*hopCnt + windowSize < samples.count) {
        
    if i*hopCnt + windowSize > samples.count {
        samplesInThisWindow = Array(samples[i*hopCnt+windowSize..<samples.count])
        samplesInThisWindow.append(
                contentsOf: [Float].init(repeating: 0, count: i*hopCnt+windowSize - samples.count)
        )
     } else {
        samplesInThisWindow = Array(samples[i*hopCnt..<i*hopCnt+windowSize])
     }
                
     let FFTValues = subroutineFromExample(samplesInThisWindow: &samplesInThisWindow)
     stftSpectrogram.append(contentOf: FFTValues)
}

return stftSpectrogram

完成此例程后,我返回样本的 STFT 变换和 Mel 频谱图尚未计算。这意味着 FFT 是一个 (time_bins x window_size) 矩阵,其中 time_bins = (samples_count - window_size)/hop_size + 1.

此时我回到使用示例中的代码计算 Mel 频谱图,它生成一个 MEL

filterBanks
矩阵,它是一个 (filterbanks_count x window_size) 矩阵(不确定,我猜是因为
makeFilterBank
方法包含以下代码:
row = i * window_size
)。然后代码继续执行以下代码,通过矩阵乘法计算频谱图:

cblas_sgemm(CblasRowMajor,
            CblasTrans,
            CblasTrans,
            Int32(1),
            Int32(self.filterbanksCount),
            Int32(self.windowSize),
            1,
            fftResultPtr.baseAddress,
            Int32(1),
            filterBank.baseAddress,
            Int32(self.windowSize),
            0,                
            sgemmResult!.baseAddress,
            Int32(self.filterbanksCount)
        )

所以,根据文档,这要么计算 C←αAB + βC 要么 C←αBA + βC 其中 A 和 B 可以选择转置。

示例中的代码期望收到一个 (1 x window_size) 矩阵作为 FFT 的结果,因为它一次处理一个时间 bin,因此在这种情况下,FFT 是 (1 x window_size),MEL

filterBanks
是 (filterbanks_count x 窗口大小)。由于
CblasTrans
是为两个输入矩阵指定的,并且 A^tB^t 和 B^tA^t 都不是产品的正确尺寸,因此我假设 MEL
filterBanks
实际上是 (window_size x filterbanks_count) ,这意味着
sgemmResult = MEL^t*FFT^t
cblas_sgemm
在C←αBA + βC模式下运行。

这意味着 sgemmResult 是一个 (filterbanks_count x 1) 矩阵。

现在归纳起来有点麻烦,因为我的界面希望接收旋转频谱图作为输入,即 (time_bins x window_size) 矩阵,而明显的归纳将替换所有硬编码

1
s 在代码中带有
FFT.count/window_size
(FFT 以 row-major order 表示)。

这样做会产生一个 (filterbanks_count x time_bins) 矩阵作为输出,结果,渲染的频谱图看起来很有趣(看起来多个频率仓被水平组合以填充可用宽度,正如我所期望的那样)。所以我的想法如下:我不计算

MEL(FFT) = MEL^t*FFT^t
而是计算
MEL(FFT)^t = FFT*MEL
并得到正确的结果。

(请注意,Apple 的开发人员代码使用

windowSize
作为 B 矩阵行数的参数(代码中的
filterBank
),因此
filterBank
矩阵只是关于上图中表示的滤波器组(转置))

这会产生以下代码:

cblas_sgemm(CblasRowMajor,  //ORDER
                    CblasNoTrans,     //Transpose A? if so, op(A) = A^t, else op(A) = A
                    CblasNoTrans,     //Transpose B? if so, op(B) = B^t, else op(B) = B
                    Int32(fftResult.count/self.windowSize), //A and C's rows.
                    Int32(self.filterbanksCount),   //B and C's cols.
                    Int32(self.windowSize), //A's cols, B's rows
                    1,  //Scale A and B's product
                    fftResultPtr.baseAddress,   //A
                    Int32(self.windowSize), //rows of op(A)^t
                    filterBank.baseAddress, //B
                    Int32(self.filterbanksCount), //rows of op(B)^t
                    0,  //Result scale
                    sgemmResult!.baseAddress,   //C
                    Int32(self.filterbanksCount)    //rows of C^t
            )

所以,如果我用上面的代码代替现有的代码,结果我得到一个频谱图,其中较低的频率占总高度的大约 20%,而较高的频率占剩余的 80%,这意味着假设将 Mel 标度应用于线性频谱图的效果被翻转了。

我的推理哪里失败了,我应该如何修复我的代码?

swift signal-processing linear-algebra cblas
© www.soinside.com 2019 - 2024. All rights reserved.