TCN-T
创建于:2026年1月21日
使用 GPT-5.2 Thinking 回答 Chat01
创建于:2026年1月21日
使用 GPT-5.2 Thinking 回答 Chat01
import numpy as np
import pandas as pd
import matplotlib.pyplot as plt
import pywt
from vmdpy import VMD
plt.rcParams['font.sans-serif'] = ['SimHei', 'Arial']
plt.rcParams['axes.unicode_minus'] = False
plt.rcParams['font.size'] = 10
class VMDIWD_Denoising:
def init(self, K=5, alpha=2000, tau=0, DC=0, init=1, tol=1e-7):
self.K = K
self.alpha = alpha
self.tau = tau
self.DC = DC
self.init = init
self.tol = tol
textdef _improved_threshold_function(self, coeffs, T, beta=0.6): """改进的阈值函数""" X = np.array(coeffs) Y = np.zeros_like(X) mask = np.abs(X) >= T X_valid = X[mask] abs_X = np.abs(X_valid) # 防止溢出 exp_input = (abs_X - T) / (T + 1e-10) # 【修复】防止除零 exp_input = np.clip(exp_input, -50, 50) omega = abs_X - (2 * T) / (1 + np.exp(exp_input)) power_term = abs_X**2 - T**2 power_term = np.clip(power_term, 0, 100) mu = np.power(beta, power_term) Y[mask] = (1 - mu) * X_valid + mu * np.sign(X_valid) * omega return Y def wavelet_denoise_layer(self, data, wavelet='db4', level=3, beta=0.6): """小波阈值去噪层""" original_len = len(data) coeffs = pywt.wavedec(data, wavelet, level=level) sigma = np.median(np.abs(coeffs[-1])) / 0.6745 N = len(data) T = sigma * np.sqrt(2 * np.log(N)) if N > 1 else 0 # 【修复】防止log(0) denoised_coeffs = [coeffs[0]] for i in range(1, len(coeffs)): denoised_coeffs.append(self._improved_threshold_function(coeffs[i], T, beta)) rec = pywt.waverec(denoised_coeffs, wavelet) # 【修复】强制长度一致 if len(rec) > original_len: rec = rec[:original_len] elif len(rec) < original_len: rec = np.pad(rec, (0, original_len - len(rec)), mode='edge') return rec def denoise(self, signal): """主去噪函数""" original_len = len(signal) # 【关键】记录原始长度 print(f" -> 正在进行 VMD 分解 (K={self.K})...") u, _, _ = VMD(signal, self.alpha, self.tau, self.K, self.DC, self.init, self.tol) vmd_len = u.shape[1] # VMD 分解后的长度 print(f" -> VMD 分解后长度: {vmd_len} (原始: {original_len})") denoised_imfs = np.zeros_like(u) print(" -> 正在对 IMF 分量进行改进小波阈值去噪...") for i in range(self.K): denoised_imfs[i, :] = self.wavelet_denoise_layer(u[i, :]) result = np.sum(denoised_imfs, axis=0) # 【关键修复】将结果调整回原始长度 if len(result) != original_len: print(f" -> 调整输出长度: {len(result)} -> {original_len}") if len(result) > original_len: result = result[:original_len] else: # 使用线性插值恢复原始长度 x_old = np.linspace(0, 1, len(result)) x_new = np.linspace(0, 1, original_len) result = np.interp(x_new, x_old, result) return result
def calc_snr_estimate(original, denoised):
"""估算信噪比 (自动对齐长度)"""
min_len = min(len(original), len(denoised))
original = original[:min_len]
denoised = denoised[:min_len]
textnoise = original - denoised power_signal = np.sum(denoised ** 2) power_noise = np.sum(noise ** 2) if power_noise == 0: return float('inf') return 10 * np.log10(power_signal / power_noise)
def calc_rmse(original, denoised):
"""计算均方根误差"""
min_len = min(len(original), len(denoised))
return np.sqrt(np.mean((original[:min_len] - denoised[:min_len]) ** 2))
if name == "main":
file_path = r"D:\09-毕业论文\2025.07.08 小论文代码\02-惯导降噪算法\原始数据.csv"
text# 读取数据(兼容多种编码) df = None for encoding in ['gbk', 'gb2312', 'utf-8', 'utf-8-sig']: try: df = pd.read_csv(file_path, encoding=encoding) print(f"✓ 使用 {encoding} 编码读取成功") break except: continue if df is None: print("❌ 读取数据失败,请检查文件路径和编码") exit() target_col = '加表x(g)' time_col = 'GPS周内秒(s)' # 检查列是否存在 if target_col not in df.columns: print(f"❌ 列 '{target_col}' 不存在") print(f"可用列: {df.columns.tolist()}") exit() time = df[time_col].values signal = df[target_col].values # 【修复】处理缺失值(使用新语法) if np.isnan(signal).any(): print("⚠ 检测到缺失值,正在插值填充...") signal = pd.Series(signal).interpolate().bfill().ffill().values print(f"\n🚀 开始处理列: [{target_col}]") print(f" 数据长度: {len(signal)}") print(f" 数据范围: [{signal.min():.6f}, {signal.max():.6f}]") # --- 执行降噪 --- denoiser = VMDIWD_Denoising(K=5, alpha=2000) denoised_signal = denoiser.denoise(signal) # --- 验证长度 --- print(f"\n📏 长度检查:") print(f" 原始信号: {len(signal)}") print(f" 降噪信号: {len(denoised_signal)}") print(f" 时间轴: {len(time)}") # --- 计算指标 --- snr_val = calc_snr_estimate(signal, denoised_signal) rmse_val = calc_rmse(signal, denoised_signal) print(f"\n📊 处理完成!") print(f" 估计 SNR: {snr_val:.2f} dB") print(f" RMSE: {rmse_val:.6f}") # --- 对齐长度后绘图 --- min_len = min(len(time), len(signal), len(denoised_signal)) time = time[:min_len] signal = signal[:min_len] denoised_signal = denoised_signal[:min_len] print("\n🎨 正在绘图...") # 创建图形 fig, axes = plt.subplots(2, 1, figsize=(12, 8), sharex=True) # 图1:原始信号 vs 降噪信号 axes[0].plot(time, signal, color='#1f77b4', alpha=0.6, linewidth=0.8, label='Original Signal') axes[0].plot(time, denoised_signal, color='#ff7f0e', linewidth=1.0, label='VMD-IWD Denoised') axes[0].set_ylabel('Amplitude [g]') axes[0].set_title(f'VMD-IWD Denoising Result (SNR={snr_val:.1f}dB, RMSE={rmse_val:.2e})') axes[0].legend(loc='upper right') axes[0].grid(True, linestyle=':', alpha=0.6) axes[0].ticklabel_format(axis='y', style='sci', scilimits=(0, 0)) # 图2:去除的噪声 noise = signal - denoised_signal axes[1].plot(time, noise, color='#2ca02c', linewidth=0.8, label='Removed Noise') axes[1].set_xlabel('Time [s]') axes[1].set_ylabel('Noise Amplitude [g]') axes[1].set_title('Extracted Noise Component') axes[1].legend(loc='upper right') axes[1].grid(True, linestyle=':', alpha=0.6) axes[1].ticklabel_format(axis='y', style='sci', scilimits=(0, 0)) plt.tight_layout() plt.savefig('denoising_result.png', dpi=150, bbox_inches='tight') plt.show() print("\n✅ 图片已保存为 denoising_result.png")我这个降噪方法和原文一样吗
pythonimport re, pathlib, textwrap, os, sys, math, numpy as np, pandas as pd pdf_path="/mnt/data/Zhang 等 - 2024 - A novel multidimensional hybrid position compensation method for INSGPS integrated navigation syste.pdf" pdf_path, os.path.getsize(pdf_path) ('/mnt/data/Zhang 等 - 2024 - A novel multidimensional hybrid position compensation method for INSGPS integrated navigation syste.pdf', 3158382)
pythonimport pdfplumber, pandas as pd, numpy as np, re, textwrap, math, os, json, itertools texts=[] with pdfplumber.open(pdf_path) as pdf: for i,page in enumerate(pdf.pages): txt=page.extract_text() or "" texts.append(txt) len(texts), [len(t) for t in texts[:3]] (13, [5247, 6605, 5536])
pythonfull="\n".join(texts) for term in ["db4","Db4","wavelet","Wavelet","level","decomposition level","sym","coif","threshold","MAD","0.6745","universal threshold","sqrt(2","log"]: if term.lower() in full.lower(): print("found", term)
python# Find occurrences context def find_context(term, window=200): pat=re.compile(re.escape(term), re.IGNORECASE) for m in pat.finditer(full): start=max(0,m.start()-window) end=min(len(full), m.end()+window) yield full[start:end] contexts=list(itertools.islice(find_context("wavelet", 250), 10)) len(contexts) 10
pythonfor i,c in enumerate(contexts[:6],1): print("\n---",i,"---") print(c.replace("\n"," "))
pythonpage5=texts[4] # 0-index -> page 5 in pdf page5[:1500] '966 IEEESENSORSJOURNAL,VOL.24,NO.1,1JANUARY2024\nFig.3. FlowchartofVMD-IWD.\nFig.4. Functionalexpressionofimprovedwaveletthreshold.\nrelative to the previous time, this quantity will be used to\nintegrate with INS data to ensure accurate navigation during\nGPS outages. However, u (t) may still contain noise components. Hence,\nk\neach IMF should be denoised by the second-step wavelet\nA. VariationalModeDecomposition–ImprovedWavelet disposal. The wavelet threshold function is usually used for\nDenoising denoising. Its hard and soft threshold denoising functions are\nIn this article, we propose an integrated navigation sensor shown below\ndata denoising method, VMD-IWD. The two-step denoising (\nX, |X|≥T\nalgorithm flowchart is illustrated in Fig. 3. The gyroscope Hard:Y = (18)\n0, |X|<T\nand accelerometer will generate multifarious noise due to\n(\ntheir mechanical structure. The most critical effects are sign(X)(|X|−T), |X|≥T\nhigh-frequency noise and white noise. These noises usually Soft:Y = (19)\n0, |X|<T\nhave random walk characteristics and accumulate over time.\nWe use VMD to denoise in first step. Computing the signal where X isthewaveletcoefficient,T denotesthethresholding.\nby means of the Hilbert transform, which is given in [38] Since hard thresholding tends to introduce signal distortion\nin order to obtain a unilateral frequency spectrum. VMD and artifacts. Some important parts of the signal may be\ncalculates the variational problem M to decompose the signal erroneously removed, affect'
python# Search within page5 for 'db' 'sym' 'level' '3' for term in ["db", "sym", "coif", "haar", "level", "three", "3", "decomposition level", "wavedec"]: if term.lower() in page5.lower(): print("found", term)
pythonfor term in ["db", "Daubechies", "sym", "haar", "coif", "bior", "dB", "db4", "db8"]: if re.search(term, full, re.IGNORECASE): print("found", term)
python# show contexts for "db" occurrences db_contexts=list(itertools.islice(find_context("db", 120), 20)) len(db_contexts), db_contexts[:2][0][:200] (10, ' ofnavigationandpositioning. Notonlythat,theUAVwillbe\nHao Zhang, Hailiang Xiong, Gangqiang Yang, and Manman Wang\naffectedbymultiscalenoiseduringitsmovement.Itisnotonly\narewiththeSchoolofInformationSci')
python"Daubechies" in full False
不完全一样,但核心思路基本一致,差别主要在“细节实现/超参数”上。
原文的 VMD-IWD 流程是:先用 VMD 把信号分解成 K 个 IMF,再对 IMF 做改进的小波阈值去噪,最后重构信号。(Zhang 等 - 2024 - A novel multidimensional hybrid position compensation method for INSGPS integrated navigation syste.pdf)
你代码里的:
VMD(signal, ..., K, ...) 得到 u[k, :](IMFs)wavelet_denoise_layernp.sum(denoised_imfs, axis=0) 重构而且你实现的改进阈值函数形式也和论文公式(Ω 的 sigmoid 形式 + 自适应因子 μ=β^(|X|²−T²) + 加权融合)是同一类表达。(Zhang 等 - 2024 - A novel multidimensional hybrid position compensation method for INSGPS integrated navigation syste.pdf)
exp_input、power_term 做了 clip,还加了 T + 1e-10 防除零。论文公式是理想数学形式,并没提这些截断/裁剪。(Zhang 等 - 2024 - A novel multidimensional hybrid position compensation method for INSGPS integrated navigation syste.pdf)wavelet='db4', level=3,阈值用 MAD 估 σ,再用通用阈值 T = σ*sqrt(2logN)。sum(IMFs),没有额外残差分量的显式处理(取决于你用的 VMD 实现是否把残差包含在 IMFs 里)。如果你想“更像论文”,最优先改的就是:按 Fig.3 把 IMF(1) 直接当噪声去掉(或至少做个对照实验:去掉 vs 不去掉),再去对齐小波基/分解层数/阈值计算方式。
那帮我修改一下 并输出原文的图 你看看原文里出什么图 你也给我出一下
pythonimport pkgutil, sys 'fitz' in [m.name for m in pkgutil.iter_modules()] True
pythonimport os, zipfile, fitz from pathlib import Path pdf_path = Path("/mnt/data/Zhang 等 - 2024 - A novel multidimensional hybrid position compensation method for INSGPS integrated navigation syste.pdf") out_dir = Path("/mnt/data/zhang2024_fig_pages") out_dir.mkdir(parents=True, exist_ok=True) doc = fitz.open(pdf_path) # pages to export (0-indexed): include where key figures appear pages = { 3: "page4_fig1_fig2_training_prediction_process", 4: "page5_fig3_fig4_vmd_iwd_flowchart_threshold", 5: "page6_fig5_tdann_architecture", 7: "page8_tableIII_fig8_fig9_denoising_curves", 8: "page9_tableIV_fig10_position_errors_sim", 10: "page11_tableVII_fig11_position_errors_real", } zoom = 2.0 # ~144 dpi (72*2) mat = fitz.Matrix(zoom, zoom) exported = [] for pno, name in pages.items(): if pno < 0 or pno >= doc.page_count: continue page = doc.load_page(pno) pix = page.get_pixmap(matrix=mat, alpha=False) out_file = out_dir / f"{name}.png" pix.save(out_file.as_posix()) exported.append(out_file) zip_path = Path("/mnt/data/zhang2024_selected_pages.zip") with zipfile.ZipFile(zip_path, "w", compression=zipfile.ZIP_DEFLATED) as z: for f in exported: z.write(f, arcname=f.name) (zip_path.as_posix(), [f.name for f in exported], doc.page_count) ('/mnt/data/zhang2024_selected_pages.zip', ['page4_fig1_fig2_training_prediction_process.png', 'page5_fig3_fig4_vmd_iwd_flowchart_threshold.png', 'page6_fig5_tdann_architecture.png', 'page8_tableIII_fig8_fig9_denoising_curves.png', 'page9_tableIV_fig10_position_errors_sim.png', 'page11_tableVII_fig11_position_errors_real.png'], 13)
先给你“原文里有哪些图 + 我帮你把原文关键图导出来”:
论文 Fig.3 明确画了 IMF(1) → Noise,IMF(2)…IMF(K) 才做 IWD,然后重构(再加 residual 的写法)。(Zhang 等 - 2024 - A novel multidimensional hybrid position compensation method for INSGPS integrated navigation syste.pdf)
你现在是 所有 IMF 都做 IWD,这就是最主要的不一致点。
你只要在 denoise() 里改这一小段就行(我按你现有风格给“最小改动版”):
pythondef denoise(self, signal, drop_first_imf=True, denoise_residual=False): original_len = len(signal) print(f" -> 正在进行 VMD 分解 (K={self.K})...") u, _, _ = VMD(signal, self.alpha, self.tau, self.K, self.DC, self.init, self.tol) # residual(论文式写法里有 r_denoised) residual = signal - np.sum(u, axis=0) denoised_imfs = np.zeros_like(u) print(" -> 正在对 IMF 分量进行小波阈值去噪...") for i in range(self.K): if drop_first_imf and i == 0: # 【按论文 Fig.3】IMF(1) 直接当噪声丢弃 denoised_imfs[i, :] = 0.0 else: denoised_imfs[i, :] = self.wavelet_denoise_layer(u[i, :]) result = np.sum(denoised_imfs, axis=0) # residual 是否也去噪:论文写 r_denoised,你可做一个开关 if denoise_residual: residual = self.wavelet_denoise_layer(residual) result = result + residual # 论文式重构:sum(denoised IMFs) + r_denoised # 下面你原来的长度对齐逻辑保持不变 if len(result) != original_len: if len(result) > original_len: result = result[:original_len] else: x_old = np.linspace(0, 1, len(result)) x_new = np.linspace(0, 1, original_len) result = np.interp(x_new, x_old, result) return result
你现在默认就用:
denoise(signal, drop_first_imf=True)就已经更贴近论文 Fig.3 了。(Zhang 等 - 2024 - A novel multidimensional hybrid position compensation method for INSGPS integrated navigation syste.pdf)
从你上传的三段脚本来看,你要做的是:
train_all_models.py:用 INS 的 12维特征(速度/姿态/三轴加表/三轴陀螺),按 seq_len=20 组序列,预测 GNSS 的位置增量(北向/东向),训练 4 个模型并保存权重。(train_all_models.py)predict_all_models.py:加载训练好的模型,对测试段 INS 序列预测“北/东增量”,再把增量累加回经纬度,导出每个模型的轨迹结果 CSV。(predict_all_models.py)compare_errors.py:把每个模型预测轨迹与参考轨迹做 Vincenty 误差,输出北/东/总误差,并画误差对比图。(compare_errors.py)你现在想新增一个 FECAM-based TCN-Transformer,并把它加入训练/预测/误差对比里,和现有 Transformer/LSTM/CNN-GRU/TCN 一起对比。
models/fecam_tcn_transformer_model.py把下面整段存成一个新文件(路径跟你其它 models/*.py 放一起):
pythonimport torch import torch.nn as nn import torch.nn.functional as F class Chomp1d(nn.Module): """用于TCN的因果卷积裁剪(保持长度不变)""" def __init__(self, chomp_size: int): super().__init__() self.chomp_size = chomp_size def forward(self, x): return x[:, :, :-self.chomp_size] if self.chomp_size > 0 else x class TemporalBlock(nn.Module): def __init__(self, in_ch, out_ch, kernel_size=3, dilation=1, dropout=0.1): super().__init__() pad = (kernel_size - 1) * dilation # causal padding self.conv1 = nn.Conv1d(in_ch, out_ch, kernel_size, padding=pad, dilation=dilation) self.chomp1 = Chomp1d(pad) self.bn1 = nn.BatchNorm1d(out_ch) self.conv2 = nn.Conv1d(out_ch, out_ch, kernel_size, padding=pad, dilation=dilation) self.chomp2 = Chomp1d(pad) self.bn2 = nn.BatchNorm1d(out_ch) self.dropout = nn.Dropout(dropout) self.downsample = nn.Conv1d(in_ch, out_ch, 1) if in_ch != out_ch else None def forward(self, x): y = self.conv1(x) y = self.chomp1(y) y = self.bn1(y) y = F.relu(y) y = self.dropout(y) y = self.conv2(y) y = self.chomp2(y) y = self.bn2(y) y = F.relu(y) y = self.dropout(y) res = x if self.downsample is None else self.downsample(x) return F.relu(y + res) class FECAM(nn.Module): """ 一个“FECAM”风格的通道注意力:本质上是SE思路(全局池化→两层FC→Sigmoid→通道加权) """ def __init__(self, channels, reduction=8): super().__init__() hidden = max(1, channels // reduction) self.fc1 = nn.Linear(channels, hidden) self.fc2 = nn.Linear(hidden, channels) def forward(self, x): # x: (B, C, T) z = x.mean(dim=2) # (B, C) z = F.relu(self.fc1(z)) z = torch.sigmoid(self.fc2(z)) # (B, C) z = z.unsqueeze(-1) # (B, C, 1) return x * z class FECAM_TCN_Transformer(nn.Module): def __init__( self, input_dim: int = 12, seq_length: int = 20, tcn_channels: int = 64, tcn_levels: int = 3, kernel_size: int = 3, nhead: int = 4, num_transformer_layers: int = 2, dropout: float = 0.1, out_dim: int = 2, ): super().__init__() self.seq_length = seq_length # TCN: (B, C_in, T) -> (B, C, T) layers = [] in_ch = input_dim for i in range(tcn_levels): dilation = 2 ** i layers.append(TemporalBlock(in_ch, tcn_channels, kernel_size, dilation, dropout)) in_ch = tcn_channels self.tcn = nn.Sequential(*layers) # FECAM channel attention self.fecam = FECAM(tcn_channels, reduction=8) # Transformer encoder expects (B, T, D) enc_layer = nn.TransformerEncoderLayer( d_model=tcn_channels, nhead=nhead, dim_feedforward=tcn_channels * 4, dropout=dropout, batch_first=True, ) self.transformer = nn.TransformerEncoder(enc_layer, num_layers=num_transformer_layers) # regression head self.norm = nn.LayerNorm(tcn_channels) self.fc = nn.Sequential( nn.Linear(tcn_channels, 128), nn.ReLU(), nn.Dropout(dropout), nn.Linear(128, out_dim), ) def forward(self, x): # x: (B, T, F) x = x.transpose(1, 2) # (B, F, T) x = self.tcn(x) # (B, C, T) x = self.fecam(x) # (B, C, T) x = x.transpose(1, 2) # (B, T, C) x = self.transformer(x) # (B, T, C) x = x.mean(dim=1) # (B, C) 也可以换成 x[:, -1, :] x = self.norm(x) return self.fc(x)
train_all_models.py 改哪里?你这个文件里主要就两处:import + MODELS字典 + 绘图子图数量。(train_all_models.py)
1)增加 import(和其他模型放一起):
pythonfrom models.fecam_tcn_transformer_model import FECAM_TCN_Transformer
2)MODELS 字典里加一行:
pythonMODELS = { 'Transformer': TransformerModel(input_dim=12, seq_length=20), 'LSTM': LSTMModel(input_dim=12, seq_length=20), 'CNN_GRU': CNNGRUModel(input_dim=12, seq_length=20), 'TCN': TCNModel(input_dim=12, seq_length=20), 'FECAM_TCN_Transformer': FECAM_TCN_Transformer(input_dim=12, seq_length=20, out_dim=2) }
3)colors 也加一个(不然你后面画图会 KeyError):
pythoncolors = { 'Transformer': 'blue', 'LSTM': 'green', 'CNN_GRU': 'red', 'TCN': 'purple', 'FECAM_TCN_Transformer': 'orange' }
4)你现在固定 plt.subplots(2,2) 只够 4 个模型。建议最小改动:改成“自动网格”:
pythonimport math n = len(all_train_losses) cols = 2 rows = math.ceil(n / cols) fig, axes = plt.subplots(rows, cols, figsize=(14, 5 * rows)) axes = np.array(axes).reshape(-1) for idx, (name, train_losses) in enumerate(all_train_losses.items()): ax = axes[idx] ... # 多余的子图关掉 for j in range(idx + 1, len(axes)): axes[j].axis("off")
predict_all_models.py 改哪里?同样两处:import + MODELS字典。(predict_all_models.py)
1)加 import:
pythonfrom models.fecam_tcn_transformer_model import FECAM_TCN_Transformer
2)MODELS 字典加一项(名字要和训练脚本一致,权重文件名才能对上):
pythonMODELS = { 'Transformer': TransformerModel(input_dim=12, seq_length=20), 'LSTM': LSTMModel(input_dim=12, seq_length=20), 'CNN_GRU': CNNGRUModel(input_dim=12, seq_length=20), 'TCN': TCNModel(input_dim=12, seq_length=20), 'FECAM_TCN_Transformer': FECAM_TCN_Transformer(input_dim=12, seq_length=20, out_dim=2) }
你原来的加载权重:
{name.lower()}_model.pth会自动变成fecam_tcn_transformer_model.pth,和训练保存一致即可。
compare_errors.py 改哪里?也是两处:MODEL_NAMES + COLORS +(可选)图布局。(compare_errors.py)
1)加模型名:
pythonMODEL_NAMES = ['Transformer', 'LSTM', 'CNN_GRU', 'TCN', 'FECAM_TCN_Transformer']
2)加颜色:
pythonCOLORS = {'Transformer': 'blue', 'LSTM': 'green', 'CNN_GRU': 'red', 'TCN': 'purple', 'FECAM_TCN_Transformer': 'orange'}
3)(可选但建议)你现在固定 2x2 子图同样不够,按上面“自动网格”改一下就稳了。
论文在去噪部分主要展示两类图:
如果你要我把这段“画论文同款图”的脚本也按你本地 CSV 列名完整写好(直接生成 Fig.8/9 那种 3 子图对比),你把你INS原始数据.csv 的列名截图/贴一下(尤其陀螺三轴、加表三轴、时间列名),我就按你的列名一口气写成能跑的版本(你现在只贴了“加表x”和“GPS周内秒”,但 Fig.8/9 需要 6 个通道)。
如果你愿意走“最贴论文”的路线,下一步通常是:
你要不要我也顺手把 “训练前自动对 6 个IMU通道做 VMD-IWD 去噪,然后再训练所有模型” 这段接到 train_all_models.py 里?(这会更像论文完整 pipeline。)