c++实现LPCC算法
时间: 2023-12-14 20:33:42 浏览: 99
根据提供的引用[1],LPCC算法是一种声音识别算法,可以使用C++实现。下面是一个简单的C++实现LPCC算法的例子:
```c++
#include <iostream>
#include <cmath>
#include <vector>
#include <Eigen/Dense>
using namespace std;
using namespace Eigen;
// 计算倒谱系数
vector<double> calcLPCC(vector<double> &signal, int p, int n) {
// 预加重
for (int i = 1; i < signal.size(); i++) {
signal[i] -= 0.95 * signal[i - 1];
}
// 分帧
int frameSize = n;
int frameShift = n / 2;
int numFrames = ceil((double) signal.size() / frameShift);
MatrixXd frames(numFrames, frameSize);
for (int i = 0; i < numFrames; i++) {
for (int j = 0; j < frameSize; j++) {
int index = i * frameShift + j;
if (index < signal.size()) {
frames(i, j) = signal[index];
} else {
frames(i, j) = 0;
}
}
}
// 加窗
VectorXd window(frameSize);
for (int i = 0; i < frameSize; i++) {
window(i) = 0.54 - 0.46 * cos(2 * M_PI * i / (frameSize - 1));
}
for (int i = 0; i < numFrames; i++) {
for (int j = 0; j < frameSize; j++) {
frames(i, j) *= window(j);
}
}
// 傅里叶变换
MatrixXcd spectrum(numFrames, frameSize);
for (int i = 0; i < numFrames; i++) {
VectorXd frame = frames.row(i);
VectorXcd spectrumFrame = VectorXcd::Zero(frameSize);
for (int j = 0; j < frameSize; j++) {
for (int k = 0; k < frameSize; k++) {
spectrumFrame(j) += frame(k) * exp(-2 * M_PI * j * k / frameSize);
}
}
spectrum.row(i) = spectrumFrame;
}
// 梅尔滤波器组
int numFilters = 20;
int sampleRate = 16000;
int fftSize = frameSize;
int lowFreq = 0;
int highFreq = sampleRate / 2;
MatrixXd filterBank(numFilters, fftSize / 2 + 1);
for (int i = 0; i < numFilters; i++) {
double melLow = 1127 * log(1 + (lowFreq + i * (highFreq - lowFreq) / (numFilters + 1)) / 700);
double melHigh = 1127 * log(1 + (lowFreq + (i + 2) * (highFreq - lowFreq) / (numFilters + 1)) / 700);
for (int j = 0; j < fftSize / 2 + 1; j++) {
double freq = j * sampleRate / fftSize;
if (freq < lowFreq || freq > highFreq) {
filterBank(i, j) = 0;
} else {
double mel = 1127 * log(1 + freq / 700);
if (mel < melLow) {
filterBank(i, j) = 0;
} else if (mel < (melLow + melHigh) / 2) {
filterBank(i, j) = 2 * (mel - melLow) / (melHigh - melLow);
} else if (mel < melHigh) {
filterBank(i, j) = 2 * (melHigh - mel) / (melHigh - melLow);
} else {
filterBank(i, j) = 0;
}
}
}
}
// 梅尔倒谱系数
MatrixXd mfcc(numFrames, p);
for (int i = 0; i < numFrames; i++) {
VectorXcd spectrumFrame = spectrum.row(i);
VectorXd powerSpectrumFrame = spectrumFrame.array().abs2();
VectorXd filteredSpectrumFrame = filterBank * powerSpectrumFrame.segment(0, fftSize / 2 + 1);
VectorXd logSpectrumFrame = filteredSpectrumFrame.array().log();
VectorXd dctSpectrumFrame = VectorXd::Zero(p);
for (int j = 0; j < p; j++) {
for (int k = 0; k < numFilters; k++) {
dctSpectrumFrame(j) += logSpectrumFrame(k) * cos(M_PI * j * (k + 0.5) / numFilters);
}
}
mfcc.row(i) = dctSpectrumFrame;
}
// LPC系数
MatrixXd lpc(numFrames, p + 1);
for (int i = 0; i < numFrames; i++) {
VectorXd mfccFrame = mfcc.row(i);
VectorXd autocorrFrame = VectorXd::Zero(p + 1);
for (int j = 0; j <= p; j++) {
for (int k = 0; k < frameSize - j; k++) {
autocorrFrame(j) += frames(i, k) * frames(i, k + j);
}
}
MatrixXd toeplitzMatrix(p, p);
for (int j = 0; j < p; j++) {
for (int k = 0; k < p; k++) {
toeplitzMatrix(j, k) = autocorrFrame(abs(j - k));
}
}
VectorXd lpcFrame = toeplitzMatrix.fullPivHouseholderQr().solve(-autocorrFrame.tail(p));
lpc.row(i) << 1, lpcFrame.transpose();
}
// LPCC系数
MatrixXd lpcc(numFrames, p);
for (int i = 0; i < numFrames; i++) {
VectorXd lpcFrame = lpc.row(i);
VectorXd lpccFrame = VectorXd::Zero(p);
for (int j = 0; j < p; j++) {
for (int k = 0; k < p - j; k++) {
lpccFrame(j) += (k + 1) * lpcFrame(k + j) * mfcc(i, k);
}
}
lpcc.row(i) = lpccFrame;
}
// 归一化
for (int i = 0; i < p; i++) {
double mean = lpcc.col(i).mean();
double std = sqrt((lpcc.col(i).array() - mean).square().sum() / numFrames);
lpcc.col(i) = (lpcc.col(i).array() - mean) / std;
}
// 取平均
vector<double> result(p);
for (int i = 0; i < p; i++) {
result[i] = lpcc.col(i).mean();
}
return result;
}
int main() {
vector<double> signal = {0.707, 0.707, -0.707, -0.707};
vector<double> lpcc = calcLPCC(signal, 10, 4);
for (int i = 0; i < lpcc.size(); i++) {
cout << lpcc[i] << " ";
}
cout << endl;
return 0;
}
```
阅读全文