根据方法2:时间向量生成(自动匹配维度),优化代码,解决“X 和 Y 必须为长度相同的向量、大小相同的矩阵,或向量和矩阵的组合,其中向量的长度与矩阵的行数或列数匹配。”的问题,给我优化后完整的代码:classdef TDMPerformanceAnalyzer < TDMSystem
properties
analysisFigure % 独立分析窗口
performanceMetrics % 扩展的性能指标
constellationAxes % 星座图坐标轴
spectrumAxes % 频谱分析坐标轴
eyeDiagramAxes % 眼图坐标轴
correlationAxes % 相关分析坐标轴
metricTable % 性能指标表格
systemMetricsLabel % 系统级指标标签
end
methods
function obj = TDMPerformanceAnalyzer(params)
% 调用父类构造函数
obj = obj@TDMSystem(params);
% 初始化扩展性能指标
obj.performanceMetrics = struct(...
'evm', [], ... % 误差矢量幅度
'throughput', [], ... % 系统吞吐量
'latency', [], ... % 系统延迟
'spectralEfficiency', [], ... % 频谱效率
'totalThroughput', [], ... % 系统总吞吐量
'overallSpectralEfficiency', [] ... % 总体频谱效率
);
end
function obj = runPerformanceAnalysis(obj)
% 运行基础仿真流程
obj = runSimulation(obj);
% 计算扩展性能指标
obj = obj.calculateExtendedMetrics();
% 创建独立分析窗口
obj.createAnalysisWindow();
% 绘制综合性能分析
obj.plotComprehensiveAnalysis();
end
function obj = calculateExtendedMetrics(obj)
% 计算扩展性能指标
numSignals = obj.params.numSignals;
obj.performanceMetrics.evm = zeros(1, numSignals);
obj.performanceMetrics.throughput = zeros(1, numSignals);
obj.performanceMetrics.latency = zeros(1, numSignals);
obj.performanceMetrics.spectralEfficiency = zeros(1, numSignals);
totalSymbols = 0;
totalBits = 0;
bandwidth = obj.params.fs; % 系统带宽
for i = 1:numSignals
% 检查信号存在性
if size(obj.originalSignals, 1) < i || ...
size(obj.syncedSignals, 1) < i || ...
isempty(obj.originalSignals) || ...
isempty(obj.syncedSignals)
obj.performanceMetrics.evm(i) = NaN;
obj.performanceMetrics.latency(i) = NaN;
continue;
end
% 获取信号并确保行向量
orig = obj.originalSignals(i, :);
decoded = obj.syncedSignals(i, :);
orig = orig(:).'; % 强制转为行向量
decoded = decoded(:).'; % 强制转为行向量
% 确保信号长度匹配
minLen = min(length(orig), length(decoded));
if minLen < 10
obj.performanceMetrics.evm(i) = NaN;
obj.performanceMetrics.latency(i) = NaN;
continue;
end
% 截取相同长度部分
orig = orig(1:minLen);
decoded = decoded(1:minLen);
% 计算误差矢量幅度(EVM)
evm = sqrt(mean(abs(orig - decoded).^2)) / ...
sqrt(mean(abs(orig).^2));
obj.performanceMetrics.evm(i) = evm * 100; % 百分比
% 计算吞吐量 (bps)
modType = obj.modulationParams.signalModulations{i};
bitsPerSymbol = obj.getBitsPerSymbol(modType);
symbolRate = obj.params.fs / bitsPerSymbol;
obj.performanceMetrics.throughput(i) = symbolRate * bitsPerSymbol;
% 估计延迟 (ms) - 基于同步过程
[corr, lags] = xcorr(orig, decoded);
if ~isempty(corr)
[~, idx] = max(abs(corr));
delay = lags(idx) / obj.params.fs * 1000; % 转换为毫秒
obj.performanceMetrics.latency(i) = delay;
else
obj.performanceMetrics.latency(i) = NaN;
end
% 计算频谱效率 (bps/Hz)
obj.performanceMetrics.spectralEfficiency(i) = ...
obj.performanceMetrics.throughput(i) / bandwidth;
% 统计总符号和比特数
if length(obj.modulatedSignals) >= i
totalSymbols = totalSymbols + length(obj.modulatedSignals{i});
end
if length(obj.encodedSignals) >= i
totalBits = totalBits + length(obj.encodedSignals{i});
end
end
% 系统级指标
if totalBits > 0 && obj.params.duration > 0
obj.performanceMetrics.totalThroughput = totalBits / obj.params.duration;
else
obj.performanceMetrics.totalThroughput = 0;
end
obj.performanceMetrics.overallSpectralEfficiency = ...
obj.performanceMetrics.totalThroughput / bandwidth;
end
function createAnalysisWindow(obj)
% 创建独立分析窗口 (使用uifigure解决兼容性问题)
obj.analysisFigure = uifigure('Name', 'TDM系统性能综合分析', ...
'Position', [100, 100, 1200, 850], ...
'Color', [0.95, 0.95, 0.95]);
% 创建网格布局 (4行3列)
gridLayout = uigridlayout(obj.analysisFigure, [4, 3]);
gridLayout.RowHeight = {'1x', '1x', '0.5x', 40}; % 第4行固定高度
gridLayout.ColumnWidth = {'1x', '1x', '1x'};
gridLayout.Padding = [10, 10, 10, 10];
gridLayout.RowSpacing = 5;
gridLayout.ColumnSpacing = 10;
gridLayout.BackgroundColor = [0.95, 0.95, 0.95];
% === 星座图坐标轴 ===
obj.constellationAxes = uiaxes(gridLayout);
obj.constellationAxes.Layout.Row = 1;
obj.constellationAxes.Layout.Column = 1;
title(obj.constellationAxes, '星座图分析');
xlabel(obj.constellationAxes, '同相分量 (I)');
ylabel(obj.constellationAxes, '正交分量 (Q)');
grid(obj.constellationAxes, 'on');
axis(obj.constellationAxes, 'equal');
% === 频谱分析坐标轴 ===
obj.spectrumAxes = uiaxes(gridLayout);
obj.spectrumAxes.Layout.Row = 1;
obj.spectrumAxes.Layout.Column = 2;
title(obj.spectrumAxes, '频谱分析');
xlabel(obj.spectrumAxes, '频率 (kHz)');
ylabel(obj.spectrumAxes, '功率谱密度 (dB/Hz)');
grid(obj.spectrumAxes, 'on');
% === 眼图坐标轴 ===
obj.eyeDiagramAxes = uiaxes(gridLayout);
obj.eyeDiagramAxes.Layout.Row = 1;
obj.eyeDiagramAxes.Layout.Column = 3;
title(obj.eyeDiagramAxes, '眼图分析');
xlabel(obj.eyeDiagramAxes, '时间 (符号周期)');
ylabel(obj.eyeDiagramAxes, '幅度');
grid(obj.eyeDiagramAxes, 'on');
% === 相关分析坐标轴 ===
obj.correlationAxes = uiaxes(gridLayout);
obj.correlationAxes.Layout.Row = 2;
obj.correlationAxes.Layout.Column = [1, 3];
title(obj.correlationAxes, '信号相关性分析');
xlabel(obj.correlationAxes, '滞后 (样本)');
ylabel(obj.correlationAxes, '相关系数');
grid(obj.correlationAxes, 'on');
% === 性能指标表格 ===
obj.metricTable = uitable(gridLayout);
obj.metricTable.Layout.Row = 3;
obj.metricTable.Layout.Column = [1, 3];
obj.metricTable.ColumnName = {'信号', 'BER', 'SNR (dB)', 'MSE', 'EVM (%)', ...
'吞吐量 (bps)', '延迟 (ms)', '频谱效率 (bps/Hz)'};
obj.metricTable.RowName = {};
obj.metricTable.FontName = 'Consolas';
obj.metricTable.ColumnWidth = {60, 80, 80, 80, 80, 100, 80, 120};
% === 系统级指标标签 ===
obj.systemMetricsLabel = uilabel(gridLayout);
obj.systemMetricsLabel.Layout.Row = 4;
obj.systemMetricsLabel.Layout.Column = [1, 3];
obj.systemMetricsLabel.Text = '系统总吞吐量: 计算中...';
obj.systemMetricsLabel.HorizontalAlignment = 'center';
obj.systemMetricsLabel.BackgroundColor = [0.9, 0.9, 0.9];
obj.systemMetricsLabel.FontSize = 12;
obj.systemMetricsLabel.FontWeight = 'bold';
end
function plotComprehensiveAnalysis(obj)
% 绘制星座图
plotConstellation(obj);
% 绘制频谱分析
plotSpectrumAnalysis(obj);
% 绘制眼图
plotEyeDiagram(obj);
% 绘制信号相关性
plotSignalCorrelation(obj);
% 更新性能指标表格
updateMetricTable(obj);
% 更新系统级指标标签
if ~isempty(obj.performanceMetrics.totalThroughput) && ...
~isempty(obj.performanceMetrics.overallSpectralEfficiency)
obj.systemMetricsLabel.Text = sprintf(...
'系统总吞吐量: %.2f Mbps | 总频谱效率: %.2f bps/Hz', ...
obj.performanceMetrics.totalThroughput/1e6, ...
obj.performanceMetrics.overallSpectralEfficiency);
else
obj.systemMetricsLabel.Text = '系统指标计算失败';
end
end
function plotConstellation(obj)
% 绘制第一个信号的星座图
signalIdx = 1;
if length(obj.demuxSignals) >= signalIdx
signal = obj.demuxSignals{signalIdx};
signal = signal(:); % 确保列向量
if length(signal) < 10
text(obj.constellationAxes, 0.5, 0.5, '样本不足', ...
'HorizontalAlignment', 'center', 'Units', 'normalized');
return;
end
% 提取实部和虚部
I = real(signal);
Q = imag(signal);
% 确保维度匹配
if length(I) ~= length(Q)
minLen = min(length(I), length(Q));
I = I(1:minLen);
Q = Q(1:minLen);
end
% 绘制星座图
scatter(obj.constellationAxes, I, Q, 15, ...
'filled', 'MarkerFaceAlpha', 0.6, 'MarkerEdgeColor', 'none');
title(obj.constellationAxes, sprintf('信号%d星座图 (%s调制)', ...
signalIdx, obj.modulationParams.signalModulations{signalIdx}));
% 添加EVM信息
if ~isnan(obj.performanceMetrics.evm(signalIdx))
text(obj.constellationAxes, ...
0.05, 0.95, ... % 归一化位置
sprintf('EVM: %.2f%%', obj.performanceMetrics.evm(signalIdx)), ...
'Units', 'normalized', ...
'BackgroundColor', [1, 1, 0.8], ...
'Margin', 3, ...
'FontSize', 10, ...
'VerticalAlignment', 'top');
end
else
text(obj.constellationAxes, 0.5, 0.5, '无可用信号数据', ...
'HorizontalAlignment', 'center', 'Units', 'normalized');
end
end
function plotSpectrumAnalysis(obj)
% 分析TDM信号的频谱
fs = obj.params.fs;
if isempty(obj.tdmSignal)
text(obj.spectrumAxes, 0.5, 0.5, '无TDM信号', ...
'HorizontalAlignment', 'center', 'Units', 'normalized');
return;
end
signal = obj.tdmSignal(:); % 强制列向量
if length(signal) < 1024
text(obj.spectrumAxes, 0.5, 0.5, '信号长度不足', ...
'HorizontalAlignment', 'center', 'Units', 'normalized');
return;
end
% 计算功率谱密度
[psd, freq] = pwelch(signal, hamming(1024), 512, 1024, fs);
% 关键修复1: 确保频率和PSD长度匹配
minLen = min(length(freq), length(psd));
freq = freq(1:minLen);
psd = psd(1:minLen);
% 关键修复2: 验证向量方向一致性
freq = freq(:); % 强制列向量
psd = psd(:); % 强制列向量
% 绘制频谱
plot(obj.spectrumAxes, freq/1e3, 10*log10(psd), ...
'LineWidth', 1.5, 'Color', [0, 0.4470, 0.7410]);
xlim(obj.spectrumAxes, [0, fs/2/1e3]);
% 添加带宽信息
try
bandwidth = obw(signal, fs)/1e3; % 占用带宽(kHz)
text(obj.spectrumAxes, ...
0.05, 0.95, ... % 归一化位置
sprintf('占用带宽: %.2f kHz', bandwidth), ...
'Units', 'normalized', ...
'BackgroundColor', [1, 1, 0.8], ...
'Margin', 3, ...
'FontSize', 10, ...
'VerticalAlignment', 'top');
catch
% 带宽计算失败时跳过
end
end
function plotEyeDiagram(obj)
% 绘制第一个信号的眼图
signalIdx = 1;
if length(obj.demuxSignals) >= signalIdx
signal = obj.demuxSignals{signalIdx};
signal = real(signal(:)); % 强制列向量并取实部
% 设置眼图参数
samplesPerSymbol = 20; % 每符号采样数
numSymbols = 500; % 显示符号数
% 创建眼图
plotEye(obj.eyeDiagramAxes, signal, samplesPerSymbol, numSymbols);
title(obj.eyeDiagramAxes, sprintf('信号%d眼图', signalIdx));
else
text(obj.eyeDiagramAxes, 0.5, 0.5, '无解复用信号数据', ...
'HorizontalAlignment', 'center', 'Units', 'normalized');
end
end
function plotSignalCorrelation(obj)
% 分析原始信号与解码信号的相关性
signalIdx = 1;
if size(obj.originalSignals, 1) >= signalIdx && ...
size(obj.syncedSignals, 1) >= signalIdx
orig = obj.originalSignals(signalIdx, :);
decoded = obj.syncedSignals(signalIdx, :);
% 强制行向量并截取相同长度
orig = orig(:).';
decoded = decoded(:).';
minLen = min(length(orig), length(decoded));
if minLen < 10
text(obj.correlationAxes, 0.5, 0.5, '信号长度不足', ...
'HorizontalAlignment', 'center', 'Units', 'normalized');
return;
end
orig = orig(1:minLen);
decoded = decoded(1:minLen);
% 计算互相关
try
[corr, lags] = xcorr(orig, decoded, 'normalized');
% 关键修复1: 检查空结果
if isempty(corr) || isempty(lags)
text(obj.correlationAxes, 0.5, 0.5, '互相关计算失败', ...
'HorizontalAlignment', 'center', 'Units', 'normalized');
return;
end
% 关键修复2: 确保维度匹配
if length(lags) ~= length(corr)
minLen = min(length(lags), length(corr));
lags = lags(1:minLen);
corr = corr(1:minLen);
end
% 关键修复3: 统一向量方向
lags = lags(:);
corr = corr(:);
% 绘制相关结果
stem(obj.correlationAxes, lags, corr, ...
'filled', 'MarkerSize', 4, 'MarkerFaceColor', [0.3010, 0.7450, 0.9330]);
title(obj.correlationAxes, '原始信号与解码信号互相关');
% 标记峰值位置
if ~isempty(corr)
[maxCorr, maxIdx] = max(abs(corr));
maxLag = lags(maxIdx);
hold(obj.correlationAxes, 'on');
plot(obj.correlationAxes, maxLag, maxCorr, 'ro', 'MarkerSize', 8, 'LineWidth', 1.5);
text(obj.correlationAxes, maxLag, maxCorr, ...
sprintf(' 延迟: %d 样本 (%.2f ms)', maxLag, maxLag/obj.params.fs*1000), ...
'VerticalAlignment', 'bottom', ...
'FontSize', 10, ...
'BackgroundColor', [1, 1, 0.8]);
hold(obj.correlationAxes, 'off');
end
catch e
% 捕获并显示相关计算错误
warning('相关计算错误: %s (信号长度: %d)', E.message, length(orig));
text(obj.correlationAxes, 0.5, 0.5, '相关计算失败', ...
'HorizontalAlignment', 'center', 'Units', 'normalized');
end
else
text(obj.correlationAxes, 0.5, 0.5, '无信号相关性数据', ...
'HorizontalAlignment', 'center', 'Units', 'normalized');
end
end
function updateMetricTable(obj)
% 准备表格数据
numSignals = obj.params.numSignals;
tableData = cell(numSignals, 8);
for i = 1:numSignals
tableData{i, 1} = sprintf('信号 %d', i);
% 处理BER数据
if i <= length(obj.performance.ber) && ~isempty(obj.performance.ber)
tableData{i, 2} = sprintf('%.2e', obj.performance.ber(i));
else
tableData{i, 2} = 'N/A';
end
% 处理SNR数据
if i <= length(obj.performance.snr) && ~isempty(obj.performance.snr)
tableData{i, 3} = sprintf('%.1f', obj.performance.snr(i));
else
tableData{i, 3} = 'N/A';
end
% 处理其他指标
tableData{i, 4} = sprintf('%.2e', obj.performance.mse(i));
tableData{i, 5} = formatNumber(obj.performanceMetrics.evm(i), '%.2f%%');
tableData{i, 6} = formatNumber(obj.performanceMetrics.throughput(i), 'bps');
tableData{i, 7} = formatNumber(obj.performanceMetrics.latency(i), '%.2f ms');
tableData{i, 8} = formatNumber(obj.performanceMetrics.spectralEfficiency(i), '%.4f bps/Hz');
end
% 设置表格数据
obj.metricTable.Data = tableData;
end
end
methods (Access = private)
function plotEye(~, ax, signal, samplesPerSymbol, numSymbols)
% 绘制眼图辅助函数
if isempty(signal) || length(signal) < samplesPerSymbol
text(ax, 0.5, 0.5, '数据不足', ...
'HorizontalAlignment', 'center', 'Units', 'normalized');
return;
end
% 确保样本数可被整除
numCompleteSymbols = floor(length(signal) / samplesPerSymbol);
if numCompleteSymbols < 1
text(ax, 0.5, 0.5, '样本不足', ...
'HorizontalAlignment', 'center', 'Units', 'normalized');
return;
end
% 限制符号数量,防止内存溢出
maxSymbols = min(numCompleteSymbols, numSymbols);
numSamples = maxSymbols * samplesPerSymbol;
signal = signal(1:numSamples);
% 重塑为矩阵 (每行代表一个符号周期)
try
% 截断信号到整数倍长度
newLength = floor(length(signal) / samplesPerSymbol) * samplesPerSymbol;
signal = signal(1:newLength);
if newLength < samplesPerSymbol
error('信号长度不足,无法形成完整的符号周期');
end
eyeMatrix = reshape(signal, samplesPerSymbol, []);
% 验证矩阵维度
if size(eyeMatrix, 1) ~= samplesPerSymbol || isempty(eyeMatrix)
error('眼图矩阵重塑失败');
end
% 创建时间向量
t = (0:(samplesPerSymbol-1)) / samplesPerSymbol;
t = t(:); % 强制列向量
% 关键修复: 验证时间向量与矩阵行数匹配
if length(t) ~= size(eyeMatrix, 1)
error('时间向量长度(%d)与矩阵行数(%d)不匹配', length(t), size(eyeMatrix, 1));
end
% 绘制眼图轨迹 (最多100条)
numTraces = min(100, size(eyeMatrix, 2));
if numTraces > 0
% 确保时间向量与数据匹配
X = repmat(t, 1, numTraces);
Y = eyeMatrix(:, 1:numTraces);
% 关键修复: 验证维度一致性
if ~isequal(size(X), size(Y))
error('X(%dx%d)和Y(%dx%d)维度不匹配', size(X,1), size(X,2), size(Y,1), size(Y,2));
end
plot(ax, X, Y, ...
'Color', [0, 0.4470, 0.7410, 0.3]);
% 计算并绘制平均值
hold(ax, 'on');
meanTrace = mean(eyeMatrix, 2);
plot(ax, t, meanTrace, 'r', 'LineWidth', 2);
hold(ax, 'off');
end
% 设置坐标轴属性
xlim(ax, [0, 1]);
grid(ax, 'on');
box(ax, 'on');
catch e
% 捕获并显示错误
warning('眼图绘制错误: %s', E.message);
text(ax, 0.5, 0.5, '眼图绘制失败', ...
'HorizontalAlignment', 'center', 'Units', 'normalized');
end
end
end
end
% 增强型辅助函数:格式化数字和单位
function str = formatNumber(num, formatSpec)
if nargin < 2
formatSpec = '%.2f';
end
if isempty(num) || isnan(num)
str = 'N/A';
return;
end
% 处理带单位的格式化
if contains(formatSpec, 'bps')
if num >= 1e9
str = sprintf([formatSpec ' Gbps'], num/1e9);
elseif num >= 1e6
str = sprintf([formatSpec ' Mbps'], num/1e6);
elseif num >= 1e3
str = sprintf([formatSpec ' Kbps'], num/1e3);
else
str = sprintf([formatSpec ' bps'], num);
end
else
% 直接应用格式规范
str = sprintf(formatSpec, num);
end
end