UILabel.text截取方式

本文介绍了在处理过长的label字符串时,使用NSLineBreakByTruncatingTail断行模式的方法,并通过具体实例演示了如何在Swift中实现这一功能。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

//    label 里面的字符串太长的话,应该用什么样的方式来截取字符串,枚举

        _movieLabel.lineBreakMode = NSLineBreakByTruncatingTail;

优化下面的代码,解决“错误使用 TDMApp8888 文件: TDMApp8888.m 行: 160 列: 43 '=' 运算符的使用不正确。 '=' 用于为变量赋值,'==' 用于比较值的相等性。”的问题,代码:classdef TDMApp8888 < matlab.apps.AppBase % Properties corresponding to app components properties (Access = public) UIFigure matlab.ui.Figure SignalConfigPanel matlab.ui.container.Panel NumSignalsEditField matlab.ui.control.NumericEditField NumSignalsLabel matlab.ui.control.Label SignalTypeDropDown matlab.ui.control.DropDown SignalTypeLabel matlab.ui.control.Label FrequencyEditField matlab.ui.control.NumericEditField FrequencyLabel matlab.ui.control.Label AddSignalButton matlab.ui.control.Button RemoveSignalButton matlab.ui.control.Button SignalsListBox matlab.ui.control.ListBox SignalsListLabel matlab.ui.control.Label StrategyPanel matlab.ui.container.P FixedRadioButton matlab.ui.control.RadioButton PriorityRadioButton matlab.ui.control.RadioButton StrategyButtonGroup matlab.ui.container.ButtonGroup TotalSlotsEditField matlab.ui.control.NumericEditField TotalSlotsLabel matlab.ui.control.Label SimulationPanel matlab.ui.container.Panel RunSimulationButton matlab.ui.control.Button RunFeedbackButton matlab.ui.control.Button RunAnalysisButton matlab.ui.control.Button ResultsTabGroup matlab.ui.container.TabGroup SignalsTab matlab.ui.container.Tab OriginalAxes matlab.ui.control.UIAxes TDMAxes matlab.ui.control.UIAxes DemuxAxes matlab.ui.control.UIAxes SyncedAxes matlab.ui.control.UIAxes PerformanceTab matlab.ui.container.Tab BERAxes matlab.ui.control.UIAxes ParametersTab matlab.ui.container.Tab ParametersTextArea matlab.ui.control.TextArea StatusLabel matlab.ui.control.Label ProgressBar matlab.ui.control.Lamp SNREditField matlab.ui.control.NumericEditField SNRLabel matlab.ui.control.Label IterationsEditField mat.ui.control.NumericEditField IterationsLabel matlab.ui.control.Label DurationEditField matlab.ui.control.NumericEditField DurationLabel matlab.ui.control.Label SamplingRateEditField matlab.ui.control.NumericEditField SamplingRateLabel matlab.ui.control.Label % 编码配置控件 EncodingPanel matlab.ui.container.Panel EncodingTypeDropDown matlab.ui.control.DropDown EncodingTypeLabel matlab.ui.control.Label QuantBitsEditField matlab.ui.control.NumericEditField QuantBitsLabel matlab.ui.control.Label StepSizeEditField matlab.ui.control.NumericEditField StepSizeLabel matlab.ui.control.Label % 调制配置控件 ModulationPanel matlab.ui.container.Panel ModulationTypeDropDown matlab.ui.control.DropDown ModulationTypeLabel matlab.ui.control.Label % 帧配置控件 FrameConfigPanel matlab.ui.container.Panel FrameHeaderEditField matlab.ui.control.EditField FrameHeaderLabel matlab.ui.control.Label CRCCheckBox matlab.ui.control.CheckBox end properties (Access = private) signals % 存储信号配置的cell数组 params % 系统参数结构体 tdmSystem % TDMSystem实例 controller % TDMFeedbackController实例 analyzer % TDMPerformanceAnalyzer实例 end methods (Access = private) function updateParams(app) % 更新系统参数 app.params = struct(); app.params.fs = app.SamplingRateEditField.Value; app.params.duration = app.DurationEditField.Value; app.params.numSignals = numel(app.signals); app.params.snrDb = app.SNREditField.Value; app.params.iterations = app.IterationsEditField.Value; app.params.totalots = app.TotalSlotsEditField.Value; % 编码参数 app.params.encodingType = app.EncodingTypeDropDown.Value; app.params.quantBits = app.QuantBitsEditField.Value; app.params.stepSize = app.StepSizeEditField.Value; % 调制参数 app.params.modulationType = app.ModulationTypeDropDown.Value; % 帧配置 app.params.frameHeader = app.FrameHeaderEditField.Value; app.params.useCRC = app.CRCCheckBox.Value; % 时隙分配策略 if app.FixedRadioButton.Value app.params.strategy = 'fixed'; else app.params.strategy = 'priority'; end % 设置信号调制方式和时钟漂移 app.params.signalModulations = cell(1, app.params.numSignals); app.params.clockDrift = zeros(1, app.params.numSignals); for i = 1:app.params.numSignals app.params.signalModulations{i} = app.signals{i}.modulation; % 设置时钟漂移 (确保长度与信号数量匹配) if i == 1 app.params.clockDrift(i) = 0.001; elseif i == 2 app.params.clockDrift(i) = 0.002; else app.params.clockDrift(i) = -0.001; end end end function generateSignals(app) % 生成信号数据 (使用linspace确保精确采样点) t = linspace(0, app.params.duration, app.params.fs * app.params.duration); app.tdmSystem.originalSignals = zeros(app.params.numSignals, length(t)); app.tdmSystem.signalInfo = cell(app.params.numSignals, 1); for i = 1:app.params.numSignals sigConfig = app.signals{i}; switch sigConfig.type case '正弦波' freq = sigConfig.frequency; app.tdmSystem.originalSignals(i, :) = sin(2*pi*freq*t); app.tdmSystem.signalInfo{i} = sprintf('正弦波 (%dHz, %s调制)', freq, sigConfig.modulation); case '方波' freq = sigConfig.frequency; app.tdmSystem.originalSignals(i, :) = square(2*pi*freq*t); app.tdmSystem.signalInfo{i} = sprintf('方波 (%dHz, %s调制)', freq, sigConfig.modulation); case '随机噪声' app.tdmSystem.originalSignals(i, :) = randn(1, length(t)); app.tdmSystem.signalInfo{i} = sprintf('随机噪声 (%s调制)', sigConfig.modulation); case '锯齿波' freq = sigConfig.frequency; app.tdmSystem.originalSignals(i, :) = sawtooth(2*pi*freq*t); app.tdmSystem.signalInfo{i} = sprintf('锯齿波 (%dHz, %s调制)', freq, sigConfig.modulation); case '脉冲信号' freq = sigConfig.frequency; duty = 0.3; % 占空比 pulseTrain = pulstran(t, 0:1/freq:app.params.duration, ... 'rectpuls', duty/freq); app.tdmSystem.originalSignals(i, 1:length(pulseTrain)) = pulseTrain; app.tdmSystem.signalInfo{i} = sprintf('脉冲信号 (%dHz, %s调制)', freq, sigConfig.modulation); end end end % 设置编码参数 app.tdmSystem.encodingParams = struct(... 'type',app.params.encodingType, ... 'quantBits',app.params.quantBits, ... 'stepSize', app.params.stepSize); % 设置调制参数 app.tdmSystem.modulationParams = struct(...) 'type', (app.params.modulationType, ...); 'signalModulations', ({app.params.signalModulations}); % 设置帧配置 app.tdmSystem.frameConfig = struct(...) 'header', app.params.frameHeader, ... end function updateParametersDisplay(app) % 更新参数显示 paramText = sprintf('系统参数:\n'); paramText = [paramText sprintf('采样频率: %d Hz\n', app.params.fs)]; paramText = [paramText sprintf('信号持续时间: %.2f 秒\n', app.params.duration)]; paramText = [paramText sprintf('信号源数量: %d\n', app.params.numSignals)]; paramText = [paramText sprintf('信噪比: %d dB\n', app.params.snrDb)]; paramText = [paramText sprintf('时隙分配策略: %s\n', app.params.strategy)]; paramText = [paramText sprintf('总时隙数量: %d\n', app.params.totalSlots)]; paramText = [paramText sprintf('仿真迭代次数: %d\n', app.params.iterations)]; % 编码参数 paramText = [paramText sprintf('\n编码配置:\n')]; paramText = [paramText sprintf(' 编码类型: %s\n', app.params.encodingType)]; paramText = [paramText sprintf(' 量化位数: %d bits\n', app.params.quantBits)]; paramText = [paramText sprintf(' 步长: %.4f\n', app.params.stepSize)]; % 调制参数 paramText = [paramText sprintf('\n调制配置:\n')]; paramText = [paramText sprintf(' 系统调制类型: %s\n', app.params.modulationType)]; % 帧配置 paramText = [paramText sprintf('\n帧配置:\n')]; paramText = [Text sprintf(' 帧头: %s\n', app.params.frameHeader)]; paramText = [paramText sprintf(' CRC校验: %s\n', ifelse(app.params.useCRC, '启用', '禁用'))]; % 信号信息 paramText = [paramText sprintf('\n信号配置:\n')]; for i = 1:app.params.numSignals sig = app.signals{i}; paramText = [paramText sprintf('信号 %d: %s (频率: %d Hz, 调制: %s)\n', i, sig.type, sig.frequency, sig.modulation)]; end app.ParametersTextArea.Value = paramText; end function plotSignals(app) % 绘制原始信号 t = linspace(0, app.params.duration, app.params.fs * app.params.duration); cla(app.OriginalAxes); hold(app.OriginalAxes, 'on'); colors = lines(app.params.numSignals); for i = 1:app.params.numSignals plot(app.OriginalAxes, t, app.tdmSystem.originalSignals(i, 1:length(t)), ... 'Color', colors(i, :), 'DisplayName', app.tdmSystem.signalInfo{i}); end hold(app.OriginalAxes, 'off'); legend(app.OriginalAxes, 'Location', 'best'); title(app.OriginalAxes, '原始信号'); xlabel(app.OriginalAxes, '时间 (s)'); ylabel(app.OriginalAxes, '幅度'); grid(app.OriginalAxes, 'on'); % 绘制TDM信号(支持复数信号) cla(app.TDMAxes); if ~isempty(app.tdmSystem.tdmSignal) plot(app.TDMAxes, t(1:length(app.tdmSystem.tdmSignal)), real(app.tdmSystem.tdmSignal)); hold(app.TDMAxes, 'on'); plot(app.TDMAxes, t(1:length(app.tdmSystem.tdmSignal)), imag(app.tdmSystem.tdmSignal)); hold(app.TDMAxes, 'off'); legend(app.TDMAxes, {'实部', '虚部'}, 'Location', 'best'); end title(app.TDMAxes, ['TDM复用信号 (' app.params.strategy '策略)']); xlabel(app.TDMAxes, '时间 (s)'); ylabel(app.TDMAxes, '幅度'); grid(app.TDMAxes, 'on'); % 绘制解复用信号 cla(app.DemuxAxes); hold(app.DemuxAxes, 'on'); for i = 1:app.params.numSignals if size(app.tdmSystem.demuxSignals, 2) >= length(t) plot(app.DemuxAxes, t, real(app.tdmSystem.demuxSignals(i, 1:length(t))), ... 'Color', colors(i, :), 'DisplayName', ['信号 ' num2str(i)]); end end hold(app.DemuxAxes, 'off'); legend(app.Demuxes, 'Location', 'best'); title(app.DemuxAxes, '解复用信号'); xlabel(app.DemuxAxes, '时间 (s)'); ylabel(app.DemuxAxes, '幅度'); grid(app.DemuxAxes, 'on'); % 绘制同步后信号 cla(app.SyncedAxes); hold(app.SyncedAxes, 'on'); for i = 1:app.params.numSignals if size(app.tdmSystem.syncedSignals, 2) >= length(t) plot(app.SyncedAxes, t, app.tdmSystem.syncedSignals(i, 1:length(t)), ... 'Color', colors(i, :), 'DisplayName', app.tdmSystem.signalInfo{i}); end end hold(app.SyncedAxes, 'off'); legend(app.SyncedAxes, 'Location', 'best'); title(app.SyncedAxes, '同步后信号'); xlabel(app.SyncedAxes, '时间 (s)'); ylabel(app.SyncedAxes, '幅度'); grid(app.SyncedAxes, 'on'); % 绘制误码率和信噪比 cla(app.BERAxes); if ~isempty(app.tdmSystem.performance) yyaxis(app.BERAxes, 'left'); bar(app.BERAxes, 1:app.params.numSignals, app.tdmSystem.ber, 0.6, 'FaceColor', [0.2 0.6 0.8]); ylabel(app.BERAxes, '均方误差 (MSE)'); yyaxis(app.BERAxes, 'right'); plot(app.BERAxes, 1:app.params.numSignals, app.tdmSystem.performance.snr, 'o-', 'LineWidth', 2, 'MarkerSize', 8); ylabel(app.BERAxes, 'SNR (dB)'); title(app.BERAxes, '信号质量分析'); xlabel(app.BERAxes, '信号编号'); grid(app.BERAxes, 'on'); xticks(app.BERAxes, 1:app.params.numSignals); legend(app.BERAxes, {'MSE', 'SNR'}, 'Location', 'best'); end end end % Callbacks that handle component events methods (Access = private) % Code that executes after component creation function startupFcn(app) % 初始化参数 app.signals = {}; app.params = struct(); app.StatusLabel.Text = '准备就绪'; app.ProgressBar.Color = 'green'; % 设置默认参数 app.SamplingRateEditField.Value = 1000; app.DurationEditField.Value = 1; app.SNREditField.Value = 20; app.IterationsEditField.Value = 5; app.TotalSlotsEditField.Value = 50; app.NumSignalsEditField.Value = 0; app.PriorityRadioButton.Value = true; % 编码参数默认值 app.EncodingTypeDropDown.Value = 'PCM'; app.QuantBitsEditField.Value = 8; app.StepSizeEditField.Value = 0.05; % 调制参数默认值 app.ModulationTypeDropDown.Value = 'BPSK'; % 帧配置默认值 app.FrameHeaderEditField.Value = 'A5A5'; app.CRCCheckBox.Value = true; % 更新参数显示 updateParams(app); updateParametersDisplay(app); end % Button pushed function: AddSignalButton function AddSignalButtonPushed(app, ~) % 添加新信号 signalType = app.SignalTypeDropDown.Value; frequency = app.FrequencyEditField.Value; modulationType = app.ModulationTypeDropDown.Value; % 获取调制类型 if frequency <= 0 uialert(app.UIFigure, '频率必须大于0', '无效参数'); return; end newSignal = struct(... 'type', signalType, ... 'frequency', frequency, ... 'modulation', modulationType); % 添加调制类型 app.signals{end+1} = newSignal; app.NumSignalsEditField.Value = numel(app.signals); % 更新信号列表 signalList = cell(1, numel(app.signals)); for i = 1:numel(app.signals) sig = app.signals{i}; signalList{i} = sprintf('信号 %d: %s (%d Hz, %s调制)', i, sig.type, sig.frequency, sig.modulation); end app.SignalsListBox.Items = signalList; % 更新参数 updateParams(app); updateParametersDisplay(app); app.StatusLabel.Text = sprintf('已添加信号: %s (%d Hz, %s调制)', signalType, frequency, modulationType); end % Button pushed function: RemoveSignalButton function RemoveSignalButtonPushed(app, ~) % 移除选中的信号 selectedIdx = app.SignalsListBox.Value; if isempty(selectedIdx) || selectedIdx > numel(app.signals) uialert(app.UIFigure, '请选择要删除的信号', '无选择'); return; end % 移除信号 removedSig = app.signals{selectedIdx}; app.signals(selectedIdx) = []; % 更新信号列表 app.NumSignalsEditField.Value = numel(app.signals); signalList = cell(1, numel(app.signals)); for i = 1:numel(app.signals) sig = app.signals{i}; signalList{i} = sprintf('信号 %极: %s (%d Hz, %s调制)', i, sig.type, sig.frequency, sig.modulation); end app.SignalsListBox.Items = signalList; % 如果没有信号,清除选择 if isempty(app.signals) app.SignalsListBox.Value = []; else app.SignalsListBox.Value = min(selectedIdx, numel(app.signals)); end % 更新参数 updateParams(app); updateParametersDisplay(app); app.StatusLabel.Text = sprintf('已移除信号: %s (%d Hz, %s调制)', removedSig.type, removedSig.frequency, removedSig.modulation); end % Value changed function: NumSignalsEditField function NumSignalsEditFieldValueChanged(app, ~) % 信号数量变化时更新 updateParams(app); updateParametersDisplay(app); end % Value changed function: SamplingRateEditField function SamplingRateEditFieldValueChanged(app, ~) updateParams(app); updateParametersDisplay(app); end % Value changed function: DurationEditField function DurationEditFieldValueChanged(app, ~) updateParams(app); updateParametersDisplay(app); end % Value changed function: SNREditField function SNREditFieldValueChanged(app, ~) updateParams(app); updateParametersDisplay(app); end % Value changed function: IterationsEditField function IterationsEditFieldValueChanged(app, ~) updateParams(app); updateParametersDisplay(app); end % Value changed function: TotalSlotsEditField function TotalSlotsEditFieldValueChanged(app, ~) updateParams(app); updateParametersDisplay(app); end % Selection changed function: StrategyButtonGroup function StrategyButtonGroupSelectionChanged(app, ~) updateParams(app); updateParametersDisplay(app); end % 编码参数变化回调 function EncodingTypeDropDownValueChanged(app, ~) updateParams(app); updateParametersDisplay(app); end function QuantBitsEditFieldValueChanged(app, ~) updateParams(app); updateParametersDisplay(app); end function StepSizeEditFieldValueChanged(app, ~) updateParams(app); updateParametersDisplay(app); end % 调制参数变化回调 function ModulationTypeDropDownValueChanged(app, ~) updateParams(app); updateParametersDisplay(app); end function FrameHeaderEditFieldValueChanged(app, ~) updateParams(app); updateParametersDisplay(app); end function CRCCheckBoxValueChanged(app, ~) updateParams(app); updateParametersDisplay(app); end % Button pushed function: RunSimulationButton function RunSimulationButtonPushed(app, ~) % 运行基础仿真 app.StatusLabel.Text = '运行基础仿真...'; app.ProgressBar.Color = 'yellow'; drawnow; try % 更新参数 updateParams(app); % 检查信号配置 if app.params.numSignals == 0 uialert(app.UIFigure, '请至少添加一个信号', '无信号'); app.ProgressBar.Color = 'red'; return; end % 创建TDM系统 app.tdmSystem = TDMSystem(app.params); % 生成信号 generateSignals(app); % 运行仿真 app.tdmSystem = app.tdmSystem.runSimulation(); % 显示结果 plotSignals(app); updateParametersDisplay(app); app.StatusLabel.Text = '基础仿真完成!'; app.ProgressBar.Color = 'green'; catch ME app.StatusLabel.Text = ['错误: ' ME.message]; app.ProgressBar.Color = 'red'; uialert(app.UIFigure, ME.message, '仿真错误'); end end % Button pushed function: RunFeedbackButton function RunFeedbackButtonPushed(app, ~) % 运行反馈控制仿真 app.StatusLabel.Text = '运行反馈控制仿真...'; app.ProgressBar.Color = 'yellow'; drawnow; try % 更新参数 updateParams(app); % 检查信号配置 if app.params.numSignals == 0 uialert(app.UIFigure, '请至少添加一个信号', '无信号'); app.ProgressBar.Color = 'red'; return; end % 创建反馈控制器 app.controller = TDMFeedbackController(app.params); % 生成信号 generateSignals(app); % 运行反馈仿真 app.controller = app.controller.runFeedbackSimulation(); % 显示结果(简化版) app.tdmSystem = app.controller; % 用于显示基本结果 plotSignals(app); updateParametersDisplay(app); app.StatusLabel.Text = '反馈控制仿真完成!'; app.ProgressBar.Color = 'green'; catch ME app.StatusLabel.Text = ['错误: ' ME.message]; app.ProgressBar.Color = 'red'; uialert(app.UIFigure, ME.message, '仿真错误'); end end % Button pushed function: RunAnalysisButton function RunAnalysisButtonPushed(app, ~) % 运行性能分析 app.StatusLabel.Text = '运行性能分析...'; app.ProgressBar.Color = 'yellow'; drawnow; try % 更新参数 updateParams(app); % 检查信号配置 if app.params.numSignals == 0 uialert(app.UIFigure, '请至少添加一个信号', '无极'); app.ProgressBar.Color = 'red'; return; end % 创建性能分析器 app.analyzer = TDMPerformanceAnalyzer(app.params); % 生成信号 generateSignals(app); % 运行性能分析 app.analyzer = app.analyzer.runPerformanceAnalysis(); % 显示结果(简化版) app.tdmSystem = app.analyzer; % 用于显示基本结果 plotSignals(app); updateParametersDisplay(app); app.StatusLabel.Text = '性能分析完成!'; app.ProgressBar.Color = 'green'; catch ME app.StatusLabel.Text = ['错误: ' ME.message]; app.ProgressBar.Color = 'red'; uialert(app.UIFigure, ME.message, '仿真错误'); end end end % App initialization and construction methods (Access = private) % Create UIFigure and components function createComponents(app) % Create UIFigure app.UIFigure = uifigure; app.UIFigure.Position = [100 100 1200 900]; app.UIFigure.Name = 'TDM通信系统仿真'; app.UIFigure.Scrollable = 'on'; % Create SignalConfigPanel app.SignalConfigPanel = uipanel(app.UIFigure); app.SignalConfigPanel.Title = '信号配置'; app.SignalConfigPanel.Position = [20 700 360 210]; % Create NumSignalsLabel app.NumSignalsLabel = uilabel(app.SignalConfigPanel); app.NumSignalsLabel.Position = [20 160 80 22]; app.NumSignalsLabel.Text = '信号数量:'; % Create NumSignalsEditField app.NumSignalsEditField = uieditfield(app.SignalConfigPanel, 'numeric'); app.NumSignalsEditField.Position = [110 160 60 22]; app.NumSignalsEditField.Value = 0; app.NumSignalsEditField.ValueChangedFcn = createCallbackFcn(app, @NumSignalsEditFieldValueChanged, true); % Create SignalTypeLabel app.SignalTypeLabel = uilabel(app.SignalConfigPanel); app.SignalTypeLabel.Position = [20 130 80 22]; app.SignalTypeLabel.Text = '信号类型:'; % Create SignalTypeDropDown app.SignalTypeown = uidropdown(app.SignalConfigPanel); app.SignalTypeDropDown.Position = [110 130 100 22]; app.SignalTypeDropDown.Items = {'正弦波', '方波', '随机噪声', '锯齿波', '脉冲信号'}; % Create FrequencyLabel app.FrequencyLabel = uilabel(app.SignalConfigPanel); app.FrequencyLabel.Position = [20 100 80]; app.FrequencyLabel.Text = '频率 (Hz):'; % Create FrequencyEditField app.FrequencyEditField = uieditfield(app.SignalConfigPanel, 'numeric'); app.FrequencyEditField.Position = [110 100 60 22]; app.FrequencyEditField.Value = 50; % Create AddSignalButton app.AddSignalButton = uibutton(app.SignalConfigPanel, 'push'); app.AddSignalButton.ButtonPushedFcn = createCallbackFcn(app, @AddSignalButtonPushed, true); app.AddSignalButton.Position = [220 130 100 22]; app.AddSignalButton.Text = '添加信号'; % Create RemoveSignalButton app.RemoveSignalButton = uibutton(app.SignalConfigPanel, 'push'); app.RemoveSignalButton.ButtonPushedFcn = createCallbackFcn(app, @RemoveSignalButtonPushed, true); app.RemoveSignalButton.Position = [220 100 100 22]; app.RemoveSignalButton.Text = '移除信号'; % Create SignalsListLabel app.SignalsListLabel = uilabel(app.SignalConfigPanel); app.SignalsListLabel.Position = [20 70 80 22]; app.SignalsListLabel.Text = '信号列表:'; % Create SignalsListBox app.SignalsListBox = uilistbox(app.SignalConfigPanel); app.SignalsListBox.Position = [20 20 300 50]; app.SignalsListBox.Items = {}; % 编码配置控件 app.EncodingPanel = uipanel(app.UIFigure); app.EncodingPanel.Title = '编码配置'; app.EncodingPanel.Position = [20 560 360 130]; app.EncodingTypeLabel = uilabel(app.EncodingPanel); app.EncodingTypeLabel.Position = [20 80 80 22]; app.EncodingTypeLabel.Text = '编码类型:'; app.EncodingTypeDropDown = uidropdown(app.EncodingPanel); app.EncodingTypeDropDown.Position = [110 80 100 22]; app.EncodingTypeDropDown.Items = {'PCM', 'DPCM', 'DM'}; app.EncodingTypeDropDown.Value = 'PCM'; app.EncodingTypeDropDown.ValueChangedFcn = createCallbackFcn(app, @EncodingTypeDropDownValueChanged, true); app.QuantBitsLabel = uilabel(app.EncodingPanel); app.QuantBitsLabel.Position = [20 50 80 22]; app.QuantBitsLabel.Text = '量化位数:'; app.QuantBitsEditField = uieditfield(app.EncodingPanel, 'numeric'); app.QuantBitsEditField.Position = [110 50 60 22]; app.QuantBitsEditField.Value = 8; app.QuantBitsEditField.ValueChangedFcn = createCallbackFcn(app, @QuantBitsEditFieldValueChanged, true); app.StepSizeLabel = uilabel(app.EncodingPanel); app.StepSizeLabel.Position = [20 20 80 22]; app.StepSizeLabel.Text = '步长:'; app.StepSizeEditField = uieditfield(app.EncodingPanel, 'numeric'); app.StepSizeEditField.Position = [110 20 60 22]; app.StepSizeEditField.Value = 0.05; app.StepSizeEditField.ValueChangedFcn = createCallbackFcn(app, @StepSizeEditFieldValueChanged, true); % 调制配置控件 app.ModulationPanel = uipanel(app.UIFigure); app.ModulationPanel.Title = '调制配置'; app.ModulationPanel.Position = [20 460 360 50]; app.ModulationTypeLabel = uilabel(app.ModulationPanel); app.ModulationTypeLabel.Position = [20 15 80 22]; app.ModulationTypeLabel.Text = '调制方式:'; app.ModulationTypeDropDown = uidropdown(app.ModulationPanel); app.ModulationTypeDropDown.Position = [110 15 100 22]; app.ModulationTypeDropDown.Items = {'None', 'BPSK', 'QPSK', '16QAM'}; app.ModulationTypeDropDown.Value = 'BPSK'; app.ModulationTypeDropDown.ValueChangedFcn = createCallbackFcn(app, @ModulationTypeDropDownValueChanged, true); % 帧配置控件 app.FrameConfigPanel = uipanel(app.UIFigure); app.FrameConfigPanel.Title = '帧配置'; app.FrameConfigPanel.Position = [20 400 360 50]; app.FrameHeaderLabel = uilabel(app.FrameConfigPanel); app.FrameHeaderLabel.Position = [20 15 80 22]; app.FrameHeaderLabel.Text = '帧头:'; app.FrameHeaderEditField = uieditfield(app.FrameConfigPanel, 'text'); app.FrameHeaderEditField.Position = [110 15 100 22]; app.FrameHeaderEditField.Value = 'A5A5'; app.FrameHeaderEditField.ValueChangedFcn = createCallbackFcn(app, @FrameHeaderEditFieldValueChanged, true); app.CRCCheckBox = uicheckbox(app.FrameConfigPanel); app.CRCCheckBox.Text = '启用CRC校验'; app.CRCCheckBox.Position = [220 15 120 22]; app.CRCCheckBox.Value = true; app.CRCCheckBox.ValueChangedFcn = createCallbackFcn(app, @CRCCheckBoxValueChanged, true); % Create StrategyPanel app.StrategyPanel = uipanel(app.UIFigure); app.StrategyPanel.Title = '时隙分配策略'; app.StrategyPanel.Position = [400 700 250 210]; % Create StrategyButtonGroup app.StrategyButtonGroup = uibuttongroup(app.StrategyPanel); app.StrategyButtonGroup.SelectionChangedFcn = createCallbackFcn(app, @StrategyButtonGroupSelectionChanged, true); app.StrategyButtonGroup.Position = [20 100 200 80]; app.StrategyButtonGroup.Title = '选择策略'; % Create FixedRadioButton app.FixedRadioButton = uiradiobutton(app.StrategyButtonGroup); app.FixedRadioButton.Text = '固定分配'; app.FixedRadioButton.Position = [11 35 75 22]; % Create PriorityRadioButton app.PriorityRadioButton = uiradiobutton(app.StrategyButtonGroup); app.PriorityRadioButton.Text = '优先级分配'; app.PriorityRadioButton.Position = [11 10 100 22]; app.PriorityRadioButton.Value = true; % Create TotalSlotsLabel app.TotalSlotsLabel = uilabel(app.StrategyPanel); app.TotalSlotsLabel.Position = [20 60 80 22]; app.TotalSlotsLabel.Text = '总时隙数:'; % Create TotalSlotsEditField app.TotalSlotsEditField = uieditfield(app.StrategyPanel, 'numeric'); app.TotalSlotsEditField.ValueChangedFcn = createCallbackFcn(app, @TotalSlotsEditFieldValueChanged, true); app.TotalSlotsEditField.Position = [110 60 60 22]; app.TotalSlotsEditField.Value = 50; % Create SimulationPanel app.SimulationPanel = uipanel(app.UIFigure); app.SimulationPanel.Title = '仿真控制'; app.SimulationPanel.Position = [670 700 250 210]; % Create RunSimulationButton app.RunSimulationButton = uibutton(app.SimulationPanel, 'push'); app.RunSimulationButton.ButtonPushedFcn = createCallbackFcn(app, @RunSimulationButtonPushed, true); app.RunSimulationButton.Position = [30 150 190 30]; app.RunSimulationButton.Text = '运行系统仿真'; % Create RunFeedbackButton app.RunFeedbackButton = uibutton(app.SimulationPanel, 'push'); app.RunFeedbackButton.ButtonPushedFcn = createCallbackFcn(app, @RunFeedbackButtonPushed, true); app.RunFeedbackButton.Position = [30 100 190 30]; app.RunFeedbackButton.Text = '运行反馈控制'; % Create RunAnalysisButton app.RunAnalysisButton = uibutton(app.SimulationPanel, 'push'); app.RunAnalysisButton.ButtonPushedFcn = createCallbackFcn(app, @RunAnalysisButtonPushed, true); app.RunAnalysisButton.Position = [30 50 190 30]; app.RunAnalysisButton.Text = '运行性能分析'; % Create ResultsTabGroup app.ResultsTabGroup = uitabgroup(app.UIFigure); app.ResultsTabGroup.Position = [20 20 1150 420]; % Create SignalsTab app.SignalsTab = uitab(app.ResultsTabGroup); app.SignalsTab.Title = '信号可视化'; % Create OriginalAxes app.OriginalAxes = uiaxes(app.SignalsTab); title(app.OriginalAxes, '原始信号') xlabel(app.OriginalAxes, '时间 (s)') ylabel(app.OriginalAxes, '幅度') app.OriginalAxes.Position = [50 240 500 150]; % Create TDMAxes app.TDMAxes = uiaxes(app.SignalsTab); title(app.TDMAxes, 'TDM复用信号') xlabel(app.TDMAxes, '时间 (s)') ylabel(app.TDMAxes, '幅度') app.TDMAxes.Position = [50 40 500 150]; % Create DemuxAxes app.DemuxAxes = uiaxes(app.SignalsTab); title(app.DemuxAxes, '解复用信号') xlabel(app.DemuxAxes, '时间 (s)') ylabel(app.DemuxAxes, '幅度') app.DemuxAxes.Position = [600 240 500 150]; % Create SyncedAxes app.SyncedAxes = uiaxes(app.SignalsTab); title(app.SyncedAxes, '同步后信号') xlabel(app.SyncedAxes, '时间 (s)') ylabel(app.SyncedAxes, '幅度') app.SyncedAxes.Position = [600 40 500 150]; % Create PerformanceTab app.PerformanceTab = uitab(app.ResultsTabGroup); app.PerformanceTab.Title = '性能分析'; % Create BERAxes app.BERAxes = uiaxes(app.PerformanceTab); title(app.BERAxes, '信号质量分析') xlabel(app.BERAxes, '信号编号') app.BERAxes.Position = [50 80 1000 250]; yyaxis(app.BERAxes, 'left'); ylabel(app.BERAxes, 'MSE'); yyaxis(app.BERAxes, 'right'); ylabel(app.BERAxes, 'SNR (dB)'); % Create ParametersTab app.ParametersTab = uitab(app.ResultsTabGroup); app.ParametersTab.Title = '系统参数'; % Create ParametersTextArea app.ParametersTextArea = uitextarea(app.ParametersTab); app.ParametersTextArea.Position = [20 50 1100 340]; app.ParametersTextArea.Value = {'系统参数将在此显示'}; % Create StatusLabel app.StatusLabel = uilabel(app.UIFigure); app.StatusLabel.HorizontalAlignment = 'right'; app.StatusLabel.Position = [100 900 800 22]; app.StatusLabel.Text = '准备就绪'; % Create ProgressBar app.ProgressBar = uilamp(app.UIFigure); app.ProgressBar.Position = [930 900 20 20]; app.ProgressBar.Color = [0.47 0.67 0.19]; % Create SNRLabel app.SNRLabel = uilabel(app.UIFigure); app.SNRLabel.Position = [950 560 80 22]; app.SNRLabel.Text = '信噪比 (dB):'; % Create SNREditField app.SNREditField = uieditfield(app.UIFigure, 'numeric'); app.SNREditField.ValueChangedFcn = createCallbackFcn(app, @SNREditFieldValueChanged, true); app.SNREditField.Position = [1040 560 60 22]; app.SNREditField.Value = 20; % Create IterationsLabel app.IterationsLabel = uilabel(app.UIFigure); app.IterationsLabel.Position = [950 530 80 22]; app.IterationsLabel.Text = '迭代次数:'; % Create IterationsEditField app.IterationsEditField = uieditfield(app.UIFigure, 'numeric'); app.IterationsEditField.ValueChangedFcn = createCallbackFcn(app, @IterationsEditFieldValueChanged, true); app.IterationsEditField.Position = [1040 530 60 22]; app.IterationsEditField.Value = 5; % Create DurationLabel app.DurationLabel = uilabel(app.UIFigure); app.DurationLabel.Position = [950 500 80 22]; app.DurationLabel.Text = '持续时间 (s):'; % Create DurationEditField app.DurationEditField = uieditfield(app.UIFigure, 'numeric'); app.DurationEditField.ValueChangedFcn = createCallbackFcn(app, @DurationEditFieldValueChanged, true); app.DurationEditField.Position = [1040 500 60 22]; app.DurationEditField.Value = 1; % Create SamplingRateLabel app.SamplingRateLabel = uilabel(app.UI); app.SamplingRateLabel.Position = [950 470 80 22]; app.SamplingRateLabel.Text = '采样率 (Hz):'; % Create SamplingRateEditField app.SamplingRateEditField = uieditfield(app.UIFigure, 'numeric'); app.SamplingRateEditField.ValueChangedFcn = createCallbackFcn(app, @SamplingRateEditFieldValueChanged, true); app.SamplingRateEditField.Position = [1040 470 60 22]; app.SamplingRateEditField.Value = 1000; end end methods (Access = public) % Construct app function app = TDMApp8888 % Create and configure components createComponents(app) % Register the app with App Designer registerApp(app, app.UIFigure) % Execute the startup function runStartupFcn(app, @startupFcn) if nargout == 0 clear app end end % Code that executes before app deletion function delete(app) % Delete UIFigure when app is deleted delete(app.UIFigure) end end end % 辅助函数 function out = ifelse(condition, true_val, false_val) if condition out = true_val; else out = false_val; end end
06-23
现在出现了关于MATLAB应用的三个问题:矩阵奇异警告、数值输入框居中对齐问题,以及仿真后无图像显示,请你帮我修复并给出完整的代码,源代码如下classdef ChladniLab < matlab.apps.AppBase % Properties that correspond to app components properties (Access = public) UIFigure matlab.ui.Figure GridLayout matlab.ui.container.GridLayout LeftPanel matlab.ui.container.Panel MaterialPanel matlab.ui.container.Panel DensityEditFieldLabel matlab.ui.control.Label DensityEditField matlab.ui.control.NumericEditField PoissonRatioEditFieldLabel matlab.ui.control.Label PoissonRatioEditField matlab.ui.control.NumericEditField ElasticEditFieldLabel matlab.ui.control.Label ElasticEditField matlab.ui.control.NumericEditField PlatePanel matlab.ui.container.Panel LengthEditFieldLabel matlab.ui.control.Label LengthEditField matlab.ui.control.NumericEditField ThicknessEditFieldLabel matlab.ui.control.Label ThicknessEditField matlab.ui.control.NumericEditField VibrationPanel matlab.ui.container.Panel FrequencyEditFieldLabel matlab.ui.control.Label FrequencyEditField matlab.ui.control.NumericEditField AmplitudeEditFieldLabel matlab.ui.control.Label AmplitudeEditField matlab.ui.control.NumericEditField SimulationPanel matlab.ui.container.Panel ResolutionEditFieldLabel matlab.ui.control.Label ResolutionEditField matlab.ui.control.NumericEditField SimTimeEditFieldLabel matlab.ui.control.Label SimTimeEditField matlab.ui.control.NumericEditField ControlPanel matlab.ui.container.Panel RunButton matlab.ui.control.Button StopButton matlab.ui.control.Button ResetButton matlab.ui.control.Button RightPanel matlab.ui.container.Panel UIAxes matlab.ui.control.UIAxes ModeDropDownLabel matlab.ui.control.Label ModeDropDown matlab.ui.control.DropDown StatusLabel matlab.ui.control.Label ProgressBar matlab.ui.control.Label end % 应用状态属性 properties (Access = private) Running = false; % 仿真运行状态 StopRequested = false; % 停止请求标志 LastResult; % 存储上次仿真结果 end % 回调方法 methods (Access = private) % 创建UI组件 function createComponents(app) % 创建主窗口 app.UIFigure = uifigure('Visible', 'off'); app.UIFigure.Position = [100 100 1200 700]; app.UIFigure.Name = 'Chladni Lab - 克拉尼图形仿真平台'; app.UIFigure.Resize = 'on'; % 允许窗口调整大小 % 创建主网格布局 app.GridLayout = uigridlayout(app.UIFigure, [1, 2]); app.GridLayout.ColumnWidth = {'1x', '2x'}; app.GridLayout.RowHeight = {'1x'}; app.GridLayout.ColumnSpacing = 10; app.GridLayout.RowSpacing = 10; app.GridLayout.Padding = [10 10 10 10]; % 创建左侧面板 app.LeftPanel = uipanel(app.GridLayout); app.LeftPanel.Layout.Row = 1; app.LeftPanel.Layout.Column = 1; app.LeftPanel.Title = '控制面板'; app.LeftPanel.FontWeight = 'bold'; app.LeftPanel.Scrollable = 'on'; % 创建左侧垂直网格布局 (替代 uix.VBox) leftGrid = uigridlayout(app.LeftPanel, [5, 1]); leftGrid.RowHeight = {120, 100, 100, 100, 'fit'}; leftGrid.ColumnWidth = {'1x'}; leftGrid.Padding = [10 10 10 10]; leftGrid.RowSpacing = 15; % 创建材料参数面板 app.MaterialPanel = uipanel(leftGrid); app.MaterialPanel.Layout.Row = 1; app.MaterialPanel.Layout.Column = 1; app.MaterialPanel.Title = '材料参数'; app.MaterialPanel.BackgroundColor = [0.96 0.96 0.96]; app.MaterialPanel.FontWeight = 'bold'; materialGrid = uigridlayout(app.MaterialPanel, [3, 2]); materialGrid.ColumnWidth = {'1x', '1.5x'}; materialGrid.RowHeight = repmat({'fit'}, 1, 3); materialGrid.Padding = [10 10 10 10]; % 密度输入 app.DensityEditFieldLabel = uilabel(materialGrid); app.DensityEditFieldLabel.HorizontalAlignment = 'right'; app.DensityEditFieldLabel.Layout.Row = 1; app.DensityEditFieldLabel.Layout.Column = 1; app.DensityEditFieldLabel.Text = '密度 (kg/m³)'; app.DensityEditField = uieditfield(materialGrid, 'numeric'); app.DensityEditField.Limits = [1 20000]; app.DensityEditField.Value = 2700; app.DensityEditField.Layout.Row = 1; app.DensityEditField.Layout.Column = 2; app.DensityEditField.Tag = 'density'; % 泊松比输入 app.PoissonRatioEditFieldLabel = uilabel(materialGrid); app.PoissonRatioEditFieldLabel.HorizontalAlignment = 'right'; app.PoissonRatioEditFieldLabel.Layout.Row = 2; app.PoissonRatioEditFieldLabel.Layout.Column = 1; app.PoissonRatioEditFieldLabel.Text = '泊松比'; app.PoissonRatioEditField = uieditfield(materialGrid, 'numeric'); app.PoissonRatioEditField.Limits = [0.1 0.5]; app.PoissonRatioEditField.Value = 0.33; app.PoissonRatioEditField.Layout.Row = 2; app.PoissonRatioEditField.Layout.Column = 2; app.PoissonRatioEditField.Tag = 'poisson'; % 弹性模量输入 app.ElasticEditFieldLabel = uilabel(materialGrid); app.ElasticEditFieldLabel.HorizontalAlignment = 'right'; app.ElasticEditFieldLabel.Layout.Row = 3; app.ElasticEditFieldLabel.Layout.Column = 1; app.ElasticEditFieldLabel.Text = '弹性模量 (Pa)'; app.ElasticEditField = uieditfield(materialGrid, 'numeric'); app.ElasticEditField.Limits = [1e9 500e9]; app.ElasticEditField.Value = 70e9; app.ElasticEditField.Layout.Row = 3; app.ElasticEditField.Layout.Column = 2; app.ElasticEditField.Tag = 'elastic'; % 创建平板参数面板 app.PlatePanel = uipanel(leftGrid); app.PlatePanel.Layout.Row = 2; app.PlatePanel.Layout.Column = 1; app.PlatePanel.Title = '平板参数'; app.PlatePanel.BackgroundColor = [0.96 0.96 0.96]; app.PlatePanel.FontWeight = 'bold'; plateGrid = uigridlayout(app.PlatePanel, [2, 2]); plateGrid.ColumnWidth = {'1x', '1.5x'}; plateGrid.RowHeight = repmat({'fit'}, 1, 2); plateGrid.Padding = [10 10 10 10]; % 边长输入 app.LengthEditFieldLabel = uilabel(plateGrid); app.LengthEditFieldLabel.HorizontalAlignment = 'right'; app.LengthEditFieldLabel.Layout.Row = 1; app.LengthEditFieldLabel.Layout.Column = 1; app.LengthEditFieldLabel.Text = '边长 (m)'; app.LengthEditField = uieditfield(plateGrid, 'numeric'); app.LengthEditField.Limits = [0.01 1]; app.LengthEditField.Value = 0.15; app.LengthEditField.Layout.Row = 1; app.LengthEditField.Layout.Column = 2; app.LengthEditField.Tag = 'length'; % 厚度输入 app.ThicknessEditFieldLabel = uilabel(plateGrid); app.ThicknessEditFieldLabel.HorizontalAlignment = 'right'; app.ThicknessEditFieldLabel.Layout.Row = 2; app.ThicknessEditFieldLabel.Layout.Column = 1; app.ThicknessEditFieldLabel.Text = '厚度 (m)'; app.ThicknessEditField = uieditfield(plateGrid, 'numeric'); app.ThicknessEditField.Limits = [0.0001 0.1]; app.ThicknessEditField.Value = 0.001; app.ThicknessEditField.Layout.Row = 2; app.ThicknessEditField.Layout.Column = 2; app.ThicknessEditField.Tag = 'thickness'; % 创建振动参数面板 app.VibrationPanel = uipanel(leftGrid); app.VibrationPanel.Layout.Row = 3; app.VibrationPanel.Layout.Column = 1; app.VibrationPanel.Title = '振动参数'; app.VibrationPanel.BackgroundColor = [0.96 0.96 0.96]; app.VibrationPanel.FontWeight = 'bold'; vibrationGrid = uigridlayout(app.VibrationPanel, [2, 2]); vibrationGrid.ColumnWidth = {'1x', '1.5x'}; vibrationGrid.RowHeight = repmat({'fit'}, 1, 2); vibrationGrid.Padding = [10 10 10 10]; % 频率输入 app.FrequencyEditFieldLabel = uilabel(vibrationGrid); app.FrequencyEditFieldLabel.HorizontalAlignment = 'right'; app.FrequencyEditFieldLabel.Layout.Row = 1; app.FrequencyEditFieldLabel.Layout.Column = 1; app.FrequencyEditFieldLabel.Text = '频率 (Hz)'; app.FrequencyEditField = uieditfield(vibrationGrid, 'numeric'); app.FrequencyEditField.Limits = [1 5000]; app.FrequencyEditField.Value = 650; app.FrequencyEditField.Layout.Row = 1; app.FrequencyEditField.Layout.Column = 2; app.FrequencyEditField.Tag = 'frequency'; % 振幅输入 app.AmplitudeEditFieldLabel = uilabel(vibrationGrid); app.AmplitudeEditFieldLabel.HorizontalAlignment = 'right'; app.AmplitudeEditFieldLabel.Layout.Row = 2; app.AmplitudeEditFieldLabel.Layout.Column = 1; app.AmplitudeEditFieldLabel.Text = '振幅 (m)'; app.AmplitudeEditField = uieditfield(vibrationGrid, 'numeric'); app.AmplitudeEditField.Limits = [0.001 0.1]; app.AmplitudeEditField.Value = 0.01; app.AmplitudeEditField.Layout.Row = 2; app.AmplitudeEditField.Layout.Column = 2; app.AmplitudeEditField.Tag = 'amplitude'; % 创建仿真参数面板 app.SimulationPanel = uipanel(leftGrid); app.SimulationPanel.Layout.Row = 4; app.SimulationPanel.Layout.Column = 1; app.SimulationPanel.Title = '仿真参数'; app.SimulationPanel.BackgroundColor = [0.96 0.96 0.96]; app.SimulationPanel.FontWeight = 'bold'; simGrid = uigridlayout(app.SimulationPanel, [2, 2]); simGrid.ColumnWidth = {'1x', '1.5x'}; simGrid.RowHeight = repmat({'fit'}, 1, 2); simGrid.Padding = [10 10 10 10]; % 分辨率输入 app.ResolutionEditFieldLabel = uilabel(simGrid); app.ResolutionEditFieldLabel.HorizontalAlignment = 'right'; app.ResolutionEditFieldLabel.Layout.Row = 1; app.ResolutionEditFieldLabel.Layout.Column = 1; app.ResolutionEditFieldLabel.Text = '网格分辨率'; app.ResolutionEditField = uieditfield(simGrid, 'numeric'); app.ResolutionEditField.Limits = [4 32]; app.ResolutionEditField.RoundFractionalValues = 'on'; app.ResolutionEditField.Value = 16; app.ResolutionEditField.Layout.Row = 1; app.ResolutionEditField.Layout.Column = 2; app.ResolutionEditField.Tag = 'resolution'; % 仿真时间输入 app.SimTimeEditFieldLabel = uilabel(simGrid); app.SimTimeEditFieldLabel.HorizontalAlignment = 'right'; app.SimTimeEditFieldLabel.Layout.Row = 2; app.SimTimeEditFieldLabel.Layout.Column = 1; app.SimTimeEditFieldLabel.Text = '仿真时间 (s)'; app.SimTimeEditField = uieditfield(simGrid, 'numeric'); app.SimTimeEditField.Limits = [0.01 1]; app.SimTimeEditField.Value = 0.03; app.SimTimeEditField.Layout.Row = 2; app.SimTimeEditField.Layout.Column = 2; app.SimTimeEditField.Tag = 'simtime'; % 创建控制按钮面板 app.ControlPanel = uipanel(leftGrid); app.ControlPanel.Layout.Row = 5; app.ControlPanel.Layout.Column = 1; app.ControlPanel.BackgroundColor = [0.96 0.96 0.96]; app.ControlPanel.FontWeight = 'bold'; controlGrid = uigridlayout(app.ControlPanel, [1, 3]); controlGrid.ColumnWidth = {'1x', '1x', '1x'}; controlGrid.RowHeight = {'fit'}; controlGrid.Padding = [10 5 10 10]; % 创建控制按钮 app.RunButton = uibutton(controlGrid, 'push'); app.RunButton.ButtonPushedFcn = createCallbackFcn(app, @RunButtonPushed, true); app.RunButton.Layout.Row = 1; app.RunButton.Layout.Column = 1; app.RunButton.Text = '开始仿真'; app.RunButton.BackgroundColor = [0.47 0.67 0.19]; app.RunButton.FontWeight = 'bold'; app.StopButton = uibutton(controlGrid, 'push'); app.StopButton.ButtonPushedFcn = createCallbackFcn(app, @StopButtonPushed, true); app.StopButton.Layout.Row = 1; app.StopButton.Layout.Column = 2; app.StopButton.Text = '停止仿真'; app.RunButton.BackgroundColor = [0.47 0.67 0.19]; app.StopButton.BackgroundColor = [0.85 0.33 0.10]; app.StopButton.FontWeight = 'bold'; app.ResetButton = uibutton(controlGrid, 'push'); app.ResetButton.ButtonPushedFcn = createCallbackFcn(app, @ResetButtonPushed, true); app.ResetButton.Layout.Row = 1; app.ResetButton.Layout.Column = 3; app.ResetButton.Text = '重置参数'; app.ResetButton.FontWeight = 'bold'; % 创建右侧面板 app.RightPanel = uipanel(app.GridLayout); app.RightPanel.Layout.Row = 1; app.RightPanel.Layout.Column = 2; app.RightPanel.Title = '克拉尼图形可视化'; app.RightPanel.FontWeight = 'bold'; % 创建坐标轴 app.UIAxes = uiaxes(app.RightPanel); app.UIAxes.Position = [50 100 700 550]; title(app.UIAxes, '克拉尼图形') xlabel(app.UIAxes, 'X (m)') ylabel(app.UIAxes, 'Y (m)') colormap(app.UIAxes, 'jet'); colorbar(app.UIAxes); app.UIAxes.FontSize = 12; app.UIAxes.TitleFontSizeMultiplier = 1.2; % 创建显示模式下拉菜单 app.ModeDropDownLabel = uilabel(app.RightPanel); app.ModeDropDownLabel.HorizontalAlignment = 'right'; app.ModeDropDownLabel.Position = [50 70 100 22]; app.ModeDropDownLabel.Text = '显示模式:'; app.ModeDropDownLabel.FontWeight = 'bold'; app.ModeDropDown = uidropdown(app.RightPanel); app.ModeDropDown.Items = {'动态波动', '振幅分布', '节点线图'}; app.ModeDropDown.ValueChangedFcn = createCallbackFcn(app, @ModeDropDownValueChanged, true); app.ModeDropDown.Position = [160 70 150 22]; app.ModeDropDown.Value = '振幅分布'; app.ModeDropDown.FontWeight = 'bold'; % 状态标签 app.StatusLabel = uilabel(app.RightPanel); app.StatusLabel.Position = [50 40 300 22]; app.StatusLabel.Text = '就绪'; app.StatusLabel.FontSize = 14; app.StatusLabel.FontWeight = 'bold'; app.StatusLabel.FontColor = [0 0.5 0]; % 进度条 app.ProgressBar = uilabel(app.RightPanel); app.ProgressBar.Position = [400 40 300 22]; app.ProgressBar.Text = ''; app.ProgressBar.FontSize = 12; app.ProgressBar.FontWeight = 'bold'; % 显示主窗口 app.UIFigure.Visible = 'on'; end % 运行按钮回调 function RunButtonPushed(app, ~) if app.Running return; end % 验证参数 if ~app.validateParameters() return; end app.Running = true; app.StopRequested = false; app.StatusLabel.Text = '仿真运行中...'; app.StatusLabel.FontColor = [0 0 1]; app.ProgressBar.Text = '初始化... 0%'; drawnow; try % 获取用户输入参数 L = app.LengthEditField.Value; h = app.ThicknessEditField.Value; mu = app.PoissonRatioEditField.Value; rho = app.DensityEditField.Value; E = app.ElasticEditField.Value; Amp = app.AmplitudeEditField.Value; Freq = app.FrequencyEditField.Value; N = app.ResolutionEditField.Value; t_end = app.SimTimeEditField.Value; % 计算弯曲刚度 D = E*h^3/(12*(1-mu^2)); % 构建网格 dt = 1e-6; % 时间步长 dx = L/N; % 网格大小 x = dx*(0:N); [X,Y] = meshgrid(x,x); % 初始化位移 [Sq,Bq] = app.Equation_Sq0(N,mu,-Amp); % 调用类方法 U0 = Sq\Bq; U1 = U0; U2 = U1; % 初始化存储 U_Out1 = zeros(N+1,N+1); U_Out2 = zeros(N+5,N+5); U_Save = zeros((N+1)^2, 200); t_Save = 1; % 准备绘图 cla(app.UIAxes); hold(app.UIAxes, 'on'); axis(app.UIAxes, 'equal'); % 根据显示模式选择绘图方式 displayMode = app.ModeDropDown.Value; % 计算动态方程 t_start = 0; jishu = 1; totalSteps = round((t_end-t_start)/dt); progressStep = round(totalSteps/10); for t_k = t_start:dt:t_end if app.StopRequested break; end % 更新进度 if mod(jishu, progressStep) == 0 progress = round(jishu/totalSteps * 100); app.ProgressBar.Text = sprintf('计算中... %d%%', progress); drawnow; end % 0点处的运动位置 u0 = Amp*cos(2*pi*Freq*t_k+pi); L_Sq = N+5; % 实际计算时网格的尺寸 if jishu == 1 % 第一步计算 [Sq,Bq] = app.Equation_Sq0(N,mu,u0); for k = 1:L_Sq^2 [r_k,c_k] = ind2sub([L_Sq,L_Sq],k); if (r_k>=3 && r_k<=L_Sq-2) && (c_k>=3 && c_k<=L_Sq-2) Sq(k,k) = 20+rho*h*dx^4/D/dt^2; Sq(k,[k+1,k-1,k+L_Sq,k-L_Sq]) = -8; Sq(k,[k+L_Sq+1,k+L_Sq-1,k-L_Sq+1,k-L_Sq-1]) = 2; Sq(k,[k+2,k-2,k-2*L_Sq,k+2*L_Sq]) = 1; Fd = -100*sign(U2(k)-U1(k))*(U2(k)-U1(k))^2/dt^2; Bq(k) = dx^4/D*(rho*h/dt^2*(2*U2(k)-U1(k))+Fd); end end Indx_Center = sub2ind([L_Sq,L_Sq],3,3); Sq(Indx_Center,:) = 0; Sq(Indx_Center,Indx_Center) = 1; Bq(Indx_Center) = u0; else for k = 1:L_Sq^2 [r_k,c_k] = ind2sub([L_Sq,L_Sq],k); if (r_k>=3 && r_k<=L_Sq-2) && (c_k>=3 && c_k<=L_Sq-2) Fd = -100*sign(U2(k)-U1(k))*(U2(k)-U1(k))^2/dt^2; Bq(k) = dx^4/D*(rho*h/dt^2*(2*U2(k)-U1(k))+Fd); end end Bq(1+2+2*L_Sq) = u0; end U3 = Sq\Bq; U1 = U2; U2 = U3; % 储存,用作输出 U_Out2(:) = U3(:); U_Out = U_Out2(3:end-2,3:end-2); % 每100步更新一次图形 if mod(jishu,100) == 1 switch displayMode case '动态波动' surf(app.UIAxes, X, Y, U_Out); shading(app.UIAxes, 'interp'); zlim(app.UIAxes, [-0.2 0.2]); title(app.UIAxes, '平板动态波动'); view(app.UIAxes, 3); case '振幅分布' pcolor(app.UIAxes, X, Y, U_Out); shading(app.UIAxes, 'interp'); title(app.UIAxes, '振幅分布'); colorbar(app.UIAxes); view(app.UIAxes, 2); case '节点线图' contour(app.UIAxes, X, Y, U_Out, 10, 'LineWidth', 1.5); title(app.UIAxes, '节点线图'); colorbar(app.UIAxes); view(app.UIAxes, 2); end drawnow; end jishu = jishu+1; % 记最后200个数据储存 if jishu+50*200 >= totalSteps if mod(jishu,50) == 1 U_Save(:,t_Save) = U_Out(:); t_Save = t_Save+1; end end end % 保存结果用于后续分析 app.LastResult.X = X; app.LastResult.Y = Y; app.LastResult.U_Save = U_Save; app.LastResult.dx = dx; app.LastResult.N = N; % 计算振幅分布 U_Out_A = U_Out; U_Out_A(:) = max(U_Save,[],2)-min(U_Save,[],2); U_Out_A2 = [fliplr(U_Out_A(:,2:end)), U_Out_A]; U_Out_A3 = [flipud(U_Out_A2(2:end,:)); U_Out_A2]; app.LastResult.U_Amplitude = U_Out_A3; app.StatusLabel.Text = '仿真完成!'; app.StatusLabel.FontColor = [0 0.5 0]; app.ProgressBar.Text = ''; catch ME app.StatusLabel.Text = ['错误: ' ME.message]; app.StatusLabel.FontColor = [1 0 0]; app.ProgressBar.Text = ''; disp(ME.getReport()); end app.Running = false; end % 参数验证 function valid = validateParameters(app) valid = true; % 检查网格分辨率是否为偶数 if mod(app.ResolutionEditField.Value, 2) ~= 0 app.StatusLabel.Text = '错误: 网格分辨率必须是偶数'; app.StatusLabel.FontColor = [1 0 0]; valid = false; return; end % 检查时间步长是否合理 if app.SimTimeEditField.Value < 0.01 app.StatusLabel.Text = '错误: 仿真时间必须至少0.01秒'; app.StatusLabel.FontColor = [1 0 0]; valid = false; return; end % 检查频率是否在合理范围内 if app.FrequencyEditField.Value < 1 || app.FrequencyEditField.Value > 5000 app.StatusLabel.Text = '错误: 频率必须在1-5000Hz范围内'; app.StatusLabel.FontColor = [1 0 0]; valid = false; return; end end % 停止按钮回调 function StopButtonPushed(app, ~) app.StopRequested = true; app.StatusLabel.Text = '仿真已停止'; app.StatusLabel.FontColor = [0.5 0.5 0.5]; app.ProgressBar.Text = ''; end % 重置按钮回调 function ResetButtonPushed(app, ~) app.LengthEditField.Value = 0.15; app.ThicknessEditField.Value = 0.001; app.PoissonRatioEditField.Value = 0.33; app.DensityEditField.Value = 2700; app.ElasticEditField.Value = 70e9; app.FrequencyEditField.Value = 650; app.AmplitudeEditField.Value = 0.01; app.ResolutionEditField.Value = 16; app.SimTimeEditField.Value = 0.03; cla(app.UIAxes); app.StatusLabel.Text = '参数已重置'; app.StatusLabel.FontColor = [0 0.5 0]; app.ProgressBar.Text = ''; end % 显示模式改变回调 function ModeDropDownValueChanged(app, ~) if ~isempty(app.LastResult) && ~isempty(app.LastResult.U_Amplitude) displayMode = app.ModeDropDown.Value; cla(app.UIAxes); hold(app.UIAxes, 'on'); axis(app.UIAxes, 'equal'); x = app.LastResult.dx*(-app.LastResult.N:app.LastResult.N); [X3,Y3] = meshgrid(x,x); switch displayMode case '动态波动' title(app.UIAxes, '动态波动 - 请重新运行仿真'); app.StatusLabel.Text = '动态波动模式需要实时仿真'; app.StatusLabel.FontColor = [0 0 1]; case '振幅分布' surf(app.UIAxes, X3, Y3, app.LastResult.U_Amplitude); shading(app.UIAxes, 'interp'); title(app.UIAxes, '振幅分布'); colorbar(app.UIAxes); view(app.UIAxes, 2); app.StatusLabel.Text = '显示振幅分布'; app.StatusLabel.FontColor = [0 0.5 0]; case '节点线图' contour(app.UIAxes, X3, Y3, app.LastResult.U_Amplitude, 10, 'LineWidth', 1.5); title(app.UIAxes, '节点线图'); colorbar(app.UIAxes); view(app.UIAxes, 2); app.StatusLabel.Text = '显示节点线图'; app.StatusLabel.FontColor = [0 0.5 0]; end end end % 辅助函数Equation_Sq0(作为类方法) function [Sq,Bq] = Equation_Sq0(app, N, mu, u0) % 外拓展两圈后平板网格的索引 L_Sq = N+5; % 定义边界点类型 Point_Corner0 = [L_Sq,L_Sq; L_Sq-1,L_Sq; L_Sq,L_Sq-1]; Point_CornerC = [L_Sq-1,L_Sq-2; L_Sq-2,L_Sq-1]; Point_Out1 = [(L_Sq-1)*ones(L_Sq-5,1),(3:L_Sq-3)'; (3:L_Sq-3)',(L_Sq-1)*ones(L_Sq-5,1)]; Point_Corner = [L_Sq-1,L_Sq-1]; Point_Out2 = [L_Sq*ones(L_Sq-4,1),(3:L_Sq-2)'; (3:L_Sq-2)',L_Sq*ones(L_Sq-4,1)]; Point_Mirror1 = [2*ones(L_Sq-2,1),(3:L_Sq)'; (3:L_Sq)',2*ones(L_Sq-2,1)]; Point_Mirror2 = [1*ones(L_Sq-2,1),(3:L_Sq)'; (3:L_Sq)',1*ones(L_Sq-2,1)]; Point_MirrorC = [1,1;1,2;2,1;2,2]; % 初始化矩阵 Sq = zeros(L_Sq^2); Bq = zeros(L_Sq^2,1); for k = 1:L_Sq^2 [r_k,c_k] = ind2sub([L_Sq,L_Sq],k); % 四周边界点处理 if app.IsRowInRowList(Point_Corner0, [r_k,c_k]) Sq(k,k) = 1; Bq(k) = 0; % 自由角垂直外边界 elseif app.IsRowInRowList(Point_CornerC, [r_k,c_k]) if r_k == L_Sq-1 Sq(k,k-2:k) = [1,-2,1]; elseif c_k == L_Sq-1 Sq(k,[k-2*L_Sq,k-L_Sq,k]) = [1,-2,1]; end Bq(k) = 0; % 第一层边界点 elseif app.IsRowInRowList(Point_Out1, [r_k,c_k]) if r_k == 2 Sq(k,[k+1-L_Sq,k+1,k+1+L_Sq]) = [-mu,2+2*mu,-mu]; Sq(k,k) = -1; Sq(k,k+2) = -1; elseif r_k == L_Sq-1 Sq(k,[k-1-L_Sq,k-1,k-1+L_Sq]) = [-mu,2+2*mu,-mu]; Sq(k,k) = -1; Sq(k,k-2) = -1; elseif c_k == 2 Sq(k,[k,k+L_Sq,k+2*L_Sq]) = [-1,2+2*mu,-1]; Sq(k,k+L_Sq-1) = -mu; Sq(k,k+L_Sq+1) = -mu; elseif c_k == L_Sq-1 Sq(k,[k,k-L_Sq,k-2*L_Sq]) = [-1,2+2*mu,-1]; Sq(k,k-L_Sq-1) = -mu; Sq(k,k-L_Sq+1) = -mu; end Bq(k) = 0; % 自由角对角线外边界 elseif app.IsRowInRowList(Point_Corner, [r_k,c_k]) if r_k == L_Sq-1 && c_k == L_Sq-1 Sq(k,[k,k-2*L_Sq-2]) = [1,1]; Sq(k,[k-2,k-2*L_Sq]) = [-1,-1]; end Bq(k) = 0; % 第二层边界点 elseif app.IsRowInRowList(Point_Out2, [r_k,c_k]) if r_k == 1 Sq(k,k) = 1; Sq(k,[k+1-L_Sq,k+1,k+1+L_Sq]) = [2-mu,2*mu-6,2-mu]; Sq(k,[k+3-L_Sq,k+3,k+3+L_Sq]) = [mu-2,-2*mu+6,mu-2]; Sq(k,k+4) = -1; end Bq(k) = 0; % 正常平板上的点 elseif (r_k>=3 && r_k<=L_Sq-2) && (c_k>=3 && c_k<=L_Sq-2) Sq(k,k) = 20; Sq(k,[k+1,k-1,k+L_Sq,k-L_Sq]) = -8; Sq(k,[k+L_Sq+1,k+L_Sq-1,k-L_Sq+1,k-L_Sq-1]) = 2; Sq(k,[k+2,k-2,k-2*L_Sq,k+2*L_Sq]) = 1; Bq(k) = 0; % 对称边界处理 elseif app.IsRowInRowList(Point_Mirror1, [r_k,c_k]) if r_k == 2 Sq(k,k) = 1; Sq(k,k+2) = -1; elseif c_k == 2 Sq(k,k) = 1; Sq(k,k+2*L_Sq) = -1; end Bq(k) = 0; elseif app.IsRowInRowList(Point_Mirror2, [r_k,c_k]) if r_k == 1 Sq(k,k) = 1; Sq(k,k+4) = -1; elseif c_k == 1 Sq(k,k) = 1; Sq(k,k+4*L_Sq) = -1; end Bq(k) = 0; elseif app.IsRowInRowList(Point_MirrorC, [r_k,c_k]) if r_k == 1 && c_k == 1 Sq(k,k) = 1; Sq(k,k+4+4*L_Sq) = -1; end Bq(k) = 0; end end % 中心点约束 Indx_Center = sub2ind([L_Sq,L_Sq],3,3); Sq(Indx_Center,:) = 0; Sq(Indx_Center,Indx_Center) = 1; Bq(Indx_Center) = u0; end % 辅助函数IsRowInRowList(作为类方法) function TF = IsRowInRowList(~, List, Point) TF1 = (List(:,1) == Point(1)); TF = any(List(TF1,2) == Point(2)); end end % 应用初始化和启动 methods (Access = public) % 构造函数 function app = ChladniLab % 创建UI组件 createComponents(app) % 注册应用 registerApp(app, app.UIFigure) if nargout == 0 clear app end end % 运行代码 function run(app) app.UIFigure.Visible = 'on'; end end % 组件销毁 methods (Access = public) function delete(app) delete(app.UIFigure) end end end
最新发布
07-27
根据第一段代码,优化第二段代码,解决“开始TDM系统仿真… 信号数量: 3, 总时隙数: 50, 策略: priority, 编码: PCM, 调制: 16QAM 使用外部提供的原始信号… 编码信号 (PCM)… 信号1: 编码后长度=8000, 填充位=0 信号2: 编码后长度=8000, 填充位=0 信号3: 编码后长度=8000, 填充位=0 调制信号… 分配时隙… 时隙分配结果: 信号 1 (正弦波 (50Hz), 无调制): 17 个时隙 (优先级: 0.33, 调制: BPSK) 信号 2 (方波 (50Hz), 无调制): 17 个时隙 (优先级: 0.33, 调制: QPSK) 信号 3 (随机噪声, 无调制): 16 个时隙 (优先级: 0.33, 调制: 16QAM) TDM复用 (包含帧头)… 仿真过程中发生错误: 要串联的数组的维度不一致。”的问题。第一段代码:classdef TDMApp8888 < matlab.apps.AppBase properties (Access = public) UIFigure matlab.ui.Figure % 左侧控制面板 ControlPanel matlab.ui.container.Panel SignalConfigPanel matlab.ui.container.Panel NumSignalsEditField matlab.ui.control.NumericEditField NumSignalsLabel matlab.ui.control.Label SignalTypeDropDown matlab.ui.control.DropDown SignalTypeLabel matlab.ui.control.Label FrequencyEditField matlab.ui.control.NumericEditField FrequencyLabel matlab.ui.control.Label AddSignalButton matlab.ui.control.Button RemoveSignalButton matlab.ui.control.Button SignalsListBox matlab.ui.control.ListBox SignalsListLabel matlab.ui.control.Label % 新增载波频率控件 CarrierFrequencyLabel matlab.ui.control.Label CarrierFrequencyEditField matlab.ui.control.NumericEditField StrategyPanel matlab.ui.container.Panel FixedRadioButton matlab.ui.control.RadioButton PriorityRadioButton matlab.ui.control.RadioButton StrategyButtonGroup matlab.ui.container.ButtonGroup TotalSlotsEditField matlab.ui.control.NumericEditField TotalSlotsLabel matlab.ui.control.Label % 编码配置控件 EncodingPanel matlab.ui.container.Panel EncodingTypeDropDown matlab.ui.control.DropDown EncodingTypeLabel matlab.ui.control.Label QuantBitsEditField matlab.ui.control.NumericEditField QuantBitsLabel matlab.ui.control.Label StepSizeEditField matlab.ui.control.NumericEditField StepSizeLabel matlab.ui.control.Label % 调制配置控件 ModulationPanel matlab.ui.container.Panel ModulationTypeDropDown matlab.ui.control.DropDown ModulationTypeLabel matlab.ui.control.Label % 帧配置控件 FrameConfigPanel matlab.ui.container.Panel FrameHeaderEditField matlab.ui.control.EditField FrameHeaderLabel matlab.ui.control.Label CRCCheckBox matlab.ui.control.CheckBox % 右侧控制面板 SimulationPanel matlab.ui.container.Panel RunSimulationButton matlab.ui.control.Button RunFeedbackButton matlab.ui.control.Button RunAnalysisButton matlab.ui.control.Button SNREditField matlab.ui.control.NumericEditField SNRLabel matlab.ui.control.Label IterationsEditField matlab.ui.control.NumericEditField IterationsLabel matlab.ui.control.Label DurationEditField matlab.ui.control.NumericEditField DurationLabel matlab.ui.control.Label SamplingRateEditField matlab.ui.control.NumericEditField SamplingRateLabel matlab.ui.control.Label StatusLabel matlab.ui.control.Label ProgressBar matlab.ui.control.Lamp % 结果显示区域 ResultsTabGroup matlab.ui.container.TabGroup SignalsTab matlab.ui.container.Tab OriginalAxes matlab.ui.control.UIAxes TDMAxes matlab.ui.control.UIAxes DemuxAxes matlab.ui.control.UIAxes SyncedAxes matlab.ui.control.UIAxes PerformanceTab matlab.ui.container.Tab BERAxes matlab.ui.control.UIAxes ParametersTab matlab.ui.container.Tab ParametersTextArea matlab.ui.control.TextArea end properties (Access = private) signals % 存储信号配置的cell数组 params % 系统参数结构体 tdmSystem % TDMSystem实例 controller % TDMFeedbackController实例 analyzer % TDMPerformanceAnalyzer实例 end methods (Access = private) function updateParams(app) % 更新系统参数 app.params = struct(); % 确保所有UI组件都存在且有效 try app.params.fs = app.SamplingRateEditField.Value; app.params.duration = app.DurationEditField.Value; app.params.numSignals = numel(app.signals); app.params.snrDb = app.SNREditField.Value; app.params.iterations = app.IterationsEditField.Value; app.params.totalSlots = app.TotalSlotsEditField.Value; % 编码参数 if isvalid(app.EncodingTypeDropDown) app.params.encodingType = app.EncodingTypeDropDown.Value; else app.params.encodingType = 'PCM'; % 默认值 end app.params.quantBits = app.QuantBitsEditField.Value; app.params.stepSize = app.StepSizeEditField.Value; % 调制参数 if isvalid(app.ModulationTypeDropDown) app.params.modulationType = app.ModulationTypeDropDown.Value; else app.params.modulationType = 'BPSK'; % 默认值 end % 帧配置 if isvalid(app.FrameHeaderEditField) app.params.frameHeader = app.FrameHeaderEditField.Value; else app.params.frameHeader = 'A5A5'; % 默认值 end if isvalid(app.CRCCheckBox) app.params.useCRC = app.CRCCheckBox.Value; else app.params.useCRC = true; % 默认值 end % 时隙分配策略 if isvalid(app.FixedRadioButton) && isvalid(app.PriorityRadioButton) if app.FixedRadioButton.Value app.params.strategy = 'fixed'; else app.params.strategy = 'priority'; end else app.params.strategy = 'priority'; % 默认值 end % 设置信号调制方式和时钟漂移 app.params.signalModulations = cell(1, app.params.numSignals); app.params.clockDrift = zeros(1, app.params.numSignals); for i = 1:app.params.numSignals if i <= numel(app.signals) app.params.signalModulations{i} = app.signals{i}.modulation; else app.params.signalModulations{i} = 'BPSK'; % 默认值 end % 设置时钟漂移 (确保长度与信号数量匹配) if i == 1 app.params.clockDrift(i) = 0.001; elseif i == 2 app.params.clockDrift(i) = 0.002; else app.params.clockDrift(i) = -0.001; end end catch ME % 错误处理:记录错误并恢复默认值 disp('更新参数时出错:'); disp(ME.message); app.params = struct('fs', 1000, 'duration', 1, 'numSignals', 0); end end function generateSignals(app) % 生成信号数据 (使用linspace确保精确采样点) if isempty(app.params) || ~isfield(app.params, 'fs') || ~isfield(app.params, 'duration') return; % 参数无效,跳过 end t = linspace(0, app.params.duration, app.params.fs * app.params.duration); app.tdmSystem.originalSignals = zeros(app.params.numSignals, length(t)); app.tdmSystem.signalInfo = cell(app.params.numSignals, 1); for i = 1:app.params.numSignals if i <= numel(app.signals) sigConfig = app.signals{i}; else % 默认值包含载波频率 sigConfig = struct('type', '正弦波', 'frequency', 50, ... 'modulation', 'BPSK', 'carrierFrequency', 1000); end baseSignal = []; % 存储基带信号 switch sigConfig.type case '正弦波' freq = sigConfig.frequency; baseSignal = sin(2*pi*freq*t); baseInfo = sprintf('正弦波 (%dHz)', freq); case '方波' freq = sigConfig.frequency; baseSignal = square(2*pi*freq*t); baseInfo = sprintf('方波 (%dHz)', freq); case '随机噪声' baseSignal = randn(1, length(t)); baseInfo = '随机噪声'; case '锯齿波' freq = sigConfig.frequency; baseSignal = sawtooth(2*pi*freq*t); baseInfo = sprintf('锯齿波 (%dHz)', freq); case '脉冲信号' freq = sigConfig.frequency; duty = 0.3; % 占空比 pulseTrain = pulstran(t, 0:1/freq:app.params.duration, ... 'rectpuls', duty/freq); % 确保长度匹配 if length(pulseTrain) > length(t) baseSignal = pulseTrain(1:length(t)); else baseSignal = zeros(1, length(t)); baseSignal(1:length(pulseTrain)) = pulseTrain; end baseInfo = sprintf('脉冲信号 (%dHz)', freq); end % ========== 应用载波调制 ========== carrierFreq = sigConfig.carrierFrequency; switch sigConfig.modulation case 'AM' % 幅度调制: (1 + m(t)) * cos(2πf_c t) modulatedSignal = (1 + 0.5*baseSignal) .* cos(2*pi*carrierFreq*t); modInfo = sprintf('AM调制 (%dHz载波)', carrierFreq); case 'FM' % 频率调制: cos(2πf_c t + 2πΔf ∫m(t)dt) kf = 0.1; % 调制指数 integral_m = cumsum(baseSignal) / app.params.fs; modulatedSignal = cos(2*pi*carrierFreq*t + 2*pi*kf*integral_m); modInfo = sprintf('FM调制 (%dHz载波)', carrierFreq); case 'PM' % 相位调制: cos(2πf_c t + k_p m(t)) kp = 1; % 相位偏移常数 modulatedSignal = cos(2*pi*carrierFreq*t + kp*baseSignal); modInfo = sprintf('PM调制 (%dHz载波)', carrierFreq); otherwise % 无调制或未知调制类型 modulatedSignal = baseSignal; modInfo = '无调制'; end app.tdmSystem.originalSignals(i, :) = modulatedSignal; app.tdmSystem.signalInfo{i} = [baseInfo ', ' modInfo]; end % 设置编码参数 if isfield(app.params, 'encodingType') && isfield(app.params, 'quantBits') && isfield(app.params, 'stepSize') app.tdmSystem.encodingParams = struct(... 'type', app.params.encodingType, ... 'quantBits', app.params.quantBits, ... 'stepSize', app.params.stepSize); else app.tdmSystem.encodingParams = struct('type', 'PCM', 'quantBits', 8, 'stepSize', 0.05); % 默认值 end % 设置调制参数 if isfield(app.params, 'modulationType') && isfield(app.params, 'signalModulations') app.tdmSystem.modulationParams = struct(... 'type', app.params.modulationType, ... 'signalModulations', {app.params.signalModulations}); else app.tdmSystem.modulationParams = struct('type', 'BPSK', 'signalModulations', {{'BPSK', 'BPSK'}}); % 默认值 end % 设置帧配置 if isfield(app.params, 'frameHeader') && isfield(app.params, 'useCRC') app.tdmSystem.frameConfig = struct(... 'header', app.params.frameHeader, ... 'useCRC', app.params.useCRC); else app.tdmSystem.frameConfig = struct('header', 'A5A5', 'useCRC', true); % 默认值 end end function updateParametersDisplay(app) % 更新参数显示 try paramText = sprintf('系统参数:\n'); if isfield(app.params, 'fs') paramText = [paramText sprintf('采样频率: %d Hz\n', app.params.fs)]; end if isfield(app.params, 'duration') paramText = [paramText sprintf('信号持续时间: %.2f 秒\n', app.params.duration)]; end if isfield(app.params, 'numSignals') paramText = [paramText sprintf('信号源数量: %d\n', app.params.numSignals)]; end if isfield(app.params, 'snrDb') paramText = [paramText sprintf('信噪比: %d dB\n', app.params.snrDb)]; end if isfield(app.params, 'strategy') paramText = [paramText sprintf('时隙分配策略: %s\n', app.params.strategy)]; end if isfield(app.params, 'totalSlots') paramText = [paramText sprintf('总时隙数量: %d\n', app.params.totalSlots)]; end if isfield(app.params, 'iterations') paramText = [paramText sprintf('仿真迭代次数: %d\n', app.params.iterations)]; end % 编码参数 paramText = [paramText sprintf('\n编码配置:\n')]; if isfield(app.params, 'encodingType') paramText = [paramText sprintf(' 编码类型: %s\n', app.params.encodingType)]; end if isfield(app.params, 'quantBits') paramText = [paramText sprintf(' 量化位数: %d bits\n', app.params.quantBits)]; end if isfield(app.params, 'stepSize') paramText = [paramText sprintf(' 步长: %.4f\n', app.params.stepSize)]; end % 调制参数 paramText = [paramText sprintf('\n调制配置:\n')]; if isfield(app.params, 'modulationType') paramText = [paramText sprintf(' 系统调制类型: %s\n', app.params.modulationType)]; end % 帧配置 paramText = [paramText sprintf('\n帧配置:\n')]; if isfield(app.params, 'frameHeader') paramText = [paramText sprintf(' 帧头: %s\n', app.params.frameHeader)]; end if isfield(app.params, 'useCRC') paramText = [paramText sprintf(' CRC校验: %s\n', ifelse(app.params.useCRC, '启用', '禁用'))]; end % 信号信息 - 包含载波频率 paramText = [paramText sprintf('\n信号配置:\n')]; for i = 1:min(app.params.numSignals, numel(app.signals)) sig = app.signals{i}; paramText = [paramText sprintf('信号 %d: %s (基带频率: %d Hz, 调制: %s, 载波频率: %d Hz)\n', ... i, sig.type, sig.frequency, sig.modulation, sig.carrierFrequency)]; end app.ParametersTextArea.Value = paramText; catch ME disp('更新参数显示时出错:'); disp(ME.message); app.ParametersTextArea.Value = '系统参数显示错误'; end end function plotSignals(app) % 绘制原始信号 try t = linspace(0, app.params.duration, app.params.fs * app.params.duration); cla(app.OriginalAxes); hold(app.OriginalAxes, 'on'); colors = lines(app.params.numSignals); for i = 1:min(app.params.numSignals, size(app.tdmSystem.originalSignals, 1)) plot(app.OriginalAxes, t, app.tdmSystem.originalSignals(i, 1:length(t)), ... 'Color', colors(i, :), 'DisplayName', app.tdmSystem.signalInfo{i}); end hold(app.OriginalAxes, 'off'); legend(app.OriginalAxes, 'Location', 'best'); title(app.OriginalAxes, '原始信号'); xlabel(app.OriginalAxes, '时间 (s)'); ylabel(app.OriginalAxes, '幅度'); grid(app.OriginalAxes, 'on'); % 绘制TDM信号(支持复数信号) cla(app.TDMAxes); if ~isempty(app.tdmSystem.tdmSignal) && isfield(app.params, 'duration') t_tdm = linspace(0, app.params.duration, length(app.tdmSystem.tdmSignal)); plot(app.TDMAxes, t_tdm, real(app.tdmSystem.tdmSignal)); hold(app.TDMAxes, 'on'); plot(app.TDMAxes, t_tdm, imag(app.tdmSystem.tdmSignal)); hold(app.TDMAxes, 'off'); legend(app.TDMAxes, {'实部', '虚部'}, 'Location', 'best'); end title(app.TDMAxes, ['TDM复用信号 (' app.params.strategy '策略)']); xlabel(app.TDMAxes, '时间 (s)'); ylabel(app.TDMAxes, '幅度'); grid(app.TDMAxes, 'on'); % 绘制解复用信号 cla(app.DemuxAxes); hold(app.DemuxAxes, 'on'); for i = 1:min(app.params.numSignals, size(app.tdmSystem.demuxSignals, 1)) if size(app.tdmSystem.demuxSignals, 2) >= length(t) plot(app.DemuxAxes, t,app.tdmSystem.demuxSignals(i, 1:length(t)), ... 'Color', colors(i, :), 'DisplayName', ['信号 ' num2str(i)]); end end hold(app.DemuxAxes, 'off'); legend(app.DemuxAxes, 'Location', 'best'); title(app.DemuxAxes, '解复用信号'); xlabel(app.DemuxAxes, '时间 (s)'); ylabel(app.DemuxAxes, '幅度'); grid(app.DemuxAxes, 'on'); % 绘制同步后信号 cla(app.SyncedAxes); hold(app.SyncedAxes, 'on'); for i = 1:min(app.params.numSignals, size(app.tdmSystem.syncedSignals, 1)) if size(app.tdmSystem.syncedSignals, 2) >= length(t) plot(app.SyncedAxes, t, app.tdmSystem.syncedSignals(i, 1:length(t)), ... 'Color', colors(i, :), 'DisplayName', app.tdmSystem.signalInfo{i}); end end hold(app.SyncedAxes, 'off'); legend(app.SyncedAxes, 'Location', 'best'); title(app.SyncedAxes, '同步后信号'); xlabel(app.SyncedAxes, '时间 (s)'); ylabel(app.SyncedAxes, '幅度'); grid(app.SyncedAxes, 'on'); % 绘制误码率和信噪比 cla(app.BERAxes); if ~isempty(app.tdmSystem.performance) && isfield(app.tdmSystem.performance, 'ber') && isfield(app.tdmSystem.performance, 'snr') yyaxis(app.BERAxes, 'left'); bar(app.BERAxes, 1:app.params.numSignals, app.tdmSystem.performance.ber, 0.6, 'FaceColor', [0.2 0.6 0.8]); ylabel(app.BERAxes, '误码率 (BER)'); yyaxis(app.BERAxes, 'right'); plot(app.BERAxes, 1:app.params.numSignals, app.tdmSystem.performance.snr, 'o-', 'LineWidth', 2, 'MarkerSize', 8); ylabel(app.BERAxes, 'SNR (dB)'); title(app.BERAxes, '信号质量分析'); xlabel(app.BERAxes, '信号编号'); grid(app.BERAxes, 'on'); xticks(app.BERAxes, 1:app.params.numSignals); legend(app.BERAxes, {'BER', 'SNR'}, 'Location', 'best'); end catch ME disp('绘图时出错:'); disp(ME.message); end end end % Callbacks that handle component events methods (Access = private) % Code that executes after component creation function startupFcn(app) % 初始化参数 app.signals = {}; app.params = struct(); app.StatusLabel.Text = '准备就绪'; app.ProgressBar.Color = 'green'; % 设置默认参数 app.SamplingRateEditField.Value = 1000; app.DurationEditField.Value = 1; app.SNREditField.Value = 20; app.IterationsEditField.Value = 5; app.TotalSlotsEditField.Value = 50; app.NumSignalsEditField.Value = 0; app.PriorityRadioButton.Value = true; % 编码参数默认值 app.EncodingTypeDropDown.Value = 'PCM'; app.QuantBitsEditField.Value = 8; app.StepSizeEditField.Value = 0.05; % 调制参数默认值 app.ModulationTypeDropDown.Value = 'BPSK'; % 帧配置默认值 app.FrameHeaderEditField.Value = 'A5A5'; app.CRCCheckBox.Value = true; % 载波频率默认值 app.CarrierFrequencyEditField.Value = 1000; % 更新参数显示 updateParams(app); updateParametersDisplay(app); end % Button pushed function: AddSignalButton function AddSignalButtonPushed(app, ~) % 添加新信号(包含载波频率) try signalType = app.SignalTypeDropDown.Value; frequency = app.FrequencyEditField.Value; modulationType = app.ModulationTypeDropDown.Value; % 获取调制类型 carrierFrequency = app.CarrierFrequencyEditField.Value; % 获取载波频率 if frequency <= 0 uialert(app.UIFigure, '基带频率必须大于0', '无效参数'); return; end if carrierFrequency <= 0 uialert(app.UIFigure, '载波频率必须大于0', '无效参数'); return; end newSignal = struct(... 'type', signalType, ... 'frequency', frequency, ... 'modulation', modulationType, ... 'carrierFrequency', carrierFrequency); % 添加载波频率 app.signals{end+1} = newSignal; app.NumSignalsEditField.Value = numel(app.signals); % 更新信号列表(包含载波频率) signalList = cell(1, numel(app.signals)); for i = 1:numel(app.signals) sig = app.signals{i}; signalList{i} = sprintf('信号 %d: %s (%d Hz基带, %s调制, %d Hz载波)', ... i, sig.type, sig.frequency, sig.modulation, sig.carrierFrequency); end app.SignalsListBox.Items = signalList; % 更新参数 updateParams(app); updateParametersDisplay(app); app.StatusLabel.Text = sprintf('已添加信号: %s (%d Hz基带, %s调制, %d Hz载波)', ... signalType, frequency, modulationType, carrierFrequency); catch ME app.StatusLabel.Text = ['添加信号错误: ' ME.message]; app.ProgressBar.Color = 'red'; end end % Button pushed function: RemoveSignalButton function RemoveSignalButtonPushed(app, ~) % 移除选中的信号(包含载波频率) try selectedIdx = app.SignalsListBox.Value; if isempty(selectedIdx) || selectedIdx > numel(app.signals) uialert(app.UIFigure, '请选择要删除的信号', '无选择'); return; end % 移除信号 removedSig = app.signals{selectedIdx}; app.signals(selectedIdx) = []; % 更新信号列表(包含载波频率) app.NumSignalsEditField.Value = numel(app.signals); signalList = cell(1, numel(app.signals)); for i = 1:numel(app.signals) sig = app.signals{i}; signalList{i} = sprintf('信号 %d: %s (%d Hz基带, %s调制, %d Hz载波)', ... i, sig.type, sig.frequency, sig.modulation, sig.carrierFrequency); end app.SignalsListBox.Items = signalList; % 如果没有信号,清除选择 if isempty(app.signals) app.SignalsListBox.Value = []; else app.SignalsListBox.Value = min(selectedIdx, numel(app.signals)); end % 更新参数 updateParams(app); updateParametersDisplay(app); app.StatusLabel.Text = sprintf('已移除信号: %s (%d Hz基带, %s调制, %d Hz载波)', ... removedSig.type, removedSig.frequency, removedSig.modulation, removedSig.carrierFrequency); catch ME app.StatusLabel.Text = ['移除信号错误: ' ME.message]; app.ProgressBar.Color = 'red'; end end % Value changed function: NumSignalsEditField function NumSignalsEditFieldValueChanged(app, ~) % 信号数量变化时更新 try updateParams(app); updateParametersDisplay(app); catch ME app.StatusLabel.Text = ['更新信号数量错误: ' ME.message]; app.ProgressBar.Color = 'red'; end end % Value changed function: SamplingRateEditField function SamplingRateEditFieldValueChanged(app, ~) try updateParams(app); updateParametersDisplay(app); catch ME app.StatusLabel.Text = ['更新采样率错误: ' ME.message]; app.ProgressBar.Color = 'red'; end end % Value changed function: DurationEditField function DurationEditFieldValueChanged(app, ~) try updateParams(app); updateParametersDisplay(app); catch ME app.StatusLabel.Text = ['更新持续时间错误: ' ME.message]; app.ProgressBar.Color = 'red'; end end % Value changed function: SNREditField function SNREditFieldValueChanged(app, ~) try updateParams(app); updateParametersDisplay(app); catch ME app.StatusLabel.Text = ['更新信噪比错误: ' ME.message]; app.ProgressBar.Color = 'red'; end end % Value changed function: IterationsEditField function IterationsEditFieldValueChanged(app, ~) try updateParams(app); updateParametersDisplay(app); catch ME app.StatusLabel.Text = ['更新迭代次数错误: ' ME.message]; app.ProgressBar.Color = 'red'; end end % Value changed function: TotalSlotsEditField function TotalSlotsEditFieldValueChanged(app, ~) try updateParams(app); updateParametersDisplay(app); catch ME app.StatusLabel.Text = ['更新总时隙数错误: ' ME.message]; app.ProgressBar.Color = 'red'; end end % Selection changed function: StrategyButtonGroup function StrategyButtonGroupSelectionChanged(app, ~) try updateParams(app); updateParametersDisplay(app); catch ME app.StatusLabel.Text = ['更新策略错误: ' ME.message]; app.ProgressBar.Color = 'red'; end end % 编码参数变化回调 function EncodingTypeDropDownValueChanged(app, ~) try updateParams(app); updateParametersDisplay(app); catch ME app.StatusLabel.Text = ['更新编码类型错误: ' ME.message]; app.ProgressBar.Color = 'red'; end end function QuantBitsEditFieldValueChanged(app, ~) try updateParams(app); updateParametersDisplay(app); catch ME app.StatusLabel.Text = ['更新量化位数错误: ' ME.message]; app.ProgressBar.Color = 'red'; end end function StepSizeEditFieldValueChanged(app, ~) try updateParams(app); updateParametersDisplay(app); catch ME app.StatusLabel.Text = ['更新步长错误: ' ME.message]; app.ProgressBar.Color = 'red'; end end % 调制参数变化回调 function ModulationTypeDropDownValueChanged(app, ~) try updateParams(app); updateParametersDisplay(app); catch ME app.StatusLabel.Text = ['更新调制方式错误: ' ME.message]; app.ProgressBar.Color = 'red'; end end function FrameHeaderEditFieldValueChanged(app, ~) try updateParams(app); updateParametersDisplay(app); catch ME app.StatusLabel.Text = ['更新帧头错误: ' ME.message]; app.ProgressBar.Color = 'red'; end end function CRCCheckBoxValueChanged(app, ~) try updateParams(app); updateParametersDisplay(app); catch ME app.StatusLabel.Text = ['更新CRC设置错误: ' ME.message]; app.ProgressBar.Color = 'red'; end end % Button pushed function: RunSimulationButton function RunSimulationButtonPushed(app, ~) % 运行基础仿真 app.StatusLabel.Text = '运行基础仿真...'; app.ProgressBar.Color = 'yellow'; drawnow; try % 更新参数 updateParams(app); % 检查信号配置 if app.params.numSignals == 0 uialert(app.UIFigure, '请至少添加一个信号', '无信号'); app.ProgressBar.Color = 'red'; return; end % 创建TDM系统 app.tdmSystem = TDMSystem(app.params); % 生成信号 generateSignals(app); % 运行仿真 app.tdmSystem = app.tdmSystem.runSimulation(); % 显示结果 plotSignals(app); updateParametersDisplay(app); app.StatusLabel.Text = '基础仿真完成!'; app.ProgressBar.Color = 'green'; catch ME app.StatusLabel.Text = ['基础仿真错误: ' ME.message]; app.ProgressBar.Color = 'red'; uialert(app.UIFigure, ME.message, '仿真错误'); end end % Button pushed function: RunFeedbackButton function RunFeedbackButtonPushed(app, ~) % 运行反馈控制仿真 app.StatusLabel.Text = '运行反馈控制仿真...'; app.ProgressBar.Color = 'yellow'; drawnow; try % 更新参数 updateParams(app); % 检查信号配置 if app.params.numSignals == 0 uialert(app.UIFigure, '请至少添加一个信号', '无信号'); app.ProgressBar.Color = 'red'; return; end % 创建反馈控制器 app.controller = TDMFeedbackController(app.params); % 生成信号 generateSignals(app); % 将生成的信号复制到控制器 app.controller.originalSignals = app.tdmSystem.originalSignals; app.controller.signalInfo = app.tdmSystem.signalInfo; app.controller.encodingParams = app.tdmSystem.encodingParams; app.controller.modulationParams = app.tdmSystem.modulationParams; app.controller.frameConfig = app.tdmSystem.frameConfig; % 运行反馈仿真 app.controller = app.controller.runSimulation(); % 显示结果 app.tdmSystem = app.controller; % 用于显示基本结果 plotSignals(app); updateParametersDisplay(app); app.StatusLabel.Text = '反馈控制仿真完成!'; app.ProgressBar.Color = 'green'; catch ME app.StatusLabel.Text = ['反馈控制错误: ' ME.message]; app.ProgressBar.Color = 'red'; uialert(app.UIFigure, ME.message, '仿真错误'); end end % Button pushed function: RunAnalysisButton function RunAnalysisButtonPushed(app, ~) % 运行性能分析 app.StatusLabel.Text = '运行性能分析...'; app.ProgressBar.Color = 'yellow'; drawnow; try % 更新参数 updateParams(app); % 检查信号配置 if app.params.numSignals == 0 uialert(app.UIFigure, '请至少添加一个信号', '无信号'); app.ProgressBar.Color = 'red'; return; end % 创建性能分析器 app.analyzer = TDMPerformanceAnalyzer(app.params); % 生成信号 generateSignals(app); % 将生成的信号复制到分析器 app.analyzer.originalSignals = app.tdmSystem.originalSignals; app.analyzer.signalInfo = app.tdmSystem.signalInfo; app.analyzer.encodingParams = app.tdmSystem.encodingParams; app.analyzer.modulationParams = app.tdmSystem.modulationParams; app.analyzer.frameConfig = app.tdmSystem.frameConfig; % 运行性能分析 app.analyzer = app.analyzer.runPerformanceAnalysis(); % 显示结果 app.tdmSystem = app.analyzer; % 用于显示基本结果 plotSignals(app); updateParametersDisplay(app); app.StatusLabel.Text = '性能分析完成!'; app.ProgressBar.Color = 'green'; catch ME app.StatusLabel.Text = ['性能分析错误: ' ME.message]; app.ProgressBar.Color = 'red'; uialert(app.UIFigure, ME.message, '仿真错误'); end end end % App initialization and construction methods (Access = private) % Create UIFigure and components function createComponents(app) % 创建主窗口 app.UIFigure = uifigure; app.UIFigure.Position = [100 100 1400 900]; app.UIFigure.Name = 'TDM通信系统仿真'; app.UIFigure.Scrollable = 'on'; % 创建控制面板容器 app.ControlPanel = uipanel(app.UIFigure); app.ControlPanel.Title = '控制面板'; app.ControlPanel.Position = [20 20 450 850]; % ==== 信号配置面板 ==== app.SignalConfigPanel = uipanel(app.ControlPanel); app.SignalConfigPanel.Title = '信号配置'; app.SignalConfigPanel.Position = [20 585 410 240]; % 增加高度以容纳载波频率控件 % 信号数量控件 app.NumSignalsLabel = uilabel(app.SignalConfigPanel); app.NumSignalsLabel.Position = [20 190 80 22]; app.NumSignalsLabel.Text = '信号数量:'; app.NumSignalsEditField = uieditfield(app.SignalConfigPanel, 'numeric'); app.NumSignalsEditField.Position = [110 190 60 22]; app.NumSignalsEditField.Value = 0; app.NumSignalsEditField.ValueChangedFcn = createCallbackFcn(app, @NumSignalsEditFieldValueChanged, true); % 信号类型控件 app.SignalTypeLabel = uilabel(app.SignalConfigPanel); app.SignalTypeLabel.Position = [20 160 80 22]; app.SignalTypeLabel.Text = '信号类型:'; app.SignalTypeDropDown = uidropdown(app.SignalConfigPanel); app.SignalTypeDropDown.Position = [110 160 80 22]; app.SignalTypeDropDown.Items = {'正弦波', '方波', '随机噪声', '锯齿波', '脉冲信号'}; % 基带频率控件 app.FrequencyLabel = uilabel(app.SignalConfigPanel); app.FrequencyLabel.Position = [20 130 80 22]; app.FrequencyLabel.Text = '基带频率 (Hz):'; app.FrequencyEditField = uieditfield(app.SignalConfigPanel, 'numeric'); app.FrequencyEditField.Position = [110 130 60 22]; app.FrequencyEditField.Value = 50; % 载波频率控件 app.CarrierFrequencyLabel = uilabel(app.SignalConfigPanel); app.CarrierFrequencyLabel.Position = [210 130 100 22]; app.CarrierFrequencyLabel.Text = '载波频率 (Hz):'; app.CarrierFrequencyEditField = uieditfield(app.SignalConfigPanel, 'numeric'); app.CarrierFrequencyEditField.Position = [300 130 60 22]; app.CarrierFrequencyEditField.Value = 1000; % 默认值 % 添加/移除按钮 app.AddSignalButton = uibutton(app.SignalConfigPanel, 'push'); app.AddSignalButton.ButtonPushedFcn = createCallbackFcn(app, @AddSignalButtonPushed, true); app.AddSignalButton.Position = [210 160 80 22]; app.AddSignalButton.Text = '添加信号'; app.RemoveSignalButton = uibutton(app.SignalConfigPanel, 'push'); app.RemoveSignalButton.ButtonPushedFcn = createCallbackFcn(app, @RemoveSignalButtonPushed, true); app.RemoveSignalButton.Position = [300 160 80 22]; app.RemoveSignalButton.Text = '移除信号'; % 信号列表 app.SignalsListLabel = uilabel(app.SignalConfigPanel); app.SignalsListLabel.Position = [20 100 80 22]; app.SignalsListLabel.Text = '信号列表:'; app.SignalsListBox = uilistbox(app.SignalConfigPanel); app.SignalsListBox.Position = [20 5 370 90]; app.SignalsListBox.Items = {}; % ==== 策略配置面板 ==== app.StrategyPanel = uipanel(app.ControlPanel); app.StrategyPanel.Title = '时隙分配策略'; app.StrategyPanel.Position = [20 425 410 150]; % 策略按钮组 app.StrategyButtonGroup = uibuttongroup(app.StrategyPanel); app.StrategyButtonGroup.SelectionChangedFcn = createCallbackFcn(app, @StrategyButtonGroupSelectionChanged, true); app.StrategyButtonGroup.Position = [20 40 200 80]; app.StrategyButtonGroup.Title = '选择策略'; % 单选按钮 app.FixedRadioButton = uiradiobutton(app.StrategyButtonGroup); app.FixedRadioButton.Text = '固定分配'; app.FixedRadioButton.Position = [11 35 75 22]; app.PriorityRadioButton = uiradiobutton(app.StrategyButtonGroup); app.PriorityRadioButton.Text = '优先级分配'; app.PriorityRadioButton.Position = [11 10 100 22]; app.PriorityRadioButton.Value = true; % 总时隙数 app.TotalSlotsLabel = uilabel(app.StrategyPanel); app.TotalSlotsLabel.Position = [240 30 80 22]; app.TotalSlotsLabel.Text = '总时隙数:'; app.TotalSlotsEditField = uieditfield(app.StrategyPanel, 'numeric'); app.TotalSlotsEditField.ValueChangedFcn = createCallbackFcn(app, @TotalSlotsEditFieldValueChanged, true); app.TotalSlotsEditField.Position = [300 30 60 22]; app.TotalSlotsEditField.Value = 50; % ==== 编码配置面板 ==== app.EncodingPanel = uipanel(app.ControlPanel); app.EncodingPanel.Title = '编码配置'; app.EncodingPanel.Position = [20 300 410 120]; app.EncodingTypeLabel = uilabel(app.EncodingPanel); app.EncodingTypeLabel.Position = [20 75 80 22]; app.EncodingTypeLabel.Text = '编码类型:'; app.EncodingTypeDropDown = uidropdown(app.EncodingPanel); app.EncodingTypeDropDown.Position = [110 75 100 22]; app.EncodingTypeDropDown.Items = {'PCM', 'DPCM', 'DM'}; app.EncodingTypeDropDown.Value = 'PCM'; app.EncodingTypeDropDown.ValueChangedFcn = createCallbackFcn(app, @EncodingTypeDropDownValueChanged, true); app.QuantBitsLabel = uilabel(app.EncodingPanel); app.QuantBitsLabel.Position = [20 45 80 22]; app.QuantBitsLabel.Text = '量化位数:'; app.QuantBitsEditField = uieditfield(app.EncodingPanel, 'numeric'); app.QuantBitsEditField.Position = [110 45 60 22]; app.QuantBitsEditField.Value = 8; app.QuantBitsEditField.ValueChangedFcn = createCallbackFcn(app, @QuantBitsEditFieldValueChanged, true); app.StepSizeLabel = uilabel(app.EncodingPanel); app.StepSizeLabel.Position = [20 15 80 22]; app.StepSizeLabel.Text = '步长:'; app.StepSizeEditField = uieditfield(app.EncodingPanel, 'numeric'); app.StepSizeEditField.Position = [110 15 60 22]; app.StepSizeEditField.Value = 0.05; app.StepSizeEditField.ValueChangedFcn = createCallbackFcn(app, @StepSizeEditFieldValueChanged, true); % ==== 调制配置面板 ==== app.ModulationPanel = uipanel(app.ControlPanel); app.ModulationPanel.Title = '调制配置'; app.ModulationPanel.Position = [20 225 410 70]; app.ModulationTypeLabel = uilabel(app.ModulationPanel); app.ModulationTypeLabel.Position = [20 15 80 22]; app.ModulationTypeLabel.Text = '调制方式:'; app.ModulationTypeDropDown = uidropdown(app.ModulationPanel); app.ModulationTypeDropDown.Position = [110 15 100 22]; app.ModulationTypeDropDown.Items = {'None', 'BPSK', 'QPSK', '16QAM'}; app.ModulationTypeDropDown.Value = 'BPSK'; app.ModulationTypeDropDown.ValueChangedFcn = createCallbackFcn(app, @ModulationTypeDropDownValueChanged, true); % ==== 帧配置面板 ==== app.FrameConfigPanel = uipanel(app.ControlPanel); app.FrameConfigPanel.Title = '帧配置'; app.FrameConfigPanel.Position = [20 150 410 70]; app.FrameHeaderLabel = uilabel(app.FrameConfigPanel); app.FrameHeaderLabel.Position = [20 15 80 22]; app.FrameHeaderLabel.Text = '帧头:'; app.FrameHeaderEditField = uieditfield(app.FrameConfigPanel, 'text'); app.FrameHeaderEditField.Position = [110 15 100 22]; app.FrameHeaderEditField.Value = 'A5A5'; app.FrameHeaderEditField.ValueChangedFcn = createCallbackFcn(app, @FrameHeaderEditFieldValueChanged, true); app.CRCCheckBox = uicheckbox(app.FrameConfigPanel); app.CRCCheckBox.Text = '启用CRC校验'; app.CRCCheckBox.Position = [220 15 120 22]; app.CRCCheckBox.Value = true; app.CRCCheckBox.ValueChangedFcn = createCallbackFcn(app, @CRCCheckBoxValueChanged, true); % ==== 仿真控制面板 ==== app.SimulationPanel = uipanel(app.ControlPanel); app.SimulationPanel.Title = '仿真控制'; app.SimulationPanel.Position = [20 5 410 140]; % 参数输入 app.SamplingRateLabel = uilabel(app.SimulationPanel); app.SamplingRateLabel.Position = [20 95 80 22]; app.SamplingRateLabel.Text = '采样率 (Hz):'; app.SamplingRateEditField = uieditfield(app.SimulationPanel, 'numeric'); app.SamplingRateEditField.ValueChangedFcn = createCallbackFcn(app, @SamplingRateEditFieldValueChanged, true); app.SamplingRateEditField.Position = [110 95 60 22]; app.SamplingRateEditField.Value = 1000; app.DurationLabel = uilabel(app.SimulationPanel); app.DurationLabel.Position = [20 65 80 22]; app.DurationLabel.Text = '持续时间 (s):'; app.DurationEditField = uieditfield(app.SimulationPanel, 'numeric'); app.DurationEditField.ValueChangedFcn = createCallbackFcn(app, @DurationEditFieldValueChanged, true); app.DurationEditField.Position = [110 65 60 22]; app.DurationEditField.Value = 1; app.SNRLabel = uilabel(app.SimulationPanel); app.SNRLabel.Position = [20 35 80 22]; app.SNRLabel.Text = '信噪比 (dB):'; app.SNREditField = uieditfield(app.SimulationPanel, 'numeric'); app.SNREditField.ValueChangedFcn = createCallbackFcn(app, @SNREditFieldValueChanged, true); app.SNREditField.Position = [110 35 60 22]; app.SNREditField.Value = 20; app.IterationsLabel = uilabel(app.SimulationPanel); app.IterationsLabel.Position = [200 95 80 22]; app.IterationsLabel.Text = '迭代次数:'; app.IterationsEditField = uieditfield(app.SimulationPanel, 'numeric'); app.IterationsEditField.ValueChangedFcn = createCallbackFcn(app, @IterationsEditFieldValueChanged, true); app.IterationsEditField.Position = [290 95 60 22]; app.IterationsEditField.Value = 5; % 状态显示 app.StatusLabel = uilabel(app.SimulationPanel); app.StatusLabel.HorizontalAlignment = 'center'; app.StatusLabel.Position = [20 5 100 22]; app.StatusLabel.Text = '准备就绪'; app.ProgressBar = uilamp(app.SimulationPanel); app.ProgressBar.Position = [150 5 110 20]; app.ProgressBar.Color = [0.47 0.67 0.19]; % 仿真按钮 app.RunSimulationButton = uibutton(app.SimulationPanel, 'push'); app.RunSimulationButton.ButtonPushedFcn = createCallbackFcn(app, @RunSimulationButtonPushed, true); app.RunSimulationButton.Position = [200 20 80 30]; app.RunSimulationButton.Text = '基础仿真'; app.RunFeedbackButton = uibutton(app.SimulationPanel, 'push'); app.RunFeedbackButton.ButtonPushedFcn = createCallbackFcn(app, @RunFeedbackButtonPushed, true); app.RunFeedbackButton.Position = [290 20 80 30]; app.RunFeedbackButton.Text = '反馈控制'; app.RunAnalysisButton = uibutton(app.SimulationPanel, 'push'); app.RunAnalysisButton.ButtonPushedFcn = createCallbackFcn(app, @RunAnalysisButtonPushed, true); app.RunAnalysisButton.Position = [200 60 170 30]; app.RunAnalysisButton.Text = '性能分析'; % ==== 结果显示区域 ==== app.ResultsTabGroup = uitabgroup(app.UIFigure); app.ResultsTabGroup.Position = [480 20 900 850]; % 信号可视化标签页 app.SignalsTab = uitab(app.ResultsTabGroup); app.SignalsTab.Title = '信号可视化'; % 创建2x2网格布局 grid = uigridlayout(app.SignalsTab); grid.RowHeight = {'1x', '1x'}; grid.ColumnWidth = {'1x', '1x'}; grid.Padding = [10 10 10 10]; grid.RowSpacing = 10; grid.ColumnSpacing = 10; % 原始信号坐标轴 app.OriginalAxes = uiaxes(grid); title(app.OriginalAxes, '原始信号'); xlabel(app.OriginalAxes, '时间 (s)'); ylabel(app.OriginalAxes, '幅度'); app.OriginalAxes.Layout.Row = 1; app.OriginalAxes.Layout.Column = 1; % TDM信号坐标轴 app.TDMAxes = uiaxes(grid); title(app.TDMAxes, 'TDM复用信号'); xlabel(app.TDMAxes, '时间 (s)'); ylabel(app.TDMAxes, '幅度'); app.TDMAxes.Layout.Row = 1; app.TDMAxes.Layout.Column = 2; % 解复用信号坐标轴 app.DemuxAxes = uiaxes(grid); title(app.DemuxAxes, '解复用信号'); xlabel(app.DemuxAxes, '时间 (s)'); ylabel(app.DemuxAxes, '幅度'); app.DemuxAxes.Layout.Row = 2; app.DemuxAxes.Layout.Column = 1; % 同步后信号坐标轴 app.SyncedAxes = uiaxes(grid); title(app.SyncedAxes, '同步后信号'); xlabel(app.SyncedAxes, '时间 (s)'); ylabel(app.SyncedAxes, '幅度'); app.SyncedAxes.Layout.Row = 2; app.SyncedAxes.Layout.Column = 2; % 性能分析标签页 app.PerformanceTab = uitab(app.ResultsTabGroup); app.PerformanceTab.Title = '性能分析'; % BER坐标轴 app.BERAxes = uiaxes(app.PerformanceTab); title(app.BERAxes, '信号质量分析'); xlabel(app.BERAxes, '信号编号'); app.BERAxes.Position = [100 200 700 500]; yyaxis(app.BERAxes, 'left'); ylabel(app.BERAxes, 'BER'); yyaxis(app.BERAxes, 'right'); ylabel(app.BERAxes, 'SNR (dB)'); % 系统参数标签页 app.ParametersTab = uitab(app.ResultsTabGroup); app.ParametersTab.Title = '系统参数'; % 参数文本区域 app.ParametersTextArea = uitextarea(app.ParametersTab); app.ParametersTextArea.Position = [20 20 860 800]; app.ParametersTextArea.Value = {'系统参数将在此显示'}; end end methods (Access = public) % Construct app function app = TDMApp8888 % Create and configure components createComponents(app) % Register the app with App Designer registerApp(app, app.UIFigure) % Execute the startup function runStartupFcn(app, @startupFcn) if nargout == 0 clear app end end % Code that executes before app deletion function delete(app) % Delete UIFigure when app is deleted delete(app.UIFigure) end end end % 辅助函数 function out = ifelse(condition, true_val, false_val) if condition out = true_val; else out = false_val; end end 第二段代码:classdef TDMSystem properties params % 系统参数 originalSignals % 原始未编码信号 encodedSignals % 编码后信号(二进制位流) modulatedSignals % 调制后信号 demodulatedSignals % 解调后信号(二进制位流) decodedSignals % 解码后信号 tdmSignal % TDM复用信号 receivedSignal % 接收信号 demuxSignals % 解复用信号 syncedSignals % 同步后信号 signalInfo % 信号信息 allocatedSlots % 分配的时隙 slotAssignment % 时隙分配矩阵 performance % 性能指标 encodingParams % 编码参数 modulationParams % 调制参数 frameConfig % 帧配置 quantizationError % 量化误差 frameHeaders % 帧头位置 crcErrors % CRC错误统计 constellationPoints % 星座图数据 paddingInfo % 填充信息(记录填充位数) debugInfo % 调试信息 end methods function obj = TDMSystem(params) % 参数验证和默认值设置 if ~isstruct(params) error('输入参数必须是结构体'); end % 必需参数检查 requiredFields = {'fs', 'duration', 'numSignals', 'snrDb', ... 'totalSlots', 'strategy', 'signalModulations'}; for i = 1:length(requiredFields) if ~isfield(params, requiredFields{i}) error('缺少必需的参数字段: %s', requiredFields{i}); end end % 设置默认值 if ~isfield(params, 'clockDrift') params.clockDrift = zeros(1, params.numSignals); end if ~isfield(params, 'priorities') params.priorities = ones(1, params.numSignals); end if ~isfield(params, 'frameHeader') params.frameHeader = 'A5A5'; end if ~isfield(params, 'useCRC') params.useCRC = true; end if ~isfield(params, 'encodingType') params.encodingType = 'PCM'; end if ~isfield(params, 'quantBits') && strcmp(params.encodingType, 'PCM') params.quantBits = 8; end if ~isfield(params, 'stepSize') && contains(params.encodingType, {'DPCM', 'DM'}) params.stepSize = 0.05; end % 归一化优先级权重 params.priorities = params.priorities / sum(params.priorities); obj.params = params; % 计算关键参数 totalSamples = params.fs * params.duration; obj.params.slotSamples = floor(totalSamples / params.totalSlots); % 初始化性能指标 obj.performance = struct(); obj.quantizationError = zeros(params.numSignals, 1); obj.crcErrors = struct('total', 0, 'perSignal', zeros(1, params.numSignals)); obj.paddingInfo = struct('encoded', zeros(1, params.numSignals)); obj.debugInfo = struct('signalLengths', []); % 初始化编码参数 obj.encodingParams = struct(... 'type', params.encodingType, ... 'quantBits', ifelse(isfield(params, 'quantBits'), params.quantBits, 8), ... 'step', ifelse(isfield(params, 'stepSize'), params.stepSize, 0.05)); % 初始化调制参数 obj.modulationParams = struct(... 'type', ifelse(isfield(params, 'modulationType'), params.modulationType, 'BPSK'), ... 'signalModulations', {params.signalModulations}); % 初始化帧配置 obj.frameConfig = struct(... 'header', params.frameHeader, ... 'useCRC', params.useCRC); end function obj = runSimulation(obj) fprintf('开始TDM系统仿真...\n'); fprintf('信号数量: %d, 总时隙数: %d, 策略: %s, 编码: %s, 调制: %s\n', ... obj.params.numSignals, obj.params.totalSlots, obj.params.strategy, ... obj.encodingParams.type, obj.modulationParams.type); try % 检查原始信号是否提供 if isempty(obj.originalSignals) || all(cellfun(@isempty, obj.signalInfo)) error('原始信号未提供'); else fprintf('使用外部提供的原始信号...\n'); end % 记录原始信号长度 obj.debugInfo.signalLengths = size(obj.originalSignals, 2); % 处理流程 fprintf('编码信号 (%s)...\n', obj.encodingParams.type); obj = obj.encodeSignals(); fprintf('调制信号...\n'); obj = obj.modulateSignals(); fprintf('分配时隙...\n'); obj = obj.allocateSlots(); fprintf('TDM复用 (包含帧头)...\n'); obj = obj.multiplex(); fprintf('信道传输 (SNR: %.1f dB)...\n', obj.params.snrDb); obj = obj.transmit(); fprintf('帧同步...\n'); obj = obj.frameSynchronization(); fprintf('解复用...\n'); obj = obj.demultiplex(); fprintf('解调信号...\n'); obj = obj.demodulateSignals(); fprintf('解码信号 (%s)...\n', obj.encodingParams.type); obj = obj.decodeSignals(); fprintf('信号同步...\n'); obj = obj.synchronize(); fprintf('性能评估...\n'); obj = obj.evaluatePerformance(); fprintf('仿真成功完成!\n'); catch ME fprintf('仿真过程中发生错误: %s\n', ME.message); rethrow(ME); end end function obj = encodeSignals(obj) obj.encodedSignals = cell(1, obj.params.numSignals); for i = 1:obj.params.numSignals signal = obj.originalSignals(i, :); switch obj.encodingParams.type case 'PCM' [quantized, quantErr] = obj.pcm_encode(signal, obj.encodingParams.quantBits); [binStream, ~] = obj.int_to_bin(quantized, obj.encodingParams.quantBits); obj.quantizationError(i) = mean(quantErr.^2); case 'DPCM' [quantized, quantErr] = obj.dpcm_encode(signal, obj.encodingParams.quantBits, obj.encodingParams.step); [binStream, ~] = obj.int_to_bin(quantized, obj.encodingParams.quantBits); obj.quantizationError(i) = mean(quantErr.^2); case 'DM' binStream = obj.dm_encode(signal, obj.encodingParams.step); otherwise error('未知编码类型: %s', obj.encodingParams.type); end % 根据调制方式预填充位流 modType = obj.modulationParams.signalModulations{i}; bitsPerSymbol = obj.getBitsPerSymbol(modType); % 计算填充位数 paddingBits = mod(length(binStream), bitsPerSymbol); if paddingBits > 0 padding = bitsPerSymbol - paddingBits; binStream = [binStream, false(1, padding)]; % 填充0 else padding = 0; end obj.paddingInfo.encoded(i) = padding; % 统一转换为逻辑数组 if ~islogical(binStream) binStream = logical(binStream); end obj.encodedSignals{i} = binStream; fprintf('信号%d: 编码后长度=%d, 填充位=%d\n', i, length(binStream), padding); end end function [binStream, padding] = int_to_bin(~, values, numBits) % 将整数数组转换为二进制位流 numValues = numel(values); totalBits = numValues * numBits; binStream = false(1, totalBits); for i = 1:numValues val = uint32(values(i)); startIdx = (i-1)*numBits + 1; for bitPos = 1:numBits bit = bitget(val, bitPos, 'uint32'); binStream(startIdx + numBits - bitPos) = (bit == 1); end end padding = 0; end function values = bin_to_int(~, binStream, numBits) % 将二进制位流转换回整数数组 numValues = floor(length(binStream) / numBits); padding = length(binStream) - numValues * numBits; if padding > 0 binStream = binStream(1:end-padding); end values = zeros(1, numValues); for i = 1:numValues startIdx = (i-1)*numBits + 1; endIdx = startIdx + numBits - 1; segment = binStream(startIdx:endIdx); % 将二进制段转换为整数 val = 0; for j = 1:numBits val = val * 2 + segment(j); end values(i) = val; end end function obj = decodeSignals(obj) totalSamples = size(obj.demodulatedSignals, 2); obj.decodedSignals = zeros(obj.params.numSignals, totalSamples); for i = 1:obj.params.numSignals binStream = obj.demodulatedSignals(i, :); switch obj.encodingParams.type case 'PCM' quantized = obj.bin_to_int(binStream, obj.encodingParams.quantBits); decoded = obj.pcm_decode(quantized, obj.encodingParams.quantBits); obj.decodedSignals(i, 1:length(decoded)) = decoded; case 'DPCM' quantized = obj.bin_to_int(binStream, obj.encodingParams.quantBits); decoded = obj.dpcm_decode(quantized, obj.encodingParams.quantBits, obj.encodingParams.step); obj.decodedSignals(i, 1:length(decoded)) = decoded; case 'DM' decoded = obj.dm_decode(binStream, obj.encodingParams.step); obj.decodedSignals(i, 1:length(decoded)) = decoded; orig = obj.originalSignals(i, 1:size(obj.decodedSignals, 2)); obj.quantizationError(i) = mean((orig - decoded).^2); end % 长度对齐 decodedLength = length(decoded); if decodedLength < totalSamples obj.decodedSignals(i, decodedLength+1:end) = 0; end end end function obj = modulateSignals(obj) obj.modulatedSignals = cell(obj.params.numSignals, 1); for i = 1:obj.params.numSignals binStream = obj.encodedSignals{i}; modulationType = obj.modulationParams.signalModulations{i}; switch modulationType case 'None' obj.modulatedSignals{i} = binStream; case 'BPSK' obj.modulatedSignals{i} = 2*double(binStream) - 1; case 'QPSK' % 重组为复数符号 symbols = reshape(binStream, 2, [])'; I = 2*double(symbols(:,1)) - 1; Q = 2*double(symbols(:,2)) - 1; obj.modulatedSignals{i} = (I + 1i*Q)/sqrt(2); case '16QAM' symbols = reshape(binStream, 4, [])'; I = 2*double(symbols(:,1)) + double(symbols(:,2)); Q = 2*double(symbols(:,3)) + double(symbols(:,4)); % 映射到星座点 I(I==0) = -3; I(I==1) = -1; I(I==2) = 1; I(I==3) = 3; Q(Q==0) = -3; Q(Q==1) = -1; Q(Q==2) = 1; Q(Q==3) = 3; obj.modulatedSignals{i} = (I + 1i*Q)/sqrt(10); otherwise error('未知的调制方式: %s', modulationType); end % 存储星座图数据 if any(strcmp(modulationType, {'BPSK', 'QPSK', '16QAM'})) points = obj.modulatedSignals{i}; obj.constellationPoints{i} = points(1:min(1000, end)); end end end function obj = demodulateSignals(obj) totalSamples = size(obj.demuxSignals{1}, 2); obj.demodulatedSignals = false(obj.params.numSignals, totalSamples); for i = 1:obj.params.numSignals modSignal = obj.demuxSignals{i}; modulationType = obj.modulationParams.signalModulations{i}; switch modulationType case 'None' bits = real(modSignal) > 0.5; case 'BPSK' bits = real(modSignal) > 0; case 'QPSK' I = real(modSignal) > 0; Q = imag(modSignal) > 0; bits = [I, Q]'; bits = bits(:)'; case '16QAM' symbols = modSignal * sqrt(10); I = real(symbols); Q = imag(symbols); % 解调I通道 bitsI1 = I > 0; bitsI2 = abs(I) > 2; % 解调Q通道 bitsQ1 = Q > 0; bitsQ2 = abs(Q) > 2; bits = [bitsI1, bitsI2, bitsQ1, bitsQ2]'; bits = bits(:)'; end % 移除填充位 padding = obj.paddingInfo.encoded(i); if padding > 0 bits = bits(1:end-padding); end % 确保输出长度匹配 endIdx = min(length(bits), totalSamples); obj.demodulatedSignals(i, 1:endIdx) = bits(1:endIdx); % 长度对齐 if endIdx < totalSamples obj.demodulatedSignals(i, endIdx+1:end) = false; end end end function obj = allocateSlots(obj) if obj.params.totalSlots < obj.params.numSignals error('总时隙数(%d)小于信号数(%d)', ... obj.params.totalSlots, obj.params.numSignals); end obj.allocatedSlots = zeros(1, obj.params.numSignals); obj.slotAssignment = zeros(obj.params.numSignals, obj.params.totalSlots); switch obj.params.strategy case 'fixed' baseSlots = floor(obj.params.totalSlots / obj.params.numSignals); obj.allocatedSlots = baseSlots * ones(1, obj.params.numSignals); remainder = obj.params.totalSlots - sum(obj.allocatedSlots); [~, sortedIdx] = sort(obj.params.priorities, 'descend'); for i = 1:remainder if i <= obj.params.numSignals obj.allocatedSlots(sortedIdx(i)) = obj.allocatedSlots(sortedIdx(i)) + 1; end end case 'priority' minSlots = ones(1, obj.params.numSignals); availableSlots = obj.params.totalSlots - sum(minSlots); if availableSlots < 0 error('总时隙数(%d)不足以分配', obj.params.totalSlots); end weights = obj.params.priorities / sum(obj.params.priorities); extraSlots = floor(availableSlots * weights); obj.allocatedSlots = minSlots + extraSlots; remainder = availableSlots - sum(extraSlots); [~, idx] = sort(obj.params.priorities, 'descend'); for i = 1:remainder obj.allocatedSlots(idx(i)) = obj.allocatedSlots(idx(i)) + 1; end otherwise error('未知策略: %s', obj.params.strategy); end % 验证分配 if sum(obj.allocatedSlots) ~= obj.params.totalSlots error('时隙分配错误: 分配数(%d) != 总数(%d)', ... sum(obj.allocatedSlots), obj.params.totalSlots); end % 构建分配矩阵 current_slot = 1; for i = 1:obj.params.numSignals slotsToAssign = obj.allocatedSlots(i); for j = 1:slotsToAssign if current_slot > obj.params.totalSlots break; end obj.slotAssignment(i, current_slot) = 1; current_slot = current_slot + 1; end end % 打印分配结果 fprintf('时隙分配结果:\n'); for i = 1:obj.params.numSignals fprintf(' 信号 %d (%s): %d 个时隙 (优先级: %.2f, 调制: %s)\n', ... i, obj.signalInfo{i}, obj.allocatedSlots(i), ... obj.params.priorities(i), obj.modulationParams.signalModulations{i}); end end function obj = multiplex(obj) totalSamples = obj.params.fs * obj.params.duration; headerBin = obj.str2bin(obj.frameConfig.header); headerLen = length(headerBin); slotSamples = obj.params.slotSamples; dataSizePerFrame = slotSamples * obj.params.totalSlots; frameSizeTotal = dataSizePerFrame + headerLen; numFrames = ceil(totalSamples / dataSizePerFrame); % 初始化复数数组 obj.tdmSignal = complex(zeros(1, numFrames * frameSizeTotal)); obj.frameHeaders = zeros(1, numFrames); for frameIdx = 1:numFrames frameStartTotal = (frameIdx-1) * frameSizeTotal + 1; headerEnd = frameStartTotal + headerLen - 1; % 帧头转换为复数存储 obj.tdmSignal(frameStartTotal:headerEnd) = complex(headerBin, 0); obj.frameHeaders(frameIdx) = frameStartTotal; dataStart = headerEnd + 1; for slot = 1:obj.params.totalSlots slotStart = dataStart + (slot-1) * slotSamples; slotEnd = slotStart + slotSamples - 1; if slotEnd > length(obj.tdmSignal) break; end signalIdx = find(obj.slotAssignment(:, slot) == 1, 1); if ~isempty(signalIdx) % 计算信号位置 signalStart = (frameIdx-1) * dataSizePerFrame + (slot-1) * slotSamples + 1; signalEnd = min(signalStart + slotSamples - 1, length(obj.modulatedSignals{signalIdx})); % 获取信号片段 signalSegment = obj.modulatedSignals{signalIdx}(signalStart:signalEnd); % 处理CRC if obj.frameConfig.useCRC crcLen = 16; if length(signalSegment) > crcLen dataPart = signalSegment(1:end-crcLen); crc = obj.calculateCRC(dataPart); if isreal(crc) crc = complex(crc, 0); end signalSegment = [dataPart, crc]; end end % 长度匹配处理 if length(signalSegment) < slotSamples padding = complex(zeros(1, slotSamples - length(signalSegment))); signalSegment = [signalSegment, padding]; elseif length(signalSegment) > slotSamples signalSegment = signalSegment(1:slotSamples); end % 插入时隙 obj.tdmSignal(slotStart:slotEnd) = signalSegment; else obj.tdmSignal(slotStart:slotEnd) = complex(zeros(1, slotSamples)); end end end % 裁剪多余部分 obj.tdmSignal = obj.tdmSignal(1:min(numFrames * frameSizeTotal, totalSamples)); end function obj = transmit(obj) signal_power = mean(abs(obj.tdmSignal).^2); if signal_power == 0 signal_power = 1e-10; end linear_snr = 10^(obj.params.snrDb/10); noise_power = signal_power / linear_snr; % 根据信号类型添加噪声 if ~isreal(obj.tdmSignal) noise = sqrt(noise_power/2) * (randn(size(obj.tdmSignal)) + 1i*randn(size(obj.tdmSignal))); else noise = sqrt(noise_power) * randn(size(obj.tdmSignal)); end obj.receivedSignal = obj.tdmSignal + noise; end function obj = frameSynchronization(obj) headerBin = obj.str2bin(obj.frameConfig.header); headerLen = length(headerBin); slotSamples = obj.params.slotSamples; dataSizePerFrame = slotSamples * obj.params.totalSlots; frameSizeTotal = dataSizePerFrame + headerLen; % 创建复数参考帧头 if isreal(obj.receivedSignal) headerRef = complex(headerBin, 0); else headerRef = complex(headerBin, zeros(size(headerBin))); end % 复数互相关计算 correlation = conv(obj.receivedSignal, conj(fliplr(headerRef)), 'same'); correlationMag = abs(correlation); % 使用稳健的峰值检测 [~, locs] = findpeaks(correlationMag, 'MinPeakHeight', 0.7*max(correlationMag), ... 'MinPeakDistance', round(frameSizeTotal*0.8)); % 验证峰值间距 detectedHeaders = []; for i = 1:length(locs) if i == 1 || (locs(i) - locs(i-1)) > 0.8 * frameSizeTotal detectedHeaders = [detectedHeaders, locs(i)]; end end obj.frameHeaders = detectedHeaders; fprintf('检测到 %d 个有效帧头\n', length(detectedHeaders)); end function obj = demultiplex(obj) totalSamples = obj.params.fs * obj.params.duration; headerBin = obj.str2bin(obj.frameConfig.header); headerLen = length(headerBin); slotSamples = obj.params.slotSamples; dataSizePerFrame = slotSamples * obj.params.totalSlots; obj.demuxSignals = cell(1, obj.params.numSignals); for i = 1:obj.params.numSignals obj.demuxSignals{i} = complex(zeros(1, totalSamples)); end obj.crcErrors.total = 0; obj.crcErrors.perSignal = zeros(1, obj.params.numSignals); for frameIdx = 1:length(obj.frameHeaders) headerStart = obj.frameHeaders(frameIdx); if headerStart + headerLen + dataSizePerFrame - 1 > length(obj.receivedSignal) continue; end frameData = obj.receivedSignal(headerStart+headerLen:headerStart+headerLen+dataSizePerFrame-1); for slot = 1:obj.params.totalSlots slotStart = (slot-1)*slotSamples + 1; slotEnd = slotStart + slotSamples - 1; if slotEnd > length(frameData) continue; end slotData = frameData(slotStart:slotEnd); signalIdx = find(obj.slotAssignment(:, slot) == 1, 1); if ~isempty(signalIdx) % CRC处理 if obj.frameConfig.useCRC crcLen = 16; if length(slotData) > crcLen data = slotData(1:end-crcLen); receivedCRC = slotData(end-crcLen+1:end); calculatedCRC = obj.calculateCRC(data); if ~isequal(real(receivedCRC), real(calculatedCRC)) obj.crcErrors.total = obj.crcErrors.total + 1; obj.crcErrors.perSignal(signalIdx) = obj.crcErrors.perSignal(signalIdx) + 1; end end else data = slotData; end % 计算信号位置 signalStart = (frameIdx-1)*dataSizePerFrame + (slot-1)*slotSamples + 1; signalEnd = signalStart + length(data) - 1; % 确保不越界 if signalEnd > totalSamples signalEnd = totalSamples; data = data(1:(signalEnd - signalStart + 1)); end % 存储解复用数据 obj.demuxSignals{signalIdx}(signalStart:signalEnd) = data; end end end end function obj = synchronize(obj) totalSamples = obj.params.fs * obj.params.duration; t = linspace(0, obj.params.duration, totalSamples); obj.syncedSignals = zeros(obj.params.numSignals, totalSamples); for i = 1:obj.params.numSignals decodedSignal = obj.decodedSignals(i, :); validIdx = find(~isnan(decodedSignal) & ~isinf(decodedSignal)); if isempty(validIdx) obj.syncedSignals(i, :) = 0; continue; end drift = obj.params.clockDrift(i); shifted_t = t * (1 + drift); % 确保时间向量不超出范围 max_time = max(shifted_t); if max_time > obj.params.duration shifted_t = shifted_t(shifted_t <= obj.params.duration); if numel(shifted_t) < totalSamples shifted_t = [shifted_t, linspace(shifted_t(end), obj.params.duration, ... totalSamples - numel(shifted_t))]; end end if numel(validIdx) > 10 obj.syncedSignals(i, :) = interp1(... t(validIdx), decodedSignal(validIdx), shifted_t, 'pchip', 0); else obj.syncedSignals(i, :) = interp1(... t(validIdx), decodedSignal(validIdx), shifted_t, 'nearest', 0); end end end function obj = evaluatePerformance(obj) obj.performance = struct(... 'snr', zeros(1, obj.params.numSignals), ... 'sdr', zeros(1, obj.params.numSignals), ... 'corr', zeros(1, obj.params.numSignals), ... 'ber', zeros(1, obj.params.numSignals), ... 'mse', zeros(1, obj.params.numSignals)); for i = 1:obj.params.numSignals % 安全长度处理 orig_signal = obj.originalSignals(i, :); synced_signal = obj.syncedSignals(i, :); % 获取最小公共长度 minLen = min(length(orig_signal), length(synced_signal)); if minLen == 0 fprintf('信号 %d: 无有效数据\n', i); continue; end % 截取公共长度段 orig_segment = orig_signal(1:minLen); synced_segment = synced_signal(1:minLen); % 计算MSE mse = mean((orig_segment - synced_segment).^2); obj.performance.mse(i) = mse; % 计算SNR signal_power = mean(orig_segment.^2); if mse > 0 obj.performance.snr(i) = 10 * log10(signal_power / mse); else obj.performance.snr(i) = Inf; end % 计算SDR distortion = obj.quantizationError(i); if distortion > 0 obj.performance.sdr(i) = 10 * log10(signal_power / distortion); else obj.performance.sdr(i) = Inf; end % 计算相关系数 if minLen > 1 obj.performance.corr(i) = corr(orig_segment(:), synced_segment(:)); else obj.performance.corr(i) = NaN; end % BER计算 modType = obj.modulationParams.signalModulations{i}; if any(strcmp(modType, {'BPSK', 'QPSK', '16QAM'})) orig_bits = obj.encodedSignals{i}; demod_bits = obj.demodulatedSignals(i, :); % 确保长度一致 minLenBits = min(length(orig_bits), length(demod_bits)); if minLenBits == 0 obj.performance.ber(i) = NaN; else orig_seg = orig_bits(1:minLenBits); demod_seg = demod_bits(1:minLenBits); bit_errors = sum(orig_seg ~= demod_seg); obj.performance.ber(i) = bit_errors / minLenBits; end else obj.performance.ber(i) = NaN; end fprintf('信号 %d (%s): MSE=%.4f, SNR=%.2f dB, SDR=%.2f dB, BER=%.4f, Corr=%.4f\n', ... i, obj.signalInfo{i}, mse, obj.performance.snr(i), ... obj.performance.sdr(i), obj.performance.ber(i), obj.performance.corr(i)); end end function bin = str2bin(~, str) % 将字符串转换为二进制数组 dec = uint8(str); binStr = dec2bin(dec, 8)'; bin = double(binStr(:)') - 48; end function crc = calculateCRC(~, data) % 支持复数数据 if ~isreal(data) realData = [real(data); imag(data)]; data = realData(:)'; end % 简化的16位CRC计算 poly = [1 0 0 0 0 0 1 0 0 0 0 0 0 0 0 1 1]; crc = zeros(1, 16); for i = 1:length(data) bit = data(i) > 0; msb = crc(1); crc(1:end-1) = crc(2:end); crc(end) = 0; if xor(msb, bit) crc = xor(crc, poly(2:end)); end end crc = complex(crc, 0); end % ================== 编码核心方法 ================== function [quantized, quantErr] = pcm_encode(~, signal, quantBits) maxVal = max(abs(signal)); quantLevels = 2^quantBits; quantStep = 2*maxVal/(quantLevels-1); minVal = -maxVal; quantized = round((signal - minVal)/quantStep); quantized = max(0, min(quantized, quantLevels-1)); quantErr = signal - (quantized*quantStep + minVal); end function decoded = pcm_decode(~, quantized, quantBits) maxVal = max(quantized) * (2^quantBits-1)/2^quantBits; minVal = -maxVal; quantStep = 2*maxVal/(2^quantBits-1); decoded = quantized*quantStep + minVal; end function [encoded, quantErr] = dpcm_encode(obj, signal, quantBits, stepSize) n = length(signal); encoded = zeros(1, n); quantErr = zeros(1, n); predictor = 0; for i = 1:n error = signal(i) - predictor; quantizedError = obj.quantize(error, quantBits, stepSize); encoded(i) = quantizedError; predictor = predictor + quantizedError; quantErr(i) = error - quantizedError; end end function decoded = dpcm_decode(~, encoded, ~, ~) n = length(encoded); decoded = zeros(1, n); predictor = 0; for i = 1:n decoded(i) = predictor + encoded(i); predictor = decoded(i); end end function encoded = dm_encode(~, signal, stepSize) n = length(signal); encoded = false(1, n); integrator = 0; for i = 1:n if signal(i) > integrator encoded(i) = true; integrator = integrator + stepSize; else encoded(i) = false; integrator = integrator - stepSize; end end end function decoded = dm_decode(~, encoded, stepSize) n = length(encoded); decoded = zeros(1, n); integrator = 0; for i = 1:n if encoded(i) integrator = integrator + stepSize; else integrator = integrator - stepSize; end decoded(i) = integrator; end end function quantized = quantize(~, value, quantBits, stepSize) levels = 2^quantBits; maxVal = (levels-1) * stepSize / 2; clipped = max(min(value, maxVal), -maxVal); quantized = round(clipped/stepSize) * stepSize; end % ==== 辅助方法:获取调制方式对应的符号位数 ==== function bits = getBitsPerSymbol(~, modType) switch modType case {'BPSK', 'None'} bits = 1; case 'QPSK' bits = 2; case '16QAM' bits = 4; otherwise bits = 1; end end end end % 辅助函数 function out = ifelse(condition, true_val, false_val) if condition out = true_val; else out = false_val; end end
06-24
function audio_pitch_correction % 创建主GUI界面 fig = uifigure('Name', '音频音准矫正系统', 'Position', [100 100 900 700]); % 创建音频选择区域 uilabel(fig, 'Position', [50 680 300 20], 'Text', '待矫正音频来源:', 'FontWeight', 'bold'); % 创建录音选项按钮组 source_btn_group = uibuttongroup(fig, 'Position', [50 630 300 40], 'Title', ''); uibutton(source_btn_group, 'Position', [10 10 130 30], 'Text', '导入音频文件', ... 'ButtonPushedFcn', @(btn,event) select_audio(fig, 'source')); uibutton(source_btn_group, 'Position', [160 10 130 30], 'Text', '录制音频', ... 'ButtonPushedFcn', @(btn,event) record_audio(fig)); % 创建参考音频选择按钮 uilabel(fig, 'Position', [400 680 300 20], 'Text', '参考音频来源:', 'FontWeight', 'bold'); uibutton(fig, 'Position', [400 630 150 30], 'Text', '导入参考音频', ... 'ButtonPushedFcn', @(btn,event) select_audio(fig, 'reference')); % 创建处理按钮 process_btn = uibutton(fig, 'Position', [600 630 150 30], ... 'Text', '开始矫正', 'Enable', 'off', ... 'ButtonPushedFcn', @(btn,event) process_audio(fig)); % 创建播放和保存按钮 uibutton(fig, 'Position', [50 580 150 30], 'Text', '播放原始音频', ... 'ButtonPushedFcn', @(btn,event) play_audio(fig, 'source')); uibutton(fig, 'Position', [250 580 150 30], 'Text', '播放矫正音频', ... 'ButtonPushedFcn', @(btn,event) play_audio(fig, 'corrected')); uibutton(fig, 'Position', [450 580 150 30], 'Text', '保存矫正音频', ... 'ButtonPushedFcn', @(btn,event) save_audio(fig)); % 创建录音状态显示 recording_label = uilabel(fig, 'Position', [650 580 200 30], ... 'Text', '准备录音', 'FontColor', [0 0.5 0]); % 创建波形显示区域 ax_source = uiaxes(fig, 'Position', [50 350 800 150]); title(ax_source, '待矫正音频波形'); ax_reference = uiaxes(fig, 'Position', [50 180 800 150]); title(ax_reference, '参考音频波形'); ax_corrected = uiaxes(fig, 'Position', [50 10 800 150]); title(ax_corrected, '矫正后音频波形'); % 存储数据 fig.UserData.source_audio = []; fig.UserData.reference_audio = []; fig.UserData.corrected_audio = []; fig.UserData.fs = 44100; % 默认采样率 fig.UserData.process_btn = process_btn; fig.UserData.axes = struct('source', ax_source, 'reference', ax_reference, 'corrected', ax_corrected); fig.UserData.recording_label = recording_label; fig.UserData.recorder = []; % 录音器对象 fig.UserData.timer = []; % 计时器对象 end function select_audio(fig, audio_type) [file, path] = uigetfile({'*.wav;*.mp3;*.ogg;*.flac', ... '音频文件 (*.wav,*.mp3,*.ogg,*.flac)'}); if isequal(file, 0) return; end filename = fullfile(path, file); [audio, fs] = audioread(filename); % 处理立体声:转换为单声道 if size(audio, 2) > 1 audio = mean(audio, 2); end % 截取前20秒 max_samples = min(20*fs, length(audio)); audio = audio(1:max_samples); % 存储数据 fig.UserData.([audio_type '_audio']) = audio; fig.UserData.fs = fs; % 更新波形显示 ax = fig.UserData.axes.(audio_type); plot(ax, (1:length(audio))/fs, audio); xlabel(ax, '时间 (s)'); ylabel(ax, '幅度'); % 启用处理按钮 if ~isempty(fig.UserData.source_audio) && ~isempty(fig.UserData.reference_audio) fig.UserData.process_btn.Enable = 'on'; end end function record_audio(fig) % 创建录音界面 record_fig = uifigure('Name', '音频录制', 'Position', [300 300 400 200]); % 录音时长设置 uilabel(record_fig, 'Position', [50 150 100 20], 'Text', '录音时长 (秒):'); duration_edit = uieditfield(record_fig, 'numeric', ... 'Position', [160 150 100 20], 'Value', 5, 'Limits', [1 30]); % 采样率设置 uilabel(record_fig, 'Position', [50 120 100 20], 'Text', '采样率:'); fs_dropdown = uidropdown(record_fig, ... 'Position', [160 120 100 20], ... 'Items', {'8000', '16000', '44100', '48000'}, ... 'Value', '44100'); % 控制按钮 record_btn = uibutton(record_fig, 'Position', [50 70 100 30], ... 'Text', '开始录音', ... 'ButtonPushedFcn', @(btn,event) start_recording(fig, duration_edit.Value, str2double(fs_dropdown.Value))); uibutton(record_fig, 'Position', [160 70 100 30], ... 'Text', '停止录音', ... 'ButtonPushedFcn', @(btn,event) stop_recording(fig)); uibutton(record_fig, 'Position', [270 70 100 30], ... 'Text', '关闭', ... 'ButtonPushedFcn', @(btn,event) close(record_fig)); end function start_recording(fig, duration, fs) % 更新状态 fig.UserData.recording_label.Text = '录音中...'; fig.UserData.recording_label.FontColor = [1 0 0]; drawnow; % 创建录音器对象 recorder = audiorecorder(fs, 16, 1); % 16-bit, 单声道 % 设置录音时长 fig.UserData.recorder = recorder; fig.UserData.fs = fs; % 开始录音 record(recorder, duration); % 创建计时器显示剩余时间 t = timer('ExecutionMode', 'fixedRate', 'Period', 1, ... 'TasksToExecute', duration, ... 'TimerFcn', @(t,~) update_recording_timer(fig, t, duration)); start(t); % 存储计时器 fig.UserData.timer = t; end function update_recording_timer(fig, t, total_duration) elapsed = t.TasksExecuted; remaining = total_duration - elapsed; fig.UserData.recording_label.Text = sprintf('录音中: %d秒', remaining); % 录音结束时自动停止 if remaining <= 0 stop_recording(fig); end end function stop_recording(fig) if ~isempty(fig.UserData.recorder) && isrecording(fig.UserData.recorder) stop(fig.UserData.recorder); end % 停止计时器 if ~isempty(fig.UserData.timer) && isvalid(fig.UserData.timer) stop(fig.UserData.timer); delete(fig.UserData.timer); fig.UserData.timer = []; end % 获取录音数据 audio = getaudiodata(fig.UserData.recorder); fs = fig.UserData.fs; % 更新状态 fig.UserData.recording_label.Text = '录音完成!'; fig.UserData.recording_label.FontColor = [0 0.5 0]; % 存储为待矫正音频 fig.UserData.source_audio = audio; % 更新波形显示 ax = fig.UserData.axes.source; plot(ax, (1:length(audio))/fs, audio); title(ax, '录制音频波形'); xlabel(ax, '时间 (s)'); ylabel(ax, '幅度'); % 启用处理按钮 if ~isempty(fig.UserData.reference_audio) fig.UserData.process_btn.Enable = 'on'; end end function process_audio(fig) source = fig.UserData.source_audio; reference = fig.UserData.reference_audio; fs = fig.UserData.fs; % 确保主图窗存在 if ~isvalid(fig) errordlg('主窗口已关闭,无法处理音频!', '处理错误'); return; end % 创建处理进度对话框 h = uiprogressdlg(fig, 'Title', '处理中', 'Message', '音频对齐...', 'Indeterminate', 'on'); % 步骤1:音频对齐 try [aligned_source, aligned_ref] = improved_align_audio(source, reference, fs); catch ME close(h); errordlg(['音频对齐失败: ' ME.message], '处理错误'); return; end % 步骤2:基频提取 h.Message = '提取音高...'; try [f0_source, time_source] = extract_pitch(aligned_source, fs); [f0_ref, time_ref] = extract_pitch(aligned_ref, fs); catch ME close(h); errordlg(['音高提取失败: ' ME.message], '处理错误'); return; end % 步骤3:音调矫正 h.Message = '矫正音调...'; try corrected = correct_pitch(fig, aligned_source, fs, f0_source, f0_ref, time_source, time_ref); catch ME close(h); errordlg(['音高校正失败: ' ME.message], '处理错误'); return; end % 关闭进度对话框 close(h); % 保存结果并更新显示 fig.UserData.corrected_audio = corrected; plot(fig.UserData.axes.corrected, (1:length(corrected))/fs, corrected); xlabel(fig.UserData.axes.corrected, '时间 (s)'); ylabel(fig.UserData.axes.corrected, '幅度'); % 绘制音高对比图 pitch_fig = figure('Name', '音高对比', 'Position', [100 100 800 600]); subplot(211); plot(time_source, f0_source, 'b', time_ref, f0_ref, 'r'); legend('原始音高', '参考音高'); title('矫正前音高对比'); xlabel('时间 (s)'); ylabel('频率 (Hz)'); subplot(212); plot(time_source, f0_source, 'b:', time_source, f0_ref, 'r-'); legend('原始音高', '目标音高'); title('矫正前后音高对比'); xlabel('时间 (s)'); ylabel('频率 (Hz)'); end function [aligned_src, aligned_ref] = improved_align_audio(src, ref, fs) % 改进的音频对齐方法:使用频谱互相关 win_size = round(0.1 * fs); % 100ms窗口 hop_size = round(0.05 * fs); % 50ms跳跃 % 计算源音频的频谱图 [S_src, f_src, t_src] = spectrogram(src, win_size, win_size-hop_size, win_size, fs); % 计算参考音频的频谱图 [S_ref, f_ref, t_ref] = spectrogram(ref, win_size, win_size-hop_size, win_size, fs); % 计算互相关 n_frames = min(length(t_src), length(t_ref)); corr_vals = zeros(1, n_frames); for i = 1:n_frames spec_src = abs(S_src(:, i)); spec_ref = abs(S_ref(:, i)); corr_vals(i) = dot(spec_src, spec_ref) / (norm(spec_src) * norm(spec_ref)); end % 找到最大相关帧 [~, max_idx] = max(corr_vals); time_diff = t_src(max_idx) - t_ref(max_idx); sample_diff = round(time_diff * fs); % 对齐音频 if sample_diff > 0 aligned_src = src(1:end-sample_diff); aligned_ref = ref(sample_diff+1:end); else aligned_src = src(-sample_diff+1:end); aligned_ref = ref(1:end+sample_diff); end % 确保等长 min_len = min(length(aligned_src), length(aligned_ref)); aligned_src = aligned_src(1:min_len); aligned_ref = aligned_ref(1:min_len); end function [f0, time] = extract_pitch(audio, fs) % 使用pitch函数提取基频(需要Audio Toolbox) frame_size = round(0.05 * fs); % 50ms帧 overlap = round(0.75 * frame_size); % 75%重叠 [f0, time] = pitch(audio, fs, ... 'WindowLength', frame_size, ... 'OverlapLength', overlap, ... 'Range', [50, 1000], ... % 50Hz-1000Hz范围 'Method', 'NCF'); % 归一化相关函数方法 end function corrected = correct_pitch(fig, audio, fs, f0_src, f0_ref, time_src, time_ref) % 创建进度条(确保使用有效的父图窗) h = uiprogressdlg(fig, 'Title', '处理中', 'Message', '音高校正...'); frame_len = round(0.05 * fs); % 50ms帧长 hop_size = round(0.25 * frame_len); % 25%跳跃 n_frames = floor((length(audio)-frame_len)/hop_size) + 1; corrected = zeros(size(audio)); for i = 1:n_frames % 计算当前帧位置 start_idx = (i-1)*hop_size + 1; end_idx = start_idx + frame_len - 1; frame = audio(start_idx:end_idx); % 查找当前帧对应的目标音高 t_frame = mean([start_idx, end_idx]) / fs; [~, idx_src] = min(abs(time_src - t_frame)); [~, idx_ref] = min(abs(time_ref - t_frame)); if idx_ref <= length(f0_ref) && idx_src <= length(f0_src) && f0_src(idx_src) > 0 target_ratio = f0_ref(idx_ref) / f0_src(idx_src); % 限制比例范围 (0.5-2.0) target_ratio = max(0.5, min(2.0, target_ratio)); else target_ratio = 1.0; % 无法获取有效音高时不调整 end % 使用相位声码器改变音高 corrected_frame = phase_vocoder(frame, target_ratio, fs); % 重叠相加 frame_end_idx = start_idx + length(corrected_frame) - 1; if frame_end_idx <= length(corrected) corrected(start_idx:frame_end_idx) = ... corrected(start_idx:frame_end_idx) + corrected_frame; end % 更新进度条 h.Value = i/n_frames; h.Message = sprintf('处理进度: %d/%d 帧 (%.1f%%)', i, n_frames, i/n_frames*100); end close(h); % 归一化防止削波 max_amp = max(abs(corrected)); if max_amp > 0 corrected = corrected / max_amp; end end function y = phase_vocoder(x, ratio, fs) % 简化的相位声码器实现 n = 2048; % FFT点数 hop_in = round(n/4); hop_out = round(hop_in * ratio); % 初始化 w = hann(n, 'periodic'); X = stft(x, 'Window', w, 'OverlapLength', n-hop_in, 'FFTLength', n); % 相位处理 Y = phase_vocoder_process(X, hop_in, hop_out); % 重建信号 y = istft(Y, 'Window', w, 'OverlapLength', n-hop_out, 'FFTLength', n, ... 'ConjugateSymmetric', true); end function Y = phase_vocoder_process(X, hop_in, hop_out) % 相位声码器核心处理 Y = zeros(size(X)); if isempty(X), return; end phase_adv = angle(X(:,1)); for i = 1:size(X,2) mag = abs(X(:,i)); phase = angle(X(:,i)); % 计算相位增量 delta_phase = phase - phase_adv; phase_adv = phase; % 计算瞬时频率 inst_freq = delta_phase / hop_in; % 调整相位 adjusted_phase = phase_adv + inst_freq * hop_out; % 合成新帧 Y(:,i) = mag .* exp(1j * adjusted_phase); end end function play_audio(fig, audio_type) if ~isvalid(fig), return; end switch audio_type case 'source' audio = fig.UserData.source_audio; title_text = '播放原始音频'; case 'corrected' audio = fig.UserData.corrected_audio; title_text = '播放矫正音频'; otherwise return; end if isempty(audio) errordlg('未找到音频数据!', '播放错误'); return; end fs = fig.UserData.fs; player = audioplayer(audio, fs); play(player); % 创建播放状态显示 play_fig = uifigure('Name', title_text, 'Position', [500 500 300 100]); uilabel(play_fig, 'Position', [50 50 200 30], 'Text', '正在播放音频...', ... 'FontSize', 16, 'HorizontalAlignment', 'center'); % 播放结束后关闭窗口 player.TimerFcn = {@stop_playback, play_fig}; player.StopFcn = {@stop_playback, play_fig}; end function stop_playback(~, ~, fig) if isvalid(fig) close(fig); end end function save_audio(fig) if ~isvalid(fig) || isempty(fig.UserData.corrected_audio) errordlg('无有效音频数据可保存!', '保存错误'); return; end [file, path] = uiputfile('*.wav', '保存矫正音频'); if isequal(file, 0), return; end audiowrite(fullfile(path, file), fig.UserData.corrected_audio, fig.UserData.fs); msgbox('音频保存成功!', '完成'); end 这是完整代码,我希望增加调整前后以及与参考音高的对比综合图,并且,我希望在每一帧能够根据提供的标准音频的音高,将待转化音频的音高尽量调整到与标准音频一样的高度,从而实现校准‘’
06-16
优化下面的代码,不显示眼图分析,具体显示其他分析,给我优化后完整的代码: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,0.3]); 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
06-25
<think>我们被要求优化代码,不显示眼图分析,而是显示其他分析。这意味着我们需要移除眼图相关的部分,并用其他分析图替换。具体步骤:1.在属性中,移除`eyeDiagramAxes`属性,因为我们不再需要眼图坐标轴。2.在`createAnalysisWindow`方法中,移除眼图坐标轴的创建,并将原来眼图的位置替换为其他分析(例如,我们可以添加一个误码率趋势图,或者信号时域波形图,或者信噪比分布图等)。这里我们选择添加一个误码率趋势图(BER趋势图),用来展示不同信噪比条件下的误码率变化。3.修改网格布局:原来第1行第3列是眼图,现在改为误码率趋势图(或其他分析图)。4.在`plotComprehensiveAnalysis`方法中,移除调用`plotEyeDiagram`的语句,并添加绘制新图的函数调用(例如`plotBERTrend`)。5.实现新的绘图函数`plotBERTrend`,用于绘制误码率趋势图。注意,我们需要有数据来绘制这个图。但是原类中可能没有存储不同SNR下的BER数据。因此,我们需要调整类的设计,以便存储或计算这些数据。然而,考虑到原代码中并没有直接提供不同SNR下的BER数据,我们需要重新考虑。由于原代码是进行单次仿真的性能分析,我们可能无法直接获取多个SNR点的数据。因此,我们可以改变思路,显示每个信号的误码率条形图(如果有多路信号)或者显示信号的时域波形对比(原始信号和解码信号)。根据要求,我们选择显示信号的时域波形对比,因为它有现成的数据(原始信号和解码信号)。具体修改:1.移除`eyeDiagramAxes`属性,添加`timeDomainAxes`属性用于时域波形显示。2.在`createAnalysisWindow`中,将原眼图坐标轴替换为时域波形坐标轴,并设置标题等。3.实现`plotTimeDomain`方法,用于绘制原始信号和解码信号的时域波形(取第一个信号的前100个点进行对比)。注意:由于眼图分析被移除,相关方法`plotEyeDiagram`和`plotEye`(私有方法)可以删除。因此,我们进行以下修改:-删除`eyeDiagramAxes`属性-添加`timeDomainAxes`属性-在`createAnalysisWindow`中创建时域波形坐标轴,位置在原来眼图的位置(第1行第3列)-在`plotComprehensiveAnalysis`中,将`plotEyeDiagram`替换为`plotTimeDomain`-实现`plotTimeDomain`方法,绘制时域波形-删除`plotEyeDiagram`方法和`plotEye`方法修改后的代码结构如下:properties...%其他属性timeDomainAxes%时域波形坐标轴...%其他属性endmethods...functioncreateAnalysisWindow(obj)...%===时域波形坐标轴===obj.timeDomainAxes=uiaxes(gridLayout);obj.timeDomainAxes.Layout.Row=1;obj.timeDomainAxes.Layout.Column=3;title(obj.timeDomainAxes,'时域波形对比');xlabel(obj.timeDomainAxes,'样本索引');ylabel(obj.timeDomainAxes,'幅度');grid(obj.timeDomainAxes,'on');...endfunctionplotComprehensiveAnalysis(obj)...%绘制时域波形plotTimeDomain(obj);...endfunctionplotTimeDomain(obj)%绘制第一个信号的原始信号和解码信号的前100个点...end%删除plotEyeDiagram和plotEye方法end下面给出完整修改后的代码。注意,为了保持代码清晰,我们删除了所有眼图相关的代码,并添加了时域波形对比图。</think>### 优化后完整代码:移除眼图分析并增强时域分析 ```matlab classdef TDMPerformanceAnalyzer < TDMSystem properties analysisFigure % 独立分析窗口 performanceMetrics % 扩展的性能指标 constellationAxes % 星座图坐标轴 spectrumAxes % 频谱分析坐标轴 timeDomainAxes % 时域波形坐标轴 (替换眼图) correlationAxes % 相关分析坐标轴 metricTable % 性能指标表格 systemMetricsLabel % 系统级指标标签 berTrendAxes % BER趋势分析坐标轴 (新增) 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) % 创建独立分析窗口 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.timeDomainAxes = uiaxes(gridLayout); obj.timeDomainAxes.Layout.Row = 1; obj.timeDomainAxes.Layout.Column = 3; title(obj.timeDomainAxes, '时域波形对比'); xlabel(obj.timeDomainAxes, '样本索引'); ylabel(obj.timeDomainAxes, '幅度'); grid(obj.timeDomainAxes, 'on'); % === BER趋势分析坐标轴 (新增) === obj.berTrendAxes = uiaxes(gridLayout); obj.berTrendAxes.Layout.Row = 2; obj.berTrendAxes.Layout.Column = 1; title(obj.berTrendAxes, 'BER随SNR变化趋势'); xlabel(obj.berTrendAxes, 'SNR (dB)'); ylabel(obj.berTrendAxes, 'BER'); grid(obj.berTrendAxes, 'on'); set(obj.berTrendAxes, 'YScale', 'log'); % === 相关分析坐标轴 === obj.correlationAxes = uiaxes(gridLayout); obj.correlationAxes.Layout.Row = 2; obj.correlationAxes.Layout.Column = [2, 3]; title(obj.correlationAxes, '信号相关性分析'); xlabel(obj.correlationAxes, '滞后 (样本)'); ylabel(obj.correlationAxes, '相关系数'); grid(obj.correlationAxes, 'on'); % === 性能指标表格 === obj.metricTable = uitable(gridLayout); obj.metricTable.Layout.R极 = 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); % 绘制时域波形对比 (替换眼图) plotTimeDomain(obj); % 绘制BER趋势 (新增) plotBERTrend(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.constellation极es, ... 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', '极ormalized'); return; end % 计算功率谱密度 [psd, freq] = pwelch(signal, hamming(1024), 512, 1024, fs); % 确保频率和PSD长度匹配 minLen = min(length(freq), length(psd)); freq = freq(1:minLen); psd = psd(1:minLen); % 验证向量方向一致性 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 plotTimeDomain(obj) % 绘制时域波形对比 (替换眼图) signalIdx = 1; maxSamples = 200; % 最多显示200个样本 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.timeDomainAxes, 0.5, 0.5, '信号长度不足', ... 'HorizontalAlignment', 'center', 'Units', 'normalized'); return; end % 截取前maxSamples个样本 plotLen = min(minLen, maxSamples); orig = orig(1:plotLen); decoded = decoded(1:plotLen); % 绘制时域波形 plot(obj.timeDomainAxes, 1:plotLen, real(orig), 'b', 'LineWidth', 1.5, 'DisplayName', '原始信号'); hold(obj.timeDomainAxes, 'on'); plot(obj.timeDomainAxes, 1:plotLen, real(decoded), 'r--', 'LineWidth', 1.2, 'DisplayName', '解码信号'); hold(obj.timeDomainAxes, 'off'); title(obj.timeDomainAxes, sprintf('信号%d时域波形对比', signalIdx)); legend(obj.timeDomainAxes, 'Location', 'best'); grid(obj.timeDomainAxes, 'on'); % 添加SNR信息 if ~isnan(obj.performance.snr(signalIdx)) text(obj.timeDomainAxes, ... 0.05, 0.95, ... % 归一化位置 sprintf('SNR: %.1f dB', obj.performance.snr(signalIdx)), ... 'Units', 'normalized', ... 'BackgroundColor', [1, 1, 0.8], ... 'Margin', 3, ... 'FontSize', 10, ... 'VerticalAlignment', 'top'); end else text(obj.timeDomainAxes, 0.5, 0.5, '无信号数据', ... 'HorizontalAlignment', 'center', 'Units', 'normalized'); end end function plotBERTrend(obj) % 绘制BER随SNR变化趋势 (新增) if isempty(obj.performance.snr) || isempty(obj.performance.ber) text(obj.berTrendAxes, 0.5, 0.5, '无BER/SNR数据', ... 'HorizontalAlignment', 'center', 'Units', 'normalized'); return; end % 获取所有信号的SNR和BER数据 snrValues = obj.performance.snr; berValues = obj.performance.ber; % 绘制BER趋势 semilogy(obj.berTrendAxes, snrValues, berValues, ... 'bo-', 'LineWidth', 1.5, 'MarkerSize', 8, 'MarkerFaceColor', 'b'); title(obj.berTrendAxes, 'BER随SNR变化趋势'); grid(obj.berTrendAxes, 'on'); % 添加理论BER曲线 (以QPSK为例) try snrRange = min(snrValues):0.5:max(snrValues); theoreticalBER = berawgn(snrRange, 'psk', 4, 'nondiff'); hold(obj.berTrendAxes, 'on'); semilogy(obj.berTrendAxes, snrRange, theoreticalBER, ... 'r--', 'LineWidth', 2, 'DisplayName', '理论QPSK'); hold(obj.berTrendAxes, 'off'); legend(obj.berTrendAxes, '实测BER', '理论QPSK', 'Location', 'southwest'); catch legend(obj.berTrendAxes, '实测BER', 'Location', 'southwest'); 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'); % 检查空结果 if isempty(corr) || isempty(lags) text(obj.correlationAxes, 0.5, 0.5, '互相关计算失败', ... 'HorizontalAlignment', 'center', 'Units', 'normalized'); return; end % 确保维度匹配 if length(lags) ~= length(corr) minLen = min(length(lags), length(corr)); lags = lags(1:minLen); corr = corr(1:minLen); end % 统一向量方向 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 ME % 捕获并显示相关计算错误 warning('相关计算错误: %s (信号长度: %d)', ME.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 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 ``` ### 主要优化内容: #### 1. 移除眼图分析并添加时域波形对比 ```matlab % === 时域波形坐标轴 (替换眼图) === obj.timeDomainAxes = uiaxes(gridLayout); obj.timeDomainAxes.Layout.Row = 1; obj.timeDomainAxes.Layout.Column = 3; title(obj.timeDomainAxes, '时域波形对比'); xlabel(obj.timeDomainAxes, '样本索引'); ylabel(obj.timeDomainAxes, '幅度'); grid(obj.timeDomainAxes, 'on'); % 绘制函数实现 function plotTimeDomain(obj) % 绘制原始信号和解码信号的时域波形 plot(obj.timeDomainAxes, 1:plotLen, real(orig), 'b', 'LineWidth', 1.5, 'DisplayName', '原始信号'); hold(obj.timeDomainAxes, 'on'); plot(obj.timeDomainAxes, 1:plotLen, real(decoded), 'r--', 'LineWidth', 1.2, 'DisplayName', '解码信号'); hold(obj.timeDomainAxes, 'off'); end ``` **优势**: - 直观展示信号质量 - 直接比较原始和解码信号 - 添加SNR信息增强分析价值 #### 2. 新增BER趋势分析 ```matlab % === BER趋势分析坐标轴 (新增) === obj.berTrendAxes = uiaxes(gridLayout); obj.berTrendAxes.Layout.Row = 2; obj.berTrendAxes.Layout.Column = 1; title(obj.berTrendAxes, 'BER随SNR变化趋势'); xlabel(obj.berTrendAxes, 'SNR (dB)'); ylabel(obj.berTrendAxes, 'BER'); set(obj.berTrendAxes, 'YScale', 'log'); % 绘制函数实现 function plotBERTrend(obj) % 绘制BER随SNR变化趋势 semilogy(obj.berTrendAxes, snrValues, berValues, 'bo-', ...); % 添加理论BER曲线 theoreticalBER = berawgn(snrRange, 'psk', 4, 'nondiff'); semilogy(obj.berTrendAxes, snrRange, theoreticalBER, 'r--', ...); end ``` **优势**: - 对数坐标清晰展示BER变化 - 添加理论曲线作为参考基准 - 直观评估系统性能极限 #### 3. 布局优化 ```matlab % 原布局: % [星座图] [频谱] [眼图] % [相关分析(全宽)] % [表格(全宽)] % [系统指标(全宽)] % 新布局: % [星座图] [频谱] [时域波形] % [BER趋势] [相关分析(2列宽)] % [表格(全宽)] % [系统指标(全宽)] ``` **改进点**: - 更合理利用空间 - 新增分析内容不增加窗口尺寸 - 逻辑分组更清晰 #### 4. 性能指标增强 ```matlab % 在时域波形中添加SNR信息 text(obj.timeDomainAxes, ... 0.05, 0.95, ... sprintf('SNR: %.1f dB', obj.performance.snr(signalIdx)), ...); % 在BER趋势图中添加理论曲线 theoreticalBER = berawgn(snrRange, 'psk', 4, 'nondiff'); ``` **价值**: - 关键指标可视化展示 - 提供理论参考基准 - 增强分析深度 ### 优化效果说明: 1. **移除眼图分析**: - 完全删除`eyeDiagramAxes`属性和相关绘图方法 - 消除眼图计算开销,提升性能 2. **增强时域分析**: - 新增时域波形对比,直观展示信号质量 - 原始信号与解码信号同图对比 - 添加SNR信息增强分析价值 3. **新增BER趋势分析**: - 展示BER随SNR变化趋势 - 对数坐标清晰展示性能变化 - 添加理论曲线作为参考基准 4. **布局优化**: - 更合理利用分析空间 - 新增内容不增加窗口尺寸 - 相关分析区域扩大,展示更多细节 5. **分析深度提升**: - 时域和频域分析结合 - 理论曲线与实际性能对比 - 关键性能指标可视化增强 ### 使用示例: ```matlab % 创建系统参数 params = struct(... 'numSignals', 3, ... 'fs', 1e6, ... % 采样率 1MHz 'duration', 0.1 ... % 仿真时长 0.1秒 ); % 初始化性能分析器 analyzer = TDMPerformanceAnalyzer(params); % 运行性能分析 analyzer.runPerformanceAnalysis(); ```
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值