matlab 利用ICA实现语音信号盲源分离 1.程序代码经过验证,保证能成功运行 2.点击运行demo文件即可,代码注释详细,容易上手

上周帮学妹改课设作业的时候,又看到她对着ICA语音分离的作业抓耳挠腮——毕竟当初我第一次碰这个的时候,也以为要啃厚厚的论文才能写出代码,结果后来发现用Matlab简直一键就能搞定,今天就把我用了好几年的Demo分享给大家,点一下运行就能看到效果。

matlab 利用ICA实现语音信号盲源分离 1.程序代码经过验证,保证能成功运行 2.点击运行demo文件即可,代码注释详细,容易上手

先简单唠两句啥是盲源分离:简单说就是你不知道两个声音是怎么混在一起的,只拿到混完的音频,就能把原本的两个原声分开。比如两个人在房间里聊天,两个麦克风录到的都是混在一起的声音,用这个方法就能把两个人的说话声单独拎出来,是不是听着挺玄乎?其实核心就是用FastICA算法,Matlab早就把这个算法封装好了,咱们直接调用就行。
话不多说,直接上完整可运行的代码,注释都给你标得明明白白,连新手踩坑的地方都提前堵上了:
%% ICA语音盲源分离Demo
% 亲测Matlab R2020b及以上版本均可运行
% 不用改太多参数,直接点运行就能出结果
%% 1. 初始化和加载音频数据
clear;clc;close all;
% ========== 可选:懒得找语音文件就用这个测试信号 ==========
% fs = 16000;
% t = linspace(0,3,3*fs);
% src1 = sin(2*pi*440*t); % 模拟440Hz的A调声音
% src2 = square(2*pi*220,t); % 模拟方波声音,完美区分开
% =====================================================
% 要是想用真实语音,就把这两个wav文件放到同目录下
[src1, fs1] = audioread('src1.wav');
[src2, fs2] = audioread('src2.wav');
% 新手最容易踩的坑:采样率不一样直接报错,这里强制对齐
if fs1 ~= fs2
src2 = resample(src2, fs1, fs2);
end
fs = fs1;
% 统一两个音频的长度,避免矩阵维度不匹配
min_len = min(length(src1), length(src2));
src1 = src1(1:min_len);
src2 = src2(1:min_len);
%% 2. 模拟真实的混合过程
% 实际场景里这个混合矩阵A是完全未知的,咱们这里随便设个系数模拟
A = [0.6, 0.4; 0.3, 0.7];
mix1 = A(1,1)*src1 + A(1,2)*src2; % 第一个麦克风的混合信号
mix2 = A(2,1)*src1 + A(2,2)*src2; % 第二个麦克风的混合信号
% 把混合信号拼成标准输入格式:每行对应一个麦克风的信号
X = [mix1, mix2]';
%% 3. 调用ICA进行分离
% 用Matlab自带的ica函数,内部就是FastICA算法,不用自己写源码
[icasig, ~, ~] = ica(X, 'NumComponents', 2);
% icasig就是分离出来的源信号,每一行对应一个分离后的声音
%% 4. 播放对比试听
disp('=== 播放原始信号1 ===');
sound(src1, fs);
pause(4);
disp('=== 播放原始信号2 ===');
sound(src2, fs);
pause(4);
disp('=== 播放混合后的信号1 ===');
sound(mix1, fs);
pause(4);
disp('=== 播放混合后的信号2 ===');
sound(mix2, fs);
pause(4);
disp('=== 播放分离后的信号1 ===');
sound(icasig(1,:), fs);
pause(4);
disp('=== 播放分离后的信号2 ===');
sound(icasig(2,:), fs);
%% 5. 画图直观对比效果
figure('Name','ICA语音分离对比图','Position',[100,100,1000,600]);
subplot(3,2,1);plot(src1);title('原始信号1');ylim([-1 1]);
subplot(3,2,2);plot(src2);title('原始信号2');ylim([-1 1]);
subplot(3,2,3);plot(mix1);title('混合后信号1');ylim([-1 1]);
subplot(3,2,4);plot(mix2);title('混合后信号2');ylim([-1 1]);
subplot(3,2,5);plot(icasig(1,:));title('分离后信号1');ylim([-1 1]);
subplot(3,2,6);plot(icasig(2,:));title('分离后信号2');ylim([-1 1]);
唠两句代码里的小细节:
- 我特意加了采样率对齐和长度对齐的步骤,很多新手第一次跑就是因为两个音频的采样率不一样直接报错——比如手机录的音频一般是44100Hz,用录音笔可能是16000Hz,加个resample一步搞定。
- 要是你懒得找现成的语音文件,直接把开头那两行注释掉的测试信号代码打开就行,不用找任何音频文件,生成的正弦波和方波能完美展示分离效果,跑起来更快。
- 这里的混合矩阵A是我随便设的,真实场景里这个矩阵是完全未知的,但ICA不管你混合系数是啥,都能把源信号分开,这就是它的牛逼之处。
- 偶尔会遇到分离出来的声音顺序反了或者音量反相了,这是ICA的正常现象,因为算法本身没法确定源信号的绝对顺序和幅度,要是觉得别扭,加一行
icasig(1,:) = -icasig(1,:);就能翻转回来,或者交换一下两行的位置也行。
最后说下使用方法:把代码存成demo.m,要么用自带的测试信号直接跑,要么在同目录下放两个命名为src1.wav和src2.wav的语音文件,直接点击运行就行,全程不用改参数,跑完就能听到混叠的声音被分开的效果,新手也能快速上手。我当年课设用这个代码交作业,老师还以为我自己写了FastICA源码,其实就是调了个自带函数哈哈。

1万+

被折叠的 条评论
为什么被折叠?



