Symbian StatusPanel

% voltageDataProcessor_complete.m - 完整的电压数据实时处理与显示程序 function voltageDataProcessor_complete() % 选择输入文件 [fileName, filePath] = uigetfile('*.dat', '选择DAT文件'); if fileName == 0 fprintf('未选择文件,程序退出。\n'); return; end % 完整文件路径 fullPath = fullfile(filePath, fileName); % 创建图形窗口 - 定义 fig 变量 fig = figure('Name', '电压数据实时处理与显示', ... 'Position', [100, 100, 1000, 700], ... 'CloseRequestFcn', @closeFigureCallback, ... 'Color', [0.95, 0.95, 0.95]); % 创建3个子图(垂直排列) ax(1) = subplot(3, 1, 1); p1 = plot(ax(1), NaN, NaN, 'b'); title('电压检测值1 (天线)'); xlabel('采样点'); ylabel('电压(V)'); grid on; ax(2) = subplot(3, 1, 2); p2 = plot(ax(2), NaN, NaN, 'g'); title('电压检测值2 (中频放大器)'); xlabel('采样点'); ylabel('电压(V)'); grid on; ax(3) = subplot(3, 1, 3); p3 = plot(ax(3), NaN, NaN, 'r'); title('电压检测值3 (低频放大器)'); xlabel('采样点'); ylabel('电压(V)'); grid on; % 初始化数据存储变量 voltage1 = []; voltage2 = []; voltage3 = []; % 文件读取状态 fileID = -1; lastPos = 0; % 滤波参数设置 filterOrder = 4; % 滤波器阶数 cutoffFreq = 0.1; % 截止频率(归一化) % 创建低通滤波器 [b, a] = butter(filterOrder, cutoffFreq, 'low'); % 创建状态面板 - 使用已定义的 fig 变量 statusPanel = uipanel(fig, 'Title', '系统状态', ... % 使用 fig 句柄 'Position', [0.02, 0.02, 0.96, 0.15], ... 'BackgroundColor', [0.95, 0.95, 0.95]); % 添加天线状态文本 antennaFaultText = uicontrol(statusPanel, 'Style', 'text', ... 'Position', [20, 80, 200, 20], ... 'String', '天线: 正常', ... 'FontSize', 10, ... 'FontWeight', 'bold', ... 'BackgroundColor', [0.95, 0.95, 0.95], ... 'ForegroundColor', [0, 0.6, 0], ... 'HorizontalAlignment', 'left'); % 状态文本 statusText = uicontrol(statusPanel, 'Style', 'text', ... 'Position', [20, 20, 600, 20], ... 'String', '准备开始...', ... 'FontSize', 10, ... 'BackgroundColor', [0.95, 0.95, 0.95], ... 'HorizontalAlignment', 'left'); freqText = uicontrol(statusPanel, 'Style', 'text', ... 'Position', [20, 50, 300, 20], ... 'String', '频率: 计算中...', ... 'FontSize', 10, ... 'BackgroundColor', [0.95, 0.95, 0.95], ... 'HorizontalAlignment', 'left'); % 中频和低频故障文本 midFaultText = uicontrol(statusPanel, 'Style', 'text', ... 'Position', [350, 80, 200, 20], ... 'String', '中频放大器: 正常', ... 'FontSize', 10, ... 'FontWeight', 'bold', ... 'BackgroundColor', [0.95, 0.95, 0.95], ... 'ForegroundColor', [0, 0.6, 0], ... 'HorizontalAlignment', 'left'); lowFaultText = uicontrol(statusPanel, 'Style', 'text', ... 'Position', [350, 50, 200, 20], ... 'String', '低频放大器: 正常', ... 'FontSize', 10, ... 'FontWeight', 'bold', ... 'BackgroundColor', [0.95, 0.95, 0.95], ... 'ForegroundColor', [0, 0.6, 0], ... 'HorizontalAlignment', 'left'); thresholdText = uicontrol(statusPanel, 'Style', 'text', ... 'Position', [600, 20, 350, 60], ... 'String', sprintf('阈值设置:\n天线故障: 连续两次Δ>0.28V\n天线恢复: 一次Δ>0.3V\n中频故障: <1.9V 正常: >1.95V\n低频故障: >1.72V 正常: <1.6V\n中频故障时低频显示正常'), ... 'FontSize', 9, ... 'BackgroundColor', [0.95, 0.95, 0.95], ... 'HorizontalAlignment', 'left'); % 停止按钮 stopBtn = uicontrol(statusPanel, 'Style', 'pushbutton', ... 'Position', [600, 80, 100, 30], ... 'String', '停止监控', ... 'Callback', @stopMonitoring, ... 'FontSize', 10, ... 'BackgroundColor', [0.9, 0.4, 0.4]); % 存储应用数据 appData = struct(... 'voltage1', voltage1, ... 'voltage2', voltage2, ... 'voltage3', voltage3, ... 'fileID', -1, ... 'lastPos', 0, ... 'fullPath', fullPath, ... 'running', true, ... 'p1', p1, ... 'p2', p2, ... 'p3', p3, ... 'ax', ax, ... 'statusText', statusText, ... 'freqText', freqText, ... 'antennaFaultText', antennaFaultText, ... 'midFaultText', midFaultText, ... 'lowFaultText', lowFaultText, ... 'b', b, ... 'a', a, ... 'maxDataPoints', 10000, ... 'maxDisplayPoints', 1000, ... 'antennaFaultState', 0, ... % 天线状态机 (0:正常, 1:第一次超差, 2:故障) 'antennaFaultStatus', false, ... % 天线当前故障状态 'midFaultStatus', false, ... % 中频放大器故障状态 'lowFaultStatus', false, ... % 低频放大器故障状态 'previousAntennaStatus', false, ...% 上一次天线状态 'previousMidStatus', false, ... % 上一次中频状态 'previousLowStatus', false ... % 上一次低频状态 ); setappdata(fig, 'appData', appData); % 打开文件 try fileID = fopen(fullPath, 'r'); if fileID == -1 error('无法打开文件: %s', fullPath); end % 更新应用数据 appData.fileID = fileID; setappdata(fig, 'appData', appData); set(statusText, 'String', '文件已打开,开始监控...'); catch ME set(statusText, 'String', ['错误: ' ME.message]); return; end % 启动定时器 timerObj = timer(... 'ExecutionMode', 'fixedRate', ... 'Period', 0.5, ... % 更新间隔0.5秒 'TimerFcn', {@updatePlots, fig}, ... 'ErrorFcn', @timerErrorCallback, ... 'BusyMode', 'drop' ... ); start(timerObj); % 存储定时器对象 appData.timerObj = timerObj; setappdata(fig, 'appData', appData); % 关闭回调函数 function closeFigureCallback(~, ~) appData = getappdata(fig, 'appData'); if isfield(appData, 'timerObj') && isvalid(appData.timerObj) stop(appData.timerObj); delete(appData.timerObj); end if isfield(appData, 'fileID') && appData.fileID > 2 fclose(appData.fileID); end delete(fig); end % 停止监控回调 function stopMonitoring(~, ~) appData = getappdata(fig, 'appData'); appData.running = false; setappdata(fig, 'appData', appData); set(statusText, 'String', '监控已停止'); if isfield(appData, 'timerObj') && isvalid(appData.timerObj) stop(appData.timerObj); end end % 定时器错误回调 function timerErrorCallback(~, event) appData = getappdata(fig, 'appData'); set(appData.statusText, 'String', ['定时器错误: ' event.Data.message]); end end % 更新图形函数 function updatePlots(~, ~, figHandle) if ~ishandle(figHandle) return; end appData = getappdata(figHandle, 'appData'); if ~appData.running return; end try % 获取当前文件大小 fseek(appData.fileID, 0, 'eof'); currentFileSize = ftell(appData.fileID); % 检查文件是否有新内容 if currentFileSize > appData.lastPos % 移动到上次结束位置 fseek(appData.fileID, appData.lastPos, 'bof'); % 读取新数据 newData = textscan(appData.fileID, '%s', 'Delimiter', '\n'); newLines = newData{1}; % 处理新数据 newVoltage1 = []; newVoltage2 = []; newVoltage3 = []; for i = 1:length(newLines) line = strtrim(newLines{i}); % 跳过空行 if isempty(line) continue; end % 提取数字 [num, success] = extractNumber(line); if success % 根据行号分配到对应的电压数组 switch mod(i-1, 3) + 1 case 1 newVoltage1 = [newVoltage1; num]; case 2 newVoltage2 = [newVoltage2; num]; case 3 newVoltage3 = [newVoltage3; num]; end end end % 更新数据 if ~isempty(newVoltage1) appData.voltage1 = [appData.voltage1; newVoltage1]; appData.voltage2 = [appData.voltage2; newVoltage2]; appData.voltage3 = [appData.voltage3; newVoltage3]; % 限制数据缓冲区大小 if length(appData.voltage1) > appData.maxDataPoints keepPoints = appData.maxDataPoints; appData.voltage1 = appData.voltage1(end-keepPoints+1:end); appData.voltage2 = appData.voltage2(end-keepPoints+1:end); appData.voltage3 = appData.voltage3(end-keepPoints+1:end); end % 更新图形 updatePlot(appData.p1, appData.voltage1, appData.maxDisplayPoints); updatePlot(appData.p2, appData.voltage2, appData.maxDisplayPoints); updatePlot(appData.p3, appData.voltage3, appData.maxDisplayPoints); % 计算并显示通道3的频率 if length(appData.voltage3) > 100 fs = 100; % 假设采样频率为100Hz frequency = calculateFrequency(appData.voltage3, fs); set(appData.freqText, 'String', sprintf('频率: %.2f Hz', frequency)); title(appData.ax(3), sprintf('电压检测值3 (主要频率: %.2f Hz)', frequency)); end % 应用滤波并更新滤波线 if length(appData.voltage1) >= 10 updateFilteredLine(appData.ax(1), appData.voltage1, appData.b, appData.a, appData.maxDisplayPoints); updateFilteredLine(appData.ax(2), appData.voltage2, appData.b, appData.a, appData.maxDisplayPoints); updateFilteredLine(appData.ax(3), appData.voltage3, appData.b, appData.a, appData.maxDisplayPoints); end % ====== 故障检测逻辑 ====== % 保存之前的状态 appData.previousAntennaStatus = appData.antennaFaultStatus; appData.previousMidStatus = appData.midFaultStatus; appData.previousLowStatus = appData.lowFaultStatus; % 1. 天线故障检测(电压检测值1) if ~isempty(appData.voltage1) && length(appData.voltage1) >= 2 % 获取最近两个电压值 lastValue1 = appData.voltage1(end); prevValue1 = appData.voltage1(end-1); % 计算变化量 delta = abs(lastValue1 - prevValue1); % 状态机实现 switch appData.antennaFaultState case 0 % 正常状态 if delta > 0.28 appData.antennaFaultState = 1; % 进入第一次超差状态 end case 1 % 第一次超差 if delta > 0.28 appData.antennaFaultState = 2; % 进入故障状态 appData.antennaFaultStatus = true; else appData.antennaFaultState = 0; % 返回正常 end case 2 % 故障状态 if delta > 0.3 appData.antennaFaultState = 0; % 返回正常 appData.antennaFaultStatus = false; end end % 更新天线状态显示 if appData.antennaFaultStatus set(appData.antennaFaultText, 'String', '天线: 故障', 'ForegroundColor', [1, 0, 0]); else set(appData.antennaFaultText, 'String', '天线: 正常', 'ForegroundColor', [0, 0.6, 0]); end end % 2. 中频放大器故障检测(电压检测值2) if ~isempty(appData.voltage2) lastValue2 = appData.voltage2(end); if lastValue2 < 1.9 % 故障条件 set(appData.midFaultText, 'String', '中频放大器: 故障', 'ForegroundColor', [1, 0, 0]); appData.midFaultStatus = true; elseif lastValue2 > 1.95 % 正常条件 set(appData.midFaultText, 'String', '中频放大器: 正常', 'ForegroundColor', [0, 0.6, 0]); appData.midFaultStatus = false; end % 1.9V-1.95V之间保持原状态 end % 3. 低频放大器故障检测(电压检测值3) if ~isempty(appData.voltage3) lastValue3 = appData.voltage3(end); % 中频故障时强制显示低频正常 if appData.midFaultStatus set(appData.lowFaultText, 'String', '低频放大器: 正常', 'ForegroundColor', [0, 0.6, 0]); appData.lowFaultStatus = false; else % 正常检测逻辑 if lastValue3 > 1.72 % 故障条件 set(appData.lowFaultText, 'String', '低频放大器: 故障', 'ForegroundColor', [1, 0, 0]); appData.lowFaultStatus = true; elseif lastValue3 < 1.6 % 正常条件 set(appData.lowFaultText, 'String', '低频放大器: 正常', 'ForegroundColor', [0, 0.6, 0]); appData.lowFaultStatus = false; end % 1.6V-1.72V之间保持原状态 end end % 检查状态变化,触发报警 faultDetected = false; faultMessage = ''; if ~appData.previousAntennaStatus && appData.antennaFaultStatus faultDetected = true; faultMessage = '检测到天线故障!'; end if ~appData.previousMidStatus && appData.midFaultStatus faultDetected = true; faultMessage = [faultMessage ' 检测到中频放大器故障!']; end if ~appData.previousLowStatus && appData.lowFaultStatus faultDetected = true; faultMessage = [faultMessage ' 检测到低频放大器故障!']; end if faultDetected playBeep(); set(appData.statusText, 'String', strtrim(faultMessage)); elseif ~appData.antennaFaultStatus && ~appData.midFaultStatus && ~appData.lowFaultStatus set(appData.statusText, 'String', '系统运行正常'); end % 更新全局状态 setappdata(figHandle, 'appData', appData); % ====== 故障检测结束 ====== % 更新文件位置 appData.lastPos = currentFileSize; setappdata(figHandle, 'appData', appData); end end % 刷新图形 drawnow limitrate; catch ME appData = getappdata(figHandle, 'appData'); set(appData.statusText, 'String', ['错误: ' ME.message]); appData.running = false; setappdata(figHandle, 'appData', appData); end end % 蜂鸣声函数 function playBeep() % 创建一个短暂的音频信号 fs = 8192; % 采样率 t = 0:1/fs:0.2; % 0.2秒 f = 1000; % 音调频率 beepSignal = sin(2*pi*f*t); % 播放声音(使用soundsc自动调整幅度) soundsc(beepSignal, fs); end % 数字提取函数 function [num, success] = extractNumber(line) % 尝试多种方法提取数字 success = false; num = NaN; % 方法1: 使用正则表达式提取第一个数字 tokens = regexp(line, '[-+]?\d*\.?\d+', 'match'); if ~isempty(tokens) num = str2double(tokens{1}); if ~isnan(num) success = true; return; end end % 方法2: 使用sscanf提取 [num, count] = sscanf(line, '%f'); if count >= 1 num = num(1); success = true; return; end % 方法3: 尝试去掉非数字字符 cleanLine = regexprep(line, '[^0-9\.\-+]', ''); if ~isempty(cleanLine) num = str2double(cleanLine); if ~isnan(num) success = true; end end end % 更新绘图函数 function updatePlot(plotHandle, data, maxDisplayPoints) if isempty(data) return; end totalPoints = length(data); % 确定显示的起始点和结束点 if totalPoints > maxDisplayPoints startIdx = totalPoints - maxDisplayPoints + 1; endIdx = totalPoints; dataToShow = data(startIdx:end); else startIdx = 1; endIdx = totalPoints; dataToShow = data; end % 更新图形数据 set(plotHandle, 'XData', startIdx:endIdx, 'YData', dataToShow); % 更新坐标轴范围 ax = get(plotHandle, 'Parent'); xlim(ax, [startIdx, endIdx]); % 动态X轴范围 % 自动调整Y轴范围 minY = min(dataToShow); maxY = max(dataToShow); range = max(0.1, maxY - minY); ylim(ax, [minY - 0.1*range, maxY + 0.1*range]); end % 更新滤波线函数 function updateFilteredLine(ax, data, b, a, maxDisplayPoints) % 检查是否已存在滤波线 lines = findobj(ax, 'Type', 'line'); filteredLine = []; % 查找滤波线(红色虚线) for i = 1:length(lines) if strcmp(get(lines(i), 'LineStyle'), '--') && ... isequal(get(lines(i), 'Color'), [1, 0, 0]) filteredLine = lines(i); break; end end % 应用滤波 if length(data) > 10 filteredData = filtfilt(b, a, data); else filteredData = data; end totalPoints = length(data); % 确定显示的起始点和结束点 if totalPoints > maxDisplayPoints startIdx = totalPoints - maxDisplayPoints + 1; endIdx = totalPoints; dataToShow = filteredData(startIdx:end); else startIdx = 1; endIdx = totalPoints; dataToShow = filteredData; end if isempty(filteredLine) % 创建新的滤波线 hold(ax, 'on'); plot(ax, startIdx:endIdx, dataToShow, 'r--', 'LineWidth', 1.5); hold(ax, 'off'); % 添加图例 if isempty(legend(ax)) legend(ax, {'原始数据', '滤波后数据'}, 'Location', 'best'); end else % 更新现有滤波线 set(filteredLine, 'XData', startIdx:endIdx, 'YData', dataToShow); end end % 频率计算函数 function freq = calculateFrequency(data, fs) % 确保数据长度足够 if length(data) < 100 freq = 0; return; end % 去直流分量 data = data - mean(data); % 使用自相关法检测周期 [acf, lags] = xcorr(data, 'coeff'); acf = acf(lags >= 0); lags = lags(lags >= 0); % 寻找主峰位置(跳过第一个点) [peaks, locs] = findpeaks(acf(2:end)); if isempty(peaks) freq = 0; return; end % 找到最高峰 [~, idx] = max(peaks); peakIdx = locs(idx) + 1; % 补偿跳过的第一个点 % 计算周期和频率 period = lags(peakIdx) / fs; freq = 1 / period; % 验证频率在合理范围内 if freq > fs/2 || freq < 0.1 % 如果自相关法失败,使用FFT作为备选 n = length(data); fftResult = fft(data); P2 = abs(fftResult/n); P1 = P2(1:floor(n/2)+1); P1(2:end-1) = 2*P1(2:end-1); f = fs*(0:(n/2))/n; [~, idx] = max(P1(2:end)); % 跳过DC分量 freq = f(idx+1); end end 帮我修改代码,要求如下当电压检测值1数据低于1.8时,判定为电源故障,数据高于2时,判断为电源正常。 当电压检测值2出现数据低于1.9V时,判定为中频放大器故障。当电压检测值2出现数据高于2V时判定为中频放大器正常 当电压检测值3出现数据高于1.72V时,判定为低频放大器故障。当电压检测值3出现数据低于1.6V时,判定为低频放大器正常。如果判定为中频放大器故障,低频放大器就不能判定为故障,显示为低频放大器正常。如果没故障时界面分别显示绿色的中频放大器正常和低频放大器正常。如果发生故障,蜂鸣器响一声提示故障具体的故障点文字变化为红色。
07-01
帮我修改代码,要求如下当电压检测值1数据低于1.8V时,判定为电源故障,数据高于2V时,判断为电源正常。 当电压检测值2出现数据低于1.9V时,判定为中频放大器故障。当电压检测值2出现数据高于2V时判定为中频放大器正常 当电压检测值3出现数据高于1.72V时,判定为低频放大器故障。当电压检测值3出现数据低于1.6V时,判定为低频放大器正常。如果没故障时界面分别显示绿色的中频放大器正常和低频放大器正常。如果发生故障,蜂鸣器响一声提示故障具体的故障点文字变化为红色。代码如下:% voltageDataProcessor_complete.m - 完整的电压数据实时处理与显示程序 function voltageDataProcessor_complete() % 选择输入文件 [fileName, filePath] = uigetfile('*.dat', '选择DAT文件'); if fileName == 0 fprintf('未选择文件,程序退出。\n'); return; end % 完整文件路径 fullPath = fullfile(filePath, fileName); % 创建图形窗口 fig = figure('Name', '电压数据实时处理与显示', ... 'Position', [100, 100, 1000, 700], ... % 调整窗口大小以适应所有元素 'CloseRequestFcn', @closeFigureCallback, ... 'Color', [0.95, 0.95, 0.95]); % 创建3个子图(垂直排列) ax(1) = subplot(3, 1, 1); p1 = plot(ax(1), NaN, NaN, 'b'); title('电压检测值1'); xlabel('采样点'); ylabel('电压(V)'); grid on; ax(2) = subplot(3, 1, 2); p2 = plot(ax(2), NaN, NaN, 'g'); title('电压检测值2 (中频放大器)'); xlabel('采样点'); ylabel('电压(V)'); grid on; ax(3) = subplot(3, 1, 3); p3 = plot(ax(3), NaN, NaN, 'r'); title('电压检测值3 (低频放大器)'); xlabel('采样点'); ylabel('电压(V)'); grid on; % 初始化数据存储变量 voltage1 = []; voltage2 = []; voltage3 = []; % 文件读取状态 fileID = -1; lastPos = 0; % 滤波参数设置 filterOrder = 4; % 滤波器阶数 cutoffFreq = 0.1; % 截止频率(归一化) % 创建低通滤波器 [b, a] = butter(filterOrder, cutoffFreq, 'low'); % 创建状态面板 statusPanel = uipanel(fig, 'Title', '系统状态', ... 'Position', [0.02, 0.02, 0.96, 0.15], ... 'BackgroundColor', [0.95, 0.95, 0.95]); % 状态文本 statusText = uicontrol(statusPanel, 'Style', 'text', ... 'Position', [20, 80, 600, 20], ... 'String', '准备开始...', ... 'FontSize', 10, ... 'BackgroundColor', [0.95, 0.95, 0.95], ... 'HorizontalAlignment', 'left'); % 频率文本 freqText = uicontrol(statusPanel, 'Style', 'text', ... 'Position', [20, 50, 300, 20], ... 'String', '频率: 计算中...', ... 'FontSize', 10, ... 'BackgroundColor', [0.95, 0.95, 0.95], ... 'HorizontalAlignment', 'left'); % 故障显示文本 midFaultText = uicontrol(statusPanel, 'Style', 'text', ... 'Position', [350, 50, 200, 20], ... 'String', '中频放大器: 正常', ... 'FontSize', 10, ... 'FontWeight', 'bold', ... 'BackgroundColor', [0.95, 0.95, 0.95], ... 'ForegroundColor', [0, 0.6, 0], ... % 绿色字体表示正常 'HorizontalAlignment', 'left'); lowFaultText = uicontrol(statusPanel, 'Style', 'text', ... 'Position', [350, 20, 200, 20], ... 'String', '低频放大器: 正常', ... 'FontSize', 10, ... 'FontWeight', 'bold', ... 'BackgroundColor', [0.95, 0.95, 0.95], ... 'ForegroundColor', [0, 0.6, 0], ... % 绿色字体表示正常 'HorizontalAlignment', 'left'); % 阈值显示文本 thresholdText = uicontrol(statusPanel, 'Style', 'text', ... 'Position', [600, 50, 300, 40], ... 'String', sprintf('阈值设置:\n中频故障: <1.95V 正常: >2.0V\n低频故障: >1.65V 正常: <1.6V'), ... 'FontSize', 9, ... 'BackgroundColor', [0.95, 0.95, 0.95], ... 'HorizontalAlignment', 'left'); % 停止按钮 stopBtn = uicontrol(statusPanel, 'Style', 'pushbutton', ... 'Position', [600, 20, 100, 30], ... 'String', '停止监控', ... 'Callback', @stopMonitoring, ... 'FontSize', 10, ... 'BackgroundColor', [0.9, 0.4, 0.4]); % 存储应用数据 appData = struct(... 'voltage1', voltage1, ... 'voltage2', voltage2, ... 'voltage3', voltage3, ... 'fileID', -1, ... 'lastPos', 0, ... 'fullPath', fullPath, ... 'running', true, ... 'p1', p1, ... 'p2', p2, ... 'p3', p3, ... 'ax', ax, ... 'statusText', statusText, ... 'freqText', freqText, ... 'midFaultText', midFaultText, ... 'lowFaultText', lowFaultText, ... 'b', b, ... 'a', a, ... 'maxDataPoints', 10000, ... 'maxDisplayPoints', 1000, ... 'midFaultStatus', false, ... % 中频放大器故障状态 'lowFaultStatus', false, ... % 低频放大器故障状态 'previousMidStatus', false, ... % 上一次中频放大器状态 'previousLowStatus', false ... % 上一次低频放大器状态 ); setappdata(fig, 'appData', appData); % 打开文件 try fileID = fopen(fullPath, 'r'); if fileID == -1 error('无法打开文件: %s', fullPath); end % 更新应用数据 appData.fileID = fileID; setappdata(fig, 'appData', appData); set(statusText, 'String', '文件已打开,开始监控...'); catch ME set(statusText, 'String', ['错误: ' ME.message]); return; end % 启动定时器 timerObj = timer(... 'ExecutionMode', 'fixedRate', ... 'Period', 0.5, ... % 更新间隔0.5秒 'TimerFcn', {@updatePlots, fig}, ... 'ErrorFcn', @timerErrorCallback, ... 'BusyMode', 'drop' ... ); start(timerObj); % 存储定时器对象 appData.timerObj = timerObj; setappdata(fig, 'appData', appData); % 关闭回调函数 function closeFigureCallback(~, ~) appData = getappdata(fig, 'appData'); if isfield(appData, 'timerObj') && isvalid(appData.timerObj) stop(appData.timerObj); delete(appData.timerObj); end if isfield(appData, 'fileID') && appData.fileID > 2 fclose(appData.fileID); end delete(fig); end % 停止监控回调 function stopMonitoring(~, ~) appData = getappdata(fig, 'appData'); appData.running = false; setappdata(fig, 'appData', appData); set(statusText, 'String', '监控已停止'); if isfield(appData, 'timerObj') && isvalid(appData.timerObj) stop(appData.timerObj); end end % 定时器错误回调 function timerErrorCallback(~, event) set(appData.statusText, 'String', ['定时器错误: ' event.Data.message]); end end % 更新图形函数 function updatePlots(~, ~, figHandle) if ~ishandle(figHandle) return; end appData = getappdata(figHandle, 'appData'); if ~appData.running return; end try % 获取当前文件大小 fseek(appData.fileID, 0, 'eof'); currentFileSize = ftell(appData.fileID); % 检查文件是否有新内容 if currentFileSize > appData.lastPos % 移动到上次结束位置 fseek(appData.fileID, appData.lastPos, 'bof'); % 读取新数据 newData = textscan(appData.fileID, '%s', 'Delimiter', '\n'); newLines = newData{1}; % 处理新数据 newVoltage1 = []; newVoltage2 = []; newVoltage3 = []; for i = 1:length(newLines) line = strtrim(newLines{i}); % 跳过空行 if isempty(line) continue; end % 提取数字 [num, success] = extractNumber(line); if success % 根据行号分配到对应的电压数组 switch mod(i-1, 3) + 1 case 1 newVoltage1 = [newVoltage1; num]; case 2 newVoltage2 = [newVoltage2; num]; case 3 newVoltage3 = [newVoltage3; num]; end end end % 更新数据 if ~isempty(newVoltage1) appData.voltage1 = [appData.voltage1; newVoltage1]; appData.voltage2 = [appData.voltage2; newVoltage2]; appData.voltage3 = [appData.voltage3; newVoltage3]; % 限制数据缓冲区大小 if length(appData.voltage1) > appData.maxDataPoints keepPoints = appData.maxDataPoints; appData.voltage1 = appData.voltage1(end-keepPoints+1:end); appData.voltage2 = appData.voltage2(end-keepPoints+1:end); appData.voltage3 = appData.voltage3(end-keepPoints+1:end); end % 更新图形 updatePlot(appData.p1, appData.voltage1, appData.maxDisplayPoints); updatePlot(appData.p2, appData.voltage2, appData.maxDisplayPoints); updatePlot(appData.p3, appData.voltage3, appData.maxDisplayPoints); % 计算并显示通道3的频率 if length(appData.voltage3) > 100 fs = 100; % 假设采样频率为100Hz frequency = calculateFrequency(appData.voltage3, fs); set(appData.freqText, 'String', sprintf('频率: %.2f Hz', frequency)); title(appData.ax(3), sprintf('电压检测值3 (主要频率: %.2f Hz)', frequency)); end % 应用滤波并更新滤波线 if length(appData.voltage1) >= 10 updateFilteredLine(appData.ax(1), appData.voltage1, appData.b, appData.a, appData.maxDisplayPoints); updateFilteredLine(appData.ax(2), appData.voltage2, appData.b, appData.a, appData.maxDisplayPoints); updateFilteredLine(appData.ax(3), appData.voltage3, appData.b, appData.a, appData.maxDisplayPoints); end % ====== 故障检测逻辑 ====== % 保存之前的状态 appData.previousMidStatus = appData.midFaultStatus; appData.previousLowStatus = appData.lowFaultStatus; % 检测中频放大器状态(电压检测值2) if ~isempty(appData.voltage2) lastValue2 = appData.voltage2(end); if lastValue2 < 1.95 % 故障条件 % 设置故障状态和显示 set(appData.midFaultText, 'String', '中频放大器: 故障', 'ForegroundColor', [1, 0, 0]); appData.midFaultStatus = true; elseif lastValue2 > 2.0 % 正常条件 set(appData.midFaultText, 'String', '中频放大器: 正常', 'ForegroundColor', [0, 0.6, 0]); appData.midFaultStatus = false; end % 注意:1.95V到2.0V之间不改变状态 end % 检测低频放大器状态(电压检测值3),但受中频放大器状态影响 if ~isempty(appData.voltage3) lastValue3 = appData.voltage3(end); if appData.midFaultStatus % 中频放大器故障,强制低频放大器为正常 set(appData.lowFaultText, 'String', '低频放大器: 正常', 'ForegroundColor', [0, 0.6, 0]); appData.lowFaultStatus = false; else % 中频放大器正常,按自身规则判断 if lastValue3 > 1.65 set(appData.lowFaultText, 'String', '低频放大器: 故障', 'ForegroundColor', [1, 0, 0]); appData.lowFaultStatus = true; elseif lastValue3 < 1.6 set(appData.lowFaultText, 'String', '低频放大器: 正常', 'ForegroundColor', [0, 0.6, 0]); appData.lowFaultStatus = false; end % 注意:1.6V到1.65V之间不改变状态 end end % 检查状态变化,触发报警 if ~appData.previousMidStatus && appData.midFaultStatus % 中频放大器从正常变为故障 playBeep(); set(appData.statusText, 'String', '检测到中频放大器故障!'); end if ~appData.previousLowStatus && appData.lowFaultStatus % 低频放大器从正常变为故障 playBeep(); set(appData.statusText, 'String', '检测到低频放大器故障!'); end % 更新全局状态文本(如果没有故障,显示正常) if ~appData.midFaultStatus && ~appData.lowFaultStatus set(appData.statusText, 'String', '系统运行正常'); end % ====== 故障检测结束 ====== % 更新文件位置 appData.lastPos = currentFileSize; setappdata(figHandle, 'appData', appData); end end % 刷新图形 drawnow limitrate; catch ME set(appData.statusText, 'String', ['错误: ' ME.message]); appData.running = false; setappdata(figHandle, 'appData', appData); end end % 蜂鸣声函数 function playBeep() % 创建一个短暂的音频信号 fs = 8192; % 采样率 t = 0:1/fs:0.2; % 0.2秒 f = 1000; % 音调频率 beepSignal = sin(2*pi*f*t); % 播放声音(使用soundsc自动调整幅度) soundsc(beepSignal, fs); end % 数字提取函数 function [num, success] = extractNumber(line) % 尝试多种方法提取数字 success = false; num = NaN; % 方法1: 使用正则表达式提取第一个数字 tokens = regexp(line, '[-+]?\d*\.?\d+', 'match'); if ~isempty(tokens) num = str2double(tokens{1}); if ~isnan(num) success = true; return; end end % 方法2: 使用sscanf提取 [num, count] = sscanf(line, '%f'); if count >= 1 num = num(1); success = true; return; end % 方法3: 尝试去掉非数字字符 cleanLine = regexprep(line, '[^0-9\.\-+]', ''); if ~isempty(cleanLine) num = str2double(cleanLine); if ~isnan(num) success = true; end end end % 更新绘图函数 function updatePlot(plotHandle, data, maxDisplayPoints) if isempty(data) return; end totalPoints = length(data); % 确定显示的起始点和结束点 if totalPoints > maxDisplayPoints startIdx = totalPoints - maxDisplayPoints + 1; endIdx = totalPoints; dataToShow = data(startIdx:end); else startIdx = 1; endIdx = totalPoints; dataToShow = data; end % 更新图形数据 set(plotHandle, 'XData', startIdx:endIdx, 'YData', dataToShow); % 更新坐标轴范围 ax = get(plotHandle, 'Parent'); xlim(ax, [startIdx, endIdx]); % 动态X轴范围 % 自动调整Y轴范围 minY = min(dataToShow); maxY = max(dataToShow); range = max(0.1, maxY - minY); ylim(ax, [minY - 0.1*range, maxY + 0.1*range]); end % 更新滤波线函数 function updateFilteredLine(ax, data, b, a, maxDisplayPoints) % 检查是否已存在滤波线 lines = findobj(ax, 'Type', 'line'); filteredLine = []; % 查找滤波线(红色虚线) for i = 1:length(lines) if strcmp(get(lines(i), 'LineStyle'), '--') && ... isequal(get(lines(i), 'Color'), [1, 0, 0]) filteredLine = lines(i); break; end end % 应用滤波 if length(data) > 10 filteredData = filtfilt(b, a, data); else filteredData = data; end totalPoints = length(data); % 确定显示的起始点和结束点 if totalPoints > maxDisplayPoints startIdx = totalPoints - maxDisplayPoints + 1; endIdx = totalPoints; dataToShow = filteredData(startIdx:end); else startIdx = 1; endIdx = totalPoints; dataToShow = filteredData; end if isempty(filteredLine) % 创建新的滤波线 hold(ax, 'on'); plot(ax, startIdx:endIdx, dataToShow, 'r--', 'LineWidth', 1.5); hold(ax, 'off'); % 添加图例 if isempty(legend(ax)) legend(ax, {'原始数据', '滤波后数据'}, 'Location', 'best'); end else % 更新现有滤波线 set(filteredLine, 'XData', startIdx:endIdx, 'YData', dataToShow); end end % 频率计算函数 function freq = calculateFrequency(data, fs) % 确保数据长度足够 if length(data) < 100 freq = 0; return; end % 去直流分量 data = data - mean(data); % 使用自相关法检测周期 [acf, lags] = xcorr(data, 'coeff'); acf = acf(lags >= 0); lags = lags(lags >= 0); % 寻找主峰位置(跳过第一个点) [peaks, locs] = findpeaks(acf(2:end)); if isempty(peaks) freq = 0; return; end % 找到最高峰 [~, idx] = max(peaks); peakIdx = locs(idx) + 1; % 补偿跳过的第一个点 % 计算周期和频率 period = lags(peakIdx) / fs; freq = 1 / period; % 验证频率在合理范围内 if freq > fs/2 || freq < 0.1 % 如果自相关法失败,使用FFT作为备选 n = length(data); fftResult = fft(data); P2 = abs(fftResult/n); P1 = P2(1:floor(n/2)+1); P1(2:end-1) = 2*P1(2:end-1); f = fs*(0:(n/2))/n; [~, idx] = max(P1(2:end)); % 跳过DC分量 freq = f(idx+1); end end
07-01
内容概要:本文详细探讨了基于MATLAB/SIMULINK的多载波无线通信系统仿真及性能分析,重点研究了以OFDM为代表的多载波技术。文章首先介绍了OFDM的基本原理和系统组成,随后通过仿真平台分析了不同调制方式的抗干扰性能、信道估计算法对系统性能的影响以及同步技术的实现与分析。文中提供了详细的MATLAB代码实现,涵盖OFDM系统的基本仿真、信道估计算法比较、同步算法实现和不同调制方式的性能比较。此外,还讨论了信道特征、OFDM关键技术、信道估计、同步技术和系统级仿真架构,并提出了未来的改进方向,如深度学习增强、混合波形设计和硬件加速方案。; 适合人群:具备无线通信基础知识,尤其是对OFDM技术有一定了解的研究人员和技术人员;从事无线通信系统设计与开发的工程师;高校通信工程专业的高年级本科生和研究生。; 使用场景及目标:①理解OFDM系统的工作原理及其在多径信道环境下的性能表现;②掌握MATLAB/SIMULINK在无线通信系统仿真中的应用;③评估不同调制方式、信道估计算法和同步算法的优劣;④为实际OFDM系统的设计和优化提供理论依据和技术支持。; 其他说明:本文不仅提供了详细的理论分析,还附带了大量的MATLAB代码示例,便于读者动手实践。建议读者在学习过程中结合代码进行调试和实验,以加深对OFDM技术的理解。此外,文中还涉及了一些最新的研究方向和技术趋势,如AI增强和毫米波通信,为读者提供了更广阔的视野。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值