MATLAB实现声纹识别特征提取
2025-12-15
MATLAB实现声纹识别特征提取
声纹识别特征概述
声纹识别依赖于从语音信号中提取能够唯一表征说话人身份的声学特征。这些特征需要具有良好的区分性、稳定性和抗噪性。
核心特征类型
- 频谱特征:MFCC、LPCC、PLP
- 基音特征:基频、共振峰
- ** prosodic特征**:能量、语速、节奏
- 高级特征:GFCC、IMFCC
特征提取流程框架
语音信号 → 预处理 → 分帧加窗 → 特征提取 → 特征后处理 → 特征向量
MATLAB实现
1. 主函数框架
function [features, featureNames] = voiceprintFeatureExtraction(audioData, fs, varargin)
% 声纹识别特征提取主函数
% 输入:
% audioData - 音频数据
% fs - 采样率
% 输出:
% features - 提取的特征向量
% featureNames - 特征名称
% 参数解析
p = inputParser;
addParameter(p, 'frameLength', 0.025, @isnumeric); % 帧长(秒)
addParameter(p, 'frameOverlap', 0.010, @isnumeric); % 帧重叠(秒)
addParameter(p, 'mfccCoeffs', 13, @isnumeric); % MFCC系数个数
addParameter(p, 'lpOrder', 12, @isnumeric); % LPC阶数
addParameter(p, 'includeDelta', true, @islogical); % 是否包含差分特征
addParameter(p, 'includeEnergy', true, @islogical); % 是否包含能量特征
parse(p, varargin{:});
params = p.Results;
fprintf('开始声纹特征提取...\n');
fprintf('采样率: %d Hz, 音频长度: %.2f 秒\n', fs, length(audioData)/fs);
% 1. 语音预处理
processedAudio = preprocessAudio(audioData, fs);
% 2. 分帧加窗
frames = frameBlocking(processedAudio, fs, params.frameLength, params.frameOverlap);
% 3. 多维度特征提取
featureSet = extractAllFeatures(frames, fs, params);
% 4. 特征后处理和统计聚合
features = postProcessFeatures(featureSet);
featureNames = generateFeatureNames(params);
fprintf('特征提取完成,特征维度: %d\n', length(features));
end
2. 语音预处理函数
function processedAudio = preprocessAudio(audioData, fs)
% 语音信号预处理
% 转换为单声道(如果是立体声)
if size(audioData, 2) > 1
audioData = mean(audioData, 2);
fprintf('转换为单声道信号\n');
end
% 预加重:提升高频分量,H(z) = 1 - 0.97z^(-1)
preemph = [1, -0.97];
processedAudio = filter(preemph, 1, audioData);
% 静音检测和端点检测(可选)
voicedFrames = voiceActivityDetection(processedAudio, fs);
processedAudio = processedAudio(voicedFrames);
% 幅度归一化
processedAudio = processedAudio / max(abs(processedAudio));
fprintf('预处理完成,有效语音长度: %.2f 秒\n', length(processedAudio)/fs);
end
function voicedSegments = voiceActivityDetection(audio, fs)
% 基于能量的端点检测
frameLen = round(0.025 * fs); % 25ms帧
overlap = round(0.015 * fs); % 15ms重叠
step = frameLen - overlap;
numFrames = floor((length(audio) - frameLen) / step) + 1;
energy = zeros(numFrames, 1);
% 计算每帧能量
for i = 1:numFrames
startIdx = (i-1)*step + 1;
endIdx = startIdx + frameLen - 1;
frame = audio(startIdx:endIdx);
energy(i) = sum(frame.^2);
end
% 基于能量阈值进行静音检测
energyThresh = 0.1 * max(energy);
voicedFrames = energy > energyThresh;
% 找到有声段的起始和结束
voicedSegments = findVoicedSegments(voicedFrames, step, frameLen, length(audio));
end
3. 分帧加窗处理
function frames = frameBlocking(audio, fs, frameLength, frameOverlap)
% 分帧和加窗处理
frameSamples = round(frameLength * fs);
overlapSamples = round(frameOverlap * fs);
stepSamples = frameSamples - overlapSamples;
numFrames = floor((length(audio) - frameSamples) / stepSamples) + 1;
frames = zeros(frameSamples, numFrames);
% 汉明窗
window = hamming(frameSamples);
for i = 1:numFrames
startIdx = (i-1)*stepSamples + 1;
endIdx = startIdx + frameSamples - 1;
if endIdx <= length(audio)
frame = audio(startIdx:endIdx) .* window;
frames(:, i) = frame;
end
end
fprintf('分帧完成: %d帧, 帧长%d点, 重叠%d点\n', ...
numFrames, frameSamples, overlapSamples);
end
4. MFCC特征提取
function mfccFeatures = extractMFCC(frames, fs, numCoeffs)
% 提取MFCC特征
[frameLength, numFrames] = size(frames);
mfccFeatures = zeros(numCoeffs, numFrames);
% 梅尔滤波器组参数
lowFreq = 0;
highFreq = fs/2;
numFilters = 26; % 梅尔滤波器数量
% 创建梅尔滤波器组
melFilterBank = createMelFilterBank(frameLength, fs, numFilters, lowFreq, highFreq);
for i = 1:numFrames
frame = frames(:, i);
% 1. 预加重(已在预处理完成)
% 2. 计算功率谱
fftFrame = fft(frame);
powerSpectrum = abs(fftFrame(1:frameLength/2+1)).^2;
% 3. 梅尔滤波器组处理
melSpectrum = melFilterBank * powerSpectrum;
logMelSpectrum = log(melSpectrum + eps); % 加eps防止log(0)
% 4. DCT变换得到MFCC
mfcc = dct(logMelSpectrum);
mfccFeatures(:, i) = mfcc(1:numCoeffs);
end
% 提升MFCC(可选)
mfccFeatures = lifterMFCC(mfccFeatures, 22);
end
function melFilterBank = createMelFilterBank(fftSize, fs, numFilters, lowFreq, highFreq)
% 创建梅尔滤波器组
% 频率转换为梅尔尺度
lowMel = 2595 * log10(1 + lowFreq/700);
highMel = 2595 * log10(1 + highFreq/700);
melPoints = linspace(lowMel, highMel, numFilters+2);
% 梅尔尺度转回频率
freqPoints = 700 * (10.^(melPoints/2595) - 1);
% 转换为FFT bin索引
fftBins = floor((fftSize/2 + 1) * freqPoints / (fs/2));
% 创建三角形滤波器
melFilterBank = zeros(numFilters, fftSize/2+1);
for i = 1:numFilters
leftBin = fftBins(i);
centerBin = fftBins(i+1);
rightBin = fftBins(i+2);
% 上升部分
if leftBin ~= centerBin
melFilterBank(i, leftBin:centerBin) = ...
linspace(0, 1, centerBin - leftBin + 1);
end
% 下降部分
if centerBin ~= rightBin
melFilterBank(i, centerBin:rightBin) = ...
linspace(1, 0, rightBin - centerBin + 1);
end
end
end
function liftedMFCC = lifterMFCC(mfcc, liftCoeff)
% MFCC提升,增强高阶系数
[numCoeffs, numFrames] = size(mfcc);
lift = 1 + (liftCoeff/2) * sin(pi * (0:numCoeffs-1)' / liftCoeff);
liftedMFCC = mfcc .* lift;
end
5. LPCC特征提取
function lpccFeatures = extractLPCC(frames, fs, lpOrder)
% 提取LPCC特征(线性预测倒谱系数)
[frameLength, numFrames] = size(frames);
lpccFeatures = zeros(lpOrder, numFrames);
for i = 1:numFrames
frame = frames(:, i);
% 计算LPC系数
lpcCoeffs = lpc(frame, lpOrder);
% LPC转LPCC
lpcc = lpc2lpcc(lpcCoeffs, lpOrder);
lpccFeatures(:, i) = lpcc;
end
end
function lpcc = lpc2lpcc(lpcCoeffs, numCoeffs)
% LPC系数转换为LPCC系数
p = length(lpcCoeffs) - 1; % LPC阶数
lpcc = zeros(numCoeffs, 1);
lpcc(1) = log(lpcCoeffs(1)); % 增益项
for n = 2:numCoeffs
if n <= p
lpcc(n) = -lpcCoeffs(n);
for k = 1:n-1
lpcc(n) = lpcc(n) - (1 - k/n) * lpcCoeffs(k) * lpcc(n-k);
end
else
lpcc(n) = 0;
for k = 1:p
lpcc(n) = lpcc(n) - (1 - k/n) * lpcCoeffs(k) * lpcc(n-k);
end
end
end
end
6. 基音和共振峰特征
function [pitch, formants] = extractProsodicFeatures(frames, fs)
% 提取基音和共振峰特征
[frameLength, numFrames] = size(frames);
pitch = zeros(1, numFrames);
formants = zeros(3, numFrames); % 提取前三个共振峰
for i = 1:numFrames
frame = frames(:, i);
% 基音提取(自相关法)
pitch(i) = computePitch(frame, fs);
% 共振峰提取(LPC谱峰值)
formants(:, i) = computeFormants(frame, fs);
end
end
function pitch = computePitch(frame, fs)
% 基于自相关的基音检测
% 预加重
preemphFrame = filter([1 -0.97], 1, frame);
% 自相关计算
correlation = xcorr(preemphFrame, 'coeff');
correlation = correlation(length(frame):end); % 取正延迟部分
% 寻找基音峰值(在合理基音范围内)
minPitch = 50; % Hz
maxPitch = 400; % Hz
minLag = round(fs / maxPitch);
maxLag = round(fs / minPitch);
[peaks, locations] = findpeaks(correlation(minLag:maxLag));
if ~isempty(peaks)
[~, maxPeakIdx] = max(peaks);
pitchLag = locations(maxPeakIdx) + minLag - 1;
pitch = fs / pitchLag;
else
pitch = 0; % 无声段
end
end
function formants = computeFormants(frame, fs)
% 基于LPC的共振峰提取
lpcOrder = 12; % LPC阶数
lpcCoeffs = lpc(frame, lpcOrder);
% 计算LPC谱
[h, w] = freqz(1, lpcCoeffs, 1024, fs);
lpcSpectrum = 20*log10(abs(h));
% 寻找频谱峰值(共振峰)
[peaks, locations] = findpeaks(lpcSpectrum, 'SortStr', 'descend');
numFormants = min(3, length(peaks));
formants = zeros(3, 1);
if numFormants > 0
formantFreqs = w(locations(1:numFormants));
formants(1:numFormants) = formantFreqs;
end
end
7. 多维度特征整合
function featureSet = extractAllFeatures(frames, fs, params)
% 提取所有特征并整合
[frameLength, numFrames] = size(frames);
featureSet = struct();
fprintf('提取MFCC特征...\n');
featureSet.mfcc = extractMFCC(frames, fs, params.mfccCoeffs);
fprintf('提取LPCC特征...\n');
featureSet.lpcc = extractLPCC(frames, fs, params.lpOrder);
fprintf('提取基音和共振峰特征...\n');
[featureSet.pitch, featureSet.formants] = extractProsodicFeatures(frames, fs);
fprintf('提取能量特征...\n');
featureSet.energy = extractEnergy(frames);
% 差分特征(一阶和二阶差分)
if params.includeDelta
featureSet.mfccDelta = computeDelta(featureSet.mfcc);
featureSet.mfccDeltaDelta = computeDelta(featureSet.mfccDelta);
featureSet.lpccDelta = computeDelta(featureSet.lpcc);
featureSet.lpccDeltaDelta = computeDelta(featureSet.lpccDelta);
end
fprintf('特征提取完成: MFCC(%dx%d), LPCC(%dx%d), 基音(%dx%d)\n', ...
size(featureSet.mfcc,1), size(featureSet.mfcc,2), ...
size(featureSet.lpcc,1), size(featureSet.lpcc,2), ...
1, size(featureSet.pitch,2));
end
function energy = extractEnergy(frames)
% 计算帧能量
energy = sum(frames.^2, 1);
end
function delta = computeDelta(staticFeatures)
% 计算差分特征(一阶导数)
[numCoeffs, numFrames] = size(staticFeatures);
delta = zeros(numCoeffs, numFrames);
for t = 2:numFrames-1
delta(:, t) = (staticFeatures(:, t+1) - staticFeatures(:, t-1)) / 2;
end
% 边界处理
delta(:, 1) = delta(:, 2);
delta(:, end) = delta(:, end-1);
end
8. 特征后处理
function finalFeatures = postProcessFeatures(featureSet)
% 特征后处理和统计聚合
featureMatrix = [];
% MFCC特征统计量(均值、标准差)
mfccMean = mean(featureSet.mfcc, 2);
mfccStd = std(featureSet.mfcc, 0, 2);
featureMatrix = [featureMatrix; mfccMean; mfccStd];
% LPCC特征统计量
lpccMean = mean(featureSet.lpcc, 2);
lpccStd = std(featureSet.lpcc, 0, 2);
featureMatrix = [featureMatrix; lpccMean; lpccStd];
% 基音特征统计量
pitchMean = mean(featureSet.pitch(featureSet.pitch > 0)); % 只统计有声段
pitchStd = std(featureSet.pitch(featureSet.pitch > 0));
featureMatrix = [featureMatrix; pitchMean; pitchStd];
% 共振峰特征统计量
formantMeans = mean(featureSet.formants, 2);
formantStds = std(featureSet.formants, 0, 2);
featureMatrix = [featureMatrix; formantMeans; formantStds];
% 能量特征统计量
energyMean = mean(featureSet.energy);
energyStd = std(featureSet.energy);
featureMatrix = [featureMatrix; energyMean; energyStd];
% 差分特征统计量
if isfield(featureSet, 'mfccDelta')
mfccDeltaMean = mean(featureSet.mfccDelta, 2);
mfccDeltaStd = std(featureSet.mfccDelta, 0, 2);
featureMatrix = [featureMatrix; mfccDeltaMean; mfccDeltaStd];
end
% 去除NaN值
finalFeatures = featureMatrix(~isnan(featureMatrix));
end
function featureNames = generateFeatureNames(params)
% 生成特征名称(用于可解释性)
featureNames = {};
% MFCC特征名
for i = 1:params.mfccCoeffs
featureNames{end+1} = sprintf('MFCC_%d_Mean', i);
end
for i = 1:params.mfccCoeffs
featureNames{end+1} = sprintf('MFCC_%d_Std', i);
end
% LPCC特征名
for i = 1:params.lpOrder
featureNames{end+1} = sprintf('LPCC_%d_Mean', i);
end
for i = 1:params.lpOrder
featureNames{end+1} = sprintf('LPCC_%d_Std', i);
end
% 其他特征名
featureNames = [featureNames, {'Pitch_Mean', 'Pitch_Std'}];
featureNames = [featureNames, {'Formant1_Mean', 'Formant1_Std'}];
featureNames = [featureNames, {'Formant2_Mean', 'Formant2_Std'}];
featureNames = [featureNames, {'Formant3_Mean', 'Formant3_Std'}];
featureNames = [featureNames, {'Energy_Mean', 'Energy_Std'}];
if params.includeDelta
for i = 1:params.mfccCoeffs
featureNames{end+1} = sprintf('MFCC_Delta_%d_Mean', i);
end
for i = 1:params.mfccCoeffs
featureNames{end+1} = sprintf('MFCC_Delta_%d_Std', i);
end
end
end
9. 可视化分析工具
function visualizeFeatures(audioData, fs, features, featureNames)
% 特征可视化分析
figure('Position', [100, 100, 1400, 800]);
% 原始语音波形
subplot(3, 3, 1);
t = (0:length(audioData)-1) / fs;
plot(t, audioData);
title('原始语音信号');
xlabel('时间(s)'); ylabel('幅度');
grid on;
% 语谱图
subplot(3, 3, 2);
spectrogram(audioData, 256, 128, 256, fs, 'yaxis');
title('语谱图');
% MFCC特征示例(第一帧)
subplot(3, 3, 3);
mfccExample = features(1:13); % 假设前13个是MFCC均值
bar(mfccExample);
title('MFCC特征示例');
xlabel('系数索引'); ylabel('幅度');
grid on;
% 特征分布直方图
subplot(3, 3, 4);
histogram(features, 30);
title('特征值分布');
xlabel('特征值'); ylabel('频数');
grid on;
% 特征重要性排序
subplot(3, 3, 5);
[~, idx] = sort(abs(features), 'descend');
topFeatures = features(idx(1:min(10, length(features))));
bar(topFeatures);
title('Top 10特征值');
xlabel('特征索引'); ylabel('幅度');
grid on;
% 特征相关性矩阵(部分特征)
subplot(3, 3, 6);
numShow = min(15, length(features));
corrMatrix = corrcoef([features(1:numShow)']);
imagesc(corrMatrix);
colorbar;
title('特征相关性矩阵');
xlabel('特征索引'); ylabel('特征索引');
% 特征维度约减可视化(PCA)
subplot(3, 3, 7);
if length(features) > 2
[coeff, score] = pca(features');
if size(score, 2) >= 2
scatter(score(:,1), score(:,2));
title('PCA可视化');
xlabel('主成分1'); ylabel('主成分2');
grid on;
end
end
% 特征统计摘要
subplot(3, 3, 8);
featureStats = [mean(features), std(features), min(features), max(features)];
bar(featureStats);
title('特征统计摘要');
set(gca, 'XTickLabel', {'均值', '标准差', '最小值', '最大值'});
grid on;
% 特征提取流水线示意图
subplot(3, 3, 9);
text(0.1, 0.5, sprintf('特征维度: %d\n特征类型: %d种\n音频长度: %.2fs', ...
length(features), length(unique(regexp(strjoin(featureNames), '_', 'split'))), ...
length(audioData)/fs), 'FontSize', 12);
title('特征提取摘要');
axis off;
end
批量处理和数据库构建
function featureDatabase = buildVoiceprintDatabase(dataFolder, outputFile)
% 构建声纹特征数据库
% 查找所有音频文件
audioFiles = dir(fullfile(dataFolder, '*.wav'));
numSpeakers = length(audioFiles);
featureDatabase = struct();
fprintf('开始构建声纹数据库,共%d个说话人...\n', numSpeakers);
for i = 1:numSpeakers
audioFile = fullfile(dataFolder, audioFiles(i).name);
% 读取音频文件
[audioData, fs] = audioread(audioFile);
% 提取特征
[features, featureNames] = voiceprintFeatureExtraction(audioData, fs);
% 存储到数据库
[~, speakerID, ~] = fileparts(audioFiles(i).name);
featureDatabase(i).speakerID = speakerID;
featureDatabase(i).features = features;
featureDatabase(i).featureNames = featureNames;
featureDatabase(i).audioFile = audioFiles(i).name;
featureDatabase(i).fs = fs;
fprintf('完成: %s (%d/%d)\n', speakerID, i, numSpeakers);
end
% 保存数据库
if nargin > 1 && ~isempty(outputFile)
save(outputFile, 'featureDatabase');
fprintf('数据库已保存到: %s\n', outputFile);
end
fprintf('声纹数据库构建完成,共%d个说话人\n', numSpeakers);
end
参考代码 声纹识别特征提取程序 www.3dddown.com/zha/79557.html
实际应用示例
示例1:单个音频文件特征提取
% 读取音频文件
[audio, fs] = audioread('speaker1.wav');
% 提取特征
[features, featureNames] = voiceprintFeatureExtraction(audio, fs, ...
'mfccCoeffs', 13, ...
'lpOrder', 12, ...
'includeDelta', true);
% 可视化分析
visualizeFeatures(audio, fs, features, featureNames);
% 显示特征统计
fprintf('提取特征数: %d\n', length(features));
fprintf('特征范围: [%.4f, %.4f]\n', min(features), max(features));
示例2:批量处理构建数据库
% 构建声纹数据库
dataFolder = 'audio_database/';
featureDatabase = buildVoiceprintDatabase(dataFolder, 'voiceprint_database.mat');
% 分析数据库统计信息
numSpeakers = length(featureDatabase);
featureDims = arrayfun(@(x) length(x.features), featureDatabase);
fprintf('数据库统计:\n');
fprintf(' 说话人数: %d\n', numSpeakers);
fprintf(' 特征维度: %d ± %d\n', mean(featureDims), std(featureDims));
注意事项和优化建议
1. 参数调优建议
% 针对不同语音类型的优化参数
if strcmp(speechType, 'telephone')
params.mfccCoeffs = 12; % 电话语音频带较窄
params.lowFreq = 300; % 调整低频截止
params.highFreq = 3400; % 调整高频截止
elseif strcmp(speechType, 'wideband')
params.mfccCoeffs = 16; % 宽带语音可用更多系数
params.highFreq = 8000; % 更高频率范围
end
2. 鲁棒性增强
% 添加噪声鲁棒性处理
function enhancedFeatures = addRobustness(features, method)
switch method
case 'CMN'
% Cepstral Mean Normalization
enhancedFeatures = features - mean(features, 2);
case 'MVN'
% Mean-Variance Normalization
enhancedFeatures = (features - mean(features, 2)) ./ std(features, 0, 2);
case 'RASTA'
% RASTA滤波
enhancedFeatures = rastaplp(features);
end
end
3. 实时处理优化
% 流式处理版本(用于实时应用)
function streamingFeatureExtraction()
% 初始化缓冲区
bufferSize = 2048;
audioBuffer = zeros(bufferSize, 1);
while hasAudioData()
% 获取新音频数据
newData = getAudioFrame();
% 更新缓冲区
audioBuffer = [audioBuffer(bufferSize/2+1:end); newData];
% 实时特征提取
features = voiceprintFeatureExtraction(audioBuffer, fs, ...
'frameLength', 0.020, ... % 更短的帧长
'frameOverlap', 0.010);
% 实时更新声纹模型
updateVoiceprintModel(features);
end
end
高级特征扩展
1. GFCC特征(Gammatone频率倒谱系数)
function gfccFeatures = extractGFCC(frames, fs, numCoeffs)
% 提取GFCC特征 - 更适合噪声环境
% 实现Gammatone滤波器组
% 类似于MFCC但使用Gammatone滤波器
end
2. 深度特征提取
function deepFeatures = extractDeepFeatures(audioData, fs)
% 使用预训练的深度学习模型提取高级特征
% 加载预训练模型
net = load('pretrained_voice_model.mat');
% 提取深度特征
deepFeatures = predict(net, audioData);
end
