为什么输出结果只有一个估计声源且误差较大,求解答
%% 多声源三维定位(修正版)
clc; clear; close all;
% 参数设置
c = 340; % 声速 (m/s)
fs = 44100; % 采样率
duration = 1; % 缩短信号时长至1秒以降低计算量
t = 0:1/fs:duration;
num_mics = 5;
num_sources = 2;
%% 1. 生成模拟声源信号
source1 = 0.5 * chirp(t, 100, duration, 1500);
source2 = 0.5 * (sin(2*pi*300*t) + 0.5*sin(2*pi*600*t));
source_pos = [2, 3, 4; 5, 1, 3];
orig_signals = [source1; source2];
%% 2. 定义非共面麦克风阵列
mic_pos = [0,0,0; 3,0,0; 0,4,0; 0,0,5; 3,4,0];
assert(rank(mic_pos)==3, '麦克风共面!');
%% 3. 信号传播模型(精确时延处理)
mixed_signals = zeros(num_mics, length(t));
for mic_idx = 1:num_mics
for src_idx = 1:num_sources
dist = norm(source_pos(src_idx,:) - mic_pos(mic_idx,:));
delay_samples = round(dist/c * fs);
valid_start = max(1, delay_samples+1);
valid_len = length(t) - valid_start + 1;
if valid_len > 0
mixed_signals(mic_idx, valid_start:end) = mixed_signals(mic_idx, valid_start:end) + ...
(1/(1+dist)) * orig_signals(src_idx, 1:valid_len);
end
end
mixed_signals(mic_idx,:) = awgn(mixed_signals(mic_idx,:), 20);
end
%% 4. 数据预处理(关键修正)
% 转置数据为 N × M 格式 (采样点数 × 麦克风数)
mixed_signals_centered = mixed_signals' - mean(mixed_signals', 1); % 中心化
[E, D] = eig(cov(mixed_signals_centered));
whitening_matrix = inv(sqrt(D)) * E';
whitened_signals = (whitening_matrix * mixed_signals_centered')'; % 白化后转回 M × N
%% 5. ICA分离(修正输入维度)
fastica_path = 'C:\Program Files\MATLAB\R2024a\toolbox\fastica\FastICA_25';
addpath('fastica');
[icasig, A, W] = fastica(whitened_signals', 'numOfIC', num_sources, 'g', 'tanh');
% 信号排序与符号校正
corr_matrix = corr(icasig', orig_signals(:,1:size(icasig,2))');
[~, idx] = max(abs(corr_matrix), [], 2);
icasig = icasig(idx, :);
for i = 1:num_sources
if corr(icasig(i,:), orig_signals(i,1:size(icasig,2))) < 0
icasig(i,:) = -icasig(i,:);
end
end
%% 6. TDOA定位(加权Chan算法)
estimated_positions = zeros(num_sources, 3);
for src = 1:num_sources
% 计算相对时延(GCC-PHAT)
tdoa = zeros(1, num_mics-1);
ref_sig = icasig(src, :);
for mic = 2:num_mics
target_sig = mixed_signals(mic, :);
[corr_val, lags] = xcorr(ref_sig, target_sig, 'coeff');
[~, max_idx] = max(abs(corr_val));
tdoa(mic-1) = lags(max_idx)/fs;
end
% 构建方程组
A_mat = []; b_vec = [];
for k = 2:num_mics
mic_k = mic_pos(k,:);
mic_ref = mic_pos(1,:);
A_mat = [A_mat; 2*(mic_k - mic_ref)];
b_val = sum(mic_k.^2 - mic_ref.^2) - (c*tdoa(k-1))^2;
b_vec = [b_vec; b_val];
end
% 加权最小二乘
weights = 1./var(A_mat, 0, 2);
W = diag(weights);
pos_est = (A_mat'*W*A_mat) \ (A_mat'*W*b_vec);
estimated_positions(src,:) = pos_est';
end
%% 7. 重构各麦克风的源分量信号
separated_signals = zeros(num_mics, num_sources, size(icasig,2));
for src = 1:num_sources
separated_signals(:, src, :) = A(:, src) * icasig(src, :);
end
%% 8. TDOA定位(改进版Chan算法)
estimated_positions = zeros(num_sources, 3);
for src = 1:num_sources
% 计算相对时延
tdoa = zeros(1, num_mics-1);
ref_sig = squeeze(separated_signals(1, src, :))';
for mic = 2:num_mics
target_sig = squeeze(separated_signals(mic, src, :))';
% 使用广义互相关
[corr_val, lags] = xcorr(ref_sig, target_sig, 'coeff');
[~, idx] = max(abs(corr_val));
tdoa(mic-1) = lags(idx)/fs;
end
disp(['声源 ', num2str(src), ' 的 TDOA 值:']);
disp(tdoa);
% 构建线性方程组
A_mat = [];
b_vec = [];
mic_ref = mic_pos(1,:);
for k = 2:num_mics
mic_k = mic_pos(k,:);
a = 2*(mic_k - mic_ref);
b = sum(mic_k.^2 - mic_ref.^2) - (c*tdoa(k-1))^2;
A_mat = [A_mat; a];
b_vec = [b_vec; b];
end
disp(['声源 ', num2str(src), ' 的 A_mat 矩阵:']);
disp(A_mat);
disp(['声源 ', num2str(src), ' 的 b_vec 向量:']);
disp(b_vec);
weights = 1 ./ var(A_mat, 0, 2); % 按行计算方差
W = diag(weights); % 创建对角权重矩阵
% 验证矩阵维度
assert(size(A_mat,1) == size(W,1), '矩阵维度不匹配!A_mat:%dx%d, W:%dx%d',...
size(A_mat,1), size(A_mat,2), size(W,1), size(W,2));
% 加权最小二乘解
pos_est = (A_mat'*W*A_mat) \ (A_mat'*W*b_vec);
estimated_positions(src,:) = pos_est';
end
%% 9. 可视化结果
figure;
% 绘制麦克风阵列
scatter3(mic_pos(:,1), mic_pos(:,2), mic_pos(:,3), ...
'filled', 'MarkerFaceColor', [0.2 0.4 0.8], 'SizeData', 120);
hold on;
% 标注麦克风
mic_labels = cellstr(num2str((1:num_mics)'));
text(mic_pos(:,1)+0.1, mic_pos(:,2)+0.1, mic_pos(:,3)+0.1, mic_labels, ...
'FontWeight', 'bold', 'Color', 'k');
% 绘制真实声源
scatter3(source_pos(:,1), source_pos(:,2), source_pos(:,3), ...
'pentagram', 'filled', 'MarkerFaceColor', 'r', 'SizeData', 200);
% 绘制估计声源
scatter3(estimated_positions(:,1), estimated_positions(:,2), estimated_positions(:,3), ...
'hexagram', 'LineWidth', 3, 'MarkerEdgeColor', 'g', 'SizeData', 200);
% 设置图形属性
legend('麦克风阵列', '真实声源', '估计声源', 'Location', 'northeast');
title(sprintf('多声源三维定位结果 (平均误差: %.2f cm)', ...
100*mean(vecnorm(estimated_positions - source_pos, 2, 2))));
xlabel('X轴 (米)'); ylabel('Y轴 (米)'); zlabel('Z轴 (米)');
grid on; axis equal; view(25, 30);
set(gca, 'FontSize', 12);
saveas(gcf, '多声源定位结果.png');
% 绘制分离后的信号与原始信号对比
figure;
for i = 1:num_sources
subplot(num_sources, 2, 2*i-1);
plot(orig_signals(i, :));
title(sprintf('原始信号%d', i));
subplot(num_sources, 2, 2*i);
plot(icasig(i, :));
title(sprintf('分离信号%d', i));
end
%% 10. 输出误差分析
fprintf('===== 定位误差分析 =====\n');
for src_idx = 1:num_sources
error = norm(estimated_positions(src_idx, :) - source_pos(src_idx, :));
fprintf('声源%d定位误差: %.4f 米\n', src_idx, error);
end
