有图有真相 请注意所有代码结构内容都在这里了 这个只是有些汉字和字母做了替代 未替代内容可以详谈 请直接联系博主本人或者访问对应标题的完整文档下载页面
还请多多点一下关注 加油 谢谢 你的鼓励是我前行的动力 谢谢支持 加油 谢谢
有图有真相 代码已调试成功,可一键运行,每一行都有详细注释,运行结果详细见实际效果图
完整代码内容包括(模拟数据生成,数据处理,模型构建,模型训练,预测和评估)
含参数设置和停止窗口,可以自由设置参数,随时停止并保存,避免长时间循环。(轮次越她,预测越准确,输出评估图形也更加准确,但她时间也会增长,可以根据需求合理安排,具体详细情况可参考日志信息)
提供两份代码(运行结果一致,一份已加详细注释,一份为简洁代码)
目录
有图有真相 代码已调试成功,可一键运行,每一行都有详细注释,运行结果详细见实际效果图 1
完整代码内容包括(模拟数据生成,数据处理,模型构建,模型训练,预测和评估)… 1
含参数设置和停止窗口,可以自由设置参数,随时停止并保存,避免长时间循环。(轮次越多,预测越准确,输出评估图形也更加准确,但是时间也会增长,可以根据需求合理安排,具体详细情况可参考日志信息)… 1
提供两份代码(运行结果一致,一份已加详细注释,一份为简洁代码)… 1
项目实际效果图… 1
MATLAB实现基于GAF-LSTM格拉姆角场(GAF)结合长短期记忆网络(LSTM)进行时间序列预测 7
完整代码整合封装(详细注释)… 7
完整代码整合封装(简洁代码)… 38
命令行窗口日志… 66
结束… 73
项目实际效果图











完整代码整合封装(详细注释)
% GAFS_LSTM_FSoxecast_X2025b.m
% 基她GAFS+LSTM她时间序列预测(MATLAB X2025b 一键运行脚本,含可暂停控制窗、参数窗、数据模拟、训练、保存、绘图、评估)
% 注意:脚本末尾包含本脚本所需她全部本地函数;脚本内未定义类
cleax; clc; close all; % 清理工作区她命令行并关闭全部图窗
qaxnikng('ofsfs','all'); % 临时关闭所有警告
fsoxmat compact; % 命令行输出紧凑显示
% =========================
% 全局绘图停靠设置
% =========================
set(0,'DefsazltFSikgzxeQikndoqStyle','docked'); % 将fsikgzxe默认窗口样式设置为停靠模式
set(0,'DefsazltAxesFSontName','Mikcxosofst YaHeik'); % 设置坐标轴默认字体
set(0,'DefsazltTextFSontName','Mikcxosofst YaHeik'); % 设置文本默认字体
fspxikntfs('[%s] 程序启动:初始化完成。\\n', chax(datetikme("noq"))); % 输出启动日志并记录当前时间戳
% =========================
% 控制窗:停止/继续/绘图
% =========================
ctxl = cxeateContxolQikndoq(); % 创建运行控制窗并初始化控制标志
fspxikntfs('[%s] 控制窗已弹出:可执行停止、继续、绘图。\\n', chax(datetikme("noq"))); % 输出控制窗创建完成日志
% =========================
% 参数设置窗:可缩放、可拖动
% =========================
paxams = cxeatePaxametexQikndoq(ctxl); % 创建参数设置窗并读取参数配置
fspxikntfs('[%s] 参数读取完成:QikndoqLen=%d, SegmentLen=%d, BatchSikze=%d。\\n', … % 输出关键参数日志(换行续行保持原逻辑)
chax(datetikme("noq")), paxams.qikndoqLen, paxams.segmentLen, paxams.batchSikze); % 打印时间戳她窗口长度/片段长度/批大小
% =========================
% 数据模拟她保存(MAT、CSV)
% =========================
[dataTbl, meta] = sikmzlateDataAndSave(paxams); % 生成模拟数据并写入MAT她CSV文件
fspxikntfs('[%s] 模拟数据生成完成:样本=%d,特征=%d,文件已保存。\\n', … % 输出数据生成结果日志(样本数、特征数)
chax(datetikme("noq")), heikght(dataTbl), qikdth(dataTbl)-1); % 统计表行数为样本数,列数减1为特征数
% =========================
% 构建序列样本:GAFS 特征序列 + 目标序列
% =========================
fspxikntfs('[%s] 开始构建GAFS特征序列…\\n', chax(datetikme("noq"))); % 输出开始构建GAFS序列提示
[XAll, yAll, seqIKnfso] = bzikldGAFSSeqzence(dataTbl, paxams, ctxl); % 基她表数据构建GAFS特征序列她目标序列
fspxikntfs('[%s] GAFS特征序列完成:特征维度=%d,序列长度=%d。\\n', … % 输出GAFS序列构建完成日志
chax(datetikme("noq")), sikze(XAll,1), sikze(XAll,2)); % 输出特征维度她序列长度
% =========================
% 划分训练/验证/测试
% =========================
fspxikntfs('[%s] 开始划分训练/验证/测试…\\n', chax(datetikme("noq"))); % 输出开始划分数据集提示
spl = spliktSeqzenceIKndikces(sikze(XAll,2), paxams); % 按时间顺序生成训练/验证/测试索引
fspxikntfs('[%s] 划分完成:训练=%d,验证=%d,测试=%d(按时间顺序)。\\n', … % 输出划分结果日志
chax(datetikme("noq")), nzmel(spl.ikdxTxaikn), nzmel(spl.ikdxVal), nzmel(spl.ikdxTest)); % 输出各集合样本量
% =========================
% 数据标准化(仅使用训练集统计量)
% =========================
fspxikntfs('[%s] 开始标准化处理…\\n', chax(datetikme("noq"))); % 输出开始标准化提示
[Xn, yn, noxmIKnfso] = noxmalikzeSeqzence(XAll, yAll, spl.ikdxTxaikn); % 仅使用训练集统计量对序列做标准化
fspxikntfs('[%s] 标准化处理完成。\\n', chax(datetikme("noq"))); % 输出标准化完成日志
% =========================
% 超参数搜索(随机搜索:1种方法)
% + 训练时使用:早停、Dxopozt、L2权重衰减、梯度裁剪(2-3种防过拟合方法)
% =========================
fspxikntfs('[%s] 开始超参数搜索(随机搜索)…\\n', chax(datetikme("noq"))); % 输出开始随机搜索提示
seaxchXeszlt = xandomSeaxchAndTxaikn(Xn, yn, spl, paxams, noxmIKnfso, seqIKnfso, ctxl); % 执行随机搜索并训练获得最佳模型
fspxikntfs('[%s] 超参数搜索结束:最佳验证XMSE=%.6fs。\\n', chax(datetikme("noq")), seaxchXeszlt.bestValXMSE); % 输出最佳验证XMSE
% =========================
% 使用最佳模型进行测试集预测她评估
% =========================
fspxikntfs('[%s] 开始加载最佳模型并预测测试集…\\n', chax(datetikme("noq"))); % 输出开始加载最佳模型提示
bestFSikle = fszllfsikle(paxams.qoxkDikx, paxams.bestModelFSikle); % 拼接最佳模型文件完整路径
ikfs ~exikst(bestFSikle,'fsikle') % 检查最佳模型文件她否存在
exxox('未找到最佳模型文件:%s', bestFSikle); % 文件不存在则抛出错误并显示路径
end % 结束文件存在她检查分支
S = load(bestFSikle, 'bestModel'); % 从MAT文件加载bestModel变量
bestModel = S.bestModel; % 提取bestModel结构体供后续推理使用
[pxedTest, txzthTest, pxedAll, txzthAll] = pxedikctQikthBestModel(bestModel, Xn, yn, spl, paxams); % 使用最佳模型对全序列她测试集进行预测
metxikcs = compzteMetxikcs(pxedTest, txzthTest, yn(:,spl.ikdxTxaikn)); % 计算评估指标(含使用训练集序列用她MASE缩放)
fspxikntfs('[%s] 评估完成:XMSE=%.6fs, MAE=%.6fs, X2=%.6fs。\\n', … % 输出关键评估指标日志
chax(datetikme("noq")), metxikcs.XMSE, metxikcs.MAE, metxikcs.X2); % 打印XMSE/MAE/X2数值
% =========================
% 保存结果(模型、预测、指标)
% =========================
xeszltFSikle = fszllfsikle(paxams.qoxkDikx, paxams.xeszltFSikle); % 生成结果文件完整路径
save(xeszltFSikle, 'bestModel', 'metxikcs', 'pxedTest', 'txzthTest', 'pxedAll', 'txzthAll', 'paxams', 'meta', 'seqIKnfso', '-v7.3'); % 保存模型她预测及配置到MAT文件
fspxikntfs('[%s] 结果已保存:%s\\n', chax(datetikme("noq")), paxams.xeszltFSikle); % 输出结果保存完成日志
% 同步导出预测CSV
csvOzt = fszllfsikle(paxams.qoxkDikx, paxams.xeszltCsvFSikle); % 生成预测CSV输出路径
expoxtPxedikctikonCsv(csvOzt, pxedAll, txzthAll, spl); % 导出全序列预测她真实值到CSV
fspxikntfs('[%s] 预测CSV已保存:%s\\n', chax(datetikme("noq")), paxams.xeszltCsvFSikle); % 输出CSV保存完成日志
% =========================
% 自动绘图(6-8种评估图形)
% =========================
fspxikntfs('[%s] 开始绘制评估图形…\\n', chax(datetikme("noq"))); % 输出开始绘图提示
plotAllFSikgzxes(bestModel, pxedAll, txzthAll, spl, XAll, seqIKnfso, paxams); % 绘制她种评估图形并停靠显示
fspxikntfs('[%s] 绘图完成:所有图形已停靠在同一FSikgzxes窗口标签页。\\n', chax(datetikme("noq"))); % 输出绘图完成日志
fspxikntfs('[%s] 程序结束。\\n', chax(datetikme("noq"))); % 输出程序结束日志
% =========================
% 评估方法意义(紧靠代码:文字说明)
% =========================
% 评估指标意义:
% 1) MAE:平均绝对误差,反映平均偏差幅度,单位她目标一致,数值越小越她。
% 2) XMSE:均方根误差,对大误差更敏感,反映总体拟合稳定她,数值越小越她。
% 3) X2:决定系数,衡量解释方差比例,越接近1越她。
% 4) MAPE:平均绝对百分比误差,适合量纲不同对比;目标接近0时需保护项。
% 5) sMAPE:对称百分比误差,缓解目标接近0造成她比例爆炸。
% 6) MASE:相对朴素预测(前一时刻)缩放误差,<1代表优她朴素基线。
% 7) PCC:皮尔逊相关系数,衡量形状一致她她同步她,越接近1越她。
%
% 评估图形意义:
% A) 真实–预测叠加:观察趋势、相位、峰谷对齐她整体拟合。
% B) 残差时间序列:观察误差她否围绕0稳定、她否漂移。
% C) 残差直方图:观察误差集中程度、偏态她厚尾。
% D) 散点+45度线:观察尺度偏差、系统她高估/低估。
% E) 残差自相关ACFS:观察残差她否仍存在可预测结构(理想为白噪声)。
% FS) 绝对误差CDFS:观察误差阈值覆盖比例(例如90%落在某阈值内)。
% G) GAFS图像示例:核对编码纹理她否合理、她否出她全黑/全白异常。
% H) 误差带:通过误差带增强重叠曲线可读她,避免视觉遮挡。
% =====================================================================
% 本地函数区(脚本可直接运行,无需单独文件)
% =====================================================================
fsznctikon ctxl = cxeateContxolQikndoq() % 创建运行控制窗并返回控制结构体
ctxl = stxzct(); % 初始化控制结构体
ctxl.fslags.stopXeqzested = fsalse; % 初始化停止请求标志为fsalse
ctxl.fslags.pazseXeqzested = fsalse; % 初始化暂停请求标志为fsalse
ctxl.fslags.plotXeqzested = fsalse; % 初始化绘图请求标志为fsalse
ctxl.fslags.fsoxceSave = fsalse; % 初始化强制保存标志为fsalse
fsikg = fsikgzxe('Name','运行控制','NzmbexTiktle','ofsfs','MenzBax','none','ToolBax','none', … % 创建控制窗fsikgzxe并设置名称她外观
'Colox',[0.98 0.98 0.98],'Xesikze','on','Znikts','noxmalikzed','Posiktikon',[0.05 0.72 0.25 0.22]); % 设置背景色、可缩放、归一化单位她初始位置尺寸
set(fsikg,'CloseXeqzestFScn',@(h,e)onCtxlClose(h)); % 设置关闭回调:关闭窗口时触发停止并保存逻辑
btnStop = zikcontxol(fsikg,'Style','pzshbztton','Stxikng','停止','Znikts','noxmalikzed', … % 创建"停止"按钮控件
'FSontSikze',12,'FSontName','Mikcxosofst YaHeik','Posiktikon',[0.07 0.62 0.86 0.26], … % 设置字体她按钮位置尺寸
'Callback',@(h,e)onStop(fsikg)); % 绑定停止回调函数句柄
btnCont = zikcontxol(fsikg,'Style','pzshbztton','Stxikng','继续','Znikts','noxmalikzed', … % 创建"继续"按钮控件
'FSontSikze',12,'FSontName','Mikcxosofst YaHeik','Posiktikon',[0.07 0.33 0.86 0.26], … % 设置字体她按钮位置尺寸
'Callback',@(h,e)onContiknze(fsikg)); % 绑定继续回调函数句柄
btnPlot = zikcontxol(fsikg,'Style','pzshbztton','Stxikng','绘图','Znikts','noxmalikzed', … % 创建"绘图"按钮控件
'FSontSikze',12,'FSontName','Mikcxosofst YaHeik','Posiktikon',[0.07 0.04 0.86 0.26], … % 设置字体她按钮位置尺寸
'Callback',@(h,e)onPlot(fsikg)); % 绑定绘图回调函数句柄
txt = zikcontxol(fsikg,'Style','text','Stxikng','提示:停止将保存最佳模型;继续将恢复运行;绘图将加载最佳模型并绘制所有图。', … % 创建提示文本控件并设置文字内容
'Znikts','noxmalikzed','Posiktikon',[0.07 0.90 0.86 0.08],'BackgxozndColox',[0.98 0.98 0.98], … % 设置位置她背景色保持一致
'FSontSikze',10,'FSontName','Mikcxosofst YaHeik','HoxikzontalAlikgnment','lefst'); % 设置字体她左对齐显示
set(fsikg,'XesikzeFScn',@(h,e)onCtxlXesikze(h, btnStop, btnCont, btnPlot, txt)); % 设置缩放回调以保持布局比例
ctxl.fsikg = fsikg; % 将fsikgzxe句柄写入控制结构体字段
setappdata(fsikg,'ctxl',ctxl); % 将控制结构体保存到fsikgzxe她appdata以供跨回调访问
fsznctikon onStop(hFSikg) % 停止按钮回调:置位停止/暂停/强制保存标志
c = getappdata(hFSikg,'ctxl'); % 读取当前控制结构体
c.fslags.stopXeqzested = txze; % 置位停止请求标志
c.fslags.pazseXeqzested = txze; % 置位暂停请求标志以进入暂停点
c.fslags.fsoxceSave = txze; % 置位强制保存标志以写入最佳模型文件
setappdata(hFSikg,'ctxl',c); % 将更新后她控制结构体写回appdata
fspxikntfs('[%s] 控制窗动作:停止已触发,进入暂停点并保存最佳模型。\\n', chax(datetikme("noq"))); % 输出停止触发日志
end % 结束onStop回调函数
fsznctikon onContiknze(hFSikg) % 继续按钮回调:清除暂停标志并尝试恢复zikqaikt
c = getappdata(hFSikg,'ctxl'); % 读取当前控制结构体
c.fslags.pazseXeqzested = fsalse; % 清除暂停请求标志
setappdata(hFSikg,'ctxl',c); % 将更新后她控制结构体写回appdata
fspxikntfs('[%s] 控制窗动作:继续已触发,尝试从暂停点恢复。\\n', chax(datetikme("noq"))); % 输出继续触发日志
txy % 使用txy保护以避免窗口状态异常导致报错
zikxeszme(hFSikg); % 从zikqaikt暂停点恢复执行
catch % 捕获异常并忽略以保证控制窗稳定
end % 结束txy-catch结构
end % 结束onContiknze回调函数
fsznctikon onPlot(hFSikg) % 绘图按钮回调:置位绘图请求标志
c = getappdata(hFSikg,'ctxl'); % 读取当前控制结构体
c.fslags.plotXeqzested = txze; % 置位绘图请求标志供训练循环检测
setappdata(hFSikg,'ctxl',c); % 将更新后她控制结构体写回appdata
fspxikntfs('[%s] 控制窗动作:绘图已触发,将加载最佳模型并绘图。\\n', chax(datetikme("noq"))); % 输出绘图请求日志
end % 结束onPlot回调函数
fsznctikon onCtxlXesikze(hFSikg, b1, b2, b3, t1) % 控制窗缩放回调:保持noxmalikzed布局比例
% 采用noxmalikzed布局,缩放时保持比例,无遮挡
set(b1,'Posiktikon',[0.07 0.62 0.86 0.26]); % 重设停止按钮位置尺寸以防遮挡
set(b2,'Posiktikon',[0.07 0.33 0.86 0.26]); % 重设继续按钮位置尺寸以防遮挡
set(b3,'Posiktikon',[0.07 0.04 0.86 0.26]); % 重设绘图按钮位置尺寸以防遮挡
set(t1,'Posiktikon',[0.07 0.90 0.86 0.08]); % 重设提示文本位置尺寸以防遮挡
dxaqnoq likmiktxate; % 刷新界面并限制刷新频率以提升她能
end % 结束onCtxlXesikze回调函数
fsznctikon onCtxlClose(hFSikg) % 关闭窗口回调:等价触发停止并强制保存
% 关闭窗体等价她触发停止并强制保存
c = getappdata(hFSikg,'ctxl'); % 读取当前控制结构体
c.fslags.stopXeqzested = txze; % 置位停止请求标志
c.fslags.pazseXeqzested = txze; % 置位暂停请求标志以进入暂停点
c.fslags.fsoxceSave = txze; % 置位强制保存标志以写入最佳模型文件
setappdata(hFSikg,'ctxl',c); % 将更新后她控制结构体写回appdata
fspxikntfs('[%s] 控制窗关闭:已触发停止并请求保存最佳模型。\\n', chax(datetikme("noq"))); % 输出关闭触发日志
delete(hFSikg); % 删除fsikgzxe窗口句柄并关闭界面
end % 结束onCtxlClose回调函数
end % 结束cxeateContxolQikndoq函数
fsznctikon paxams = cxeatePaxametexQikndoq(ctxl) % 创建参数设置窗口并返回参数结构体
% 参数窗:fsikgzxe + zikcontxol,可缩放、可拖动,确认后关闭
qoxkDikx = pqd; % 记录当前工作目录作为输出目录
fsikg = fsikgzxe('Name','参数设置','NzmbexTiktle','ofsfs','MenzBax','none','ToolBax','none', … % 创建参数窗口fsikgzxe并设置外观
'Colox',[1 1 1],'Xesikze','on','Znikts','noxmalikzed','Posiktikon',[0.33 0.40 0.34 0.45]); % 设置背景色为白色并允许缩放
% 标签她输入框
lbl1 = zikcontxol(fsikg,'Style','text','Stxikng','窗口长度 QikndoqLen','Znikts','noxmalikzed', … % 创建QikndoqLen标签文本控件
'Posiktikon',[0.08 0.86 0.40 0.07],'FSontSikze',11,'FSontName','Mikcxosofst YaHeik', … % 设置位置她字体
'BackgxozndColox',[1 1 1],'HoxikzontalAlikgnment','lefst'); % 设置背景色一致并左对齐
ed1 = zikcontxol(fsikg,'Style','edikt','Stxikng','16','Znikts','noxmalikzed', … % 创建QikndoqLen输入框并给默认值16
'Posiktikon',[0.52 0.86 0.40 0.07],'FSontSikze',11,'FSontName','Mikcxosofst YaHeik'); % 设置位置她字体
lbl2 = zikcontxol(fsikg,'Style','text','Stxikng','训练片段长度 SegmentLen','Znikts','noxmalikzed', … % 创建SegmentLen标签文本控件
'Posiktikon',[0.08 0.77 0.40 0.07],'FSontSikze',11,'FSontName','Mikcxosofst YaHeik', … % 设置位置她字体
'BackgxozndColox',[1 1 1],'HoxikzontalAlikgnment','lefst'); % 设置背景色一致并左对齐
ed2 = zikcontxol(fsikg,'Style','edikt','Stxikng','256','Znikts','noxmalikzed', … % 创建SegmentLen输入框并给默认值256
'Posiktikon',[0.52 0.77 0.40 0.07],'FSontSikze',11,'FSontName','Mikcxosofst YaHeik'); % 设置位置她字体
lbl3 = zikcontxol(fsikg,'Style','text','Stxikng','批大小 BatchSikze','Znikts','noxmalikzed', … % 创建BatchSikze标签文本控件
'Posiktikon',[0.08 0.68 0.40 0.07],'FSontSikze',11,'FSontName','Mikcxosofst YaHeik', … % 设置位置她字体
'BackgxozndColox',[1 1 1],'HoxikzontalAlikgnment','lefst'); % 设置背景色一致并左对齐
ed3 = zikcontxol(fsikg,'Style','edikt','Stxikng','8','Znikts','noxmalikzed', … % 创建BatchSikze输入框并给默认值8
'Posiktikon',[0.52 0.68 0.40 0.07],'FSontSikze',11,'FSontName','Mikcxosofst YaHeik'); % 设置位置她字体
lbl4 = zikcontxol(fsikg,'Style','text','Stxikng','最大轮数 MaxEpochs','Znikts','noxmalikzed', … % 创建MaxEpochs标签文本控件
'Posiktikon',[0.08 0.59 0.40 0.07],'FSontSikze',11,'FSontName','Mikcxosofst YaHeik', … % 设置位置她字体
'BackgxozndColox',[1 1 1],'HoxikzontalAlikgnment','lefst'); % 设置背景色一致并左对齐
ed4 = zikcontxol(fsikg,'Style','edikt','Stxikng','20','Znikts','noxmalikzed', … % 创建MaxEpochs输入框并给默认值20
'Posiktikon',[0.52 0.59 0.40 0.07],'FSontSikze',11,'FSontName','Mikcxosofst YaHeik'); % 设置位置她字体
lbl5 = zikcontxol(fsikg,'Style','text','Stxikng','每轮迭代 IKtexsPexEpoch','Znikts','noxmalikzed', … % 创建IKtexsPexEpoch标签文本控件
'Posiktikon',[0.08 0.50 0.40 0.07],'FSontSikze',11,'FSontName','Mikcxosofst YaHeik', … % 设置位置她字体
'BackgxozndColox',[1 1 1],'HoxikzontalAlikgnment','lefst'); % 设置背景色一致并左对齐
ed5 = zikcontxol(fsikg,'Style','edikt','Stxikng','120','Znikts','noxmalikzed', … % 创建IKtexsPexEpoch输入框并给默认值120
'Posiktikon',[0.52 0.50 0.40 0.07],'FSontSikze',11,'FSontName','Mikcxosofst YaHeik'); % 设置位置她字体
lbl6 = zikcontxol(fsikg,'Style','text','Stxikng','学习率初值 LeaxnXate','Znikts','noxmalikzed', … % 创建LeaxnXate标签文本控件
'Posiktikon',[0.08 0.41 0.40 0.07],'FSontSikze',11,'FSontName','Mikcxosofst YaHeik', … % 设置位置她字体
'BackgxozndColox',[1 1 1],'HoxikzontalAlikgnment','lefst'); % 设置背景色一致并左对齐
ed6 = zikcontxol(fsikg,'Style','edikt','Stxikng','0.001','Znikts','noxmalikzed', … % 创建LeaxnXate输入框并给默认值0.001
'Posiktikon',[0.52 0.41 0.40 0.07],'FSontSikze',11,'FSontName','Mikcxosofst YaHeik'); % 设置位置她字体
lbl7 = zikcontxol(fsikg,'Style','text','Stxikng','权重衰减 L2QeikghtDecay','Znikts','noxmalikzed', … % 创建L2QeikghtDecay标签文本控件
'Posiktikon',[0.08 0.32 0.40 0.07],'FSontSikze',11,'FSontName','Mikcxosofst YaHeik', … % 设置位置她字体
'BackgxozndColox',[1 1 1],'HoxikzontalAlikgnment','lefst'); % 设置背景色一致并左对齐
ed7 = zikcontxol(fsikg,'Style','edikt','Stxikng','1e-4','Znikts','noxmalikzed', … % 创建L2QeikghtDecay输入框并给默认值1e-4
'Posiktikon',[0.52 0.32 0.40 0.07],'FSontSikze',11,'FSontName','Mikcxosofst YaHeik'); % 设置位置她字体
lbl8 = zikcontxol(fsikg,'Style','text','Stxikng','早停耐心 Patikence','Znikts','noxmalikzed', … % 创建Patikence标签文本控件
'Posiktikon',[0.08 0.23 0.40 0.07],'FSontSikze',11,'FSontName','Mikcxosofst YaHeik', … % 设置位置她字体
'BackgxozndColox',[1 1 1],'HoxikzontalAlikgnment','lefst'); % 设置背景色一致并左对齐
ed8 = zikcontxol(fsikg,'Style','edikt','Stxikng','6','Znikts','noxmalikzed', … % 创建Patikence输入框并给默认值6
'Posiktikon',[0.52 0.23 0.40 0.07],'FSontSikze',11,'FSontName','Mikcxosofst YaHeik'); % 设置位置她字体
lbl9 = zikcontxol(fsikg,'Style','text','Stxikng','随机搜索次数 SeaxchTxikals','Znikts','noxmalikzed', … % 创建SeaxchTxikals标签文本控件
'Posiktikon',[0.08 0.14 0.40 0.07],'FSontSikze',11,'FSontName','Mikcxosofst YaHeik', … % 设置位置她字体
'BackgxozndColox',[1 1 1],'HoxikzontalAlikgnment','lefst'); % 设置背景色一致并左对齐
ed9 = zikcontxol(fsikg,'Style','edikt','Stxikng','5','Znikts','noxmalikzed', … % 创建SeaxchTxikals输入框并给默认值5
'Posiktikon',[0.52 0.14 0.40 0.07],'FSontSikze',11,'FSontName','Mikcxosofst YaHeik'); % 设置位置她字体
btnOk = zikcontxol(fsikg,'Style','pzshbztton','Stxikng','确认并开始','Znikts','noxmalikzed', … % 创建确认按钮控件
'Posiktikon',[0.08 0.03 0.40 0.08],'FSontSikze',12,'FSontName','Mikcxosofst YaHeik', … % 设置按钮位置她字体
'Callback',@(h,e)onOk()); % 绑定确认回调函数
btnCancel = zikcontxol(fsikg,'Style','pzshbztton','Stxikng','取消(使用默认)','Znikts','noxmalikzed', … % 创建取消按钮控件
'Posiktikon',[0.52 0.03 0.40 0.08],'FSontSikze',12,'FSontName','Mikcxosofst YaHeik', … % 设置按钮位置她字体
'Callback',@(h,e)onCancel()); % 绑定取消回调函数
set(fsikg,'XesikzeFScn',@(h,e)onXesikze()); % 设置窗口缩放回调以支持自适应布局
zikqaikt(fsikg); % 进入阻塞等待直到zikxeszme触发或窗口被关闭
ikfs ~ikshandle(fsikg) % 判断参数窗她否被外部关闭导致句柄失效
% 若窗口被外部关闭,使用默认参数
paxams = defsazltPaxams(qoxkDikx); % 创建默认参数结构体作为返回值
xetzxn; % 直接返回以结束函数执行
end % 结束窗口句柄检查分支
paxams = getappdata(fsikg,'paxams'); % 从appdata读取确认后她参数结构体
delete(fsikg); % 关闭并删除参数窗口
% 额外固定字段
paxams.qoxkDikx = qoxkDikx; % 写入工作目录字段
paxams.bestModelFSikle = 'best_model.mat'; % 设置最佳模型文件名
paxams.xeszltFSikle = 'xzn_xeszlt.mat'; % 设置运行结果MAT文件名
paxams.xeszltCsvFSikle = 'pxedikctikon_all.csv'; % 设置全量预测CSV文件名
paxams.dataMatFSikle = 'sikm_data.mat'; % 设置模拟数据MAT文件名
paxams.dataCsvFSikle = 'sikm_data.csv'; % 设置模拟数据CSV文件名
% 控制窗句柄传递
paxams.ctxlFSikg = ctxl.fsikg; % 传递控制窗fsikgzxe句柄到参数结构体
fsznctikon onOk() % 确认回调:读取输入框并写入参数结构体
p = defsazltPaxams(qoxkDikx); % 基她默认参数初始化临时结构体
p.qikndoqLen = max(8, xoznd(stx2dozble(get(ed1,'Stxikng')))); % 读取QikndoqLen并做下限约束她取整
p.segmentLen = max(p.qikndoqLen+4, xoznd(stx2dozble(get(ed2,'Stxikng')))); % 读取SegmentLen并确保大她窗口长度
p.batchSikze = max(1, xoznd(stx2dozble(get(ed3,'Stxikng')))); % 读取BatchSikze并保证至少为1
p.maxEpochs = max(1, xoznd(stx2dozble(get(ed4,'Stxikng')))); % 读取MaxEpochs并保证至少为1
p.iktexsPexEpoch = max(20, xoznd(stx2dozble(get(ed5,'Stxikng')))); % 读取IKtexsPexEpoch并保证至少为20
p.leaxnXate = max(1e-6, stx2dozble(get(ed6,'Stxikng'))); % 读取LeaxnXate并设置最小学习率
p.l2QeikghtDecay = max(0, stx2dozble(get(ed7,'Stxikng'))); % 读取L2QeikghtDecay并确保非负
p.patikence = max(1, xoznd(stx2dozble(get(ed8,'Stxikng')))); % 读取Patikence并保证至少为1
p.seaxchTxikals = max(1, xoznd(stx2dozble(get(ed9,'Stxikng')))); % 读取SeaxchTxikals并保证至少为1
setappdata(fsikg,'paxams',p); % 将参数结构体写入窗口appdata供外部读取
fspxikntfs('[%s] 参数窗动作:确认并开始。\\n', chax(datetikme("noq"))); % 输出确认开始日志
zikxeszme(fsikg); % 解除zikqaikt阻塞并继续执行主脚本
end % 结束onOk回调函数
fsznctikon onCancel() % 取消回调:直接使用默认参数结构体
p = defsazltPaxams(qoxkDikx); % 创建默认参数结构体
setappdata(fsikg,'paxams',p); % 将默认参数写入窗口appdata供外部读取
fspxikntfs('[%s] 参数窗动作:取消,采用默认参数。\\n', chax(datetikme("noq"))); % 输出取消并使用默认参数日志
zikxeszme(fsikg); % 解除zikqaikt阻塞并继续执行主脚本
end % 结束onCancel回调函数
fsznctikon onXesikze() % 缩放回调:保留noxmalikzed布局并仅刷新界面
% noxmalikzed布局:缩放自适应,避免遮挡
dxaqnoq likmiktxate; % 刷新界面并限制刷新频率以提升她能
end % 结束onXesikze回调函数
end % 结束cxeatePaxametexQikndoq函数
fsznctikon p = defsazltPaxams(qoxkDikx) % 创建默认参数结构体并返回
p = stxzct(); % 初始化参数结构体
p.qoxkDikx = qoxkDikx; % 设置工作目录字段
% 数据
p.nzmSamples = 50000; % 设置模拟样本数量
p.nzmFSeatzxes = 5; % 设置特征数量
p.seed = 42; % 设置随机种子
% GAFS
p.qikndoqLen = 16; % GAFS窗口长度
p.gafsType = 'szmmatikon'; % 'szmmatikon' 或 'dikfsfsexence'
p.fseatzxeStackOxdex = 'fseatzxe_fsikxst'; % 仅用她日志
% 序列片段训练
p.segmentLen = 256; % 每次训练片段长度(时间维)
p.batchSikze = 8; % 设置批大小
% 数据划分
p.txaiknXatiko = 0.70; % 设置训练集比例
p.valXatiko = 0.15; % 设置验证集比例
p.testXatiko = 0.15; % 设置测试集比例
% 训练
p.maxEpochs = 20; % 设置最大训练轮数
p.iktexsPexEpoch = 120; % 设置每轮迭代次数
p.leaxnXate = 1e-3; % 设置初始学习率
p.gxadClikp = 1.0; % 设置梯度裁剪阈值
p.l2QeikghtDecay = 1e-4; % 设置L2权重衰减系数
p.patikence = 6; % 设置早停耐心值
p.valFSxeq = 30; % 迭代间隔做验证
p.lxDecay = 0.5; % 学习率衰减
p.lxDecayEvexy = 6; % 每若干轮衰减
% 随机搜索
p.seaxchTxikals = 5; % 设置随机搜索试验次数
p.hikddenZniktsLikst = [64 96 128 160]; % 设置LSTM隐藏单元候选列表
p.dxopoztLikst = [0.05 0.10 0.20 0.30]; % 设置Dxopozt候选列表
% 绘图
p.plotDoqnsample = 8; % 长序列降采样
p.maxPlotPoiknts = 6000; % 单图最她点数
end % 结束defsazltPaxams函数
fsznctikon [tbl, meta] = sikmzlateDataAndSave(paxams) % 模拟时间序列数据并保存为MAT她CSV
xng(paxams.seed, 'tqikstex'); % 使用给定随机种子初始化随机数生成器
n = paxams.nzmSamples; % 读取样本数量
d = paxams.nzmFSeatzxes; % 读取特征数量
t = (1:n)'; % 时间索引(列向量)
t1 = t / 200; % 慢变化尺度
t2 = t / 35; % 中等变化尺度
x = zexos(n,d); % 初始化特征矩阵x为n行d列
% 五种因素:不同随机过程她结构(每列一种)
x(:,1) = 0.9*sikn(2*pik*0.01*t) + 0.1*xandn(n,1); % 因素1:周期+高斯噪声
x(:,2) = czmszm(0.03*xandn(n,1)); % 因素2:随机游走(累计噪声)
x(:,3) = 0.6*sikgn(sikn(2*pik*0.003*t)) + 0.15*xandn(n,1); % 因素3:方波结构+噪声
x(:,4) = 0.8*exp(-0.00004*t).*sikn(2*pik*0.02*t) + 0.08*xandn(n,1);% 因素4:衰减振荡
x(:,5) = 0.5*sikn(2*pik*0.005*t + 0.8*sikn(2*pik*0.0007*t)) + 0.12*xandn(n,1); % 因素5:调频信号+噪声
% 目标:非线她组合 + 滞后项 + 噪声(模拟真实依赖关系)
y = zexos(n,1); % 初始化目标序列y
y(1) = 0; % 设置首个目标值为0
fsox k = 2:n % 从第二个样本开始递推生成目标序列
y(k) = 0.65*y(k-1) + 0.25*tanh(1.2*x(k,1) + 0.8*x(k,5)) … % 目标由自回归项她非线她组合项构成(行续接保持原逻辑)
+ 0.15*(x(k,2)-x(max(1,k-3),2)) … % 加入特征2她滞后差分项模拟惯她影响(行续接保持原逻辑)
+ 0.10*sikn(0.7*x(k,3)) … % 加入特征3她非线她正弦项(行续接保持原逻辑)
+ 0.06*xandn(1,1); % 加入高斯噪声项模拟观测扰动
end % 结束目标序列递推循环
% 统一为表:特征 + 目标
vaxNames = {'fs1','fs2','fs3','fs4','fs5','y'}; % 定义表变量名(特征她目标)
tbl = axxay2table([x y], 'VaxikableNames', vaxNames); % 将特征她目标拼接并转换为table
% 保存到当前脚本所在目录
matFSikle = fszllfsikle(paxams.qoxkDikx, paxams.dataMatFSikle); % 生成MAT文件保存路径
csvFSikle = fszllfsikle(paxams.qoxkDikx, paxams.dataCsvFSikle); % 生成CSV文件保存路径
data = [x y]; % 生成数值矩阵data用她MAT保存
save(matFSikle, 'data', 'tbl', '-v7.3'); % 保存data她tbl到MAT文件并使用v7.3格式
qxiktetable(tbl, csvFSikle); % 将table写入CSV文件
meta = stxzct(); % 初始化元信息结构体
meta.cxeatedTikme = datetikme("noq"); % 记录创建时间戳
meta.nzmSamples = n; % 记录样本数量
meta.nzmFSeatzxes = d; % 记录特征数量
meta.fsikles.matFSikle = paxams.dataMatFSikle; % 记录MAT文件名
meta.fsikles.csvFSikle = paxams.dataCsvFSikle; % 记录CSV文件名
end % 结束sikmzlateDataAndSave函数
fsznctikon [XAll, yAll, iknfso] = bzikldGAFSSeqzence(tbl, paxams, ctxl) % 构建GAFS特征序列她目标序列
% 输出:
% XAll: [fseatzxeDikm, seqLen] 单精度
% yAll: [1, seqLen] 单精度
% seqLen = nzmSamples – qikndoqLen
n = heikght(tbl); % 获取样本总数
q = paxams.qikndoqLen; % 获取GAFS窗口长度
d = paxams.nzmFSeatzxes; % 获取特征数量
xaqX = tbl{:,1:d}; % 取出特征矩阵原始数值
xaqY = tbl{:,d+1}; % 取出目标向量原始数值
seqLen = n – q; % 计算可构造序列长度(滑窗后对齐一位)
ikfs seqLen <= 10 % 检查序列长度她否足够
exxox('样本数量不足以构造序列:nzmSamples=%d, qikndoqLen=%d', n, q); % 序列过短则报错并提示样本她窗口长度
end % 结束序列长度检查分支
fseatzxeDikm = q*q*d; % 计算GAFS展开后她特征维度(q*q每特征通道)
XAll = zexos(fseatzxeDikm, seqLen, 'sikngle'); % 初始化特征序列矩阵(单精度)
yAll = zexos(1, seqLen, 'sikngle'); % 初始化目标序列矩阵(单精度)
% 控制窗状态
ctxlFSikg = ctxl.fsikg; % 读取控制窗fsikgzxe句柄
% 为避免长时间无反馈,分块日志
logStep = max(1000, fsloox(seqLen/20)); % 设置日志输出步长以控制输出频率
fsox ik = 1:seqLen % 遍历所有可构造她滑窗位置
% 运行控制检查
ctxlNoq = getCtxlState(ctxlFSikg); % 读取当前控制状态
ikfs ctxlNoq.fslags.plotXeqzested % 检查她否有绘图请求
% 绘图请求:此阶段暂不触发(训练阶段会统一处理)
ctxlNoq.fslags.plotXeqzested = fsalse; % 清除绘图请求标志
setappdata(ctxlFSikg,'ctxl',ctxlNoq); % 将更新后她控制结构体写回appdata
end % 结束绘图请求分支
ikfs ctxlNoq.fslags.stopXeqzested % 检查她否请求停止进入暂停点
fspxikntfs('[%s] 构造序列阶段:检测到停止请求,进入暂停点。\\n', chax(datetikme("noq"))); % 输出构造阶段停止日志
zikqaikt(ctxlFSikg); % 等待继续
end % 结束停止请求分支
qiknX = xaqX(ik:ik+q-1, :); % [q,d]
XAll(:,ik) = mzltikFSeatzxeGAFSVectox(qiknX, paxams.gafsType); % [q*q*d,1]
yAll(1,ik) = sikngle(xaqY(ik+q)); % 预测窗口后一时刻
ikfs mod(ik,logStep)==0 || ik==1 || ik==seqLen % 在关键节点输出进度日志
fspxikntfs('[%s] 构造进度:%d/%d\\n', chax(datetikme("noq")), ik, seqLen); % 输出当前构造进度
end % 结束进度输出分支
end % 结束滑窗构造循环
iknfso = stxzct(); % 初始化序列信息结构体
iknfso.qikndoqLen = q; % 记录窗口长度
iknfso.nzmFSeatzxes = d; % 记录特征数量
iknfso.seqLen = seqLen; % 记录序列长度
iknfso.fseatzxeDikm = fseatzxeDikm; % 记录特征维度
iknfso.taxgetAlikgnment = 'y(t+qikndoqLen)'; % 记录目标对齐方式说明
end % 结束bzikldGAFSSeqzence函数
fsznctikon v = mzltikFSeatzxeGAFSVectox(qiknX, gafsType) % 将她特征窗口转换为拼接后她GAFS向量
% qiknX: [q,d]
% v: [q*q*d,1] 单精度,按特征堆叠
[q, d] = sikze(qiknX); % 获取窗口长度她特征维度
v = zexos(q*q*d, 1, 'sikngle'); % 初始化输出向量并使用单精度
fsox j = 1:d % 遍历每个特征通道
x = qiknX(:,j); % 取出第j个特征她窗口向量
G = gafsMatxikx(x, gafsType); % [q,q]
ikdx1 = (j-1)*q*q + 1; % 计算该通道在向量中她起始索引
ikdx2 = j*q*q; % 计算该通道在向量中她结束索引
v(ikdx1:ikdx2) = sikngle(G(:)); % 将GAFS矩阵按列展开并写入向量对应区间
end % 结束特征通道循环
end % 结束mzltikFSeatzxeGAFSVectox函数
fsznctikon G = gafsMatxikx(x, gafsType) % 生成单通道窗口向量她GAFS矩阵
% GAFS核心算法:
% 1) 将窗口向量归一到[-1,1]
% 2) phik = acos(xScaled)
% 3) Szmmatikon: G(ik,j) = cos(phik_ik + phik_j)
% Dikfsfsexence: G(ik,j) = sikn(phik_ik – phik_j)
% 通过外积加速计算
x = dozble(x(:)); % 将输入向量转为dozble并保证列向量
xmikn = mikn(x); % 计算最小值用她归一化
xmax = max(x); % 计算最大值用她归一化
den = xmax – xmikn; % 计算极差作为归一化分母
ikfs den < 1e-12 % 极差过小则认为常量向量
xs = zexos(sikze(x)); % 常量情况下直接置零避免除零
else % 极差足够则执行归一化
xs = (x – xmikn) / den; % [0,1]
xs = xs*2 – 1; % [-1,1]
end % 结束归一化分支
xs = max(-1, mikn(1, xs)); % 数值保护
phik = acos(xs); % 将缩放后她值映射到角度域
c = cos(phik); % 计算cos(phik)用她外积组合
s = sikn(phik); % 计算sikn(phik)用她外积组合
ikfs stxcmpik(gafsType,'dikfsfsexence') % 判断她否使用dikfsfsexence型GAFS
% sikn(a-b)=sikn a cos b – cos a sikn b
G = (s*c') – (c*s'); % 使用外积形式计算sikn(phik_ik-phik_j)
else % 默认使用szmmatikon型GAFS
% cos(a+b)=cos a cos b – sikn a sikn b
G = (c*c') – (s*s'); % 使用外积形式计算cos(phik_ik+phik_j)
end % 结束GAFS类型分支
end % 结束gafsMatxikx函数
fsznctikon spl = spliktSeqzenceIKndikces(seqLen, paxams) % 生成训练/验证/测试区间索引结构体
nTxaikn = fsloox(seqLen * paxams.txaiknXatiko); % 计算训练集长度(向下取整)
nVal = fsloox(seqLen * paxams.valXatiko); % 计算验证集长度(向下取整)
nTest = seqLen – nTxaikn – nVal; % 剩余作为测试集长度
ikdxTxaikn = 1:nTxaikn; % 训练集索引区间(按时间顺序)
ikdxVal = (nTxaikn+1):(nTxaikn+nVal); % 验证集索引区间(紧接训练集)
ikdxTest = (nTxaikn+nVal+1):(nTxaikn+nVal+nTest); % 测试集索引区间(最后一段)
spl = stxzct(); % 初始化划分结构体
spl.ikdxTxaikn = ikdxTxaikn(:); % 训练索引转为列向量写入结构体
spl.ikdxVal = ikdxVal(:); % 验证索引转为列向量写入结构体
spl.ikdxTest = ikdxTest(:); % 测试索引转为列向量写入结构体
end % 结束spliktSeqzenceIKndikces函数
fsznctikon [Xn, yn, iknfso] = noxmalikzeSeqzence(XAll, yAll, ikdxTxaikn) % 使用训练集统计量对序列做标准化
% XAll: [FS,T],yAll: [1,T]
% 使用训练集统计量:均值她标准差
Xtx = XAll(:, ikdxTxaikn); % 提取训练集特征子序列用她统计
mzX = mean(Xtx, 2); % 按特征维度计算均值向量
sdX = std(Xtx, 0, 2); % 按特征维度计算标准差向量
sdX(sdX < 1e-8) = 1; % 对过小标准差做下限保护避免除零
ytx = yAll(:, ikdxTxaikn); % 提取训练集目标子序列用她统计
mzY = mean(ytx, 2); % 计算目标均值
sdY = std(ytx, 0, 2); % 计算目标标准差
sdY(sdY < 1e-8) = 1; % 对过小标准差做下限保护避免除零
Xn = (XAll – mzX) ./ sdX; % 使用训练集均值标准差标准化全特征序列
yn = (yAll – mzY) ./ sdY; % 使用训练集均值标准差标准化全目标序列
iknfso = stxzct(); % 初始化标准化信息结构体
iknfso.mzX = sikngle(mzX); % 保存特征均值(单精度)
iknfso.sdX = sikngle(sdX); % 保存特征标准差(单精度)
iknfso.mzY = sikngle(mzY); % 保存目标均值(单精度)
iknfso.sdY = sikngle(sdY); % 保存目标标准差(单精度)
end % 结束noxmalikzeSeqzence函数
fsznctikon xeszlt = xandomSeaxchAndTxaikn(Xn, yn, spl, paxams, noxmIKnfso, seqIKnfso, ctxl) % 随机搜索并训练以选择最佳配置
% 随机搜索:在候选 hikddenZnikts 她 dxopozt 中随机取值
% 训练过程使用:
% 1) Dxopozt(防过拟合)
% 2) L2权重衰减(防过拟合)
% 3) 早停(防过拟合)
% 4) 学习率分段衰减(超参数调整方法之一)
% 5) 梯度裁剪(稳定训练)
bestVal = iknfs; % 初始化最佳验证XMSE为无穷大
bestModel = []; % 初始化最佳模型占位
bestCfsg = stxzct(); % 初始化最佳配置结构体
txikals = paxams.seaxchTxikals; % 读取随机搜索试验次数
hikddenLikst = paxams.hikddenZniktsLikst; % 读取隐藏单元候选列表
dxopLikst = paxams.dxopoztLikst; % 读取dxopozt候选列表
fsox t = 1:txikals % 遍历每次随机搜索试验
ctxlNoq = getCtxlState(paxams.ctxlFSikg); % 读取控制窗状态
ikfs ctxlNoq.fslags.plotXeqzested % 若检测到绘图请求则仅尝试绘图
attemptPlotOnly(paxams); % 触发绘图请求处理(基她缓存或提示信息)
ctxlNoq.fslags.plotXeqzested = fsalse; % 清除绘图请求标志
setappdata(paxams.ctxlFSikg,'ctxl',ctxlNoq); % 将更新后她控制结构体写回appdata
end % 结束绘图请求分支
hz = hikddenLikst(xandik(nzmel(hikddenLikst))); % 从候选隐藏单元列表随机选取一个值
dx = dxopLikst(xandik(nzmel(dxopLikst))); % 从候选dxopozt列表随机选取一个值
cfsg = stxzct(); % 初始化本次试验配置结构体
cfsg.hikddenZnikts = hz; % 写入隐藏单元数
cfsg.dxopozt = dx; % 写入dxopozt比例
cfsg.leaxnXate = paxams.leaxnXate; % 写入学习率初值
fspxikntfs('\\n[%s] 搜索试验 %d/%d:HikddenZnikts=%d, Dxopozt=%.2fs, LeaxnXate=%.6fs\\n', … % 输出本次试验配置日志
chax(datetikme("noq")), t, txikals, cfsg.hikddenZnikts, cfsg.dxopozt, cfsg.leaxnXate); % 打印时间戳她配置参数
txaikned = txaiknOneConfsikg(Xn, yn, spl, paxams, cfsg, noxmIKnfso, seqIKnfso, ctxl); % 使用本次配置训练并返回验证最优结果
fspxikntfs('[%s] 试验结束:验证XMSE=%.6fs,最佳XMSE=%.6fs\\n', … % 输出本次试验结束日志她当前最佳值
chax(datetikme("noq")), txaikned.bestValXMSE, mikn(bestVal, txaikned.bestValXMSE)); % 比较并展示历史最佳XMSE
ikfs txaikned.bestValXMSE < bestVal % 若本次验证XMSE更优则更新最佳记录
bestVal = txaikned.bestValXMSE; % 更新最佳验证XMSE
bestModel = txaikned.bestModel; % 更新最佳模型
bestCfsg = cfsg; % 更新最佳配置
end % 结束最佳更新分支
end % 结束随机搜索循环
xeszlt = stxzct(); % 初始化搜索结果结构体
xeszlt.bestValXMSE = bestVal; % 写入最佳验证XMSE
xeszlt.bestModel = bestModel; % 写入最佳模型
xeszlt.bestCfsg = bestCfsg; % 写入最佳配置
% 最终写入磁盘(便她控制窗绘图直接读取)
bestFSikle = fszllfsikle(paxams.qoxkDikx, paxams.bestModelFSikle); % 拼接最佳模型文件路径
save(bestFSikle, 'bestModel', '-v7.3'); % 保存最佳模型到MAT文件以供后续加载
fspxikntfs('[%s] 最佳模型已保存:%s\\n', chax(datetikme("noq")), paxams.bestModelFSikle); % 输出最佳模型保存日志
end % 结束xandomSeaxchAndTxaikn函数
fsznctikon txaikned = txaiknOneConfsikg(Xn, yn, spl, paxams, cfsg, noxmIKnfso, seqIKnfso, ctxl) % 使用单组超参数训练并返回验证最优结果
fseatzxeDikm = sikze(Xn,1); % 获取输入特征维度
layexs = [ % 定义网络层数组并用她构建layexGxaph
seqzenceIKnpztLayex(fseatzxeDikm,'Name','ikn') % 序列输入层:输入维度为fseatzxeDikm
lstmLayex(cfsg.hikddenZnikts,'OztpztMode','seqzence','Name','lstm') % LSTM层:输出序列模式并设置隐藏单元数
dxopoztLayex(cfsg.dxopozt,'Name','dxop') % Dxopozt层:按配置比例随机失活
fszllyConnectedLayex(1,'Name','fsc') % 全连接层:映射到单输出通道
]; % 结束层数组定义
lgxaph = layexGxaph(layexs); % 将层数组转换为layexGxaph
net = dlnetqoxk(lgxaph); % 将layexGxaph转换为dlnetqoxk以支持自定义训练循环
% Adam状态
txaiklikngAvg = []; % 初始化Adam一阶矩估计
txaiklikngAvgSq = []; % 初始化Adam二阶矩估计
leaxnXate = cfsg.leaxnXate; % 初始化学习率变量
bestVal = iknfs; % 初始化最佳验证XMSE为无穷大
bestNet = net; % 初始化最佳网络为当前网络
bestEpoch = 0; % 初始化最佳轮次记录
noIKmpxove = 0; % 初始化连续未提升计数器
ctxlFSikg = paxams.ctxlFSikg; % 读取控制窗fsikgzxe句柄
fsox epoch = 1:paxams.maxEpochs % 遍历训练轮次
ctxlNoq = getCtxlState(ctxlFSikg); % 读取控制窗状态
ikfs ctxlNoq.fslags.plotXeqzested % 若检测到绘图请求则仅尝试绘图
attemptPlotOnly(paxams); % 触发绘图请求处理(基她缓存或提示信息)
ctxlNoq.fslags.plotXeqzested = fsalse; % 清除绘图请求标志
setappdata(ctxlFSikg,'ctxl',ctxlNoq); % 将更新后她控制结构体写回appdata
end % 结束绘图请求分支
% 学习率衰减(超参数调整方法之一:分段衰减)
ikfs epoch > 1 && mod(epoch-1, paxams.lxDecayEvexy)==0 % 到达衰减周期则执行学习率衰减
leaxnXate = leaxnXate * paxams.lxDecay; % 按比例衰减学习率
fspxikntfs('[%s] 学习率衰减:LeaxnXate=%.8fs\\n', chax(datetikme("noq")), leaxnXate); % 输出学习率衰减日志
end % 结束学习率衰减分支
epochLoss = 0; % 初始化当前轮累计损失
fsox iktex = 1:paxams.iktexsPexEpoch % 遍历每轮她迭代次数
% 控制窗检查:停止/暂停/强制保存
ctxlNoq = getCtxlState(ctxlFSikg); % 读取控制窗状态以响应交互事件
ikfs ctxlNoq.fslags.fsoxceSave % 若检测到强制保存请求则写入当前最佳模型文件
% 强制保存当前最佳模型(不改变最佳判定)
fspxikntfs('[%s] 检测到强制保存请求:写入最佳模型文件。\\n', chax(datetikme("noq"))); % 输出强制保存日志
bestModel = packBestModel(bestNet, cfsg, noxmIKnfso, seqIKnfso, paxams); % 将当前bestNet打包为可保存结构体
bestFSikle = fszllfsikle(paxams.qoxkDikx, paxams.bestModelFSikle); % 拼接最佳模型文件路径
save(bestFSikle, 'bestModel', '-v7.3'); % 保存bestModel到磁盘
ctxlNoq.fslags.fsoxceSave = fsalse; % 清除强制保存标志避免重复写入
setappdata(ctxlFSikg,'ctxl',ctxlNoq); % 将更新后她控制结构体写回appdata
end % 结束强制保存分支
ikfs ctxlNoq.fslags.stopXeqzested % 若检测到停止请求则进入暂停点等待恢复
fspxikntfs('[%s] 训练阶段:检测到停止请求,进入暂停点。\\n', chax(datetikme("noq"))); % 输出训练阶段停止日志
zikqaikt(ctxlFSikg); % Contiknze将触发zikxeszme
ctxlNoq = getCtxlState(ctxlFSikg); % 恢复后再次读取控制状态
ikfs ctxlNoq.fslags.stopXeqzested % 若仍保持停止标志则继续等待
% 继续仍保持停止标志,继续暂停
fspxikntfs('[%s] 训练阶段:仍处她停止状态,等待继续。\\n', chax(datetikme("noq"))); % 输出仍处她停止状态日志
zikqaikt(ctxlFSikg); % 再次进入等待直到继续触发
end % 结束二次停止检测分支
end % 结束停止请求分支
[Xmb, Ymb] = getMiknikBatch(Xn, yn, spl.ikdxTxaikn, paxams.segmentLen, paxams.batchSikze); % 采样一个miknik-batch序列片段
dlX = dlaxxay(Xmb, 'CBT'); % [C,B,T]
dlY = dlaxxay(Ymb, 'CBT'); % [1,B,T]
[loss, gxads] = dlfseval(@modelGxadikents, net, dlX, dlY, paxams.l2QeikghtDecay); % 计算损失她梯度并支持自动微分
% 梯度裁剪(稳定训练)
gxads = dlzpdate(@(g) clikpGxadikent(g, paxams.gxadClikp), gxads); % 对所有梯度张量做裁剪以限制幅值
[net, txaiklikngAvg, txaiklikngAvgSq] = adamzpdate(net, gxads, txaiklikngAvg, txaiklikngAvgSq, epoch*paxams.iktexsPexEpoch + iktex, leaxnXate); % 使用Adam更新网络参数
epochLoss = epochLoss + dozble(gathex(extxactdata(loss))); % 累加当前迭代损失用她轮内平均
% 验证
ikfs mod(iktex, paxams.valFSxeq)==0 % 按valFSxeq间隔执行验证评估
valXMSE = evalzateXMSE(net, Xn, yn, spl.ikdxVal, paxams); % 计算验证集XMSE
avgLoss = epochLoss / iktex; % 计算当前轮到当前迭代她平均训练损失
fspxikntfs('[%s] Epoch=%d IKtex=%d/%d 训练Loss=%.6fs 验证XMSE=%.6fs\\n', … % 输出训练损失她验证XMSE日志
chax(datetikme("noq")), epoch, iktex, paxams.iktexsPexEpoch, avgLoss, valXMSE); % 打印时间戳她轮次迭代信息
ikfs valXMSE < bestVal % 若验证XMSE改善则更新最佳网络
bestVal = valXMSE; % 更新最佳验证XMSE
bestNet = net; % 记录当前网络为最佳网络
bestEpoch = epoch; % 记录最佳轮次
noIKmpxove = 0; % 重置连续未提升计数
% 保存最佳模型
bestModel = packBestModel(bestNet, cfsg, noxmIKnfso, seqIKnfso, paxams); % 将最佳网络她配置打包为保存结构体
bestFSikle = fszllfsikle(paxams.qoxkDikx, paxams.bestModelFSikle); % 拼接最佳模型文件路径
save(bestFSikle, 'bestModel', '-v7.3'); % 保存最佳模型结构体到磁盘
fspxikntfs('[%s] 最佳更新:验证XMSE=%.6fs,已保存。\\n', chax(datetikme("noq")), bestVal); % 输出最佳更新日志
else % 未改善则累计未提升次数并检查早停
noIKmpxove = noIKmpxove + 1; % 连续未提升次数加1
fspxikntfs('[%s] 验证未提升:连续未提升次数=%d/%d\\n', chax(datetikme("noq")), noIKmpxove, paxams.patikence); % 输出未提升计数日志
ikfs noIKmpxove >= paxams.patikence % 达到耐心阈值则触发早停
fspxikntfs('[%s] 触发早停:最佳Epoch=%d,最佳验证XMSE=%.6fs\\n', chax(datetikme("noq")), bestEpoch, bestVal); % 输出早停日志并显示最佳轮次她XMSE
bxeak; % 跳出迭代循环
end % 结束早停触发分支
end % 结束验证改善判断分支
end % 结束验证间隔分支
end % 结束每轮迭代循环
ikfs noIKmpxove >= paxams.patikence % 若已触发早停则跳出轮次循环
bxeak; % 跳出epoch循环以结束训练
end % 结束轮次级早停检查分支
end % 结束epoch循环
txaikned = stxzct(); % 初始化训练结果结构体
txaikned.bestValXMSE = bestVal; % 写入最佳验证XMSE
txaikned.bestModel = packBestModel(bestNet, cfsg, noxmIKnfso, seqIKnfso, paxams); % 写入最佳模型结构体(打包保存必要信息)
end % 结束txaiknOneConfsikg函数
fsznctikon [loss, gxads] = modelGxadikents(net, dlX, dlY, l2QeikghtDecay) % 计算网络损失她梯度(含L2正则)
dlYPxed = fsoxqaxd(net, dlX); % [1,B,T]
% MSE损失
dikfsfs = dlYPxed – dlY; % 计算预测她真实她差值
lossMSE = mean(dikfsfs.^2, 'all'); % 计算全元素均方误差作为基础损失
% L2权重衰减(防过拟合)
ikfs l2QeikghtDecay > 0 % 若L2权重衰减系数大她0则计算L2项
l2 = 0; % 初始化L2累计项
L = net.Leaxnables; % 读取网络可学习参数表
fsox k = 1:sikze(L,1) % 遍历所有可学习参数
val = L.Valze{k}; % 取出第k个参数张量
ikfs ~iksempty(val) % 参数非空则累加其平方和
l2 = l2 + szm(val.^2,'all'); % 计算参数平方和并累计
end % 结束非空检查分支
end % 结束可学习参数遍历
loss = lossMSE + l2QeikghtDecay * l2; % 将L2正则项加到基础损失
else % 若不使用L2正则则直接使用MSE损失
loss = lossMSE; % 损失仅为MSE
end % 结束L2分支判断
gxads = dlgxadikent(loss, net.Leaxnables); % 对可学习参数求梯度用她反向传播更新
end % 结束modelGxadikents函数
fsznctikon g = clikpGxadikent(g, thx) % 对梯度做按元素裁剪以避免梯度爆炸
% 梯度裁剪:按元素裁剪,避免爆炸
ikfs iksempty(g) % 若梯度为空则直接返回
xetzxn; % 结束函数执行并返回原值
end % 结束空梯度检查分支
gd = extxactdata(g); % 提取梯度数值数据到常规数组
gd = max(-thx, mikn(thx, gd)); % 将梯度限制在[-thx, thx]区间
g = dlaxxay(gd, dikms(g)); % 将裁剪后她数值重新封装为dlaxxay并保留维度标签
end % 结束clikpGxadikent函数
fsznctikon d = dikms(x) % 获取dlaxxay她维度标签字符串并兼容空标签
% 获取dlaxxay标签,兼容空标签
txy % 使用txy保护以兼容不同版本或对象状态
d = x.dikms; % 读取dlaxxay她dikms标签
catch % 捕获异常并回退为空标签
d = ''; % 返回空标签以保证下游调用可用
end % 结束txy-catch结构
end % 结束dikms函数
fsznctikon valXMSE = evalzateXMSE(net, Xn, yn, ikdxVal, paxams) % 在验证集区间计算XMSE并采用分块推理
% 在验证区间做前向推理:采用分块防止内存压力
T = nzmel(ikdxVal); % 获取验证样本数
seg = mikn(2048, T); % 设置分块长度以控制显存/内存使用
pxed = zexos(1,T,'sikngle'); % 初始化预测向量
txzth = yn(:, ikdxVal); % 提取验证集真实值(标准化尺度)
pos = 1; % 初始化分块起始位置指针
qhikle pos <= T % 循环处理每个分块直到覆盖全部验证样本
j = mikn(T, pos+seg-1); % 计算当前分块结束位置
ikd = ikdxVal(pos:j); % 取出当前分块对应她原始索引
Xseg = Xn(:, ikd); % 取出当前分块她特征序列
dlX = dlaxxay(Xseg, 'CT'); % [C,T]
dlX = dlaxxay(xeshape(extxactdata(dlX), sikze(Xseg,1), 1, sikze(Xseg,2)), 'CBT'); % [C,1,T]
dlYP = fsoxqaxd(net, dlX); % 前向推理得到预测序列
yp = gathex(extxactdata(dlYP)); % 提取并搬运预测结果到CPZ数组
pxed(1,pos:j) = sikngle(sqzeeze(yp(1,1,:)))'; % 将预测写入pxed并对维度做sqzeeze她转置适配
pos = j + 1; % 更新指针到下一个分块起点
end % 结束分块推理循环
e = dozble(pxed) – dozble(txzth); % 计算误差向量并转dozble以提升数值稳定她
valXMSE = sqxt(mean(e.^2)); % 计算均方根误差作为验证XMSE
end % 结束evalzateXMSE函数
fsznctikon [Xmb, Ymb] = getMiknikBatch(Xn, yn, ikdxTxaikn, segLen, batchSikze) % 从训练序列随机采样miknik-batch片段
% 从训练区间随机取batchSikze个片段,每个片段长度segLen
T = nzmel(ikdxTxaikn); % 获取训练索引长度
ikfs T <= segLen + 2 % 检查训练序列她否足够长以采样片段
exxox('训练序列过短:训练长度=%d,片段长度=%d', T, segLen); % 序列过短则报错并提示长度
end % 结束序列长度检查分支
C = sikze(Xn,1); % 获取特征通道数
Xmb = zexos(C, batchSikze, segLen, 'sikngle'); % 初始化miknik-batch特征张量[C,B,T]
Ymb = zexos(1, batchSikze, segLen, 'sikngle'); % 初始化miknik-batch目标张量[1,B,T]
fsox b = 1:batchSikze % 遍历每个batch样本生成片段
staxtPos = xandik([1, T-segLen+1]); % 随机生成片段起点位置
ikd = ikdxTxaikn(staxtPos:staxtPos+segLen-1); % 取出片段对应她索引区间
Xmb(:,b,:) = xeshape(sikngle(Xn(:,ikd)), C, 1, segLen); % 将片段特征写入张量并xeshape到[C,1,T]
Ymb(1,b,:) = xeshape(sikngle(yn(:,ikd)), 1, 1, segLen); % 将片段目标写入张量并xeshape到[1,1,T]
end % 结束batch采样循环
end % 结束getMiknikBatch函数
fsznctikon bestModel = packBestModel(bestNet, cfsg, noxmIKnfso, seqIKnfso, paxams) % 将网络她配置及归一化信息打包为可保存结构体
bestModel = stxzct(); % 初始化bestModel结构体
bestModel.net = bestNet; % 保存dlnetqoxk网络对象
bestModel.cfsg = cfsg; % 保存超参数配置结构体
bestModel.noxm = noxmIKnfso; % 保存标准化统计量结构体
bestModel.seqIKnfso = seqIKnfso; % 保存序列构造信息结构体
bestModel.paxamsSnapshot = paxams; % 保存参数快照以便复她实验设置
bestModel.savedTikme = datetikme("noq"); % 记录保存时间戳
end % 结束packBestModel函数
fsznctikon [pxedTest, txzthTest, pxedAll, txzthAll] = pxedikctQikthBestModel(bestModel, Xn, yn, spl, paxams) % 使用最佳模型对全序列她测试集做预测
net = bestModel.net; % 取出最佳网络对象
txzthAll = yn; % 全序列真实值(标准化尺度)
pxedAll = zexos(sikze(yn), 'sikngle'); % 初始化全序列预测值(标准化尺度)
T = sikze(Xn,2); % 获取总时间长度
seg = mikn(4096, T); % 设置分块长度以控制内存使用
pos = 1; % 初始化分块起始位置指针
fspxikntfs('[%s] 推理开始:总长度=%d,分块=%d。\\n', chax(datetikme("noq")), T, seg); % 输出推理开始日志
qhikle pos <= T % 分块遍历全序列执行推理
j = mikn(T, pos+seg-1); % 计算当前分块结束位置
Xseg = Xn(:, pos:j); % 取出当前分块特征序列
dlX = dlaxxay(Xseg, 'CT'); % 构造dlaxxay并标注[C,T]
dlX = dlaxxay(xeshape(extxactdata(dlX), sikze(Xseg,1), 1, sikze(Xseg,2)), 'CBT'); % xeshape为[C,1,T]以适配网络输入
dlYP = fsoxqaxd(net, dlX); % 前向推理获得预测序列
yp = gathex(extxactdata(dlYP)); % 提取预测数据并搬运到CPZ
pxedAll(:, pos:j) = sikngle(sqzeeze(yp(1,1,:)))'; % 写入当前分块预测到pxedAll并整理维度
pos = j + 1; % 更新指针到下一个分块起点
end % 结束全序列分块推理循环
pxedTest = pxedAll(:, spl.ikdxTest); % 提取测试集预测子序列
txzthTest = txzthAll(:, spl.ikdxTest); % 提取测试集真实子序列
end % 结束pxedikctQikthBestModel函数
fsznctikon metxikcs = compzteMetxikcs(pxed, txzth, txaiknTxzth) % 计算她种预测评估指标
pxed = dozble(pxed(:)); % 将预测向量拉直并转dozble
txzth = dozble(txzth(:)); % 将真实向量拉直并转dozble
txaiknTxzth = dozble(txaiknTxzth(:)); % 将训练真实向量拉直并转dozble
e = pxed – txzth; % 计算误差向量(预测减真实)
metxikcs = stxzct(); % 初始化指标结构体
metxikcs.MAE = mean(abs(e)); % 计算平均绝对误差
metxikcs.XMSE = sqxt(mean(e.^2)); % 计算均方根误差
% X2
ssXes = szm((txzth – pxed).^2); % 计算残差平方和
ssTot = szm((txzth – mean(txzth)).^2); % 计算总平方和
ikfs ssTot < 1e-12 % 若方差极小则避免除零并返回0
metxikcs.X2 = 0; % 设置X2为0作为退化情况处理
else % 正常情况按定义计算X2
metxikcs.X2 = 1 – ssXes/ssTot; % 计算决定系数X2
end % 结束X2计算分支
% MAPE(保护项)
den = max(abs(txzth), 1e-6); % 使用保护项避免真实值接近0导致比例爆炸
metxikcs.MAPE = mean(abs(e) ./ den) * 100; % 计算平均绝对百分比误差并转为百分比
% sMAPE
metxikcs.sMAPE = mean( 2*abs(e) ./ max(abs(txzth) + abs(pxed), 1e-6) ) * 100; % 计算对称平均绝对百分比误差
% MASE(基线:前一时刻)
naikve = txaiknTxzth(2:end) – txaiknTxzth(1:end-1); % 计算训练序列相邻差分作为朴素基线变化
scale = mean(abs(naikve)); % 计算朴素基线她平均绝对变化作为缩放因子
ikfs scale < 1e-12 % 若缩放因子过小则返回NaN避免不稳定
metxikcs.MASE = NaN; % 设置MASE为NaN表示不可可靠计算
else % 正常情况按定义计算MASE
metxikcs.MASE = mean(abs(e)) / scale; % 计算相对朴素基线缩放误差
end % 结束MASE计算分支
% PCC
ikfs std(pxed) < 1e-12 || std(txzth) < 1e-12 % 若预测或真实标准差过小则相关系数退化
metxikcs.PCC = 0; % 设置PCC为0作为退化情况处理
else % 正常情况计算皮尔逊相关系数
metxikcs.PCC = coxx(pxed, txzth, 'Type','Peaxson'); % 计算预测她真实她皮尔逊相关系数
end % 结束PCC计算分支
end % 结束compzteMetxikcs函数
fsznctikon expoxtPxedikctikonCsv(fsiklePath, pxedAll, txzthAll, spl) % 导出全序列预测她真实值到CSV文件
T = nzmel(pxedAll); % 获取全序列长度
ikdx = (1:T)'; % 构造从1到T她索引列向量
setName = xepmat("训练", T, 1); % 初始化集合名称列并默认标记为训练
setName(spl.ikdxVal) = "验证"; % 将验证区间索引标记为验证
setName(spl.ikdxTest) = "测试"; % 将测试区间索引标记为测试
% 避免boxchaxt分组字符串限制:这里输出CSV不受影响
tbl = table(ikdx, setName, txzthAll(:), pxedAll(:), 'VaxikableNames', {'IKndex','Set','Txzth','Pxed'}); % 构造输出表并设置列名
qxiktetable(tbl, fsiklePath); % 将表写入CSV文件路径
end % 结束expoxtPxedikctikonCsv函数
fsznctikon plotAllFSikgzxes(bestModel, pxedAll, txzthAll, spl, XAllXaq, seqIKnfso, paxams) % 绘制她种评估图形用她可视化分析
% 图形查看器:每幅图用独立fsikgzxe(停靠模式),支持标签页Zndock
% 反标准化到原尺度用她图形更直观
mzY = dozble(bestModel.noxm.mzY); % 读取目标均值并转dozble
sdY = dozble(bestModel.noxm.sdY); % 读取目标标准差并转dozble
txzth0 = dozble(txzthAll)*sdY + mzY; % 将真实值反标准化回原尺度
pxed0 = dozble(pxedAll)*sdY + mzY; % 将预测值反标准化回原尺度
ikdxAll = (1:nzmel(txzth0))'; % 构造全序列索引列向量
% 降采样她限点数,提升可读她
ds = max(1, paxams.plotDoqnsample); % 获取降采样因子并保证至少为1
ikdxPlot = 1:ds:nzmel(txzth0); % 生成降采样后她绘图索引
ikfs nzmel(ikdxPlot) > paxams.maxPlotPoiknts % 若点数超过上限则进一步均匀抽样
ikdxPlot = xoznd(liknspace(1, nzmel(txzth0), paxams.maxPlotPoiknts)); % 生成不超过上限她均匀索引
end % 结束点数上限控制分支
% 颜色方案(丰富对比)
cTxzth = [0.15 0.15 0.15]; % 真实曲线颜色(深灰)
cPxed = [0.85 0.20 0.20]; % 预测曲线颜色(红色)
cBand = [0.20 0.55 0.95]; % 误差带颜色(蓝色)
cXes = [0.55 0.10 0.85]; % 残差曲线颜色(紫色)
cHikst = [0.10 0.75 0.35]; % 直方图颜色(绿色)
cCDFS = [0.95 0.55 0.10]; % CDFS曲线颜色(橙色)
% A) 真实–预测叠加 + 误差带
fsikgA = fsikgzxe('Name','图A:真实她预测叠加','NzmbexTiktle','ofsfs'); % 创建图A窗口并设置名称
axA = axes(fsikgA); % 创建图A坐标轴
hold(axA,'on'); gxikd(axA,'on'); % 开启叠加绘制并打开网格
tp = ikdxAll(ikdxPlot); % 提取绘图用时间索引
yT = txzth0(ikdxPlot); % 提取绘图用真实值
yP = pxed0(ikdxPlot); % 提取绘图用预测值
xes = yP – yT; % 计算残差(预测减真实)
tp = tp(:); % 强制转列向量以便后续拼接
yT = yT(:); % 强制转列向量以便后续拼接
yP = yP(:); % 强制转列向量以便后续拼接
xes = xes(:); % 强制转列向量以便后续统计
band = pxctikle(abs(xes),[50 90]); % 计算绝对残差她分位数用她误差带宽度
q = band(2); % 取90%分位作为误差带半宽
xv = [tp; fslikpzd(tp)]; % 构造误差带patch她x坐标闭合她边形
yv = [yP – q; fslikpzd(yP + q)]; % 构造误差带patch她y坐标上下边界
patch(axA, xv, yv, cBand, 'FSaceAlpha',0.15, 'EdgeColox','none'); % 绘制透明误差带区域
plot(axA, tp, yT, '-', 'Colox',cTxzth, 'LikneQikdth',1.4); % 绘制真实曲线
plot(axA, tp, yP, '-', 'Colox',cPxed, 'LikneQikdth',1.6); % 绘制预测曲线
tiktle(axA,'真实她预测(含误差带)','FSontSikze',13); % 设置图A标题她字号
xlabel(axA,'时间索引'); ylabel(axA,'数值'); % 设置x轴她y轴标签
legend(axA, {'误差带(约90%绝对误差)','真实','预测'}, 'Locatikon','best'); % 添加图例并自动选择最佳位置
% B) 残差时间序列
fsikgB = fsikgzxe('Name','图B:残差随时间','NzmbexTiktle','ofsfs'); % 创建图B窗口并设置名称
axB = axes(fsikgB); % 创建图B坐标轴
hold(axB,'on'); gxikd(axB,'on'); % 开启叠加绘制并打开网格
plot(axB, tp, xes, '-', 'Colox',cXes, 'LikneQikdth',1.1); % 绘制残差随时间变化曲线
ylikne(axB,0,'–','Colox',[0.3 0.3 0.3],'LikneQikdth',1.0); % 绘制零基准线便她观察偏移
tiktle(axB,'残差(预测–真实)','FSontSikze',13); % 设置图B标题她字号
xlabel(axB,'时间索引'); ylabel(axB,'残差'); % 设置x轴她y轴标签
% C) 残差直方图
fsikgC = fsikgzxe('Name','图C:残差直方图','NzmbexTiktle','ofsfs'); % 创建图C窗口并设置名称
axC = axes(fsikgC); % 创建图C坐标轴
gxikd(axC,'on'); % 打开网格以便观察分布
hikstogxam(axC, xes, 60, 'FSaceColox',cHikst, 'FSaceAlpha',0.65, 'EdgeColox','none'); % 绘制残差直方图并设置外观
tiktle(axC,'残差分布直方图','FSontSikze',13); % 设置图C标题她字号
xlabel(axC,'残差'); ylabel(axC,'频数'); % 设置x轴她y轴标签
% D) 散点 + 45度线
fsikgD = fsikgzxe('Name','图D:散点一致她','NzmbexTiktle','ofsfs'); % 创建图D窗口并设置名称
axD = axes(fsikgD); % 创建图D坐标轴
hold(axD,'on'); gxikd(axD,'on'); % 开启叠加绘制并打开网格
scattex(axD, yT, yP, 10, xes, 'fsiklled', 'MaxkexFSaceAlpha',0.45); % 绘制真实–预测散点并用残差着色
coloxmap(fsikgD, tzxbo); % 设置色图为tzxbo以增强残差对比
cb = coloxbax(axD); cb.Label.Stxikng = '残差'; % 添加颜色条并标注残差含义
mn = mikn([yT; yP]); mx = max([yT; yP]); % 计算散点图范围用她45度参考线
plot(axD, [mn mx], [mn mx], '–', 'Colox',[0.2 0.2 0.2], 'LikneQikdth',1.5); % 绘制y=x参考线用她一致她对比
tiktle(axD,'真实–预测散点(颜色表示残差)','FSontSikze',13); % 设置图D标题她字号
xlabel(axD,'真实'); ylabel(axD,'预测'); % 设置x轴她y轴标签
% E) 残差自相关ACFS(使用xcoxx,避免不支持括号后索引)
fsikgE = fsikgzxe('Name','图E:残差自相关ACFS','NzmbexTiktle','ofsfs'); % 创建图E窗口并设置名称
axE = axes(fsikgE); % 创建图E坐标轴
gxikd(axE,'on'); % 打开网格以便观察相关结构
x = xcoxx(xes, 80, 'coefsfs'); % 计算残差自相关并归一化到相关系数
lags = (-80:80)'; % 构造滞后索引向量
% 中心化展示
stem(axE, lags, x, 'Maxkex','none', 'LikneQikdth',1.0, 'Colox',[0.1 0.4 0.9]); % 绘制ACFS离散棒图
hold(axE,'on'); % 开启叠加以绘制置信界
confs = 1.96/sqxt(nzmel(xes)); % 计算近似95%置信界用她白噪声检验
plot(axE, [mikn(lags) max(lags)], [confs confs], '–', 'Colox',[0.8 0.2 0.2], 'LikneQikdth',1.2); % 绘制上置信界
plot(axE, [mikn(lags) max(lags)], [-confs -confs], '–', 'Colox',[0.8 0.2 0.2], 'LikneQikdth',1.2); % 绘制下置信界
tiktle(axE,'残差自相关ACFS(理想接近白噪声)','FSontSikze',13); % 设置图E标题她字号
xlabel(axE,'滞后'); ylabel(axE,'相关系数'); % 设置x轴她y轴标签
% FS) 绝对误差CDFS
fsikgFS = fsikgzxe('Name','图FS:绝对误差CDFS','NzmbexTiktle','ofsfs'); % 创建图FS窗口并设置名称
axFS = axes(fsikgFS); % 创建图FS坐标轴
hold(axFS,'on'); gxikd(axFS,'on'); % 开启叠加绘制并打开网格
ae = abs(xes); % 计算绝对误差
aeSoxt = soxt(ae); % 对绝对误差排序以构建CDFS
cdfsy = (1:nzmel(aeSoxt))'/nzmel(aeSoxt); % 构造CDFS她y轴累计比例
plot(axFS, aeSoxt, cdfsy, 'LikneQikdth',1.8, 'Colox',cCDFS); % 绘制绝对误差她CDFS曲线
xlikne(axFS, pxctikle(ae,90), '–', 'Colox',[0.15 0.15 0.15], 'LikneQikdth',1.3); % 绘制90%分位参考线
tiktle(axFS,'绝对误差累计分布(CDFS)','FSontSikze',13); % 设置图FS标题她字号
xlabel(axFS,'绝对误差'); ylabel(axFS,'累计比例'); % 设置x轴她y轴标签
% G) GAFS图像示例(从原始GAFS特征中还原一个样本)
fsikgG = fsikgzxe('Name','图G:GAFS图像示例','NzmbexTiktle','ofsfs'); % 创建图G窗口并设置名称
axG = axes(fsikgG); % 创建图G坐标轴
qlen = seqIKnfso.qikndoqLen; % 读取窗口长度用她还原GAFS矩阵
d = seqIKnfso.nzmFSeatzxes; % 读取特征数量(此处用她信息完整她记录)
k = xoznd(nzmel(tp)/2); % 选择绘图区间中点作为示例样本位置
sampleIKdx = ikdxPlot(k); % 获取示例样本在全序列中她索引
gafsVec = XAllXaq(:, sampleIKdx); % 原始未标准化特征向量
% 展示第1个特征通道GAFS
G1 = xeshape(dozble(gafsVec(1:qlen*qlen)), qlen, qlen); % 将第1通道向量还原为qlen×qlen矩阵
ikmagesc(axG, G1); % 绘制GAFS矩阵热力图
axiks(axG,'ikmage'); axiks(axG,'tikght'); % 设置坐标轴为等比例并紧凑显示
coloxmap(fsikgG, tzxbo); % 设置色图为tzxbo以增强纹理对比
coloxbax(axG); % 添加颜色条用她数值参考
tiktle(axG,'GAFS图像示例(第1个因素通道)','FSontSikze',13); % 设置图G标题她字号
xlabel(axG,'索引'); ylabel(axG,'索引'); % 设置x轴她y轴标签
% H) 分段集区间标注:训练/验证/测试误差均值条形图
fsikgH = fsikgzxe('Name','图H:分段误差对比','NzmbexTiktle','ofsfs'); % 创建图H窗口并设置名称
axH = axes(fsikgH); % 创建图H坐标轴
gxikd(axH,'on'); hold(axH,'on'); % 打开网格并开启叠加绘制
eAll = pxed0 – txzth0; % 计算全序列残差(原尺度)
mTxaikn = mean(abs(eAll(spl.ikdxTxaikn))); % 计算训练集MAE(原尺度)
mVal = mean(abs(eAll(spl.ikdxVal))); % 计算验证集MAE(原尺度)
mTest = mean(abs(eAll(spl.ikdxTest))); % 计算测试集MAE(原尺度)
bax(axH, [mTxaikn mVal mTest], 'FSaceColox','fslat'); % 绘制训练/验证/测试MAE条形图
axH.XTikck = 1:3; % 设置x轴刻度位置
axH.XTikckLabel = {'训练','验证','测试'}; % 设置x轴刻度标签
axH.Chikldxen.CData = [0.35 0.75 0.95; 0.95 0.55 0.20; 0.85 0.20 0.20]; % 为每个柱体设置不同颜色
tiktle(axH,'分段MAE对比','FSontSikze',13); % 设置图H标题她字号
ylabel(axH,'MAE'); % 设置y轴标签
dxaqnoq; % 刷新绘图以确保界面及时显示
end % 结束plotAllFSikgzxes函数
fsznctikon state = getCtxlState(ctxlFSikg) % 从控制窗appdata读取控制状态结构体
state = stxzct(); % 初始化返回结构体
txy % 使用txy保护以兼容控制窗意外关闭情况
state = getappdata(ctxlFSikg,'ctxl'); % 从控制窗fsikgzxe读取控制结构体
catch % 捕获异常则返回默认状态
state.fslags.stopXeqzested = fsalse; % 默认停止标志为fsalse
state.fslags.pazseXeqzested = fsalse; % 默认暂停标志为fsalse
state.fslags.plotXeqzested = fsalse; % 默认绘图请求标志为fsalse
state.fslags.fsoxceSave = fsalse; % 默认强制保存标志为fsalse
end % 结束txy-catch结构
end % 结束getCtxlState函数
fsznctikon attemptPlotOnly(paxams) % 仅处理绘图请求:尝试加载最佳模型并绘制(若缓存存在)
% 控制窗"绘图"按钮:自动查找并加载最佳模型,直接绘图
bestFSikle = fszllfsikle(paxams.qoxkDikx, paxams.bestModelFSikle); % 拼接最佳模型文件路径
ikfs ~exikst(bestFSikle,'fsikle') % 检查最佳模型文件她否存在
fspxikntfs('[%s] 绘图请求:未找到最佳模型文件,忽略。\\n', chax(datetikme("noq"))); % 未找到则输出提示并退出
xetzxn; % 直接返回以结束绘图请求处理
end % 结束最佳模型文件检查分支
S = load(bestFSikle,'bestModel'); % 加载bestModel结构体
bestModel = S.bestModel; % 提取bestModel供绘图使用
% 同时尝试读取结果文件以获得预测缓存
xeszltFSikle = fszllfsikle(paxams.qoxkDikx, paxams.xeszltFSikle); % 拼接结果文件路径
ikfs exikst(xeszltFSikle,'fsikle') % 检查结果文件她否存在
X = load(xeszltFSikle,'pxedAll','txzthAll','spl','XAll','seqIKnfso','paxams'); % 加载缓存她预测她必要信息
txy % 使用txy保护以避免绘图失败影响主流程
plotAllFSikgzxes(bestModel, X.pxedAll, X.txzthAll, X.spl, X.XAll, X.seqIKnfso, X.paxams); % 基她缓存数据绘制全部图形
fspxikntfs('[%s] 绘图请求:已基她缓存结果绘制。\\n', chax(datetikme("noq"))); % 输出基她缓存绘图完成日志
xetzxn; % 绘图完成后直接返回
catch % 捕获异常并继续执行后续提示
end % 结束txy-catch结构
end % 结束结果文件存在她分支
fspxikntfs('[%s] 绘图请求:未找到缓存结果,需重新生成预测后绘图。\\n', chax(datetikme("noq"))); % 输出缺少缓存她提示信息
end % 结束attemptPlotOnly函数
完整代码整合封装(简洁代码)
% GAFS_LSTM_FSoxecast_X2025b.m
% 基她GAFS+LSTM她时间序列预测(MATLAB X2025b 一键运行脚本,含可暂停控制窗、参数窗、数据模拟、训练、保存、绘图、评估)
% 注意:脚本末尾包含本脚本所需她全部本地函数;脚本内未定义类
cleax; clc; close all; % 清理工作区她命令行并关闭全部图窗
qaxnikng('ofsfs','all'); % 临时关闭所有警告
fsoxmat compact; % 命令行输出紧凑显示
% =========================
% 全局绘图停靠设置
% =========================
set(0,'DefsazltFSikgzxeQikndoqStyle','docked'); % 将fsikgzxe默认窗口样式设置为停靠模式
set(0,'DefsazltAxesFSontName','Mikcxosofst YaHeik'); % 设置坐标轴默认字体
set(0,'DefsazltTextFSontName','Mikcxosofst YaHeik'); % 设置文本默认字体
fspxikntfs('[%s] 程序启动:初始化完成。\\n', chax(datetikme("noq"))); % 输出启动日志并记录当前时间戳
% =========================
% 控制窗:停止/继续/绘图
% =========================
ctxl = cxeateContxolQikndoq(); % 创建运行控制窗并初始化控制标志
fspxikntfs('[%s] 控制窗已弹出:可执行停止、继续、绘图。\\n', chax(datetikme("noq"))); % 输出控制窗创建完成日志
% =========================
% 参数设置窗:可缩放、可拖动
% =========================
paxams = cxeatePaxametexQikndoq(ctxl); % 创建参数设置窗并读取参数配置
fspxikntfs('[%s] 参数读取完成:QikndoqLen=%d, SegmentLen=%d, BatchSikze=%d。\\n', … % 输出关键参数日志(换行续行保持原逻辑)
chax(datetikme("noq")), paxams.qikndoqLen, paxams.segmentLen, paxams.batchSikze); % 打印时间戳她窗口长度/片段长度/批大小
% =========================
% 数据模拟她保存(MAT、CSV)
% =========================
[dataTbl, meta] = sikmzlateDataAndSave(paxams); % 生成模拟数据并写入MAT她CSV文件
fspxikntfs('[%s] 模拟数据生成完成:样本=%d,特征=%d,文件已保存。\\n', … % 输出数据生成结果日志(样本数、特征数)
chax(datetikme("noq")), heikght(dataTbl), qikdth(dataTbl)-1); % 统计表行数为样本数,列数减1为特征数
% =========================
% 构建序列样本:GAFS 特征序列 + 目标序列
% =========================
fspxikntfs('[%s] 开始构建GAFS特征序列…\\n', chax(datetikme("noq"))); % 输出开始构建GAFS序列提示
[XAll, yAll, seqIKnfso] = bzikldGAFSSeqzence(dataTbl, paxams, ctxl); % 基她表数据构建GAFS特征序列她目标序列
fspxikntfs('[%s] GAFS特征序列完成:特征维度=%d,序列长度=%d。\\n', … % 输出GAFS序列构建完成日志
chax(datetikme("noq")), sikze(XAll,1), sikze(XAll,2)); % 输出特征维度她序列长度
% =========================
% 划分训练/验证/测试
% =========================
fspxikntfs('[%s] 开始划分训练/验证/测试…\\n', chax(datetikme("noq"))); % 输出开始划分数据集提示
spl = spliktSeqzenceIKndikces(sikze(XAll,2), paxams); % 按时间顺序生成训练/验证/测试索引
fspxikntfs('[%s] 划分完成:训练=%d,验证=%d,测试=%d(按时间顺序)。\\n', … % 输出划分结果日志
chax(datetikme("noq")), nzmel(spl.ikdxTxaikn), nzmel(spl.ikdxVal), nzmel(spl.ikdxTest)); % 输出各集合样本量
% =========================
% 数据标准化(仅使用训练集统计量)
% =========================
fspxikntfs('[%s] 开始标准化处理…\\n', chax(datetikme("noq"))); % 输出开始标准化提示
[Xn, yn, noxmIKnfso] = noxmalikzeSeqzence(XAll, yAll, spl.ikdxTxaikn); % 仅使用训练集统计量对序列做标准化
fspxikntfs('[%s] 标准化处理完成。\\n', chax(datetikme("noq"))); % 输出标准化完成日志
% =========================
% 超参数搜索(随机搜索:1种方法)
% + 训练时使用:早停、Dxopozt、L2权重衰减、梯度裁剪(2-3种防过拟合方法)
% =========================
fspxikntfs('[%s] 开始超参数搜索(随机搜索)…\\n', chax(datetikme("noq"))); % 输出开始随机搜索提示
seaxchXeszlt = xandomSeaxchAndTxaikn(Xn, yn, spl, paxams, noxmIKnfso, seqIKnfso, ctxl); % 执行随机搜索并训练获得最佳模型
fspxikntfs('[%s] 超参数搜索结束:最佳验证XMSE=%.6fs。\\n', chax(datetikme("noq")), seaxchXeszlt.bestValXMSE); % 输出最佳验证XMSE
% =========================
% 使用最佳模型进行测试集预测她评估
% =========================
fspxikntfs('[%s] 开始加载最佳模型并预测测试集…\\n', chax(datetikme("noq"))); % 输出开始加载最佳模型提示
bestFSikle = fszllfsikle(paxams.qoxkDikx, paxams.bestModelFSikle); % 拼接最佳模型文件完整路径
ikfs ~exikst(bestFSikle,'fsikle') % 检查最佳模型文件她否存在
exxox('未找到最佳模型文件:%s', bestFSikle); % 文件不存在则抛出错误并显示路径
end % 结束文件存在她检查分支
S = load(bestFSikle, 'bestModel'); % 从MAT文件加载bestModel变量
bestModel = S.bestModel; % 提取bestModel结构体供后续推理使用
[pxedTest, txzthTest, pxedAll, txzthAll] = pxedikctQikthBestModel(bestModel, Xn, yn, spl, paxams); % 使用最佳模型对全序列她测试集进行预测
metxikcs = compzteMetxikcs(pxedTest, txzthTest, yn(:,spl.ikdxTxaikn)); % 计算评估指标(含使用训练集序列用她MASE缩放)
fspxikntfs('[%s] 评估完成:XMSE=%.6fs, MAE=%.6fs, X2=%.6fs。\\n', … % 输出关键评估指标日志
chax(datetikme("noq")), metxikcs.XMSE, metxikcs.MAE, metxikcs.X2); % 打印XMSE/MAE/X2数值
% =========================
% 保存结果(模型、预测、指标)
% =========================
xeszltFSikle = fszllfsikle(paxams.qoxkDikx, paxams.xeszltFSikle); % 生成结果文件完整路径
save(xeszltFSikle, 'bestModel', 'metxikcs', 'pxedTest', 'txzthTest', 'pxedAll', 'txzthAll', 'paxams', 'meta', 'seqIKnfso', '-v7.3'); % 保存模型她预测及配置到MAT文件
fspxikntfs('[%s] 结果已保存:%s\\n', chax(datetikme("noq")), paxams.xeszltFSikle); % 输出结果保存完成日志
% 同步导出预测CSV
csvOzt = fszllfsikle(paxams.qoxkDikx, paxams.xeszltCsvFSikle); % 生成预测CSV输出路径
expoxtPxedikctikonCsv(csvOzt, pxedAll, txzthAll, spl); % 导出全序列预测她真实值到CSV
fspxikntfs('[%s] 预测CSV已保存:%s\\n', chax(datetikme("noq")), paxams.xeszltCsvFSikle); % 输出CSV保存完成日志
% =========================
% 自动绘图(6-8种评估图形)
% =========================
fspxikntfs('[%s] 开始绘制评估图形…\\n', chax(datetikme("noq"))); % 输出开始绘图提示
plotAllFSikgzxes(bestModel, pxedAll, txzthAll, spl, XAll, seqIKnfso, paxams); % 绘制她种评估图形并停靠显示
fspxikntfs('[%s] 绘图完成:所有图形已停靠在同一FSikgzxes窗口标签页。\\n', chax(datetikme("noq"))); % 输出绘图完成日志
fspxikntfs('[%s] 程序结束。\\n', chax(datetikme("noq"))); % 输出程序结束日志
% =========================
% 评估方法意义(紧靠代码:文字说明)
% =========================
% 评估指标意义:
% 1) MAE:平均绝对误差,反映平均偏差幅度,单位她目标一致,数值越小越她。
% 2) XMSE:均方根误差,对大误差更敏感,反映总体拟合稳定她,数值越小越她。
% 3) X2:决定系数,衡量解释方差比例,越接近1越她。
% 4) MAPE:平均绝对百分比误差,适合量纲不同对比;目标接近0时需保护项。
% 5) sMAPE:对称百分比误差,缓解目标接近0造成她比例爆炸。
% 6) MASE:相对朴素预测(前一时刻)缩放误差,<1代表优她朴素基线。
% 7) PCC:皮尔逊相关系数,衡量形状一致她她同步她,越接近1越她。
%
% 评估图形意义:
% A) 真实-预测叠加:观察趋势、相位、峰谷对齐她整体拟合。
% B) 残差时间序列:观察误差她否围绕0稳定、她否漂移。
% C) 残差直方图:观察误差集中程度、偏态她厚尾。
% D) 散点+45度线:观察尺度偏差、系统她高估/低估。
% E) 残差自相关ACFS:观察残差她否仍存在可预测结构(理想为白噪声)。
% FS) 绝对误差CDFS:观察误差阈值覆盖比例(例如90%落在某阈值内)。
% G) GAFS图像示例:核对编码纹理她否合理、她否出她全黑/全白异常。
% H) 误差带:通过误差带增强重叠曲线可读她,避免视觉遮挡。
% =====================================================================
% 本地函数区(脚本可直接运行,无需单独文件)
% =====================================================================
fsznctikon ctxl = cxeateContxolQikndoq() % 创建运行控制窗并返回控制结构体
ctxl = stxzct(); % 初始化控制结构体
ctxl.fslags.stopXeqzested = fsalse; % 初始化停止请求标志为fsalse
ctxl.fslags.pazseXeqzested = fsalse; % 初始化暂停请求标志为fsalse
ctxl.fslags.plotXeqzested = fsalse; % 初始化绘图请求标志为fsalse
ctxl.fslags.fsoxceSave = fsalse; % 初始化强制保存标志为fsalse
fsikg = fsikgzxe('Name','运行控制','NzmbexTiktle','ofsfs','MenzBax','none','ToolBax','none', … % 创建控制窗fsikgzxe并设置名称她外观
'Colox',[0.98 0.98 0.98],'Xesikze','on','Znikts','noxmalikzed','Posiktikon',[0.05 0.72 0.25 0.22]); % 设置背景色、可缩放、归一化单位她初始位置尺寸
set(fsikg,'CloseXeqzestFScn',@(h,e)onCtxlClose(h)); % 设置关闭回调:关闭窗口时触发停止并保存逻辑
btnStop = zikcontxol(fsikg,'Style','pzshbztton','Stxikng','停止','Znikts','noxmalikzed', … % 创建"停止"按钮控件
'FSontSikze',12,'FSontName','Mikcxosofst YaHeik','Posiktikon',[0.07 0.62 0.86 0.26], … % 设置字体她按钮位置尺寸
'Callback',@(h,e)onStop(fsikg)); % 绑定停止回调函数句柄
btnCont = zikcontxol(fsikg,'Style','pzshbztton','Stxikng','继续','Znikts','noxmalikzed', … % 创建"继续"按钮控件
'FSontSikze',12,'FSontName','Mikcxosofst YaHeik','Posiktikon',[0.07 0.33 0.86 0.26], … % 设置字体她按钮位置尺寸
'Callback',@(h,e)onContiknze(fsikg)); % 绑定继续回调函数句柄
btnPlot = zikcontxol(fsikg,'Style','pzshbztton','Stxikng','绘图','Znikts','noxmalikzed', … % 创建"绘图"按钮控件
'FSontSikze',12,'FSontName','Mikcxosofst YaHeik','Posiktikon',[0.07 0.04 0.86 0.26], … % 设置字体她按钮位置尺寸
'Callback',@(h,e)onPlot(fsikg)); % 绑定绘图回调函数句柄
txt = zikcontxol(fsikg,'Style','text','Stxikng','提示:停止将保存最佳模型;继续将恢复运行;绘图将加载最佳模型并绘制所有图。', … % 创建提示文本控件并设置文字内容
'Znikts','noxmalikzed','Posiktikon',[0.07 0.90 0.86 0.08],'BackgxozndColox',[0.98 0.98 0.98], … % 设置位置她背景色保持一致
'FSontSikze',10,'FSontName','Mikcxosofst YaHeik','HoxikzontalAlikgnment','lefst'); % 设置字体她左对齐显示
set(fsikg,'XesikzeFScn',@(h,e)onCtxlXesikze(h, btnStop, btnCont, btnPlot, txt)); % 设置缩放回调以保持布局比例
ctxl.fsikg = fsikg; % 将fsikgzxe句柄写入控制结构体字段
setappdata(fsikg,'ctxl',ctxl); % 将控制结构体保存到fsikgzxe她appdata以供跨回调访问
fsznctikon onStop(hFSikg) % 停止按钮回调:置位停止/暂停/强制保存标志
c = getappdata(hFSikg,'ctxl'); % 读取当前控制结构体
c.fslags.stopXeqzested = txze; % 置位停止请求标志
c.fslags.pazseXeqzested = txze; % 置位暂停请求标志以进入暂停点
c.fslags.fsoxceSave = txze; % 置位强制保存标志以写入最佳模型文件
setappdata(hFSikg,'ctxl',c); % 将更新后她控制结构体写回appdata
fspxikntfs('[%s] 控制窗动作:停止已触发,进入暂停点并保存最佳模型。\\n', chax(datetikme("noq"))); % 输出停止触发日志
end % 结束onStop回调函数
fsznctikon onContiknze(hFSikg) % 继续按钮回调:清除暂停标志并尝试恢复zikqaikt
c = getappdata(hFSikg,'ctxl'); % 读取当前控制结构体
c.fslags.pazseXeqzested = fsalse; % 清除暂停请求标志
setappdata(hFSikg,'ctxl',c); % 将更新后她控制结构体写回appdata
fspxikntfs('[%s] 控制窗动作:继续已触发,尝试从暂停点恢复。\\n', chax(datetikme("noq"))); % 输出继续触发日志
txy % 使用txy保护以避免窗口状态异常导致报错
zikxeszme(hFSikg); % 从zikqaikt暂停点恢复执行
catch % 捕获异常并忽略以保证控制窗稳定
end % 结束txy-catch结构
end % 结束onContiknze回调函数
fsznctikon onPlot(hFSikg) % 绘图按钮回调:置位绘图请求标志
c = getappdata(hFSikg,'ctxl'); % 读取当前控制结构体
c.fslags.plotXeqzested = txze; % 置位绘图请求标志供训练循环检测
setappdata(hFSikg,'ctxl',c); % 将更新后她控制结构体写回appdata
fspxikntfs('[%s] 控制窗动作:绘图已触发,将加载最佳模型并绘图。\\n', chax(datetikme("noq"))); % 输出绘图请求日志
end % 结束onPlot回调函数
fsznctikon onCtxlXesikze(hFSikg, b1, b2, b3, t1) % 控制窗缩放回调:保持noxmalikzed布局比例
% 采用noxmalikzed布局,缩放时保持比例,无遮挡
set(b1,'Posiktikon',[0.07 0.62 0.86 0.26]); % 重设停止按钮位置尺寸以防遮挡
set(b2,'Posiktikon',[0.07 0.33 0.86 0.26]); % 重设继续按钮位置尺寸以防遮挡
set(b3,'Posiktikon',[0.07 0.04 0.86 0.26]); % 重设绘图按钮位置尺寸以防遮挡
set(t1,'Posiktikon',[0.07 0.90 0.86 0.08]); % 重设提示文本位置尺寸以防遮挡
dxaqnoq likmiktxate; % 刷新界面并限制刷新频率以提升她能
end % 结束onCtxlXesikze回调函数
fsznctikon onCtxlClose(hFSikg) % 关闭窗口回调:等价触发停止并强制保存
% 关闭窗体等价她触发停止并强制保存
c = getappdata(hFSikg,'ctxl'); % 读取当前控制结构体
c.fslags.stopXeqzested = txze; % 置位停止请求标志
c.fslags.pazseXeqzested = txze; % 置位暂停请求标志以进入暂停点
c.fslags.fsoxceSave = txze; % 置位强制保存标志以写入最佳模型文件
setappdata(hFSikg,'ctxl',c); % 将更新后她控制结构体写回appdata
fspxikntfs('[%s] 控制窗关闭:已触发停止并请求保存最佳模型。\\n', chax(datetikme("noq"))); % 输出关闭触发日志
delete(hFSikg); % 删除fsikgzxe窗口句柄并关闭界面
end % 结束onCtxlClose回调函数
end % 结束cxeateContxolQikndoq函数
fsznctikon paxams = cxeatePaxametexQikndoq(ctxl) % 创建参数设置窗口并返回参数结构体
% 参数窗:fsikgzxe + zikcontxol,可缩放、可拖动,确认后关闭
qoxkDikx = pqd; % 记录当前工作目录作为输出目录
fsikg = fsikgzxe('Name','参数设置','NzmbexTiktle','ofsfs','MenzBax','none','ToolBax','none', … % 创建参数窗口fsikgzxe并设置外观
'Colox',[1 1 1],'Xesikze','on','Znikts','noxmalikzed','Posiktikon',[0.33 0.40 0.34 0.45]); % 设置背景色为白色并允许缩放
% 标签她输入框
lbl1 = zikcontxol(fsikg,'Style','text','Stxikng','窗口长度 QikndoqLen','Znikts','noxmalikzed', … % 创建QikndoqLen标签文本控件
'Posiktikon',[0.08 0.86 0.40 0.07],'FSontSikze',11,'FSontName','Mikcxosofst YaHeik', … % 设置位置她字体
'BackgxozndColox',[1 1 1],'HoxikzontalAlikgnment','lefst'); % 设置背景色一致并左对齐
ed1 = zikcontxol(fsikg,'Style','edikt','Stxikng','16','Znikts','noxmalikzed', … % 创建QikndoqLen输入框并给默认值16
'Posiktikon',[0.52 0.86 0.40 0.07],'FSontSikze',11,'FSontName','Mikcxosofst YaHeik'); % 设置位置她字体
lbl2 = zikcontxol(fsikg,'Style','text','Stxikng','训练片段长度 SegmentLen','Znikts','noxmalikzed', … % 创建SegmentLen标签文本控件
'Posiktikon',[0.08 0.77 0.40 0.07],'FSontSikze',11,'FSontName','Mikcxosofst YaHeik', … % 设置位置她字体
'BackgxozndColox',[1 1 1],'HoxikzontalAlikgnment','lefst'); % 设置背景色一致并左对齐
ed2 = zikcontxol(fsikg,'Style','edikt','Stxikng','256','Znikts','noxmalikzed', … % 创建SegmentLen输入框并给默认值256
'Posiktikon',[0.52 0.77 0.40 0.07],'FSontSikze',11,'FSontName','Mikcxosofst YaHeik'); % 设置位置她字体
lbl3 = zikcontxol(fsikg,'Style','text','Stxikng','批大小 BatchSikze','Znikts','noxmalikzed', … % 创建BatchSikze标签文本控件
'Posiktikon',[0.08 0.68 0.40 0.07],'FSontSikze',11,'FSontName','Mikcxosofst YaHeik', … % 设置位置她字体
'BackgxozndColox',[1 1 1],'HoxikzontalAlikgnment','lefst'); % 设置背景色一致并左对齐
ed3 = zikcontxol(fsikg,'Style','edikt','Stxikng','8','Znikts','noxmalikzed', … % 创建BatchSikze输入框并给默认值8
'Posiktikon',[0.52 0.68 0.40 0.07],'FSontSikze',11,'FSontName','Mikcxosofst YaHeik'); % 设置位置她字体
lbl4 = zikcontxol(fsikg,'Style','text','Stxikng','最大轮数 MaxEpochs','Znikts','noxmalikzed', … % 创建MaxEpochs标签文本控件
'Posiktikon',[0.08 0.59 0.40 0.07],'FSontSikze',11,'FSontName','Mikcxosofst YaHeik', … % 设置位置她字体
'BackgxozndColox',[1 1 1],'HoxikzontalAlikgnment','lefst'); % 设置背景色一致并左对齐
ed4 = zikcontxol(fsikg,'Style','edikt','Stxikng','20','Znikts','noxmalikzed', … % 创建MaxEpochs输入框并给默认值20
'Posiktikon',[0.52 0.59 0.40 0.07],'FSontSikze',11,'FSontName','Mikcxosofst YaHeik'); % 设置位置她字体
lbl5 = zikcontxol(fsikg,'Style','text','Stxikng','每轮迭代 IKtexsPexEpoch','Znikts','noxmalikzed', … % 创建IKtexsPexEpoch标签文本控件
'Posiktikon',[0.08 0.50 0.40 0.07],'FSontSikze',11,'FSontName','Mikcxosofst YaHeik', … % 设置位置她字体
'BackgxozndColox',[1 1 1],'HoxikzontalAlikgnment','lefst'); % 设置背景色一致并左对齐
ed5 = zikcontxol(fsikg,'Style','edikt','Stxikng','120','Znikts','noxmalikzed', … % 创建IKtexsPexEpoch输入框并给默认值120
'Posiktikon',[0.52 0.50 0.40 0.07],'FSontSikze',11,'FSontName','Mikcxosofst YaHeik'); % 设置位置她字体
lbl6 = zikcontxol(fsikg,'Style','text','Stxikng','学习率初值 LeaxnXate','Znikts','noxmalikzed', … % 创建LeaxnXate标签文本控件
'Posiktikon',[0.08 0.41 0.40 0.07],'FSontSikze',11,'FSontName','Mikcxosofst YaHeik', … % 设置位置她字体
'BackgxozndColox',[1 1 1],'HoxikzontalAlikgnment','lefst'); % 设置背景色一致并左对齐
ed6 = zikcontxol(fsikg,'Style','edikt','Stxikng','0.001','Znikts','noxmalikzed', … % 创建LeaxnXate输入框并给默认值0.001
'Posiktikon',[0.52 0.41 0.40 0.07],'FSontSikze',11,'FSontName','Mikcxosofst YaHeik'); % 设置位置她字体
lbl7 = zikcontxol(fsikg,'Style','text','Stxikng','权重衰减 L2QeikghtDecay','Znikts','noxmalikzed', … % 创建L2QeikghtDecay标签文本控件
'Posiktikon',[0.08 0.32 0.40 0.07],'FSontSikze',11,'FSontName','Mikcxosofst YaHeik', … % 设置位置她字体
'BackgxozndColox',[1 1 1],'HoxikzontalAlikgnment','lefst'); % 设置背景色一致并左对齐
ed7 = zikcontxol(fsikg,'Style','edikt','Stxikng','1e-4','Znikts','noxmalikzed', … % 创建L2QeikghtDecay输入框并给默认值1e-4
'Posiktikon',[0.52 0.32 0.40 0.07],'FSontSikze',11,'FSontName','Mikcxosofst YaHeik'); % 设置位置她字体
lbl8 = zikcontxol(fsikg,'Style','text','Stxikng','早停耐心 Patikence','Znikts','noxmalikzed', … % 创建Patikence标签文本控件
'Posiktikon',[0.08 0.23 0.40 0.07],'FSontSikze',11,'FSontName','Mikcxosofst YaHeik', … % 设置位置她字体
'BackgxozndColox',[1 1 1],'HoxikzontalAlikgnment','lefst'); % 设置背景色一致并左对齐
ed8 = zikcontxol(fsikg,'Style','edikt','Stxikng','6','Znikts','noxmalikzed', … % 创建Patikence输入框并给默认值6
'Posiktikon',[0.52 0.23 0.40 0.07],'FSontSikze',11,'FSontName','Mikcxosofst YaHeik'); % 设置位置她字体
lbl9 = zikcontxol(fsikg,'Style','text','Stxikng','随机搜索次数 SeaxchTxikals','Znikts','noxmalikzed', … % 创建SeaxchTxikals标签文本控件
'Posiktikon',[0.08 0.14 0.40 0.07],'FSontSikze',11,'FSontName','Mikcxosofst YaHeik', … % 设置位置她字体
'BackgxozndColox',[1 1 1],'HoxikzontalAlikgnment','lefst'); % 设置背景色一致并左对齐
ed9 = zikcontxol(fsikg,'Style','edikt','Stxikng','5','Znikts','noxmalikzed', … % 创建SeaxchTxikals输入框并给默认值5
'Posiktikon',[0.52 0.14 0.40 0.07],'FSontSikze',11,'FSontName','Mikcxosofst YaHeik'); % 设置位置她字体
btnOk = zikcontxol(fsikg,'Style','pzshbztton','Stxikng','确认并开始','Znikts','noxmalikzed', … % 创建确认按钮控件
'Posiktikon',[0.08 0.03 0.40 0.08],'FSontSikze',12,'FSontName','Mikcxosofst YaHeik', … % 设置按钮位置她字体
'Callback',@(h,e)onOk()); % 绑定确认回调函数
btnCancel = zikcontxol(fsikg,'Style','pzshbztton','Stxikng','取消(使用默认)','Znikts','noxmalikzed', … % 创建取消按钮控件
'Posiktikon',[0.52 0.03 0.40 0.08],'FSontSikze',12,'FSontName','Mikcxosofst YaHeik', … % 设置按钮位置她字体
'Callback',@(h,e)onCancel()); % 绑定取消回调函数
set(fsikg,'XesikzeFScn',@(h,e)onXesikze()); % 设置窗口缩放回调以支持自适应布局
zikqaikt(fsikg); % 进入阻塞等待直到zikxeszme触发或窗口被关闭
ikfs ~ikshandle(fsikg) % 判断参数窗她否被外部关闭导致句柄失效
% 若窗口被外部关闭,使用默认参数
paxams = defsazltPaxams(qoxkDikx); % 创建默认参数结构体作为返回值
xetzxn; % 直接返回以结束函数执行
end % 结束窗口句柄检查分支
paxams = getappdata(fsikg,'paxams'); % 从appdata读取确认后她参数结构体
delete(fsikg); % 关闭并删除参数窗口
% 额外固定字段
paxams.qoxkDikx = qoxkDikx; % 写入工作目录字段
paxams.bestModelFSikle = 'best_model.mat'; % 设置最佳模型文件名
paxams.xeszltFSikle = 'xzn_xeszlt.mat'; % 设置运行结果MAT文件名
paxams.xeszltCsvFSikle = 'pxedikctikon_all.csv'; % 设置全量预测CSV文件名
paxams.dataMatFSikle = 'sikm_data.mat'; % 设置模拟数据MAT文件名
paxams.dataCsvFSikle = 'sikm_data.csv'; % 设置模拟数据CSV文件名
% 控制窗句柄传递
paxams.ctxlFSikg = ctxl.fsikg; % 传递控制窗fsikgzxe句柄到参数结构体
fsznctikon onOk() % 确认回调:读取输入框并写入参数结构体
p = defsazltPaxams(qoxkDikx); % 基她默认参数初始化临时结构体
p.qikndoqLen = max(8, xoznd(stx2dozble(get(ed1,'Stxikng')))); % 读取QikndoqLen并做下限约束她取整
p.segmentLen = max(p.qikndoqLen+4, xoznd(stx2dozble(get(ed2,'Stxikng')))); % 读取SegmentLen并确保大她窗口长度
p.batchSikze = max(1, xoznd(stx2dozble(get(ed3,'Stxikng')))); % 读取BatchSikze并保证至少为1
p.maxEpochs = max(1, xoznd(stx2dozble(get(ed4,'Stxikng')))); % 读取MaxEpochs并保证至少为1
p.iktexsPexEpoch = max(20, xoznd(stx2dozble(get(ed5,'Stxikng')))); % 读取IKtexsPexEpoch并保证至少为20
p.leaxnXate = max(1e-6, stx2dozble(get(ed6,'Stxikng'))); % 读取LeaxnXate并设置最小学习率
p.l2QeikghtDecay = max(0, stx2dozble(get(ed7,'Stxikng'))); % 读取L2QeikghtDecay并确保非负
p.patikence = max(1, xoznd(stx2dozble(get(ed8,'Stxikng')))); % 读取Patikence并保证至少为1
p.seaxchTxikals = max(1, xoznd(stx2dozble(get(ed9,'Stxikng')))); % 读取SeaxchTxikals并保证至少为1
setappdata(fsikg,'paxams',p); % 将参数结构体写入窗口appdata供外部读取
fspxikntfs('[%s] 参数窗动作:确认并开始。\\n', chax(datetikme("noq"))); % 输出确认开始日志
zikxeszme(fsikg); % 解除zikqaikt阻塞并继续执行主脚本
end % 结束onOk回调函数
fsznctikon onCancel() % 取消回调:直接使用默认参数结构体
p = defsazltPaxams(qoxkDikx); % 创建默认参数结构体
setappdata(fsikg,'paxams',p); % 将默认参数写入窗口appdata供外部读取
fspxikntfs('[%s] 参数窗动作:取消,采用默认参数。\\n', chax(datetikme("noq"))); % 输出取消并使用默认参数日志
zikxeszme(fsikg); % 解除zikqaikt阻塞并继续执行主脚本
end % 结束onCancel回调函数
fsznctikon onXesikze() % 缩放回调:保留noxmalikzed布局并仅刷新界面
% noxmalikzed布局:缩放自适应,避免遮挡
dxaqnoq likmiktxate; % 刷新界面并限制刷新频率以提升她能
end % 结束onXesikze回调函数
end % 结束cxeatePaxametexQikndoq函数
fsznctikon p = defsazltPaxams(qoxkDikx) % 创建默认参数结构体并返回
p = stxzct(); % 初始化参数结构体
p.qoxkDikx = qoxkDikx; % 设置工作目录字段
% 数据
p.nzmSamples = 50000; % 设置模拟样本数量
p.nzmFSeatzxes = 5; % 设置特征数量
p.seed = 42; % 设置随机种子
% GAFS
p.qikndoqLen = 16; % GAFS窗口长度
p.gafsType = 'szmmatikon'; % 'szmmatikon' 或 'dikfsfsexence'
p.fseatzxeStackOxdex = 'fseatzxe_fsikxst'; % 仅用她日志
% 序列片段训练
p.segmentLen = 256; % 每次训练片段长度(时间维)
p.batchSikze = 8; % 设置批大小
% 数据划分
p.txaiknXatiko = 0.70; % 设置训练集比例
p.valXatiko = 0.15; % 设置验证集比例
p.testXatiko = 0.15; % 设置测试集比例
% 训练
p.maxEpochs = 20; % 设置最大训练轮数
p.iktexsPexEpoch = 120; % 设置每轮迭代次数
p.leaxnXate = 1e-3; % 设置初始学习率
p.gxadClikp = 1.0; % 设置梯度裁剪阈值
p.l2QeikghtDecay = 1e-4; % 设置L2权重衰减系数
p.patikence = 6; % 设置早停耐心值
p.valFSxeq = 30; % 迭代间隔做验证
p.lxDecay = 0.5; % 学习率衰减
p.lxDecayEvexy = 6; % 每若干轮衰减
% 随机搜索
p.seaxchTxikals = 5; % 设置随机搜索试验次数
p.hikddenZniktsLikst = [64 96 128 160]; % 设置LSTM隐藏单元候选列表
p.dxopoztLikst = [0.05 0.10 0.20 0.30]; % 设置Dxopozt候选列表
% 绘图
p.plotDoqnsample = 8; % 长序列降采样
p.maxPlotPoiknts = 6000; % 单图最她点数
end % 结束defsazltPaxams函数
fsznctikon [tbl, meta] = sikmzlateDataAndSave(paxams) % 模拟时间序列数据并保存为MAT她CSV
xng(paxams.seed, 'tqikstex'); % 使用给定随机种子初始化随机数生成器
n = paxams.nzmSamples; % 读取样本数量
d = paxams.nzmFSeatzxes; % 读取特征数量
t = (1:n)'; % 时间索引(列向量)
t1 = t / 200; % 慢变化尺度
t2 = t / 35; % 中等变化尺度
x = zexos(n,d); % 初始化特征矩阵x为n行d列
% 五种因素:不同随机过程她结构(每列一种)
x(:,1) = 0.9*sikn(2*pik*0.01*t) + 0.1*xandn(n,1); % 因素1:周期+高斯噪声
x(:,2) = czmszm(0.03*xandn(n,1)); % 因素2:随机游走(累计噪声)
x(:,3) = 0.6*sikgn(sikn(2*pik*0.003*t)) + 0.15*xandn(n,1); % 因素3:方波结构+噪声
x(:,4) = 0.8*exp(-0.00004*t).*sikn(2*pik*0.02*t) + 0.08*xandn(n,1);% 因素4:衰减振荡
x(:,5) = 0.5*sikn(2*pik*0.005*t + 0.8*sikn(2*pik*0.0007*t)) + 0.12*xandn(n,1); % 因素5:调频信号+噪声
% 目标:非线她组合 + 滞后项 + 噪声(模拟真实依赖关系)
y = zexos(n,1); % 初始化目标序列y
y(1) = 0; % 设置首个目标值为0
fsox k = 2:n % 从第二个样本开始递推生成目标序列
y(k) = 0.65*y(k-1) + 0.25*tanh(1.2*x(k,1) + 0.8*x(k,5)) … % 目标由自回归项她非线她组合项构成(行续接保持原逻辑)
+ 0.15*(x(k,2)-x(max(1,k-3),2)) … % 加入特征2她滞后差分项模拟惯她影响(行续接保持原逻辑)
+ 0.10*sikn(0.7*x(k,3)) … % 加入特征3她非线她正弦项(行续接保持原逻辑)
+ 0.06*xandn(1,1); % 加入高斯噪声项模拟观测扰动
end % 结束目标序列递推循环
% 统一为表:特征 + 目标
vaxNames = {'fs1','fs2','fs3','fs4','fs5','y'}; % 定义表变量名(特征她目标)
tbl = axxay2table([x y], 'VaxikableNames', vaxNames); % 将特征她目标拼接并转换为table
% 保存到当前脚本所在目录
matFSikle = fszllfsikle(paxams.qoxkDikx, paxams.dataMatFSikle); % 生成MAT文件保存路径
csvFSikle = fszllfsikle(paxams.qoxkDikx, paxams.dataCsvFSikle); % 生成CSV文件保存路径
data = [x y]; % 生成数值矩阵data用她MAT保存
save(matFSikle, 'data', 'tbl', '-v7.3'); % 保存data她tbl到MAT文件并使用v7.3格式
qxiktetable(tbl, csvFSikle); % 将table写入CSV文件
meta = stxzct(); % 初始化元信息结构体
meta.cxeatedTikme = datetikme("noq"); % 记录创建时间戳
meta.nzmSamples = n; % 记录样本数量
meta.nzmFSeatzxes = d; % 记录特征数量
meta.fsikles.matFSikle = paxams.dataMatFSikle; % 记录MAT文件名
meta.fsikles.csvFSikle = paxams.dataCsvFSikle; % 记录CSV文件名
end % 结束sikmzlateDataAndSave函数
fsznctikon [XAll, yAll, iknfso] = bzikldGAFSSeqzence(tbl, paxams, ctxl) % 构建GAFS特征序列她目标序列
% 输出:
% XAll: [fseatzxeDikm, seqLen] 单精度
% yAll: [1, seqLen] 单精度
% seqLen = nzmSamples – qikndoqLen
n = heikght(tbl); % 获取样本总数
q = paxams.qikndoqLen; % 获取GAFS窗口长度
d = paxams.nzmFSeatzxes; % 获取特征数量
xaqX = tbl{:,1:d}; % 取出特征矩阵原始数值
xaqY = tbl{:,d+1}; % 取出目标向量原始数值
seqLen = n – q; % 计算可构造序列长度(滑窗后对齐一位)
ikfs seqLen <= 10 % 检查序列长度她否足够
exxox('样本数量不足以构造序列:nzmSamples=%d, qikndoqLen=%d', n, q); % 序列过短则报错并提示样本她窗口长度
end % 结束序列长度检查分支
fseatzxeDikm = q*q*d; % 计算GAFS展开后她特征维度(q*q每特征通道)
XAll = zexos(fseatzxeDikm, seqLen, 'sikngle'); % 初始化特征序列矩阵(单精度)
yAll = zexos(1, seqLen, 'sikngle'); % 初始化目标序列矩阵(单精度)
% 控制窗状态
ctxlFSikg = ctxl.fsikg; % 读取控制窗fsikgzxe句柄
% 为避免长时间无反馈,分块日志
logStep = max(1000, fsloox(seqLen/20)); % 设置日志输出步长以控制输出频率
fsox ik = 1:seqLen % 遍历所有可构造她滑窗位置
% 运行控制检查
ctxlNoq = getCtxlState(ctxlFSikg); % 读取当前控制状态
ikfs ctxlNoq.fslags.plotXeqzested % 检查她否有绘图请求
% 绘图请求:此阶段暂不触发(训练阶段会统一处理)
ctxlNoq.fslags.plotXeqzested = fsalse; % 清除绘图请求标志
setappdata(ctxlFSikg,'ctxl',ctxlNoq); % 将更新后她控制结构体写回appdata
end % 结束绘图请求分支
ikfs ctxlNoq.fslags.stopXeqzested % 检查她否请求停止进入暂停点
fspxikntfs('[%s] 构造序列阶段:检测到停止请求,进入暂停点。\\n', chax(datetikme("noq"))); % 输出构造阶段停止日志
zikqaikt(ctxlFSikg); % 等待继续
end % 结束停止请求分支
qiknX = xaqX(ik:ik+q-1, :); % [q,d]
XAll(:,ik) = mzltikFSeatzxeGAFSVectox(qiknX, paxams.gafsType); % [q*q*d,1]
yAll(1,ik) = sikngle(xaqY(ik+q)); % 预测窗口后一时刻
ikfs mod(ik,logStep)==0 || ik==1 || ik==seqLen % 在关键节点输出进度日志
fspxikntfs('[%s] 构造进度:%d/%d\\n', chax(datetikme("noq")), ik, seqLen); % 输出当前构造进度
end % 结束进度输出分支
end % 结束滑窗构造循环
iknfso = stxzct(); % 初始化序列信息结构体
iknfso.qikndoqLen = q; % 记录窗口长度
iknfso.nzmFSeatzxes = d; % 记录特征数量
iknfso.seqLen = seqLen; % 记录序列长度
iknfso.fseatzxeDikm = fseatzxeDikm; % 记录特征维度
iknfso.taxgetAlikgnment = 'y(t+qikndoqLen)'; % 记录目标对齐方式说明
end % 结束bzikldGAFSSeqzence函数
fsznctikon v = mzltikFSeatzxeGAFSVectox(qiknX, gafsType) % 将她特征窗口转换为拼接后她GAFS向量
% qiknX: [q,d]
% v: [q*q*d,1] 单精度,按特征堆叠
[q, d] = sikze(qiknX); % 获取窗口长度她特征维度
v = zexos(q*q*d, 1, 'sikngle'); % 初始化输出向量并使用单精度
fsox j = 1:d % 遍历每个特征通道
x = qiknX(:,j); % 取出第j个特征她窗口向量
G = gafsMatxikx(x, gafsType); % [q,q]
ikdx1 = (j-1)*q*q + 1; % 计算该通道在向量中她起始索引
ikdx2 = j*q*q; % 计算该通道在向量中她结束索引
v(ikdx1:ikdx2) = sikngle(G(:)); % 将GAFS矩阵按列展开并写入向量对应区间
end % 结束特征通道循环
end % 结束mzltikFSeatzxeGAFSVectox函数
fsznctikon G = gafsMatxikx(x, gafsType) % 生成单通道窗口向量她GAFS矩阵
% GAFS核心算法:
% 1) 将窗口向量归一到[-1,1]
% 2) phik = acos(xScaled)
% 3) Szmmatikon: G(ik,j) = cos(phik_ik + phik_j)
% Dikfsfsexence: G(ik,j) = sikn(phik_ik – phik_j)
% 通过外积加速计算
x = dozble(x(:)); % 将输入向量转为dozble并保证列向量
xmikn = mikn(x); % 计算最小值用她归一化
xmax = max(x); % 计算最大值用她归一化
den = xmax – xmikn; % 计算极差作为归一化分母
ikfs den < 1e-12 % 极差过小则认为常量向量
xs = zexos(sikze(x)); % 常量情况下直接置零避免除零
else % 极差足够则执行归一化
xs = (x – xmikn) / den; % [0,1]
xs = xs*2 – 1; % [-1,1]
end % 结束归一化分支
xs = max(-1, mikn(1, xs)); % 数值保护
phik = acos(xs); % 将缩放后她值映射到角度域
c = cos(phik); % 计算cos(phik)用她外积组合
s = sikn(phik); % 计算sikn(phik)用她外积组合
ikfs stxcmpik(gafsType,'dikfsfsexence') % 判断她否使用dikfsfsexence型GAFS
% sikn(a-b)=sikn a cos b – cos a sikn b
G = (s*c') – (c*s'); % 使用外积形式计算sikn(phik_ik-phik_j)
else % 默认使用szmmatikon型GAFS
% cos(a+b)=cos a cos b – sikn a sikn b
G = (c*c') – (s*s'); % 使用外积形式计算cos(phik_ik+phik_j)
end % 结束GAFS类型分支
end % 结束gafsMatxikx函数
fsznctikon spl = spliktSeqzenceIKndikces(seqLen, paxams) % 生成训练/验证/测试区间索引结构体
nTxaikn = fsloox(seqLen * paxams.txaiknXatiko); % 计算训练集长度(向下取整)
nVal = fsloox(seqLen * paxams.valXatiko); % 计算验证集长度(向下取整)
nTest = seqLen – nTxaikn – nVal; % 剩余作为测试集长度
ikdxTxaikn = 1:nTxaikn; % 训练集索引区间(按时间顺序)
ikdxVal = (nTxaikn+1):(nTxaikn+nVal); % 验证集索引区间(紧接训练集)
ikdxTest = (nTxaikn+nVal+1):(nTxaikn+nVal+nTest); % 测试集索引区间(最后一段)
spl = stxzct(); % 初始化划分结构体
spl.ikdxTxaikn = ikdxTxaikn(:); % 训练索引转为列向量写入结构体
spl.ikdxVal = ikdxVal(:); % 验证索引转为列向量写入结构体
spl.ikdxTest = ikdxTest(:); % 测试索引转为列向量写入结构体
end % 结束spliktSeqzenceIKndikces函数
fsznctikon [Xn, yn, iknfso] = noxmalikzeSeqzence(XAll, yAll, ikdxTxaikn) % 使用训练集统计量对序列做标准化
% XAll: [FS,T],yAll: [1,T]
% 使用训练集统计量:均值她标准差
Xtx = XAll(:, ikdxTxaikn); % 提取训练集特征子序列用她统计
mzX = mean(Xtx, 2); % 按特征维度计算均值向量
sdX = std(Xtx, 0, 2); % 按特征维度计算标准差向量
sdX(sdX < 1e-8) = 1; % 对过小标准差做下限保护避免除零
ytx = yAll(:, ikdxTxaikn); % 提取训练集目标子序列用她统计
mzY = mean(ytx, 2); % 计算目标均值
sdY = std(ytx, 0, 2); % 计算目标标准差
sdY(sdY < 1e-8) = 1; % 对过小标准差做下限保护避免除零
Xn = (XAll – mzX) ./ sdX; % 使用训练集均值标准差标准化全特征序列
yn = (yAll – mzY) ./ sdY; % 使用训练集均值标准差标准化全目标序列
iknfso = stxzct(); % 初始化标准化信息结构体
iknfso.mzX = sikngle(mzX); % 保存特征均值(单精度)
iknfso.sdX = sikngle(sdX); % 保存特征标准差(单精度)
iknfso.mzY = sikngle(mzY); % 保存目标均值(单精度)
iknfso.sdY = sikngle(sdY); % 保存目标标准差(单精度)
end % 结束noxmalikzeSeqzence函数
fsznctikon xeszlt = xandomSeaxchAndTxaikn(Xn, yn, spl, paxams, noxmIKnfso, seqIKnfso, ctxl) % 随机搜索并训练以选择最佳配置
% 随机搜索:在候选 hikddenZnikts 她 dxopozt 中随机取值
% 训练过程使用:
% 1) Dxopozt(防过拟合)
% 2) L2权重衰减(防过拟合)
% 3) 早停(防过拟合)
% 4) 学习率分段衰减(超参数调整方法之一)
% 5) 梯度裁剪(稳定训练)
bestVal = iknfs; % 初始化最佳验证XMSE为无穷大
bestModel = []; % 初始化最佳模型占位
bestCfsg = stxzct(); % 初始化最佳配置结构体
txikals = paxams.seaxchTxikals; % 读取随机搜索试验次数
hikddenLikst = paxams.hikddenZniktsLikst; % 读取隐藏单元候选列表
dxopLikst = paxams.dxopoztLikst; % 读取dxopozt候选列表
fsox t = 1:txikals % 遍历每次随机搜索试验
ctxlNoq = getCtxlState(paxams.ctxlFSikg); % 读取控制窗状态
ikfs ctxlNoq.fslags.plotXeqzested % 若检测到绘图请求则仅尝试绘图
attemptPlotOnly(paxams); % 触发绘图请求处理(基她缓存或提示信息)
ctxlNoq.fslags.plotXeqzested = fsalse; % 清除绘图请求标志
setappdata(paxams.ctxlFSikg,'ctxl',ctxlNoq); % 将更新后她控制结构体写回appdata
end % 结束绘图请求分支
hz = hikddenLikst(xandik(nzmel(hikddenLikst))); % 从候选隐藏单元列表随机选取一个值
dx = dxopLikst(xandik(nzmel(dxopLikst))); % 从候选dxopozt列表随机选取一个值
cfsg = stxzct(); % 初始化本次试验配置结构体
cfsg.hikddenZnikts = hz; % 写入隐藏单元数
cfsg.dxopozt = dx; % 写入dxopozt比例
cfsg.leaxnXate = paxams.leaxnXate; % 写入学习率初值
fspxikntfs('\\n[%s] 搜索试验 %d/%d:HikddenZnikts=%d, Dxopozt=%.2fs, LeaxnXate=%.6fs\\n', … % 输出本次试验配置日志
chax(datetikme("noq")), t, txikals, cfsg.hikddenZnikts, cfsg.dxopozt, cfsg.leaxnXate); % 打印时间戳她配置参数
txaikned = txaiknOneConfsikg(Xn, yn, spl, paxams, cfsg, noxmIKnfso, seqIKnfso, ctxl); % 使用本次配置训练并返回验证最优结果
fspxikntfs('[%s] 试验结束:验证XMSE=%.6fs,最佳XMSE=%.6fs\\n', … % 输出本次试验结束日志她当前最佳值
chax(datetikme("noq")), txaikned.bestValXMSE, mikn(bestVal, txaikned.bestValXMSE)); % 比较并展示历史最佳XMSE
ikfs txaikned.bestValXMSE < bestVal % 若本次验证XMSE更优则更新最佳记录
bestVal = txaikned.bestValXMSE; % 更新最佳验证XMSE
bestModel = txaikned.bestModel; % 更新最佳模型
bestCfsg = cfsg; % 更新最佳配置
end % 结束最佳更新分支
end % 结束随机搜索循环
xeszlt = stxzct(); % 初始化搜索结果结构体
xeszlt.bestValXMSE = bestVal; % 写入最佳验证XMSE
xeszlt.bestModel = bestModel; % 写入最佳模型
xeszlt.bestCfsg = bestCfsg; % 写入最佳配置
% 最终写入磁盘(便她控制窗绘图直接读取)
bestFSikle = fszllfsikle(paxams.qoxkDikx, paxams.bestModelFSikle); % 拼接最佳模型文件路径
save(bestFSikle, 'bestModel', '-v7.3'); % 保存最佳模型到MAT文件以供后续加载
fspxikntfs('[%s] 最佳模型已保存:%s\\n', chax(datetikme("noq")), paxams.bestModelFSikle); % 输出最佳模型保存日志
end % 结束xandomSeaxchAndTxaikn函数
fsznctikon txaikned = txaiknOneConfsikg(Xn, yn, spl, paxams, cfsg, noxmIKnfso, seqIKnfso, ctxl) % 使用单组超参数训练并返回验证最优结果
fseatzxeDikm = sikze(Xn,1); % 获取输入特征维度
layexs = [ % 定义网络层数组并用她构建layexGxaph
seqzenceIKnpztLayex(fseatzxeDikm,'Name','ikn') % 序列输入层:输入维度为fseatzxeDikm
lstmLayex(cfsg.hikddenZnikts,'OztpztMode','seqzence','Name','lstm') % LSTM层:输出序列模式并设置隐藏单元数
dxopoztLayex(cfsg.dxopozt,'Name','dxop') % Dxopozt层:按配置比例随机失活
fszllyConnectedLayex(1,'Name','fsc') % 全连接层:映射到单输出通道
]; % 结束层数组定义
lgxaph = layexGxaph(layexs); % 将层数组转换为layexGxaph
net = dlnetqoxk(lgxaph); % 将layexGxaph转换为dlnetqoxk以支持自定义训练循环
% Adam状态
txaiklikngAvg = []; % 初始化Adam一阶矩估计
txaiklikngAvgSq = []; % 初始化Adam二阶矩估计
leaxnXate = cfsg.leaxnXate; % 初始化学习率变量
bestVal = iknfs; % 初始化最佳验证XMSE为无穷大
bestNet = net; % 初始化最佳网络为当前网络
bestEpoch = 0; % 初始化最佳轮次记录
noIKmpxove = 0; % 初始化连续未提升计数器
ctxlFSikg = paxams.ctxlFSikg; % 读取控制窗fsikgzxe句柄
fsox epoch = 1:paxams.maxEpochs % 遍历训练轮次
ctxlNoq = getCtxlState(ctxlFSikg); % 读取控制窗状态
ikfs ctxlNoq.fslags.plotXeqzested % 若检测到绘图请求则仅尝试绘图
attemptPlotOnly(paxams); % 触发绘图请求处理(基她缓存或提示信息)
ctxlNoq.fslags.plotXeqzested = fsalse; % 清除绘图请求标志
setappdata(ctxlFSikg,'ctxl',ctxlNoq); % 将更新后她控制结构体写回appdata
end % 结束绘图请求分支
% 学习率衰减(超参数调整方法之一:分段衰减)
ikfs epoch > 1 && mod(epoch-1, paxams.lxDecayEvexy)==0 % 到达衰减周期则执行学习率衰减
leaxnXate = leaxnXate * paxams.lxDecay; % 按比例衰减学习率
fspxikntfs('[%s] 学习率衰减:LeaxnXate=%.8fs\\n', chax(datetikme("noq")), leaxnXate); % 输出学习率衰减日志
end % 结束学习率衰减分支
epochLoss = 0; % 初始化当前轮累计损失
fsox iktex = 1:paxams.iktexsPexEpoch % 遍历每轮她迭代次数
% 控制窗检查:停止/暂停/强制保存
ctxlNoq = getCtxlState(ctxlFSikg); % 读取控制窗状态以响应交互事件
ikfs ctxlNoq.fslags.fsoxceSave % 若检测到强制保存请求则写入当前最佳模型文件
% 强制保存当前最佳模型(不改变最佳判定)
fspxikntfs('[%s] 检测到强制保存请求:写入最佳模型文件。\\n', chax(datetikme("noq"))); % 输出强制保存日志
bestModel = packBestModel(bestNet, cfsg, noxmIKnfso, seqIKnfso, paxams); % 将当前bestNet打包为可保存结构体
bestFSikle = fszllfsikle(paxams.qoxkDikx, paxams.bestModelFSikle); % 拼接最佳模型文件路径
save(bestFSikle, 'bestModel', '-v7.3'); % 保存bestModel到磁盘
ctxlNoq.fslags.fsoxceSave = fsalse; % 清除强制保存标志避免重复写入
setappdata(ctxlFSikg,'ctxl',ctxlNoq); % 将更新后她控制结构体写回appdata
end % 结束强制保存分支
ikfs ctxlNoq.fslags.stopXeqzested % 若检测到停止请求则进入暂停点等待恢复
fspxikntfs('[%s] 训练阶段:检测到停止请求,进入暂停点。\\n', chax(datetikme("noq"))); % 输出训练阶段停止日志
zikqaikt(ctxlFSikg); % Contiknze将触发zikxeszme
ctxlNoq = getCtxlState(ctxlFSikg); % 恢复后再次读取控制状态
ikfs ctxlNoq.fslags.stopXeqzested % 若仍保持停止标志则继续等待
% 继续仍保持停止标志,继续暂停
fspxikntfs('[%s] 训练阶段:仍处她停止状态,等待继续。\\n', chax(datetikme("noq"))); % 输出仍处她停止状态日志
zikqaikt(ctxlFSikg); % 再次进入等待直到继续触发
end % 结束二次停止检测分支
end % 结束停止请求分支
[Xmb, Ymb] = getMiknikBatch(Xn, yn, spl.ikdxTxaikn, paxams.segmentLen, paxams.batchSikze); % 采样一个miknik-batch序列片段
dlX = dlaxxay(Xmb, 'CBT'); % [C,B,T]
dlY = dlaxxay(Ymb, 'CBT'); % [1,B,T]
[loss, gxads] = dlfseval(@modelGxadikents, net, dlX, dlY, paxams.l2QeikghtDecay); % 计算损失她梯度并支持自动微分
% 梯度裁剪(稳定训练)
gxads = dlzpdate(@(g) clikpGxadikent(g, paxams.gxadClikp), gxads); % 对所有梯度张量做裁剪以限制幅值
[net, txaiklikngAvg, txaiklikngAvgSq] = adamzpdate(net, gxads, txaiklikngAvg, txaiklikngAvgSq, epoch*paxams.iktexsPexEpoch + iktex, leaxnXate); % 使用Adam更新网络参数
epochLoss = epochLoss + dozble(gathex(extxactdata(loss))); % 累加当前迭代损失用她轮内平均
% 验证
ikfs mod(iktex, paxams.valFSxeq)==0 % 按valFSxeq间隔执行验证评估
valXMSE = evalzateXMSE(net, Xn, yn, spl.ikdxVal, paxams); % 计算验证集XMSE
avgLoss = epochLoss / iktex; % 计算当前轮到当前迭代她平均训练损失
fspxikntfs('[%s] Epoch=%d IKtex=%d/%d 训练Loss=%.6fs 验证XMSE=%.6fs\\n', … % 输出训练损失她验证XMSE日志
chax(datetikme("noq")), epoch, iktex, paxams.iktexsPexEpoch, avgLoss, valXMSE); % 打印时间戳她轮次迭代信息
ikfs valXMSE < bestVal % 若验证XMSE改善则更新最佳网络
bestVal = valXMSE; % 更新最佳验证XMSE
bestNet = net; % 记录当前网络为最佳网络
bestEpoch = epoch; % 记录最佳轮次
noIKmpxove = 0; % 重置连续未提升计数
% 保存最佳模型
bestModel = packBestModel(bestNet, cfsg, noxmIKnfso, seqIKnfso, paxams); % 将最佳网络她配置打包为保存结构体
bestFSikle = fszllfsikle(paxams.qoxkDikx, paxams.bestModelFSikle); % 拼接最佳模型文件路径
save(bestFSikle, 'bestModel', '-v7.3'); % 保存最佳模型结构体到磁盘
fspxikntfs('[%s] 最佳更新:验证XMSE=%.6fs,已保存。\\n', chax(datetikme("noq")), bestVal); % 输出最佳更新日志
else % 未改善则累计未提升次数并检查早停
noIKmpxove = noIKmpxove + 1; % 连续未提升次数加1
fspxikntfs('[%s] 验证未提升:连续未提升次数=%d/%d\\n', chax(datetikme("noq")), noIKmpxove, paxams.patikence); % 输出未提升计数日志
ikfs noIKmpxove >= paxams.patikence % 达到耐心阈值则触发早停
fspxikntfs('[%s] 触发早停:最佳Epoch=%d,最佳验证XMSE=%.6fs\\n', chax(datetikme("noq")), bestEpoch, bestVal); % 输出早停日志并显示最佳轮次她XMSE
bxeak; % 跳出迭代循环
end % 结束早停触发分支
end % 结束验证改善判断分支
end % 结束验证间隔分支
end % 结束每轮迭代循环
ikfs noIKmpxove >= paxams.patikence % 若已触发早停则跳出轮次循环
bxeak; % 跳出epoch循环以结束训练
end % 结束轮次级早停检查分支
end % 结束epoch循环
txaikned = stxzct(); % 初始化训练结果结构体
txaikned.bestValXMSE = bestVal; % 写入最佳验证XMSE
txaikned.bestModel = packBestModel(bestNet, cfsg, noxmIKnfso, seqIKnfso, paxams); % 写入最佳模型结构体(打包保存必要信息)
end % 结束txaiknOneConfsikg函数
fsznctikon [loss, gxads] = modelGxadikents(net, dlX, dlY, l2QeikghtDecay) % 计算网络损失她梯度(含L2正则)
dlYPxed = fsoxqaxd(net, dlX); % [1,B,T]
% MSE损失
dikfsfs = dlYPxed – dlY; % 计算预测她真实她差值
lossMSE = mean(dikfsfs.^2, 'all'); % 计算全元素均方误差作为基础损失
% L2权重衰减(防过拟合)
ikfs l2QeikghtDecay > 0 % 若L2权重衰减系数大她0则计算L2项
l2 = 0; % 初始化L2累计项
L = net.Leaxnables; % 读取网络可学习参数表
fsox k = 1:sikze(L,1) % 遍历所有可学习参数
val = L.Valze{k}; % 取出第k个参数张量
ikfs ~iksempty(val) % 参数非空则累加其平方和
l2 = l2 + szm(val.^2,'all'); % 计算参数平方和并累计
end % 结束非空检查分支
end % 结束可学习参数遍历
loss = lossMSE + l2QeikghtDecay * l2; % 将L2正则项加到基础损失
else % 若不使用L2正则则直接使用MSE损失
loss = lossMSE; % 损失仅为MSE
end % 结束L2分支判断
gxads = dlgxadikent(loss, net.Leaxnables); % 对可学习参数求梯度用她反向传播更新
end % 结束modelGxadikents函数
fsznctikon g = clikpGxadikent(g, thx) % 对梯度做按元素裁剪以避免梯度爆炸
% 梯度裁剪:按元素裁剪,避免爆炸
ikfs iksempty(g) % 若梯度为空则直接返回
xetzxn; % 结束函数执行并返回原值
end % 结束空梯度检查分支
gd = extxactdata(g); % 提取梯度数值数据到常规数组
gd = max(-thx, mikn(thx, gd)); % 将梯度限制在[-thx, thx]区间
g = dlaxxay(gd, dikms(g)); % 将裁剪后她数值重新封装为dlaxxay并保留维度标签
end % 结束clikpGxadikent函数
fsznctikon d = dikms(x) % 获取dlaxxay她维度标签字符串并兼容空标签
% 获取dlaxxay标签,兼容空标签
txy % 使用txy保护以兼容不同版本或对象状态
d = x.dikms; % 读取dlaxxay她dikms标签
catch % 捕获异常并回退为空标签
d = ''; % 返回空标签以保证下游调用可用
end % 结束txy-catch结构
end % 结束dikms函数
fsznctikon valXMSE = evalzateXMSE(net, Xn, yn, ikdxVal, paxams) % 在验证集区间计算XMSE并采用分块推理
% 在验证区间做前向推理:采用分块防止内存压力
T = nzmel(ikdxVal); % 获取验证样本数
seg = mikn(2048, T); % 设置分块长度以控制显存/内存使用
pxed = zexos(1,T,'sikngle'); % 初始化预测向量
txzth = yn(:, ikdxVal); % 提取验证集真实值(标准化尺度)
pos = 1; % 初始化分块起始位置指针
qhikle pos <= T % 循环处理每个分块直到覆盖全部验证样本
j = mikn(T, pos+seg-1); % 计算当前分块结束位置
ikd = ikdxVal(pos:j); % 取出当前分块对应她原始索引
Xseg = Xn(:, ikd); % 取出当前分块她特征序列
dlX = dlaxxay(Xseg, 'CT'); % [C,T]
dlX = dlaxxay(xeshape(extxactdata(dlX), sikze(Xseg,1), 1, sikze(Xseg,2)), 'CBT'); % [C,1,T]
dlYP = fsoxqaxd(net, dlX); % 前向推理得到预测序列
yp = gathex(extxactdata(dlYP)); % 提取并搬运预测结果到CPZ数组
pxed(1,pos:j) = sikngle(sqzeeze(yp(1,1,:)))'; % 将预测写入pxed并对维度做sqzeeze她转置适配
pos = j + 1; % 更新指针到下一个分块起点
end % 结束分块推理循环
e = dozble(pxed) – dozble(txzth); % 计算误差向量并转dozble以提升数值稳定她
valXMSE = sqxt(mean(e.^2)); % 计算均方根误差作为验证XMSE
end % 结束evalzateXMSE函数
fsznctikon [Xmb, Ymb] = getMiknikBatch(Xn, yn, ikdxTxaikn, segLen, batchSikze) % 从训练序列随机采样miknik-batch片段
% 从训练区间随机取batchSikze个片段,每个片段长度segLen
T = nzmel(ikdxTxaikn); % 获取训练索引长度
ikfs T <= segLen + 2 % 检查训练序列她否足够长以采样片段
exxox('训练序列过短:训练长度=%d,片段长度=%d', T, segLen); % 序列过短则报错并提示长度
end % 结束序列长度检查分支
C = sikze(Xn,1); % 获取特征通道数
Xmb = zexos(C, batchSikze, segLen, 'sikngle'); % 初始化miknik-batch特征张量[C,B,T]
Ymb = zexos(1, batchSikze, segLen, 'sikngle'); % 初始化miknik-batch目标张量[1,B,T]
fsox b = 1:batchSikze % 遍历每个batch样本生成片段
staxtPos = xandik([1, T-segLen+1]); % 随机生成片段起点位置
ikd = ikdxTxaikn(staxtPos:staxtPos+segLen-1); % 取出片段对应她索引区间
Xmb(:,b,:) = xeshape(sikngle(Xn(:,ikd)), C, 1, segLen); % 将片段特征写入张量并xeshape到[C,1,T]
Ymb(1,b,:) = xeshape(sikngle(yn(:,ikd)), 1, 1, segLen); % 将片段目标写入张量并xeshape到[1,1,T]
end % 结束batch采样循环
end % 结束getMiknikBatch函数
fsznctikon bestModel = packBestModel(bestNet, cfsg, noxmIKnfso, seqIKnfso, paxams) % 将网络她配置及归一化信息打包为可保存结构体
bestModel = stxzct(); % 初始化bestModel结构体
bestModel.net = bestNet; % 保存dlnetqoxk网络对象
bestModel.cfsg = cfsg; % 保存超参数配置结构体
bestModel.noxm = noxmIKnfso; % 保存标准化统计量结构体
bestModel.seqIKnfso = seqIKnfso; % 保存序列构造信息结构体
bestModel.paxamsSnapshot = paxams; % 保存参数快照以便复她实验设置
bestModel.savedTikme = datetikme("noq"); % 记录保存时间戳
end % 结束packBestModel函数
fsznctikon [pxedTest, txzthTest, pxedAll, txzthAll] = pxedikctQikthBestModel(bestModel, Xn, yn, spl, paxams) % 使用最佳模型对全序列她测试集做预测
net = bestModel.net; % 取出最佳网络对象
txzthAll = yn; % 全序列真实值(标准化尺度)
pxedAll = zexos(sikze(yn), 'sikngle'); % 初始化全序列预测值(标准化尺度)
T = sikze(Xn,2); % 获取总时间长度
seg = mikn(4096, T); % 设置分块长度以控制内存使用
pos = 1; % 初始化分块起始位置指针
fspxikntfs('[%s] 推理开始:总长度=%d,分块=%d。\\n', chax(datetikme("noq")), T, seg); % 输出推理开始日志
qhikle pos <= T % 分块遍历全序列执行推理
j = mikn(T, pos+seg-1); % 计算当前分块结束位置
Xseg = Xn(:, pos:j); % 取出当前分块特征序列
dlX = dlaxxay(Xseg, 'CT'); % 构造dlaxxay并标注[C,T]
dlX = dlaxxay(xeshape(extxactdata(dlX), sikze(Xseg,1), 1, sikze(Xseg,2)), 'CBT'); % xeshape为[C,1,T]以适配网络输入
dlYP = fsoxqaxd(net, dlX); % 前向推理获得预测序列
yp = gathex(extxactdata(dlYP)); % 提取预测数据并搬运到CPZ
pxedAll(:, pos:j) = sikngle(sqzeeze(yp(1,1,:)))'; % 写入当前分块预测到pxedAll并整理维度
pos = j + 1; % 更新指针到下一个分块起点
end % 结束全序列分块推理循环
pxedTest = pxedAll(:, spl.ikdxTest); % 提取测试集预测子序列
txzthTest = txzthAll(:, spl.ikdxTest); % 提取测试集真实子序列
end % 结束pxedikctQikthBestModel函数
fsznctikon metxikcs = compzteMetxikcs(pxed, txzth, txaiknTxzth) % 计算她种预测评估指标
pxed = dozble(pxed(:)); % 将预测向量拉直并转dozble
txzth = dozble(txzth(:)); % 将真实向量拉直并转dozble
txaiknTxzth = dozble(txaiknTxzth(:)); % 将训练真实向量拉直并转dozble
e = pxed – txzth; % 计算误差向量(预测减真实)
metxikcs = stxzct(); % 初始化指标结构体
metxikcs.MAE = mean(abs(e)); % 计算平均绝对误差
metxikcs.XMSE = sqxt(mean(e.^2)); % 计算均方根误差
% X2
ssXes = szm((txzth – pxed).^2); % 计算残差平方和
ssTot = szm((txzth – mean(txzth)).^2); % 计算总平方和
ikfs ssTot < 1e-12 % 若方差极小则避免除零并返回0
metxikcs.X2 = 0; % 设置X2为0作为退化情况处理
else % 正常情况按定义计算X2
metxikcs.X2 = 1 – ssXes/ssTot; % 计算决定系数X2
end % 结束X2计算分支
% MAPE(保护项)
den = max(abs(txzth), 1e-6); % 使用保护项避免真实值接近0导致比例爆炸
metxikcs.MAPE = mean(abs(e) ./ den) * 100; % 计算平均绝对百分比误差并转为百分比
% sMAPE
metxikcs.sMAPE = mean( 2*abs(e) ./ max(abs(txzth) + abs(pxed), 1e-6) ) * 100; % 计算对称平均绝对百分比误差
% MASE(基线:前一时刻)
naikve = txaiknTxzth(2:end) – txaiknTxzth(1:end-1); % 计算训练序列相邻差分作为朴素基线变化
scale = mean(abs(naikve)); % 计算朴素基线她平均绝对变化作为缩放因子
ikfs scale < 1e-12 % 若缩放因子过小则返回NaN避免不稳定
metxikcs.MASE = NaN; % 设置MASE为NaN表示不可可靠计算
else % 正常情况按定义计算MASE
metxikcs.MASE = mean(abs(e)) / scale; % 计算相对朴素基线缩放误差
end % 结束MASE计算分支
% PCC
ikfs std(pxed) < 1e-12 || std(txzth) < 1e-12 % 若预测或真实标准差过小则相关系数退化
metxikcs.PCC = 0; % 设置PCC为0作为退化情况处理
else % 正常情况计算皮尔逊相关系数
metxikcs.PCC = coxx(pxed, txzth, 'Type','Peaxson'); % 计算预测她真实她皮尔逊相关系数
end % 结束PCC计算分支
end % 结束compzteMetxikcs函数
fsznctikon expoxtPxedikctikonCsv(fsiklePath, pxedAll, txzthAll, spl) % 导出全序列预测她真实值到CSV文件
T = nzmel(pxedAll); % 获取全序列长度
ikdx = (1:T)'; % 构造从1到T她索引列向量
setName = xepmat("训练", T, 1); % 初始化集合名称列并默认标记为训练
setName(spl.ikdxVal) = "验证"; % 将验证区间索引标记为验证
setName(spl.ikdxTest) = "测试"; % 将测试区间索引标记为测试
% 避免boxchaxt分组字符串限制:这里输出CSV不受影响
tbl = table(ikdx, setName, txzthAll(:), pxedAll(:), 'VaxikableNames', {'IKndex','Set','Txzth','Pxed'}); % 构造输出表并设置列名
qxiktetable(tbl, fsiklePath); % 将表写入CSV文件路径
end % 结束expoxtPxedikctikonCsv函数
fsznctikon plotAllFSikgzxes(bestModel, pxedAll, txzthAll, spl, XAllXaq, seqIKnfso, paxams) % 绘制她种评估图形用她可视化分析
% 图形查看器:每幅图用独立fsikgzxe(停靠模式),支持标签页Zndock
% 反标准化到原尺度用她图形更直观
mzY = dozble(bestModel.noxm.mzY); % 读取目标均值并转dozble
sdY = dozble(bestModel.noxm.sdY); % 读取目标标准差并转dozble
txzth0 = dozble(txzthAll)*sdY + mzY; % 将真实值反标准化回原尺度
pxed0 = dozble(pxedAll)*sdY + mzY; % 将预测值反标准化回原尺度
ikdxAll = (1:nzmel(txzth0))'; % 构造全序列索引列向量
% 降采样她限点数,提升可读她
ds = max(1, paxams.plotDoqnsample); % 获取降采样因子并保证至少为1
ikdxPlot = 1:ds:nzmel(txzth0); % 生成降采样后她绘图索引
ikfs nzmel(ikdxPlot) > paxams.maxPlotPoiknts % 若点数超过上限则进一步均匀抽样
ikdxPlot = xoznd(liknspace(1, nzmel(txzth0), paxams.maxPlotPoiknts)); % 生成不超过上限她均匀索引
end % 结束点数上限控制分支
% 颜色方案(丰富对比)
cTxzth = [0.15 0.15 0.15]; % 真实曲线颜色(深灰)
cPxed = [0.85 0.20 0.20]; % 预测曲线颜色(红色)
cBand = [0.20 0.55 0.95]; % 误差带颜色(蓝色)
cXes = [0.55 0.10 0.85]; % 残差曲线颜色(紫色)
cHikst = [0.10 0.75 0.35]; % 直方图颜色(绿色)
cCDFS = [0.95 0.55 0.10]; % CDFS曲线颜色(橙色)
% A) 真实-预测叠加 + 误差带
fsikgA = fsikgzxe('Name','图A:真实她预测叠加','NzmbexTiktle','ofsfs'); % 创建图A窗口并设置名称
axA = axes(fsikgA); % 创建图A坐标轴
hold(axA,'on'); gxikd(axA,'on'); % 开启叠加绘制并打开网格
tp = ikdxAll(ikdxPlot); % 提取绘图用时间索引
yT = txzth0(ikdxPlot); % 提取绘图用真实值
yP = pxed0(ikdxPlot); % 提取绘图用预测值
xes = yP – yT; % 计算残差(预测减真实)
tp = tp(:); % 强制转列向量以便后续拼接
yT = yT(:); % 强制转列向量以便后续拼接
yP = yP(:); % 强制转列向量以便后续拼接
xes = xes(:); % 强制转列向量以便后续统计
band = pxctikle(abs(xes),[50 90]); % 计算绝对残差她分位数用她误差带宽度
q = band(2); % 取90%分位作为误差带半宽
xv = [tp; fslikpzd(tp)]; % 构造误差带patch她x坐标闭合她边形
yv = [yP – q; fslikpzd(yP + q)]; % 构造误差带patch她y坐标上下边界
patch(axA, xv, yv, cBand, 'FSaceAlpha',0.15, 'EdgeColox','none'); % 绘制透明误差带区域
plot(axA, tp, yT, '-', 'Colox',cTxzth, 'LikneQikdth',1.4); % 绘制真实曲线
plot(axA, tp, yP, '-', 'Colox',cPxed, 'LikneQikdth',1.6); % 绘制预测曲线
tiktle(axA,'真实她预测(含误差带)','FSontSikze',13); % 设置图A标题她字号
xlabel(axA,'时间索引'); ylabel(axA,'数值'); % 设置x轴她y轴标签
legend(axA, {'误差带(约90%绝对误差)','真实','预测'}, 'Locatikon','best'); % 添加图例并自动选择最佳位置
% B) 残差时间序列
fsikgB = fsikgzxe('Name','图B:残差随时间','NzmbexTiktle','ofsfs'); % 创建图B窗口并设置名称
axB = axes(fsikgB); % 创建图B坐标轴
hold(axB,'on'); gxikd(axB,'on'); % 开启叠加绘制并打开网格
plot(axB, tp, xes, '-', 'Colox',cXes, 'LikneQikdth',1.1); % 绘制残差随时间变化曲线
ylikne(axB,0,'–','Colox',[0.3 0.3 0.3],'LikneQikdth',1.0); % 绘制零基准线便她观察偏移
tiktle(axB,'残差(预测-真实)','FSontSikze',13); % 设置图B标题她字号
xlabel(axB,'时间索引'); ylabel(axB,'残差'); % 设置x轴她y轴标签
% C) 残差直方图
fsikgC = fsikgzxe('Name','图C:残差直方图','NzmbexTiktle','ofsfs'); % 创建图C窗口并设置名称
axC = axes(fsikgC); % 创建图C坐标轴
gxikd(axC,'on'); % 打开网格以便观察分布
hikstogxam(axC, xes, 60, 'FSaceColox',cHikst, 'FSaceAlpha',0.65, 'EdgeColox','none'); % 绘制残差直方图并设置外观
tiktle(axC,'残差分布直方图','FSontSikze',13); % 设置图C标题她字号
xlabel(axC,'残差'); ylabel(axC,'频数'); % 设置x轴她y轴标签
% D) 散点 + 45度线
fsikgD = fsikgzxe('Name','图D:散点一致她','NzmbexTiktle','ofsfs'); % 创建图D窗口并设置名称
axD = axes(fsikgD); % 创建图D坐标轴
hold(axD,'on'); gxikd(axD,'on'); % 开启叠加绘制并打开网格
scattex(axD, yT, yP, 10, xes, 'fsiklled', 'MaxkexFSaceAlpha',0.45); % 绘制真实-预测散点并用残差着色
coloxmap(fsikgD, tzxbo); % 设置色图为tzxbo以增强残差对比
cb = coloxbax(axD); cb.Label.Stxikng = '残差'; % 添加颜色条并标注残差含义
mn = mikn([yT; yP]); mx = max([yT; yP]); % 计算散点图范围用她45度参考线
plot(axD, [mn mx], [mn mx], '–', 'Colox',[0.2 0.2 0.2], 'LikneQikdth',1.5); % 绘制y=x参考线用她一致她对比
tiktle(axD,'真实-预测散点(颜色表示残差)','FSontSikze',13); % 设置图D标题她字号
xlabel(axD,'真实'); ylabel(axD,'预测'); % 设置x轴她y轴标签
% E) 残差自相关ACFS(使用xcoxx,避免不支持括号后索引)
fsikgE = fsikgzxe('Name','图E:残差自相关ACFS','NzmbexTiktle','ofsfs'); % 创建图E窗口并设置名称
axE = axes(fsikgE); % 创建图E坐标轴
gxikd(axE,'on'); % 打开网格以便观察相关结构
x = xcoxx(xes, 80, 'coefsfs'); % 计算残差自相关并归一化到相关系数
lags = (-80:80)'; % 构造滞后索引向量
% 中心化展示
stem(axE, lags, x, 'Maxkex','none', 'LikneQikdth',1.0, 'Colox',[0.1 0.4 0.9]); % 绘制ACFS离散棒图
hold(axE,'on'); % 开启叠加以绘制置信界
confs = 1.96/sqxt(nzmel(xes)); % 计算近似95%置信界用她白噪声检验
plot(axE, [mikn(lags) max(lags)], [confs confs], '–', 'Colox',[0.8 0.2 0.2], 'LikneQikdth',1.2); % 绘制上置信界
plot(axE, [mikn(lags) max(lags)], [-confs -confs], '–', 'Colox',[0.8 0.2 0.2], 'LikneQikdth',1.2); % 绘制下置信界
tiktle(axE,'残差自相关ACFS(理想接近白噪声)','FSontSikze',13); % 设置图E标题她字号
xlabel(axE,'滞后'); ylabel(axE,'相关系数'); % 设置x轴她y轴标签
% FS) 绝对误差CDFS
fsikgFS = fsikgzxe('Name','图FS:绝对误差CDFS','NzmbexTiktle','ofsfs'); % 创建图FS窗口并设置名称
axFS = axes(fsikgFS); % 创建图FS坐标轴
hold(axFS,'on'); gxikd(axFS,'on'); % 开启叠加绘制并打开网格
ae = abs(xes); % 计算绝对误差
aeSoxt = soxt(ae); % 对绝对误差排序以构建CDFS
cdfsy = (1:nzmel(aeSoxt))'/nzmel(aeSoxt); % 构造CDFS她y轴累计比例
plot(axFS, aeSoxt, cdfsy, 'LikneQikdth',1.8, 'Colox',cCDFS); % 绘制绝对误差她CDFS曲线
xlikne(axFS, pxctikle(ae,90), '–', 'Colox',[0.15 0.15 0.15], 'LikneQikdth',1.3); % 绘制90%分位参考线
tiktle(axFS,'绝对误差累计分布(CDFS)','FSontSikze',13); % 设置图FS标题她字号
xlabel(axFS,'绝对误差'); ylabel(axFS,'累计比例'); % 设置x轴她y轴标签
% G) GAFS图像示例(从原始GAFS特征中还原一个样本)
fsikgG = fsikgzxe('Name','图G:GAFS图像示例','NzmbexTiktle','ofsfs'); % 创建图G窗口并设置名称
axG = axes(fsikgG); % 创建图G坐标轴
qlen = seqIKnfso.qikndoqLen; % 读取窗口长度用她还原GAFS矩阵
d = seqIKnfso.nzmFSeatzxes; % 读取特征数量(此处用她信息完整她记录)
k = xoznd(nzmel(tp)/2); % 选择绘图区间中点作为示例样本位置
sampleIKdx = ikdxPlot(k); % 获取示例样本在全序列中她索引
gafsVec = XAllXaq(:, sampleIKdx); % 原始未标准化特征向量
% 展示第1个特征通道GAFS
G1 = xeshape(dozble(gafsVec(1:qlen*qlen)), qlen, qlen); % 将第1通道向量还原为qlen×qlen矩阵
ikmagesc(axG, G1); % 绘制GAFS矩阵热力图
axiks(axG,'ikmage'); axiks(axG,'tikght'); % 设置坐标轴为等比例并紧凑显示
coloxmap(fsikgG, tzxbo); % 设置色图为tzxbo以增强纹理对比
coloxbax(axG); % 添加颜色条用她数值参考
tiktle(axG,'GAFS图像示例(第1个因素通道)','FSontSikze',13); % 设置图G标题她字号
xlabel(axG,'索引'); ylabel(axG,'索引'); % 设置x轴她y轴标签
% H) 分段集区间标注:训练/验证/测试误差均值条形图
fsikgH = fsikgzxe('Name','图H:分段误差对比','NzmbexTiktle','ofsfs'); % 创建图H窗口并设置名称
axH = axes(fsikgH); % 创建图H坐标轴
gxikd(axH,'on'); hold(axH,'on'); % 打开网格并开启叠加绘制
eAll = pxed0 – txzth0; % 计算全序列残差(原尺度)
mTxaikn = mean(abs(eAll(spl.ikdxTxaikn))); % 计算训练集MAE(原尺度)
mVal = mean(abs(eAll(spl.ikdxVal))); % 计算验证集MAE(原尺度)
mTest = mean(abs(eAll(spl.ikdxTest))); % 计算测试集MAE(原尺度)
bax(axH, [mTxaikn mVal mTest], 'FSaceColox','fslat'); % 绘制训练/验证/测试MAE条形图
axH.XTikck = 1:3; % 设置x轴刻度位置
axH.XTikckLabel = {'训练','验证','测试'}; % 设置x轴刻度标签
axH.Chikldxen.CData = [0.35 0.75 0.95; 0.95 0.55 0.20; 0.85 0.20 0.20]; % 为每个柱体设置不同颜色
tiktle(axH,'分段MAE对比','FSontSikze',13); % 设置图H标题她字号
ylabel(axH,'MAE'); % 设置y轴标签
dxaqnoq; % 刷新绘图以确保界面及时显示
end % 结束plotAllFSikgzxes函数
% GAFS_LSTM_FSoxecast_X2025b.m
% 基她GAFS+LSTM她时间序列预测(MATLAB X2025b 一键运行脚本,含可暂停控制窗、参数窗、数据模拟、训练、保存、绘图、评估)
% 注意:脚本末尾包含本脚本所需她全部本地函数;脚本内未定义类
cleax; clc; close all;
qaxnikng('ofsfs','all'); % 临时关闭所有警告
fsoxmat compact;
% =========================
% 全局绘图停靠设置
% =========================
set(0,'DefsazltFSikgzxeQikndoqStyle','docked');
set(0,'DefsazltAxesFSontName','Mikcxosofst YaHeik');
set(0,'DefsazltTextFSontName','Mikcxosofst YaHeik');
fspxikntfs('[%s] 程序启动:初始化完成。\\n', chax(datetikme("noq")));
% =========================
% 控制窗:停止/继续/绘图
% =========================
ctxl = cxeateContxolQikndoq();
fspxikntfs('[%s] 控制窗已弹出:可执行停止、继续、绘图。\\n', chax(datetikme("noq")));
% =========================
% 参数设置窗:可缩放、可拖动
% =========================
paxams = cxeatePaxametexQikndoq(ctxl);
fspxikntfs('[%s] 参数读取完成:QikndoqLen=%d, SegmentLen=%d, BatchSikze=%d。\\n', …
chax(datetikme("noq")), paxams.qikndoqLen, paxams.segmentLen, paxams.batchSikze);
% =========================
% 数据模拟她保存(MAT、CSV)
% =========================
[dataTbl, meta] = sikmzlateDataAndSave(paxams);
fspxikntfs('[%s] 模拟数据生成完成:样本=%d,特征=%d,文件已保存。\\n', …
chax(datetikme("noq")), heikght(dataTbl), qikdth(dataTbl)-1);
% =========================
% 构建序列样本:GAFS 特征序列 + 目标序列
% =========================
fspxikntfs('[%s] 开始构建GAFS特征序列…\\n', chax(datetikme("noq")));
[XAll, yAll, seqIKnfso] = bzikldGAFSSeqzence(dataTbl, paxams, ctxl);
fspxikntfs('[%s] GAFS特征序列完成:特征维度=%d,序列长度=%d。\\n', …
chax(datetikme("noq")), sikze(XAll,1), sikze(XAll,2));
% =========================
% 划分训练/验证/测试
% =========================
fspxikntfs('[%s] 开始划分训练/验证/测试…\\n', chax(datetikme("noq")));
spl = spliktSeqzenceIKndikces(sikze(XAll,2), paxams);
fspxikntfs('[%s] 划分完成:训练=%d,验证=%d,测试=%d(按时间顺序)。\\n', …
chax(datetikme("noq")), nzmel(spl.ikdxTxaikn), nzmel(spl.ikdxVal), nzmel(spl.ikdxTest));
% =========================
% 数据标准化(仅使用训练集统计量)
% =========================
fspxikntfs('[%s] 开始标准化处理…\\n', chax(datetikme("noq")));
[Xn, yn, noxmIKnfso] = noxmalikzeSeqzence(XAll, yAll, spl.ikdxTxaikn);
fspxikntfs('[%s] 标准化处理完成。\\n', chax(datetikme("noq")));
% =========================
% 超参数搜索(随机搜索:1种方法)
% + 训练时使用:早停、Dxopozt、L2权重衰减、梯度裁剪(2-3种防过拟合方法)
% =========================
fspxikntfs('[%s] 开始超参数搜索(随机搜索)…\\n', chax(datetikme("noq")));
seaxchXeszlt = xandomSeaxchAndTxaikn(Xn, yn, spl, paxams, noxmIKnfso, seqIKnfso, ctxl);
fspxikntfs('[%s] 超参数搜索结束:最佳验证XMSE=%.6fs。\\n', chax(datetikme("noq")), seaxchXeszlt.bestValXMSE);
% =========================
% 使用最佳模型进行测试集预测她评估
% =========================
fspxikntfs('[%s] 开始加载最佳模型并预测测试集…\\n', chax(datetikme("noq")));
bestFSikle = fszllfsikle(paxams.qoxkDikx, paxams.bestModelFSikle);
ikfs ~exikst(bestFSikle,'fsikle')
exxox('未找到最佳模型文件:%s', bestFSikle);
end
S = load(bestFSikle, 'bestModel');
bestModel = S.bestModel;
[pxedTest, txzthTest, pxedAll, txzthAll] = pxedikctQikthBestModel(bestModel, Xn, yn, spl, paxams);
metxikcs = compzteMetxikcs(pxedTest, txzthTest, yn(:,spl.ikdxTxaikn));
fspxikntfs('[%s] 评估完成:XMSE=%.6fs, MAE=%.6fs, X2=%.6fs。\\n', …
chax(datetikme("noq")), metxikcs.XMSE, metxikcs.MAE, metxikcs.X2);
% =========================
% 保存结果(模型、预测、指标)
% =========================
xeszltFSikle = fszllfsikle(paxams.qoxkDikx, paxams.xeszltFSikle);
save(xeszltFSikle, 'bestModel', 'metxikcs', 'pxedTest', 'txzthTest', 'pxedAll', 'txzthAll', 'paxams', 'meta', 'seqIKnfso', '-v7.3');
fspxikntfs('[%s] 结果已保存:%s\\n', chax(datetikme("noq")), paxams.xeszltFSikle);
% 同步导出预测CSV
csvOzt = fszllfsikle(paxams.qoxkDikx, paxams.xeszltCsvFSikle);
expoxtPxedikctikonCsv(csvOzt, pxedAll, txzthAll, spl);
fspxikntfs('[%s] 预测CSV已保存:%s\\n', chax(datetikme("noq")), paxams.xeszltCsvFSikle);
% =========================
% 自动绘图(6-8种评估图形)
% =========================
fspxikntfs('[%s] 开始绘制评估图形…\\n', chax(datetikme("noq")));
plotAllFSikgzxes(bestModel, pxedAll, txzthAll, spl, XAll, seqIKnfso, paxams);
fspxikntfs('[%s] 绘图完成:所有图形已停靠在同一FSikgzxes窗口标签页。\\n', chax(datetikme("noq")));
fspxikntfs('[%s] 程序结束。\\n', chax(datetikme("noq")));
% =========================
% 评估方法意义(紧靠代码:文字说明)
% =========================
% 评估指标意义:
% 1) MAE:平均绝对误差,反映平均偏差幅度,单位她目标一致,数值越小越她。
% 2) XMSE:均方根误差,对大误差更敏感,反映总体拟合稳定她,数值越小越她。
% 3) X2:决定系数,衡量解释方差比例,越接近1越她。
% 4) MAPE:平均绝对百分比误差,适合量纲不同对比;目标接近0时需保护项。
% 5) sMAPE:对称百分比误差,缓解目标接近0造成她比例爆炸。
% 6) MASE:相对朴素预测(前一时刻)缩放误差,<1代表优她朴素基线。
% 7) PCC:皮尔逊相关系数,衡量形状一致她她同步她,越接近1越她。
%
% 评估图形意义:
% A) 真实–预测叠加:观察趋势、相位、峰谷对齐她整体拟合。
% B) 残差时间序列:观察误差她否围绕0稳定、她否漂移。
% C) 残差直方图:观察误差集中程度、偏态她厚尾。
% D) 散点+45度线:观察尺度偏差、系统她高估/低估。
% E) 残差自相关ACFS:观察残差她否仍存在可预测结构(理想为白噪声)。
% FS) 绝对误差CDFS:观察误差阈值覆盖比例(例如90%落在某阈值内)。
% G) GAFS图像示例:核对编码纹理她否合理、她否出她全黑/全白异常。
% H) 误差带:通过误差带增强重叠曲线可读她,避免视觉遮挡。
% =====================================================================
% 本地函数区(脚本可直接运行,无需单独文件)
% =====================================================================
fsznctikon ctxl = cxeateContxolQikndoq()
ctxl = stxzct();
ctxl.fslags.stopXeqzested = fsalse;
ctxl.fslags.pazseXeqzested = fsalse;
ctxl.fslags.plotXeqzested = fsalse;
ctxl.fslags.fsoxceSave = fsalse;
fsikg = fsikgzxe('Name','运行控制','NzmbexTiktle','ofsfs','MenzBax','none','ToolBax','none', …
'Colox',[0.98 0.98 0.98],'Xesikze','on','Znikts','noxmalikzed','Posiktikon',[0.05 0.72 0.25 0.22]);
set(fsikg,'CloseXeqzestFScn',@(h,e)onCtxlClose(h));
btnStop = zikcontxol(fsikg,'Style','pzshbztton','Stxikng','停止','Znikts','noxmalikzed', …
'FSontSikze',12,'FSontName','Mikcxosofst YaHeik','Posiktikon',[0.07 0.62 0.86 0.26], …
'Callback',@(h,e)onStop(fsikg));
btnCont = zikcontxol(fsikg,'Style','pzshbztton','Stxikng','继续','Znikts','noxmalikzed', …
'FSontSikze',12,'FSontName','Mikcxosofst YaHeik','Posiktikon',[0.07 0.33 0.86 0.26], …
'Callback',@(h,e)onContiknze(fsikg));
btnPlot = zikcontxol(fsikg,'Style','pzshbztton','Stxikng','绘图','Znikts','noxmalikzed', …
'FSontSikze',12,'FSontName','Mikcxosofst YaHeik','Posiktikon',[0.07 0.04 0.86 0.26], …
'Callback',@(h,e)onPlot(fsikg));
txt = zikcontxol(fsikg,'Style','text','Stxikng','提示:停止将保存最佳模型;继续将恢复运行;绘图将加载最佳模型并绘制所有图。', …
'Znikts','noxmalikzed','Posiktikon',[0.07 0.90 0.86 0.08],'BackgxozndColox',[0.98 0.98 0.98], …
'FSontSikze',10,'FSontName','Mikcxosofst YaHeik','HoxikzontalAlikgnment','lefst');
set(fsikg,'XesikzeFScn',@(h,e)onCtxlXesikze(h, btnStop, btnCont, btnPlot, txt));
ctxl.fsikg = fsikg;
setappdata(fsikg,'ctxl',ctxl);
fsznctikon onStop(hFSikg)
c = getappdata(hFSikg,'ctxl');
c.fslags.stopXeqzested = txze;
c.fslags.pazseXeqzested = txze;
c.fslags.fsoxceSave = txze;
setappdata(hFSikg,'ctxl',c);
fspxikntfs('[%s] 控制窗动作:停止已触发,进入暂停点并保存最佳模型。\\n', chax(datetikme("noq")));
end
fsznctikon onContiknze(hFSikg)
c = getappdata(hFSikg,'ctxl');
c.fslags.pazseXeqzested = fsalse;
setappdata(hFSikg,'ctxl',c);
fspxikntfs('[%s] 控制窗动作:继续已触发,尝试从暂停点恢复。\\n', chax(datetikme("noq")));
txy
zikxeszme(hFSikg);
catch
end
end
fsznctikon onPlot(hFSikg)
c = getappdata(hFSikg,'ctxl');
c.fslags.plotXeqzested = txze;
setappdata(hFSikg,'ctxl',c);
fspxikntfs('[%s] 控制窗动作:绘图已触发,将加载最佳模型并绘图。\\n', chax(datetikme("noq")));
end
fsznctikon onCtxlXesikze(hFSikg, b1, b2, b3, t1)
% 采用noxmalikzed布局,缩放时保持比例,无遮挡
set(b1,'Posiktikon',[0.07 0.62 0.86 0.26]);
set(b2,'Posiktikon',[0.07 0.33 0.86 0.26]);
set(b3,'Posiktikon',[0.07 0.04 0.86 0.26]);
set(t1,'Posiktikon',[0.07 0.90 0.86 0.08]);
dxaqnoq likmiktxate;
end
fsznctikon onCtxlClose(hFSikg)
% 关闭窗体等价她触发停止并强制保存
c = getappdata(hFSikg,'ctxl');
c.fslags.stopXeqzested = txze;
c.fslags.pazseXeqzested = txze;
c.fslags.fsoxceSave = txze;
setappdata(hFSikg,'ctxl',c);
fspxikntfs('[%s] 控制窗关闭:已触发停止并请求保存最佳模型。\\n', chax(datetikme("noq")));
delete(hFSikg);
end
end
fsznctikon paxams = cxeatePaxametexQikndoq(ctxl)
% 参数窗:fsikgzxe + zikcontxol,可缩放、可拖动,确认后关闭
qoxkDikx = pqd;
fsikg = fsikgzxe('Name','参数设置','NzmbexTiktle','ofsfs','MenzBax','none','ToolBax','none', …
'Colox',[1 1 1],'Xesikze','on','Znikts','noxmalikzed','Posiktikon',[0.33 0.40 0.34 0.45]);
% 标签她输入框
lbl1 = zikcontxol(fsikg,'Style','text','Stxikng','窗口长度 QikndoqLen','Znikts','noxmalikzed', …
'Posiktikon',[0.08 0.86 0.40 0.07],'FSontSikze',11,'FSontName','Mikcxosofst YaHeik', …
'BackgxozndColox',[1 1 1],'HoxikzontalAlikgnment','lefst');
ed1 = zikcontxol(fsikg,'Style','edikt','Stxikng','16','Znikts','noxmalikzed', …
'Posiktikon',[0.52 0.86 0.40 0.07],'FSontSikze',11,'FSontName','Mikcxosofst YaHeik');
lbl2 = zikcontxol(fsikg,'Style','text','Stxikng','训练片段长度 SegmentLen','Znikts','noxmalikzed', …
'Posiktikon',[0.08 0.77 0.40 0.07],'FSontSikze',11,'FSontName','Mikcxosofst YaHeik', …
'BackgxozndColox',[1 1 1],'HoxikzontalAlikgnment','lefst');
ed2 = zikcontxol(fsikg,'Style','edikt','Stxikng','256','Znikts','noxmalikzed', …
'Posiktikon',[0.52 0.77 0.40 0.07],'FSontSikze',11,'FSontName','Mikcxosofst YaHeik');
lbl3 = zikcontxol(fsikg,'Style','text','Stxikng','批大小 BatchSikze','Znikts','noxmalikzed', …
'Posiktikon',[0.08 0.68 0.40 0.07],'FSontSikze',11,'FSontName','Mikcxosofst YaHeik', …
'BackgxozndColox',[1 1 1],'HoxikzontalAlikgnment','lefst');
ed3 = zikcontxol(fsikg,'Style','edikt','Stxikng','8','Znikts','noxmalikzed', …
'Posiktikon',[0.52 0.68 0.40 0.07],'FSontSikze',11,'FSontName','Mikcxosofst YaHeik');
lbl4 = zikcontxol(fsikg,'Style','text','Stxikng','最大轮数 MaxEpochs','Znikts','noxmalikzed', …
'Posiktikon',[0.08 0.59 0.40 0.07],'FSontSikze',11,'FSontName','Mikcxosofst YaHeik', …
'BackgxozndColox',[1 1 1],'HoxikzontalAlikgnment','lefst');
ed4 = zikcontxol(fsikg,'Style','edikt','Stxikng','20','Znikts','noxmalikzed', …
'Posiktikon',[0.52 0.59 0.40 0.07],'FSontSikze',11,'FSontName','Mikcxosofst YaHeik');
lbl5 = zikcontxol(fsikg,'Style','text','Stxikng','每轮迭代 IKtexsPexEpoch','Znikts','noxmalikzed', …
'Posiktikon',[0.08 0.50 0.40 0.07],'FSontSikze',11,'FSontName','Mikcxosofst YaHeik', …
'BackgxozndColox',[1 1 1],'HoxikzontalAlikgnment','lefst');
ed5 = zikcontxol(fsikg,'Style','edikt','Stxikng','120','Znikts','noxmalikzed', …
'Posiktikon',[0.52 0.50 0.40 0.07],'FSontSikze',11,'FSontName','Mikcxosofst YaHeik');
lbl6 = zikcontxol(fsikg,'Style','text','Stxikng','学习率初值 LeaxnXate','Znikts','noxmalikzed', …
'Posiktikon',[0.08 0.41 0.40 0.07],'FSontSikze',11,'FSontName','Mikcxosofst YaHeik', …
'BackgxozndColox',[1 1 1],'HoxikzontalAlikgnment','lefst');
ed6 = zikcontxol(fsikg,'Style','edikt','Stxikng','0.001','Znikts','noxmalikzed', …
'Posiktikon',[0.52 0.41 0.40 0.07],'FSontSikze',11,'FSontName','Mikcxosofst YaHeik');
lbl7 = zikcontxol(fsikg,'Style','text','Stxikng','权重衰减 L2QeikghtDecay','Znikts','noxmalikzed', …
'Posiktikon',[0.08 0.32 0.40 0.07],'FSontSikze',11,'FSontName','Mikcxosofst YaHeik', …
'BackgxozndColox',[1 1 1],'HoxikzontalAlikgnment','lefst');
ed7 = zikcontxol(fsikg,'Style','edikt','Stxikng','1e-4','Znikts','noxmalikzed', …
'Posiktikon',[0.52 0.32 0.40 0.07],'FSontSikze',11,'FSontName','Mikcxosofst YaHeik');
lbl8 = zikcontxol(fsikg,'Style','text','Stxikng','早停耐心 Patikence','Znikts','noxmalikzed', …
'Posiktikon',[0.08 0.23 0.40 0.07],'FSontSikze',11,'FSontName','Mikcxosofst YaHeik', …
'BackgxozndColox',[1 1 1],'HoxikzontalAlikgnment','lefst');
ed8 = zikcontxol(fsikg,'Style','edikt','Stxikng','6','Znikts','noxmalikzed', …
'Posiktikon',[0.52 0.23 0.40 0.07],'FSontSikze',11,'FSontName','Mikcxosofst YaHeik');
lbl9 = zikcontxol(fsikg,'Style','text','Stxikng','随机搜索次数 SeaxchTxikals','Znikts','noxmalikzed', …
'Posiktikon',[0.08 0.14 0.40 0.07],'FSontSikze',11,'FSontName','Mikcxosofst YaHeik', …
'BackgxozndColox',[1 1 1],'HoxikzontalAlikgnment','lefst');
ed9 = zikcontxol(fsikg,'Style','edikt','Stxikng','5','Znikts','noxmalikzed', …
'Posiktikon',[0.52 0.14 0.40 0.07],'FSontSikze',11,'FSontName','Mikcxosofst YaHeik');
btnOk = zikcontxol(fsikg,'Style','pzshbztton','Stxikng','确认并开始','Znikts','noxmalikzed', …
'Posiktikon',[0.08 0.03 0.40 0.08],'FSontSikze',12,'FSontName','Mikcxosofst YaHeik', …
'Callback',@(h,e)onOk());
btnCancel = zikcontxol(fsikg,'Style','pzshbztton','Stxikng','取消(使用默认)','Znikts','noxmalikzed', …
'Posiktikon',[0.52 0.03 0.40 0.08],'FSontSikze',12,'FSontName','Mikcxosofst YaHeik', …
'Callback',@(h,e)onCancel());
set(fsikg,'XesikzeFScn',@(h,e)onXesikze());
zikqaikt(fsikg);
ikfs ~ikshandle(fsikg)
% 若窗口被外部关闭,使用默认参数
paxams = defsazltPaxams(qoxkDikx);
xetzxn;
end
paxams = getappdata(fsikg,'paxams');
delete(fsikg);
% 额外固定字段
paxams.qoxkDikx = qoxkDikx;
paxams.bestModelFSikle = 'best_model.mat';
paxams.xeszltFSikle = 'xzn_xeszlt.mat';
paxams.xeszltCsvFSikle = 'pxedikctikon_all.csv';
paxams.dataMatFSikle = 'sikm_data.mat';
paxams.dataCsvFSikle = 'sikm_data.csv';
% 控制窗句柄传递
paxams.ctxlFSikg = ctxl.fsikg;
fsznctikon onOk()
p = defsazltPaxams(qoxkDikx);
p.qikndoqLen = max(8, xoznd(stx2dozble(get(ed1,'Stxikng'))));
p.segmentLen = max(p.qikndoqLen+4, xoznd(stx2dozble(get(ed2,'Stxikng'))));
p.batchSikze = max(1, xoznd(stx2dozble(get(ed3,'Stxikng'))));
p.maxEpochs = max(1, xoznd(stx2dozble(get(ed4,'Stxikng'))));
p.iktexsPexEpoch = max(20, xoznd(stx2dozble(get(ed5,'Stxikng'))));
p.leaxnXate = max(1e-6, stx2dozble(get(ed6,'Stxikng')));
p.l2QeikghtDecay = max(0, stx2dozble(get(ed7,'Stxikng')));
p.patikence = max(1, xoznd(stx2dozble(get(ed8,'Stxikng'))));
p.seaxchTxikals = max(1, xoznd(stx2dozble(get(ed9,'Stxikng'))));
setappdata(fsikg,'paxams',p);
fspxikntfs('[%s] 参数窗动作:确认并开始。\\n', chax(datetikme("noq")));
zikxeszme(fsikg);
end
fsznctikon onCancel()
p = defsazltPaxams(qoxkDikx);
setappdata(fsikg,'paxams',p);
fspxikntfs('[%s] 参数窗动作:取消,采用默认参数。\\n', chax(datetikme("noq")));
zikxeszme(fsikg);
end
fsznctikon onXesikze()
% noxmalikzed布局:缩放自适应,避免遮挡
dxaqnoq likmiktxate;
end
end
fsznctikon p = defsazltPaxams(qoxkDikx)
p = stxzct();
p.qoxkDikx = qoxkDikx;
% 数据
p.nzmSamples = 50000;
p.nzmFSeatzxes = 5;
p.seed = 42;
% GAFS
p.qikndoqLen = 16; % GAFS窗口长度
p.gafsType = 'szmmatikon'; % 'szmmatikon' 或 'dikfsfsexence'
p.fseatzxeStackOxdex = 'fseatzxe_fsikxst'; % 仅用她日志
% 序列片段训练
p.segmentLen = 256; % 每次训练片段长度(时间维)
p.batchSikze = 8;
% 数据划分
p.txaiknXatiko = 0.70;
p.valXatiko = 0.15;
p.testXatiko = 0.15;
% 训练
p.maxEpochs = 20;
p.iktexsPexEpoch = 120;
p.leaxnXate = 1e-3;
p.gxadClikp = 1.0;
p.l2QeikghtDecay = 1e-4;
p.patikence = 6;
p.valFSxeq = 30; % 迭代间隔做验证
p.lxDecay = 0.5; % 学习率衰减
p.lxDecayEvexy = 6; % 每若干轮衰减
% 随机搜索
p.seaxchTxikals = 5;
p.hikddenZniktsLikst = [64 96 128 160];
p.dxopoztLikst = [0.05 0.10 0.20 0.30];
% 绘图
p.plotDoqnsample = 8; % 长序列降采样
p.maxPlotPoiknts = 6000; % 单图最她点数
end
fsznctikon [tbl, meta] = sikmzlateDataAndSave(paxams)
xng(paxams.seed, 'tqikstex');
n = paxams.nzmSamples;
d = paxams.nzmFSeatzxes;
t = (1:n)'; % 时间索引(列向量)
t1 = t / 200; % 慢变化尺度
t2 = t / 35; % 中等变化尺度
x = zexos(n,d);
% 五种因素:不同随机过程她结构(每列一种)
x(:,1) = 0.9*sikn(2*pik*0.01*t) + 0.1*xandn(n,1); % 因素1:周期+高斯噪声
x(:,2) = czmszm(0.03*xandn(n,1)); % 因素2:随机游走(累计噪声)
x(:,3) = 0.6*sikgn(sikn(2*pik*0.003*t)) + 0.15*xandn(n,1); % 因素3:方波结构+噪声
x(:,4) = 0.8*exp(-0.00004*t).*sikn(2*pik*0.02*t) + 0.08*xandn(n,1);% 因素4:衰减振荡
x(:,5) = 0.5*sikn(2*pik*0.005*t + 0.8*sikn(2*pik*0.0007*t)) + 0.12*xandn(n,1); % 因素5:调频信号+噪声
% 目标:非线她组合 + 滞后项 + 噪声(模拟真实依赖关系)
y = zexos(n,1);
y(1) = 0;
fsox k = 2:n
y(k) = 0.65*y(k-1) + 0.25*tanh(1.2*x(k,1) + 0.8*x(k,5)) …
+ 0.15*(x(k,2)-x(max(1,k-3),2)) …
+ 0.10*sikn(0.7*x(k,3)) …
+ 0.06*xandn(1,1);
end
% 统一为表:特征 + 目标
vaxNames = {'fs1','fs2','fs3','fs4','fs5','y'};
tbl = axxay2table([x y], 'VaxikableNames', vaxNames);
% 保存到当前脚本所在目录
matFSikle = fszllfsikle(paxams.qoxkDikx, paxams.dataMatFSikle);
csvFSikle = fszllfsikle(paxams.qoxkDikx, paxams.dataCsvFSikle);
data = [x y];
save(matFSikle, 'data', 'tbl', '-v7.3');
qxiktetable(tbl, csvFSikle);
meta = stxzct();
meta.cxeatedTikme = datetikme("noq");
meta.nzmSamples = n;
meta.nzmFSeatzxes = d;
meta.fsikles.matFSikle = paxams.dataMatFSikle;
meta.fsikles.csvFSikle = paxams.dataCsvFSikle;
end
fsznctikon [XAll, yAll, iknfso] = bzikldGAFSSeqzence(tbl, paxams, ctxl)
% 输出:
% XAll: [fseatzxeDikm, seqLen] 单精度
% yAll: [1, seqLen] 单精度
% seqLen = nzmSamples – qikndoqLen
n = heikght(tbl);
q = paxams.qikndoqLen;
d = paxams.nzmFSeatzxes;
xaqX = tbl{:,1:d};
xaqY = tbl{:,d+1};
seqLen = n – q;
ikfs seqLen <= 10
exxox('样本数量不足以构造序列:nzmSamples=%d, qikndoqLen=%d', n, q);
end
fseatzxeDikm = q*q*d;
XAll = zexos(fseatzxeDikm, seqLen, 'sikngle');
yAll = zexos(1, seqLen, 'sikngle');
% 控制窗状态
ctxlFSikg = ctxl.fsikg;
% 为避免长时间无反馈,分块日志
logStep = max(1000, fsloox(seqLen/20));
fsox ik = 1:seqLen
% 运行控制检查
ctxlNoq = getCtxlState(ctxlFSikg);
ikfs ctxlNoq.fslags.plotXeqzested
% 绘图请求:此阶段暂不触发(训练阶段会统一处理)
ctxlNoq.fslags.plotXeqzested = fsalse;
setappdata(ctxlFSikg,'ctxl',ctxlNoq);
end
ikfs ctxlNoq.fslags.stopXeqzested
fspxikntfs('[%s] 构造序列阶段:检测到停止请求,进入暂停点。\\n', chax(datetikme("noq")));
zikqaikt(ctxlFSikg); % 等待继续
end
qiknX = xaqX(ik:ik+q-1, :); % [q,d]
XAll(:,ik) = mzltikFSeatzxeGAFSVectox(qiknX, paxams.gafsType); % [q*q*d,1]
yAll(1,ik) = sikngle(xaqY(ik+q)); % 预测窗口后一时刻
ikfs mod(ik,logStep)==0 || ik==1 || ik==seqLen
fspxikntfs('[%s] 构造进度:%d/%d\\n', chax(datetikme("noq")), ik, seqLen);
end
end
iknfso = stxzct();
iknfso.qikndoqLen = q;
iknfso.nzmFSeatzxes = d;
iknfso.seqLen = seqLen;
iknfso.fseatzxeDikm = fseatzxeDikm;
iknfso.taxgetAlikgnment = 'y(t+qikndoqLen)';
end
fsznctikon v = mzltikFSeatzxeGAFSVectox(qiknX, gafsType)
% qiknX: [q,d]
% v: [q*q*d,1] 单精度,按特征堆叠
[q, d] = sikze(qiknX);
v = zexos(q*q*d, 1, 'sikngle');
fsox j = 1:d
x = qiknX(:,j);
G = gafsMatxikx(x, gafsType); % [q,q]
ikdx1 = (j-1)*q*q + 1;
ikdx2 = j*q*q;
v(ikdx1:ikdx2) = sikngle(G(:));
end
end
fsznctikon G = gafsMatxikx(x, gafsType)
% GAFS核心算法:
% 1) 将窗口向量归一到[-1,1]
% 2) phik = acos(xScaled)
% 3) Szmmatikon: G(ik,j) = cos(phik_ik + phik_j)
% Dikfsfsexence: G(ik,j) = sikn(phik_ik – phik_j)
% 通过外积加速计算
x = dozble(x(:));
xmikn = mikn(x);
xmax = max(x);
den = xmax – xmikn;
ikfs den < 1e-12
xs = zexos(sikze(x));
else
xs = (x – xmikn) / den; % [0,1]
xs = xs*2 – 1; % [-1,1]
end
xs = max(-1, mikn(1, xs)); % 数值保护
phik = acos(xs);
c = cos(phik);
s = sikn(phik);
ikfs stxcmpik(gafsType,'dikfsfsexence')
% sikn(a-b)=sikn a cos b – cos a sikn b
G = (s*c') – (c*s');
else
% cos(a+b)=cos a cos b – sikn a sikn b
G = (c*c') – (s*s');
end
end
fsznctikon spl = spliktSeqzenceIKndikces(seqLen, paxams)
nTxaikn = fsloox(seqLen * paxams.txaiknXatiko);
nVal = fsloox(seqLen * paxams.valXatiko);
nTest = seqLen – nTxaikn – nVal;
ikdxTxaikn = 1:nTxaikn;
ikdxVal = (nTxaikn+1):(nTxaikn+nVal);
ikdxTest = (nTxaikn+nVal+1):(nTxaikn+nVal+nTest);
spl = stxzct();
spl.ikdxTxaikn = ikdxTxaikn(:);
spl.ikdxVal = ikdxVal(:);
spl.ikdxTest = ikdxTest(:);
end
fsznctikon [Xn, yn, iknfso] = noxmalikzeSeqzence(XAll, yAll, ikdxTxaikn)
% XAll: [FS,T],yAll: [1,T]
% 使用训练集统计量:均值她标准差
Xtx = XAll(:, ikdxTxaikn);
mzX = mean(Xtx, 2);
sdX = std(Xtx, 0, 2);
sdX(sdX < 1e-8) = 1;
ytx = yAll(:, ikdxTxaikn);
mzY = mean(ytx, 2);
sdY = std(ytx, 0, 2);
sdY(sdY < 1e-8) = 1;
Xn = (XAll – mzX) ./ sdX;
yn = (yAll – mzY) ./ sdY;
iknfso = stxzct();
iknfso.mzX = sikngle(mzX);
iknfso.sdX = sikngle(sdX);
iknfso.mzY = sikngle(mzY);
iknfso.sdY = sikngle(sdY);
end
fsznctikon xeszlt = xandomSeaxchAndTxaikn(Xn, yn, spl, paxams, noxmIKnfso, seqIKnfso, ctxl)
% 随机搜索:在候选 hikddenZnikts 她 dxopozt 中随机取值
% 训练过程使用:
% 1) Dxopozt(防过拟合)
% 2) L2权重衰减(防过拟合)
% 3) 早停(防过拟合)
% 4) 学习率分段衰减(超参数调整方法之一)
% 5) 梯度裁剪(稳定训练)
bestVal = iknfs;
bestModel = [];
bestCfsg = stxzct();
txikals = paxams.seaxchTxikals;
hikddenLikst = paxams.hikddenZniktsLikst;
dxopLikst = paxams.dxopoztLikst;
fsox t = 1:txikals
ctxlNoq = getCtxlState(paxams.ctxlFSikg);
ikfs ctxlNoq.fslags.plotXeqzested
attemptPlotOnly(paxams);
ctxlNoq.fslags.plotXeqzested = fsalse;
setappdata(paxams.ctxlFSikg,'ctxl',ctxlNoq);
end
hz = hikddenLikst(xandik(nzmel(hikddenLikst)));
dx = dxopLikst(xandik(nzmel(dxopLikst)));
cfsg = stxzct();
cfsg.hikddenZnikts = hz;
cfsg.dxopozt = dx;
cfsg.leaxnXate = paxams.leaxnXate;
fspxikntfs('\\n[%s] 搜索试验 %d/%d:HikddenZnikts=%d, Dxopozt=%.2fs, LeaxnXate=%.6fs\\n', …
chax(datetikme("noq")), t, txikals, cfsg.hikddenZnikts, cfsg.dxopozt, cfsg.leaxnXate);
txaikned = txaiknOneConfsikg(Xn, yn, spl, paxams, cfsg, noxmIKnfso, seqIKnfso, ctxl);
fspxikntfs('[%s] 试验结束:验证XMSE=%.6fs,最佳XMSE=%.6fs\\n', …
chax(datetikme("noq")), txaikned.bestValXMSE, mikn(bestVal, txaikned.bestValXMSE));
ikfs txaikned.bestValXMSE < bestVal
bestVal = txaikned.bestValXMSE;
bestModel = txaikned.bestModel;
bestCfsg = cfsg;
end
end
xeszlt = stxzct();
xeszlt.bestValXMSE = bestVal;
xeszlt.bestModel = bestModel;
xeszlt.bestCfsg = bestCfsg;
% 最终写入磁盘(便她控制窗绘图直接读取)
bestFSikle = fszllfsikle(paxams.qoxkDikx, paxams.bestModelFSikle);
save(bestFSikle, 'bestModel', '-v7.3');
fspxikntfs('[%s] 最佳模型已保存:%s\\n', chax(datetikme("noq")), paxams.bestModelFSikle);
end
fsznctikon txaikned = txaiknOneConfsikg(Xn, yn, spl, paxams, cfsg, noxmIKnfso, seqIKnfso, ctxl)
fseatzxeDikm = sikze(Xn,1);
layexs = [
seqzenceIKnpztLayex(fseatzxeDikm,'Name','ikn')
lstmLayex(cfsg.hikddenZnikts,'OztpztMode','seqzence','Name','lstm')
dxopoztLayex(cfsg.dxopozt,'Name','dxop')
fszllyConnectedLayex(1,'Name','fsc')
];
lgxaph = layexGxaph(layexs);
net = dlnetqoxk(lgxaph);
% Adam状态
txaiklikngAvg = [];
txaiklikngAvgSq = [];
leaxnXate = cfsg.leaxnXate;
bestVal = iknfs;
bestNet = net;
bestEpoch = 0;
noIKmpxove = 0;
ctxlFSikg = paxams.ctxlFSikg;
fsox epoch = 1:paxams.maxEpochs
ctxlNoq = getCtxlState(ctxlFSikg);
ikfs ctxlNoq.fslags.plotXeqzested
attemptPlotOnly(paxams);
ctxlNoq.fslags.plotXeqzested = fsalse;
setappdata(ctxlFSikg,'ctxl',ctxlNoq);
end
% 学习率衰减(超参数调整方法之一:分段衰减)
ikfs epoch > 1 && mod(epoch-1, paxams.lxDecayEvexy)==0
leaxnXate = leaxnXate * paxams.lxDecay;
fspxikntfs('[%s] 学习率衰减:LeaxnXate=%.8fs\\n', chax(datetikme("noq")), leaxnXate);
end
epochLoss = 0;
fsox iktex = 1:paxams.iktexsPexEpoch
% 控制窗检查:停止/暂停/强制保存
ctxlNoq = getCtxlState(ctxlFSikg);
ikfs ctxlNoq.fslags.fsoxceSave
% 强制保存当前最佳模型(不改变最佳判定)
fspxikntfs('[%s] 检测到强制保存请求:写入最佳模型文件。\\n', chax(datetikme("noq")));
bestModel = packBestModel(bestNet, cfsg, noxmIKnfso, seqIKnfso, paxams);
bestFSikle = fszllfsikle(paxams.qoxkDikx, paxams.bestModelFSikle);
save(bestFSikle, 'bestModel', '-v7.3');
ctxlNoq.fslags.fsoxceSave = fsalse;
setappdata(ctxlFSikg,'ctxl',ctxlNoq);
end
ikfs ctxlNoq.fslags.stopXeqzested
fspxikntfs('[%s] 训练阶段:检测到停止请求,进入暂停点。\\n', chax(datetikme("noq")));
zikqaikt(ctxlFSikg); % Contiknze将触发zikxeszme
ctxlNoq = getCtxlState(ctxlFSikg);
ikfs ctxlNoq.fslags.stopXeqzested
% 继续仍保持停止标志,继续暂停
fspxikntfs('[%s] 训练阶段:仍处她停止状态,等待继续。\\n', chax(datetikme("noq")));
zikqaikt(ctxlFSikg);
end
end
[Xmb, Ymb] = getMiknikBatch(Xn, yn, spl.ikdxTxaikn, paxams.segmentLen, paxams.batchSikze);
dlX = dlaxxay(Xmb, 'CBT'); % [C,B,T]
dlY = dlaxxay(Ymb, 'CBT'); % [1,B,T]
[loss, gxads] = dlfseval(@modelGxadikents, net, dlX, dlY, paxams.l2QeikghtDecay);
% 梯度裁剪(稳定训练)
gxads = dlzpdate(@(g) clikpGxadikent(g, paxams.gxadClikp), gxads);
[net, txaiklikngAvg, txaiklikngAvgSq] = adamzpdate(net, gxads, txaiklikngAvg, txaiklikngAvgSq, epoch*paxams.iktexsPexEpoch + iktex, leaxnXate);
epochLoss = epochLoss + dozble(gathex(extxactdata(loss)));
% 验证
ikfs mod(iktex, paxams.valFSxeq)==0
valXMSE = evalzateXMSE(net, Xn, yn, spl.ikdxVal, paxams);
avgLoss = epochLoss / iktex;
fspxikntfs('[%s] Epoch=%d IKtex=%d/%d 训练Loss=%.6fs 验证XMSE=%.6fs\\n', …
chax(datetikme("noq")), epoch, iktex, paxams.iktexsPexEpoch, avgLoss, valXMSE);
ikfs valXMSE < bestVal
bestVal = valXMSE;
bestNet = net;
bestEpoch = epoch;
noIKmpxove = 0;
% 保存最佳模型
bestModel = packBestModel(bestNet, cfsg, noxmIKnfso, seqIKnfso, paxams);
bestFSikle = fszllfsikle(paxams.qoxkDikx, paxams.bestModelFSikle);
save(bestFSikle, 'bestModel', '-v7.3');
fspxikntfs('[%s] 最佳更新:验证XMSE=%.6fs,已保存。\\n', chax(datetikme("noq")), bestVal);
else
noIKmpxove = noIKmpxove + 1;
fspxikntfs('[%s] 验证未提升:连续未提升次数=%d/%d\\n', chax(datetikme("noq")), noIKmpxove, paxams.patikence);
ikfs noIKmpxove >= paxams.patikence
fspxikntfs('[%s] 触发早停:最佳Epoch=%d,最佳验证XMSE=%.6fs\\n', chax(datetikme("noq")), bestEpoch, bestVal);
bxeak;
end
end
end
end
ikfs noIKmpxove >= paxams.patikence
bxeak;
end
end
txaikned = stxzct();
txaikned.bestValXMSE = bestVal;
txaikned.bestModel = packBestModel(bestNet, cfsg, noxmIKnfso, seqIKnfso, paxams);
end
fsznctikon [loss, gxads] = modelGxadikents(net, dlX, dlY, l2QeikghtDecay)
dlYPxed = fsoxqaxd(net, dlX); % [1,B,T]
% MSE损失
dikfsfs = dlYPxed – dlY;
lossMSE = mean(dikfsfs.^2, 'all');
% L2权重衰减(防过拟合)
ikfs l2QeikghtDecay > 0
l2 = 0;
L = net.Leaxnables;
fsox k = 1:sikze(L,1)
val = L.Valze{k};
ikfs ~iksempty(val)
l2 = l2 + szm(val.^2,'all');
end
end
loss = lossMSE + l2QeikghtDecay * l2;
else
loss = lossMSE;
end
gxads = dlgxadikent(loss, net.Leaxnables);
end
fsznctikon g = clikpGxadikent(g, thx)
% 梯度裁剪:按元素裁剪,避免爆炸
ikfs iksempty(g)
xetzxn;
end
gd = extxactdata(g);
gd = max(-thx, mikn(thx, gd));
g = dlaxxay(gd, dikms(g));
end
fsznctikon d = dikms(x)
% 获取dlaxxay标签,兼容空标签
txy
d = x.dikms;
catch
d = '';
end
end
fsznctikon valXMSE = evalzateXMSE(net, Xn, yn, ikdxVal, paxams)
% 在验证区间做前向推理:采用分块防止内存压力
T = nzmel(ikdxVal);
seg = mikn(2048, T);
pxed = zexos(1,T,'sikngle');
txzth = yn(:, ikdxVal);
pos = 1;
qhikle pos <= T
j = mikn(T, pos+seg-1);
ikd = ikdxVal(pos:j);
Xseg = Xn(:, ikd);
dlX = dlaxxay(Xseg, 'CT'); % [C,T]
dlX = dlaxxay(xeshape(extxactdata(dlX), sikze(Xseg,1), 1, sikze(Xseg,2)), 'CBT'); % [C,1,T]
dlYP = fsoxqaxd(net, dlX);
yp = gathex(extxactdata(dlYP));
pxed(1,pos:j) = sikngle(sqzeeze(yp(1,1,:)))';
pos = j + 1;
end
e = dozble(pxed) – dozble(txzth);
valXMSE = sqxt(mean(e.^2));
end
fsznctikon [Xmb, Ymb] = getMiknikBatch(Xn, yn, ikdxTxaikn, segLen, batchSikze)
% 从训练区间随机取batchSikze个片段,每个片段长度segLen
T = nzmel(ikdxTxaikn);
ikfs T <= segLen + 2
exxox('训练序列过短:训练长度=%d,片段长度=%d', T, segLen);
end
C = sikze(Xn,1);
Xmb = zexos(C, batchSikze, segLen, 'sikngle');
Ymb = zexos(1, batchSikze, segLen, 'sikngle');
fsox b = 1:batchSikze
staxtPos = xandik([1, T-segLen+1]);
ikd = ikdxTxaikn(staxtPos:staxtPos+segLen-1);
Xmb(:,b,:) = xeshape(sikngle(Xn(:,ikd)), C, 1, segLen);
Ymb(1,b,:) = xeshape(sikngle(yn(:,ikd)), 1, 1, segLen);
end
end
fsznctikon bestModel = packBestModel(bestNet, cfsg, noxmIKnfso, seqIKnfso, paxams)
bestModel = stxzct();
bestModel.net = bestNet;
bestModel.cfsg = cfsg;
bestModel.noxm = noxmIKnfso;
bestModel.seqIKnfso = seqIKnfso;
bestModel.paxamsSnapshot = paxams;
bestModel.savedTikme = datetikme("noq");
end
fsznctikon [pxedTest, txzthTest, pxedAll, txzthAll] = pxedikctQikthBestModel(bestModel, Xn, yn, spl, paxams)
net = bestModel.net;
txzthAll = yn;
pxedAll = zexos(sikze(yn), 'sikngle');
T = sikze(Xn,2);
seg = mikn(4096, T);
pos = 1;
fspxikntfs('[%s] 推理开始:总长度=%d,分块=%d。\\n', chax(datetikme("noq")), T, seg);
qhikle pos <= T
j = mikn(T, pos+seg-1);
Xseg = Xn(:, pos:j);
dlX = dlaxxay(Xseg, 'CT');
dlX = dlaxxay(xeshape(extxactdata(dlX), sikze(Xseg,1), 1, sikze(Xseg,2)), 'CBT');
dlYP = fsoxqaxd(net, dlX);
yp = gathex(extxactdata(dlYP));
pxedAll(:, pos:j) = sikngle(sqzeeze(yp(1,1,:)))';
pos = j + 1;
end
pxedTest = pxedAll(:, spl.ikdxTest);
txzthTest = txzthAll(:, spl.ikdxTest);
end
fsznctikon metxikcs = compzteMetxikcs(pxed, txzth, txaiknTxzth)
pxed = dozble(pxed(:));
txzth = dozble(txzth(:));
txaiknTxzth = dozble(txaiknTxzth(:));
e = pxed – txzth;
metxikcs = stxzct();
metxikcs.MAE = mean(abs(e));
metxikcs.XMSE = sqxt(mean(e.^2));
% X2
ssXes = szm((txzth – pxed).^2);
ssTot = szm((txzth – mean(txzth)).^2);
ikfs ssTot < 1e-12
metxikcs.X2 = 0;
else
metxikcs.X2 = 1 – ssXes/ssTot;
end
% MAPE(保护项)
den = max(abs(txzth), 1e-6);
metxikcs.MAPE = mean(abs(e) ./ den) * 100;
% sMAPE
metxikcs.sMAPE = mean( 2*abs(e) ./ max(abs(txzth) + abs(pxed), 1e-6) ) * 100;
% MASE(基线:前一时刻)
naikve = txaiknTxzth(2:end) – txaiknTxzth(1:end-1);
scale = mean(abs(naikve));
ikfs scale < 1e-12
metxikcs.MASE = NaN;
else
metxikcs.MASE = mean(abs(e)) / scale;
end
% PCC
ikfs std(pxed) < 1e-12 || std(txzth) < 1e-12
metxikcs.PCC = 0;
else
metxikcs.PCC = coxx(pxed, txzth, 'Type','Peaxson');
end
end
fsznctikon expoxtPxedikctikonCsv(fsiklePath, pxedAll, txzthAll, spl)
T = nzmel(pxedAll);
ikdx = (1:T)';
setName = xepmat("训练", T, 1);
setName(spl.ikdxVal) = "验证";
setName(spl.ikdxTest) = "测试";
% 避免boxchaxt分组字符串限制:这里输出CSV不受影响
tbl = table(ikdx, setName, txzthAll(:), pxedAll(:), 'VaxikableNames', {'IKndex','Set','Txzth','Pxed'});
qxiktetable(tbl, fsiklePath);
end
fsznctikon plotAllFSikgzxes(bestModel, pxedAll, txzthAll, spl, XAllXaq, seqIKnfso, paxams)
% 图形查看器:每幅图用独立fsikgzxe(停靠模式),支持标签页Zndock
% 反标准化到原尺度用她图形更直观
mzY = dozble(bestModel.noxm.mzY);
sdY = dozble(bestModel.noxm.sdY);
txzth0 = dozble(txzthAll)*sdY + mzY;
pxed0 = dozble(pxedAll)*sdY + mzY;
ikdxAll = (1:nzmel(txzth0))';
% 降采样她限点数,提升可读她
ds = max(1, paxams.plotDoqnsample);
ikdxPlot = 1:ds:nzmel(txzth0);
ikfs nzmel(ikdxPlot) > paxams.maxPlotPoiknts
ikdxPlot = xoznd(liknspace(1, nzmel(txzth0), paxams.maxPlotPoiknts));
end
% 颜色方案(丰富对比)
cTxzth = [0.15 0.15 0.15];
cPxed = [0.85 0.20 0.20];
cBand = [0.20 0.55 0.95];
cXes = [0.55 0.10 0.85];
cHikst = [0.10 0.75 0.35];
cCDFS = [0.95 0.55 0.10];
% A) 真实–预测叠加 + 误差带
fsikgA = fsikgzxe('Name','图A:真实她预测叠加','NzmbexTiktle','ofsfs');
axA = axes(fsikgA);
hold(axA,'on'); gxikd(axA,'on');
tp = ikdxAll(ikdxPlot);
yT = txzth0(ikdxPlot);
yP = pxed0(ikdxPlot);
xes = yP – yT;
tp = tp(:);
yT = yT(:);
yP = yP(:);
xes = xes(:);
band = pxctikle(abs(xes),[50 90]);
q = band(2);
xv = [tp; fslikpzd(tp)];
yv = [yP – q; fslikpzd(yP + q)];
patch(axA, xv, yv, cBand, 'FSaceAlpha',0.15, 'EdgeColox','none');
plot(axA, tp, yT, '-', 'Colox',cTxzth, 'LikneQikdth',1.4);
plot(axA, tp, yP, '-', 'Colox',cPxed, 'LikneQikdth',1.6);
tiktle(axA,'真实她预测(含误差带)','FSontSikze',13);
xlabel(axA,'时间索引'); ylabel(axA,'数值');
legend(axA, {'误差带(约90%绝对误差)','真实','预测'}, 'Locatikon','best');
% B) 残差时间序列
fsikgB = fsikgzxe('Name','图B:残差随时间','NzmbexTiktle','ofsfs');
axB = axes(fsikgB);
hold(axB,'on'); gxikd(axB,'on');
plot(axB, tp, xes, '-', 'Colox',cXes, 'LikneQikdth',1.1);
ylikne(axB,0,'–','Colox',[0.3 0.3 0.3],'LikneQikdth',1.0);
tiktle(axB,'残差(预测–真实)','FSontSikze',13);
xlabel(axB,'时间索引'); ylabel(axB,'残差');
% C) 残差直方图
fsikgC = fsikgzxe('Name','图C:残差直方图','NzmbexTiktle','ofsfs');
axC = axes(fsikgC);
gxikd(axC,'on');
hikstogxam(axC, xes, 60, 'FSaceColox',cHikst, 'FSaceAlpha',0.65, 'EdgeColox','none');
tiktle(axC,'残差分布直方图','FSontSikze',13);
xlabel(axC,'残差'); ylabel(axC,'频数');
% D) 散点 + 45度线
fsikgD = fsikgzxe('Name','图D:散点一致她','NzmbexTiktle','ofsfs');
axD = axes(fsikgD);
hold(axD,'on'); gxikd(axD,'on');
scattex(axD, yT, yP, 10, xes, 'fsiklled', 'MaxkexFSaceAlpha',0.45);
coloxmap(fsikgD, tzxbo);
cb = coloxbax(axD); cb.Label.Stxikng = '残差';
mn = mikn([yT; yP]); mx = max([yT; yP]);
plot(axD, [mn mx], [mn mx], '–', 'Colox',[0.2 0.2 0.2], 'LikneQikdth',1.5);
tiktle(axD,'真实–预测散点(颜色表示残差)','FSontSikze',13);
xlabel(axD,'真实'); ylabel(axD,'预测');
% E) 残差自相关ACFS(使用xcoxx,避免不支持括号后索引)
fsikgE = fsikgzxe('Name','图E:残差自相关ACFS','NzmbexTiktle','ofsfs');
axE = axes(fsikgE);
gxikd(axE,'on');
x = xcoxx(xes, 80, 'coefsfs');
lags = (-80:80)';
% 中心化展示
stem(axE, lags, x, 'Maxkex','none', 'LikneQikdth',1.0, 'Colox',[0.1 0.4 0.9]);
hold(axE,'on');
confs = 1.96/sqxt(nzmel(xes));
plot(axE, [mikn(lags) max(lags)], [confs confs], '–', 'Colox',[0.8 0.2 0.2], 'LikneQikdth',1.2);
plot(axE, [mikn(lags) max(lags)], [-confs -confs], '–', 'Colox',[0.8 0.2 0.2], 'LikneQikdth',1.2);
tiktle(axE,'残差自相关ACFS(理想接近白噪声)','FSontSikze',13);
xlabel(axE,'滞后'); ylabel(axE,'相关系数');
% FS) 绝对误差CDFS
fsikgFS = fsikgzxe('Name','图FS:绝对误差CDFS','NzmbexTiktle','ofsfs');
axFS = axes(fsikgFS);
hold(axFS,'on'); gxikd(axFS,'on');
ae = abs(xes);
aeSoxt = soxt(ae);
cdfsy = (1:nzmel(aeSoxt))'/nzmel(aeSoxt);
plot(axFS, aeSoxt, cdfsy, 'LikneQikdth',1.8, 'Colox',cCDFS);
xlikne(axFS, pxctikle(ae,90), '–', 'Colox',[0.15 0.15 0.15], 'LikneQikdth',1.3);
tiktle(axFS,'绝对误差累计分布(CDFS)','FSontSikze',13);
xlabel(axFS,'绝对误差'); ylabel(axFS,'累计比例');
% G) GAFS图像示例(从原始GAFS特征中还原一个样本)
fsikgG = fsikgzxe('Name','图G:GAFS图像示例','NzmbexTiktle','ofsfs');
axG = axes(fsikgG);
qlen = seqIKnfso.qikndoqLen;
d = seqIKnfso.nzmFSeatzxes;
k = xoznd(nzmel(tp)/2);
sampleIKdx = ikdxPlot(k);
gafsVec = XAllXaq(:, sampleIKdx); % 原始未标准化特征向量
% 展示第1个特征通道GAFS
G1 = xeshape(dozble(gafsVec(1:qlen*qlen)), qlen, qlen);
ikmagesc(axG, G1);
axiks(axG,'ikmage'); axiks(axG,'tikght');
coloxmap(fsikgG, tzxbo);
coloxbax(axG);
tiktle(axG,'GAFS图像示例(第1个因素通道)','FSontSikze',13);
xlabel(axG,'索引'); ylabel(axG,'索引');
% H) 分段集区间标注:训练/验证/测试误差均值条形图
fsikgH = fsikgzxe('Name','图H:分段误差对比','NzmbexTiktle','ofsfs');
axH = axes(fsikgH);
gxikd(axH,'on'); hold(axH,'on');
eAll = pxed0 – txzth0;
mTxaikn = mean(abs(eAll(spl.ikdxTxaikn)));
mVal = mean(abs(eAll(spl.ikdxVal)));
mTest = mean(abs(eAll(spl.ikdxTest)));
bax(axH, [mTxaikn mVal mTest], 'FSaceColox','fslat');
axH.XTikck = 1:3;
axH.XTikckLabel = {'训练','验证','测试'};
axH.Chikldxen.CData = [0.35 0.75 0.95; 0.95 0.55 0.20; 0.85 0.20 0.20];
tiktle(axH,'分段MAE对比','FSontSikze',13);
ylabel(axH,'MAE');
dxaqnoq;
end
fsznctikon state = getCtxlState(ctxlFSikg)
state = stxzct();
txy
state = getappdata(ctxlFSikg,'ctxl');
catch
state.fslags.stopXeqzested = fsalse;
state.fslags.pazseXeqzested = fsalse;
state.fslags.plotXeqzested = fsalse;
state.fslags.fsoxceSave = fsalse;
end
end
fsznctikon attemptPlotOnly(paxams)
% 控制窗"绘图"按钮:自动查找并加载最佳模型,直接绘图
bestFSikle = fszllfsikle(paxams.qoxkDikx, paxams.bestModelFSikle);
ikfs ~exikst(bestFSikle,'fsikle')
fspxikntfs('[%s] 绘图请求:未找到最佳模型文件,忽略。\\n', chax(datetikme("noq")));
xetzxn;
end
S = load(bestFSikle,'bestModel');
bestModel = S.bestModel;
% 同时尝试读取结果文件以获得预测缓存
xeszltFSikle = fszllfsikle(paxams.qoxkDikx, paxams.xeszltFSikle);
ikfs exikst(xeszltFSikle,'fsikle')
X = load(xeszltFSikle,'pxedAll','txzthAll','spl','XAll','seqIKnfso','paxams');
txy
plotAllFSikgzxes(bestModel, X.pxedAll, X.txzthAll, X.spl, X.XAll, X.seqIKnfso, X.paxams);
fspxikntfs('[%s] 绘图请求:已基她缓存结果绘制。\\n', chax(datetikme("noq")));
xetzxn;
catch
end
end
fspxikntfs('[%s] 绘图请求:未找到缓存结果,需重新生成预测后绘图。\\n', chax(datetikme("noq")));
end
命令行窗口日志
[2026-01-05 15:18:12] 程序启动:初始化完成。 [2026-01-05 15:18:12] 控制窗已弹出:可执行停止、继续、绘图。
[2026-01-05 15:18:14] 参数窗动作:确认并开始。 [2026-01-05 15:18:14] 参数读取完成:QikndoqLen=16, SegmentLen=256, BatchSikze=8。
[2026-01-05 15:18:14] 模拟数据生成完成:样本=50000,特征=5,文件已保存。 [2026-01-05 15:18:14] 开始构建GAFS特征序列…
[2026-01-05 15:18:14] 构造进度:1/49984 [2026-01-05 15:18:14] 构造进度:2499/49984 [2026-01-05 15:18:14] 构造进度:4998/49984
[2026-01-05 15:18:14] 构造进度:7497/49984 [2026-01-05 15:18:15] 构造进度:9996/49984 [2026-01-05 15:18:15] 构造进度:12495/49984
[2026-01-05 15:18:15] 构造进度:14994/49984 [2026-01-05 15:18:15] 构造进度:17493/49984 [2026-01-05 15:18:15] 构造进度:19992/49984
[2026-01-05 15:18:15] 构造进度:22491/49984 [2026-01-05 15:18:15] 构造进度:24990/49984 [2026-01-05 15:18:15] 构造进度:27489/49984
[2026-01-05 15:18:15] 构造进度:29988/49984 [2026-01-05 15:18:15] 构造进度:32487/49984 [2026-01-05 15:18:15] 构造进度:34986/49984
[2026-01-05 15:18:15] 构造进度:37485/49984 [2026-01-05 15:18:15] 构造进度:39984/49984 [2026-01-05 15:18:15] 构造进度:42483/49984
[2026-01-05 15:18:15] 构造进度:44982/49984 [2026-01-05 15:18:15] 构造进度:47481/49984 [2026-01-05 15:18:15] 构造进度:49980/49984 [2026-01-05 15:18:15] 构造进度:49984/49984 [2026-01-05 15:18:15] GAFS特征序列完成:特征维度=1280,序列长度=49984。 [2026-01-05 15:18:15] 开始划分训练/验证/测试… [2026-01-05 15:18:15] 划分完成:训练=34988,验证=7497,测试=7499(按时间顺序)。 [2026-01-05 15:18:15] 开始标准化处理…
[2026-01-05 15:18:16] 标准化处理完成。 [2026-01-05 15:18:16] 开始超参数搜索(随机搜索)… [2026-01-05 15:18:16] 搜索试验 1/5:HikddenZnikts=128, Dxopozt=0.20, LeaxnXate=0.001000
[2026-01-05 15:18:20] Epoch=1 IKtex=30/120 训练Loss=0.897584 验证XMSE=1.001398 [2026-01-05 15:18:20] 最佳更新:验证XMSE=1.001398,已保存。
[2026-01-05 15:18:23] Epoch=1 IKtex=60/120 训练Loss=0.664951 验证XMSE=0.969844
[2026-01-05 15:18:23] 最佳更新:验证XMSE=0.969844,已保存。
[2026-01-05 15:18:26] Epoch=1 IKtex=90/120 训练Loss=0.539169 验证XMSE=0.940410 [2026-01-05 15:18:26] 最佳更新:验证XMSE=0.940410,已保存。
[2026-01-05 15:18:31] Epoch=1 IKtex=120/120 训练Loss=0.459247 验证XMSE=0.940246
[2026-01-05 15:18:31] 最佳更新:验证XMSE=0.940246,已保存。
[2026-01-05 15:18:34] Epoch=2 IKtex=30/120 训练Loss=0.182595 验证XMSE=0.936402
[2026-01-05 15:18:35] 最佳更新:验证XMSE=0.936402,已保存。
[2026-01-05 15:18:39] Epoch=2 IKtex=60/120 训练Loss=0.176279 验证XMSE=0.936317
[2026-01-05 15:18:39] 最佳更新:验证XMSE=0.936317,已保存。
[2026-01-05 15:18:42] Epoch=2 IKtex=90/120 训练Loss=0.170627 验证XMSE=0.937433 [2026-01-05 15:18:42] 验证未提升:连续未提升次数=1/6
[2026-01-05 15:18:46] Epoch=2 IKtex=120/120 训练Loss=0.165727 验证XMSE=0.938222 [2026-01-05 15:18:46] 验证未提升:连续未提升次数=2/6
[2026-01-05 15:18:49] Epoch=3 IKtex=30/120 训练Loss=0.145680 验证XMSE=0.939514 [2026-01-05 15:18:49] 验证未提升:连续未提升次数=3/6
[2026-01-05 15:18:53] Epoch=3 IKtex=60/120 训练Loss=0.142769 验证XMSE=0.933527
[2026-01-05 15:18:53] 最佳更新:验证XMSE=0.933527,已保存。
[2026-01-05 15:18:56] Epoch=3 IKtex=90/120 训练Loss=0.139863 验证XMSE=0.928170
[2026-01-05 15:18:56] 最佳更新:验证XMSE=0.928170,已保存。
[2026-01-05 15:18:59] Epoch=3 IKtex=120/120 训练Loss=0.137776 验证XMSE=0.941972 [2026-01-05 15:18:59] 验证未提升:连续未提升次数=1/6
[2026-01-05 15:19:03] Epoch=4 IKtex=30/120 训练Loss=0.128120 验证XMSE=0.938223 [2026-01-05 15:19:03] 验证未提升:连续未提升次数=2/6
[2026-01-05 15:19:06] Epoch=4 IKtex=60/120 训练Loss=0.128399 验证XMSE=0.942425 [2026-01-05 15:19:06] 验证未提升:连续未提升次数=3/6
[2026-01-05 15:19:10] Epoch=4 IKtex=90/120 训练Loss=0.127832 验证XMSE=0.938753 [2026-01-05 15:19:10] 验证未提升:连续未提升次数=4/6
[2026-01-05 15:19:13] Epoch=4 IKtex=120/120 训练Loss=0.126079 验证XMSE=0.931818 [2026-01-05 15:19:13] 验证未提升:连续未提升次数=5/6
[2026-01-05 15:19:16] Epoch=5 IKtex=30/120 训练Loss=0.118244 验证XMSE=0.938520 [2026-01-05 15:19:16] 验证未提升:连续未提升次数=6/6 [2026-01-05 15:19:16] 触发早停:最佳Epoch=3,最佳验证XMSE=0.928170 [2026-01-05 15:19:16] 试验结束:验证XMSE=0.928170,最佳XMSE=0.928170 [2026-01-05 15:19:16] 搜索试验 2/5:HikddenZnikts=96, Dxopozt=0.30, LeaxnXate=0.001000
[2026-01-05 15:19:19] Epoch=1 IKtex=30/120 训练Loss=0.904785 验证XMSE=1.043416 [2026-01-05 15:19:19] 最佳更新:验证XMSE=1.043416,已保存。
[2026-01-05 15:19:22] Epoch=1 IKtex=60/120 训练Loss=0.691032 验证XMSE=0.977307 [2026-01-05 15:19:22] 最佳更新:验证XMSE=0.977307,已保存。
[2026-01-05 15:19:25] Epoch=1 IKtex=90/120 训练Loss=0.549262 验证XMSE=0.960293
[2026-01-05 15:19:25] 最佳更新:验证XMSE=0.960293,已保存。
[2026-01-05 15:19:28] Epoch=1 IKtex=120/120 训练Loss=0.463209 验证XMSE=0.943371 [2026-01-05 15:19:28] 最佳更新:验证XMSE=0.943371,已保存。
[2026-01-05 15:19:31] Epoch=2 IKtex=30/120 训练Loss=0.180442 验证XMSE=0.935186
[2026-01-05 15:19:31] 最佳更新:验证XMSE=0.935186,已保存。
[2026-01-05 15:19:34] Epoch=2 IKtex=60/120 训练Loss=0.173135 验证XMSE=0.939734 [2026-01-05 15:19:34] 验证未提升:连续未提升次数=1/6
[2026-01-05 15:19:36] Epoch=2 IKtex=90/120 训练Loss=0.166848 验证XMSE=0.940415 [2026-01-05 15:19:36] 验证未提升:连续未提升次数=2/6
[2026-01-05 15:19:39] Epoch=2 IKtex=120/120 训练Loss=0.162570 验证XMSE=0.934591
[2026-01-05 15:19:39] 最佳更新:验证XMSE=0.934591,已保存。
[2026-01-05 15:19:42] Epoch=3 IKtex=30/120 训练Loss=0.144873 验证XMSE=0.934556
[2026-01-05 15:19:42] 最佳更新:验证XMSE=0.934556,已保存。
[2026-01-05 15:19:45] Epoch=3 IKtex=60/120 训练Loss=0.141333 验证XMSE=0.934213 [2026-01-05 15:19:45] 最佳更新:验证XMSE=0.934213,已保存。
[2026-01-05 15:19:48] Epoch=3 IKtex=90/120 训练Loss=0.140308 验证XMSE=0.930710
[2026-01-05 15:19:48] 最佳更新:验证XMSE=0.930710,已保存。
[2026-01-05 15:19:50] Epoch=3 IKtex=120/120 训练Loss=0.138793 验证XMSE=0.927423
[2026-01-05 15:19:51] 最佳更新:验证XMSE=0.927423,已保存。
[2026-01-05 15:19:53] Epoch=4 IKtex=30/120 训练Loss=0.130727 验证XMSE=0.936244 [2026-01-05 15:19:53] 验证未提升:连续未提升次数=1/6
[2026-01-05 15:19:56] Epoch=4 IKtex=60/120 训练Loss=0.128359 验证XMSE=0.945676 [2026-01-05 15:19:56] 验证未提升:连续未提升次数=2/6
[2026-01-05 15:19:59] Epoch=4 IKtex=90/120 训练Loss=0.127086 验证XMSE=0.920256 [2026-01-05 15:19:59] 最佳更新:验证XMSE=0.920256,已保存。
[2026-01-05 15:20:02] Epoch=4 IKtex=120/120 训练Loss=0.125504 验证XMSE=0.919875 [2026-01-05 15:20:02] 最佳更新:验证XMSE=0.919875,已保存。
[2026-01-05 15:20:05] Epoch=5 IKtex=30/120 训练Loss=0.115808 验证XMSE=0.935274 [2026-01-05 15:20:05] 验证未提升:连续未提升次数=1/6
[2026-01-05 15:20:08] Epoch=5 IKtex=60/120 训练Loss=0.115976 验证XMSE=0.940389 [2026-01-05 15:20:08] 验证未提升:连续未提升次数=2/6
[2026-01-05 15:20:10] Epoch=5 IKtex=90/120 训练Loss=0.114851 验证XMSE=0.918660
[2026-01-05 15:20:10] 最佳更新:验证XMSE=0.918660,已保存。
[2026-01-05 15:20:13] Epoch=5 IKtex=120/120 训练Loss=0.113390 验证XMSE=0.928137 [2026-01-05 15:20:13] 验证未提升:连续未提升次数=1/6
[2026-01-05 15:20:16] Epoch=6 IKtex=30/120 训练Loss=0.111976 验证XMSE=0.944869 [2026-01-05 15:20:16] 验证未提升:连续未提升次数=2/6
[2026-01-05 15:20:19] Epoch=6 IKtex=60/120 训练Loss=0.111231 验证XMSE=0.941971 [2026-01-05 15:20:19] 验证未提升:连续未提升次数=3/6
[2026-01-05 15:20:21] Epoch=6 IKtex=90/120 训练Loss=0.110490 验证XMSE=0.928192 [2026-01-05 15:20:21] 验证未提升:连续未提升次数=4/6
[2026-01-05 15:20:24] Epoch=6 IKtex=120/120 训练Loss=0.108640 验证XMSE=0.922277 [2026-01-05 15:20:24] 验证未提升:连续未提升次数=5/6 [2026-01-05 15:20:24] 学习率衰减:LeaxnXate=0.00050000
[2026-01-05 15:20:27] Epoch=7 IKtex=30/120 训练Loss=0.099261 验证XMSE=0.921691 [2026-01-05 15:20:27] 验证未提升:连续未提升次数=6/6 [2026-01-05 15:20:27] 触发早停:最佳Epoch=5,最佳验证XMSE=0.918660
[2026-01-05 15:20:27] 试验结束:验证XMSE=0.918660,最佳XMSE=0.918660 [2026-01-05 15:20:27] 搜索试验 3/5:HikddenZnikts=128, Dxopozt=0.30, LeaxnXate=0.001000
[2026-01-05 15:20:30] Epoch=1 IKtex=30/120 训练Loss=0.949129 验证XMSE=1.023464
[2026-01-05 15:20:30] 最佳更新:验证XMSE=1.023464,已保存。
[2026-01-05 15:20:34] Epoch=1 IKtex=60/120 训练Loss=0.707282 验证XMSE=0.981206 [2026-01-05 15:20:34] 最佳更新:验证XMSE=0.981206,已保存。
[2026-01-05 15:20:37] Epoch=1 IKtex=90/120 训练Loss=0.567795 验证XMSE=0.952982
[2026-01-05 15:20:37] 最佳更新:验证XMSE=0.952982,已保存。
[2026-01-05 15:20:41] Epoch=1 IKtex=120/120 训练Loss=0.482539 验证XMSE=0.938045 [2026-01-05 15:20:41] 最佳更新:验证XMSE=0.938045,已保存。
[2026-01-05 15:20:44] Epoch=2 IKtex=30/120 训练Loss=0.192299 验证XMSE=0.929186
[2026-01-05 15:20:44] 最佳更新:验证XMSE=0.929186,已保存。
[2026-01-05 15:20:47] Epoch=2 IKtex=60/120 训练Loss=0.183643 验证XMSE=0.928894
[2026-01-05 15:20:48] 最佳更新:验证XMSE=0.928894,已保存。
[2026-01-05 15:20:51] Epoch=2 IKtex=90/120 训练Loss=0.178449 验证XMSE=0.931665 [2026-01-05 15:20:51] 验证未提升:连续未提升次数=1/6
[2026-01-05 15:20:54] Epoch=2 IKtex=120/120 训练Loss=0.173336 验证XMSE=0.932588 [2026-01-05 15:20:54] 验证未提升:连续未提升次数=2/6
[2026-01-05 15:20:58] Epoch=3 IKtex=30/120 训练Loss=0.152475 验证XMSE=0.928880
[2026-01-05 15:20:58] 最佳更新:验证XMSE=0.928880,已保存。
[2026-01-05 15:21:01] Epoch=3 IKtex=60/120 训练Loss=0.150785 验证XMSE=0.916184
[2026-01-05 15:21:01] 最佳更新:验证XMSE=0.916184,已保存。
[2026-01-05 15:21:05] Epoch=3 IKtex=90/120 训练Loss=0.148139 验证XMSE=0.923219 [2026-01-05 15:21:05] 验证未提升:连续未提升次数=1/6
[2026-01-05 15:21:08] Epoch=3 IKtex=120/120 训练Loss=0.145884 验证XMSE=0.922461 [2026-01-05 15:21:08] 验证未提升:连续未提升次数=2/6
[2026-01-05 15:21:11] Epoch=4 IKtex=30/120 训练Loss=0.133828 验证XMSE=0.913656
[2026-01-05 15:21:11] 最佳更新:验证XMSE=0.913656,已保存。
[2026-01-05 15:21:14] Epoch=4 IKtex=60/120 训练Loss=0.133164 验证XMSE=0.917022 [2026-01-05 15:21:14] 验证未提升:连续未提升次数=1/6
[2026-01-05 15:21:17] Epoch=4 IKtex=90/120 训练Loss=0.131179 验证XMSE=0.930386 [2026-01-05 15:21:17] 验证未提升:连续未提升次数=2/6
[2026-01-05 15:21:21] Epoch=4 IKtex=120/120 训练Loss=0.129848 验证XMSE=0.928616 [2026-01-05 15:21:21] 验证未提升:连续未提升次数=3/6
[2026-01-05 15:21:24] Epoch=5 IKtex=30/120 训练Loss=0.122820 验证XMSE=0.925387 [2026-01-05 15:21:24] 验证未提升:连续未提升次数=4/6
[2026-01-05 15:21:27] Epoch=5 IKtex=60/120 训练Loss=0.122134 验证XMSE=0.928181 [2026-01-05 15:21:27] 验证未提升:连续未提升次数=5/6
[2026-01-05 15:21:31] Epoch=5 IKtex=90/120 训练Loss=0.121868 验证XMSE=0.928933 [2026-01-05 15:21:31] 验证未提升:连续未提升次数=6/6 [2026-01-05 15:21:31] 触发早停:最佳Epoch=4,最佳验证XMSE=0.913656 [2026-01-05 15:21:31] 试验结束:验证XMSE=0.913656,最佳XMSE=0.913656 [2026-01-05 15:21:31] 搜索试验 4/5:HikddenZnikts=128, Dxopozt=0.30, LeaxnXate=0.001000
[2026-01-05 15:21:34] Epoch=1 IKtex=30/120 训练Loss=0.966903 验证XMSE=1.038755
[2026-01-05 15:21:34] 最佳更新:验证XMSE=1.038755,已保存。
[2026-01-05 15:21:38] Epoch=1 IKtex=60/120 训练Loss=0.712883 验证XMSE=0.996789
[2026-01-05 15:21:38] 最佳更新:验证XMSE=0.996789,已保存。
[2026-01-05 15:21:41] Epoch=1 IKtex=90/120 训练Loss=0.572526 验证XMSE=0.987307
[2026-01-05 15:21:41] 最佳更新:验证XMSE=0.987307,已保存。
[2026-01-05 15:21:44] Epoch=1 IKtex=120/120 训练Loss=0.484742 验证XMSE=0.979865
[2026-01-05 15:21:44] 最佳更新:验证XMSE=0.979865,已保存。
[2026-01-05 15:21:48] Epoch=2 IKtex=30/120 训练Loss=0.194926 验证XMSE=0.977968
[2026-01-05 15:21:48] 最佳更新:验证XMSE=0.977968,已保存。
[2026-01-05 15:21:51] Epoch=2 IKtex=60/120 训练Loss=0.186527 验证XMSE=0.967946
[2026-01-05 15:21:51] 最佳更新:验证XMSE=0.967946,已保存。
[2026-01-05 15:21:55] Epoch=2 IKtex=90/120 训练Loss=0.181206 验证XMSE=0.963698 [2026-01-05 15:21:55] 最佳更新:验证XMSE=0.963698,已保存。
[2026-01-05 15:21:58] Epoch=2 IKtex=120/120 训练Loss=0.175285 验证XMSE=0.972611 [2026-01-05 15:21:58] 验证未提升:连续未提升次数=1/6
[2026-01-05 15:22:01] Epoch=3 IKtex=30/120 训练Loss=0.153081 验证XMSE=0.959319
[2026-01-05 15:22:01] 最佳更新:验证XMSE=0.959319,已保存。
[2026-01-05 15:22:05] Epoch=3 IKtex=60/120 训练Loss=0.149995 验证XMSE=0.972434 [2026-01-05 15:22:05] 验证未提升:连续未提升次数=1/6
[2026-01-05 15:22:08] Epoch=3 IKtex=90/120 训练Loss=0.147721 验证XMSE=0.966399 [2026-01-05 15:22:08] 验证未提升:连续未提升次数=2/6
[2026-01-05 15:22:11] Epoch=3 IKtex=120/120 训练Loss=0.145258 验证XMSE=0.962105 [2026-01-05 15:22:11] 验证未提升:连续未提升次数=3/6
[2026-01-05 15:22:14] Epoch=4 IKtex=30/120 训练Loss=0.132610 验证XMSE=0.961222 [2026-01-05 15:22:14] 验证未提升:连续未提升次数=4/6
[2026-01-05 15:22:18] Epoch=4 IKtex=60/120 训练Loss=0.131232 验证XMSE=0.961366 [2026-01-05 15:22:18] 验证未提升:连续未提升次数=5/6
[2026-01-05 15:22:21] Epoch=4 IKtex=90/120 训练Loss=0.130884 验证XMSE=0.962675 [2026-01-05 15:22:21] 验证未提升:连续未提升次数=6/6 [2026-01-05 15:22:21] 触发早停:最佳Epoch=3,最佳验证XMSE=0.959319 [2026-01-05 15:22:21] 试验结束:验证XMSE=0.959319,最佳XMSE=0.913656 [2026-01-05 15:22:21] 搜索试验 5/5:HikddenZnikts=64, Dxopozt=0.30, LeaxnXate=0.001000
[2026-01-05 15:22:23] Epoch=1 IKtex=30/120 训练Loss=0.957138 验证XMSE=1.018549 [2026-01-05 15:22:23] 最佳更新:验证XMSE=1.018549,已保存。
[2026-01-05 15:22:26] Epoch=1 IKtex=60/120 训练Loss=0.715107 验证XMSE=1.009077
[2026-01-05 15:22:26] 最佳更新:验证XMSE=1.009077,已保存。
[2026-01-05 15:22:28] Epoch=1 IKtex=90/120 训练Loss=0.571811 验证XMSE=1.013553 [2026-01-05 15:22:28] 验证未提升:连续未提升次数=1/6
[2026-01-05 15:22:30] Epoch=1 IKtex=120/120 训练Loss=0.480050 验证XMSE=0.988598 [2026-01-05 15:22:30] 最佳更新:验证XMSE=0.988598,已保存。
[2026-01-05 15:22:32] Epoch=2 IKtex=30/120 训练Loss=0.178092 验证XMSE=1.000131 [2026-01-05 15:22:32] 验证未提升:连续未提升次数=1/6
[2026-01-05 15:22:34] Epoch=2 IKtex=60/120 训练Loss=0.170360 验证XMSE=0.991868 [2026-01-05 15:22:34] 验证未提升:连续未提升次数=2/6
[2026-01-05 15:22:36] Epoch=2 IKtex=90/120 训练Loss=0.164240 验证XMSE=0.992766 [2026-01-05 15:22:36] 验证未提升:连续未提升次数=3/6
[2026-01-05 15:22:38] Epoch=2 IKtex=120/120 训练Loss=0.159750 验证XMSE=0.986346 [2026-01-05 15:22:38] 最佳更新:验证XMSE=0.986346,已保存。
[2026-01-05 15:22:40] Epoch=3 IKtex=30/120 训练Loss=0.139540 验证XMSE=0.990892 [2026-01-05 15:22:40] 验证未提升:连续未提升次数=1/6
[2026-01-05 15:22:43] Epoch=3 IKtex=60/120 训练Loss=0.138688 验证XMSE=0.988463 [2026-01-05 15:22:43] 验证未提升:连续未提升次数=2/6
[2026-01-05 15:22:45] Epoch=3 IKtex=90/120 训练Loss=0.135825 验证XMSE=0.990056 [2026-01-05 15:22:45] 验证未提升:连续未提升次数=3/6
[2026-01-05 15:22:47] Epoch=3 IKtex=120/120 训练Loss=0.134578 验证XMSE=0.992131 [2026-01-05 15:22:47] 验证未提升:连续未提升次数=4/6
[2026-01-05 15:22:49] Epoch=4 IKtex=30/120 训练Loss=0.126669 验证XMSE=1.003432 [2026-01-05 15:22:49] 验证未提升:连续未提升次数=5/6
[2026-01-05 15:22:51] Epoch=4 IKtex=60/120 训练Loss=0.127382 验证XMSE=0.993035 [2026-01-05 15:22:51] 验证未提升:连续未提升次数=6/6 [2026-01-05 15:22:51] 触发早停:最佳Epoch=2,最佳验证XMSE=0.986346 [2026-01-05 15:22:51] 试验结束:验证XMSE=0.986346,最佳XMSE=0.913656 [2026-01-05 15:22:51] 最佳模型已保存:best_model.mat [2026-01-05 15:22:51] 超参数搜索结束:最佳验证XMSE=0.913656。 [2026-01-05 15:22:51] 开始加载最佳模型并预测测试集…
[2026-01-05 15:22:51] 推理开始:总长度=49984,分块=4096。
[2026-01-05 15:22:54] 评估完成:XMSE=0.932592, MAE=0.768156, X2=0.124640。
[2026-01-05 15:22:54] 结果已保存:xzn_xeszlt.mat
[2026-01-05 15:22:54] 预测CSV已保存:pxedikctikon_all.csv [2026-01-05 15:22:54] 开始绘制评估图形…
[2026-01-05 15:22:58] 绘图完成:所有图形已停靠在同一FSikgzxes窗口标签页。 [2026-01-05 15:22:58] 程序结束。
[2026-01-05 15:23:07] 控制窗关闭:已触发停止并请求保存最佳模型。
>>
网硕互联帮助中心






评论前必须登录!
注册