简介:这份资源面向电离层物理、空间天气与无线电传播方向的研究人员和学生,提供名为 codeTEC_L 的 MATLAB 脚本,用于处理与可视化 CODEtec 相关的电离层数据。压缩包内仅含 1 个 .m 文件,体积约 1KB,属于轻量级工具脚本,便于直接嵌入既有分析流程。脚本围绕电子密度与总电子含量展开,涉及数据读取与清洗、缺失值和噪声处理、电离层模型参数校准、全球分布二维或三维绘图、时间序列与周期性特征分析,以及频谱滤波等信号处理环节,同时兼顾大规模数据下的算法优化与代码模块化组织。已有 487 人学习,适合希望快速上手电离层数据解析、复现可视化结果并理解 CODEtec 数据组织方式的读者参考,也可作为空间天气对通信与导航影响研究的入门脚本。
1. 电离层 TEC 数据处理:从 codeTEC_L.m 看 CODEtec 工具链的落地方式
做 GNSS 电离层监测的同行大概率都遇到过这种局面:手头攒了一批观测站的 TEC 序列,想快速看全球分布、看单站日变化、看磁暴期间的扰动响应,结果卡在数据解析和绘图这两步上。codeTEC_L.m就是冲着这个场景来的——它是 CODEtec 工具链里负责电离层 TEC 数据处理与可视化的 MATLAB 脚本,配套的codeTEC_L.zip里打包了脚本本体和运行所需的辅助文件。CODEtec 这套东西的核心思路是把电子密度和总电子含量(TEC)的编码、解码、建模、成图串成一条流水线,codeTEC_L.m是其中偏"L 波段 / 单站或局域"处理的那一环。它适合两类人:一是刚接触电离层 TEC 数据、需要一套能跑通的最小可用脚本的研究生和工程师;二是已经有自己的数据源、但想借一套现成的预处理加绘图框架来省掉重复造轮子的人。下面按"这东西怎么用 → 参数怎么调 → 坑在哪"的顺序拆开讲。
2. 把 codeTEC_L.m 跑起来:环境、数据接口与首次出图
2.1 运行环境与依赖确认
codeTEC_L.m是纯 MATLAB 脚本,不依赖 Simulink,也不强制要求额外工具箱,但有几处会用到 MATLAB 的基础绘图和矩阵运算能力,建议 R2018b 及以上版本。如果你的数据量到了全球多站、长时间序列的级别,Parallel Computing Toolbox 能明显缩短循环耗时,但这不是跑通脚本的前提。
拿到codeTEC_L.zip之后,先解压到一个不含中文和空格的路径下,这一点在 Windows 上尤其重要——MATLAB 对含中文的路径处理在部分版本上会出问题,属于典型的"还没开始就算翻车"。
# 解压后建议的目录结构 codeTEC_L/ ├── codeTEC_L.m # 主脚本 ├── data/ # 放你的 TEC 观测数据 └── output/ # 脚本输出的图和数据解压完先别急着改代码,直接在 MATLAB 里cd到脚本所在目录,运行一次看报错信息。首次运行大概率会因为找不到数据文件而中断,这是正常的——脚本里读取数据的路径需要你按自己的实际情况改。
2.2 数据读取与格式适配
CODEtec 体系下的 TEC 数据常见来源有两类:一类是 GNSS 双频观测反演出来的 TEC 序列,通常存成文本或 MAT 文件;另一类是电离层模型输出的格网数据。codeTEC_L.m里读取数据的部分一般集中在脚本开头,你需要关注的是文件路径、列分隔符和时间格式这三处。
% 读取 TEC 数据(示例,按实际文件格式调整) dataFile = fullfile('data', 'tec_obs.txt'); % 假设文件为逗号分隔,第一列是时间(年 月 日 时 分),后续列是各站 TEC rawData = readmatrix(dataFile, 'Delimiter', ','); % 提取时间列并转换为 MATLAB datetime timeVec = datetime(rawData(:,1:5)); % 提取 TEC 数值列 tecMatrix = rawData(:, 6:end);这里readmatrix是 R2019a 之后推荐的读法,老版本用dlmread或textscan也行。关键参数是Delimiter,如果你的文件是空格或制表符分隔,要相应改成' '或'\t'。datetime那一步把年月日时分拼成时间戳,后面画时间序列图时直接拿它当横轴,比手动拼字符串省事得多。如果你的数据本身已经是 MATLAB 的.mat文件,那就跳过解析,直接load进来,但要注意变量名和脚本里后续引用的名字对得上。
2.3 预处理:去野值、补缺失、平滑
真实观测数据里出现负 TEC、突跳、整段缺失是家常便饭。codeTEC_L.m通常会带一段预处理逻辑,但默认参数未必适合你的数据。常见的做法是先用中位数绝对偏差(MAD)做粗筛,再用滑动窗口做平滑。
% 基于 MAD 的野值剔除 medVal = median(tecMatrix, 'omitnan'); madVal = mad(tecMatrix, 1); % 超过 3 倍 MAD 的判为野值,置为 NaN outlierMask = abs(tecMatrix - medVal) > 3 * madVal; tecMatrix(outlierMask) = NaN; % 滑动窗口平滑(窗口长度按采样率调整) winLen = 5; tecSmooth = movmean(tecMatrix, winLen, 'omitnan');mad的第二个参数设为 1 表示按中位数归一化,这是电离层数据处理里比较稳妥的选择。movmean的窗口长度winLen要根据你的采样间隔来定——如果是 30 秒采样,5 点窗口对应 2.5 分钟,对 TEC 这种缓变量来说够用;如果是 1 秒高频采样,窗口可以拉到 30 甚至 60。注意'omitnan'这个选项,不加的话一旦窗口里混进 NaN,整段平滑结果都会变成 NaN,这是很多人第一次跑会踩的坑。
2.4 首次出图与结果核对
预处理完就可以出图了。codeTEC_L.m的绘图部分一般会生成两类图:单站 TEC 时间序列和(如果有经纬度信息)区域或全球 TEC 分布图。
% 单站 TEC 日变化曲线 figure; plot(timeVec, tecSmooth(:, 1), 'LineWidth', 1.2); xlabel('UT'); ylabel('TEC (TECU)'); title('单站 TEC 日变化'); grid on; % 多站对比(取前 5 个站) figure; plot(timeVec, tecSmooth(:, 1:5), 'LineWidth', 1); legend('STA01','STA02','STA03','STA04','STA05'); xlabel('UT'); ylabel('TEC (TECU)'); title('多站 TEC 对比');出图之后别只看曲线好不好看,要核对三件事:一是 TEC 量级是否合理,中纬度白天一般在 10 到 50 TECU 之间,如果动辄几百,多半是单位或反演系数出了问题;二是日变化形态是否正常,白天高、夜间低是基本规律,如果反了或者完全没规律,检查时间列有没有解析错;三是缺失段是否被正确断开了,如果 NaN 被当成 0 画进去,曲线会出现不自然的掉底。
3. 参数调优与建模扩展:让 codeTEC_L.m 适配你的数据
3.1 时间分辨率与重采样策略
不同来源的 TEC 数据时间分辨率差别很大,地面 GNSS 站常见 30 秒,低轨卫星掩星可能到 1 秒,而一些模型输出是 1 小时。codeTEC_L.m默认按输入数据的原始分辨率处理,但如果你要拿它跟其他数据源做对比,重采样就绕不开。
% 将 30 秒采样重采样为 5 分钟均值 tecResampled = retime(... timetable(tecSmooth, 'RowTimes', timeVec), ... 'regular', 'mean', 'TimeStep', minutes(5));retime是处理时间表(timetable)的利器,'regular'表示按固定步长输出,'mean'是聚合方式。这里要注意,重采样之前最好先把野值处理干净,否则均值会被个别极端值拉偏。如果你的数据里有明显的周期性(比如与太阳活动相关的 27 天周期),重采样步长不要设得太大,否则会把周期信号抹平。
3.2 电离层建模接口:IRI 与经验模型
codeTEC_L.m本身是一个数据处理脚本,不是完整的电离层物理模型,但它通常会预留跟经验模型对接的接口。最常见的做法是调用 IRI(国际参考电离层)模型输出作为背景场,然后拿观测 TEC 去减背景,看残差扰动。
% 调用 IRI 模型获取背景 TEC(需 IRI MATLAB 接口) % 假设 iriTEC 已经通过 IRI 接口算好,维度与 tecSmooth 一致 tecResidual = tecSmooth - iriTEC; % 绘制残差 figure; plot(timeVec, tecResidual(:, 1), 'LineWidth', 1); xlabel('UT'); ylabel('TEC 残差 (TECU)'); title('观测 TEC 减 IRI 背景'); grid on;这里的关键是 IRI 接口的输入参数要对齐:时间、经纬度、高度范围、太阳活动指数(F10.7)和地磁指数(Ap 或 Kp)。F10.7 和 Ap 的取值日期必须跟观测时间匹配,用错日期的指数是新手常犯的错误,出来的背景场会整体偏移。如果你没有 IRI 接口,也可以用多项式拟合或滑动中位数当背景,虽然粗糙,但对识别大尺度扰动够用。
3.3 并行加速:多站大数据量的处理
当站点数量上百、时间跨度几个月时,逐站循环会明显拖慢速度。MATLAB 的parfor可以把循环分配到多核上,但有几个限制:循环体内不能有跨迭代的依赖,不能直接往同一个文件写数据。
% 多站并行预处理 numStations = size(tecMatrix, 2); tecProcessed = nan(size(tecMatrix)); parfor s = 1:numStations col = tecMatrix(:, s); medVal = median(col, 'omitnan'); madVal = mad(col, 1); col(abs(col - medVal) > 3 * madVal) = NaN; tecProcessed(:, s) = movmean(col, 5, 'omitnan'); endparfor启动本身有开销,如果每个站的数据量很小、站数也不多,用普通for反而更快。判断标准很简单:单次循环体耗时超过几毫秒、循环次数上百,才值得上并行。另外parfor里用的变量要提前声明好大小,tecProcessed先nan初始化就是干这个的,否则 MATLAB 会在每次迭代里动态扩数组,速度反而更慢。
3.4 输出与批量成图
处理完的数据和图片需要批量导出时,建议把文件命名规则固定下来,方便后续检索和对比。
% 批量导出图片 outDir = 'output'; if ~exist(outDir, 'dir'); mkdir(outDir); end for s = 1:numStations f = figure('Visible', 'off'); plot(timeVec, tecProcessed(:, s)); xlabel('UT'); ylabel('TEC (TECU)'); title(sprintf('Station %02d', s)); saveas(f, fullfile(outDir, sprintf('sta_%02d.png', s))); close(f); end'Visible', 'off'让图在后台生成,不弹窗,批量跑的时候不会满屏窗口。saveas的格式由扩展名决定,要矢量图就写.eps或.pdf,要位图就.png。如果图很多,建议把figure和close配对写,不然内存会越吃越多,跑到后面可能直接卡死。
4. 避坑与排查:codeTEC_L.m 实际使用中的五类问题
4.1 现象:脚本运行报"未定义函数或变量"
原因通常有两个:一是codeTEC_L.zip解压后目录结构被改动,辅助函数不在 MATLAB 搜索路径里;二是脚本里引用了某个工具箱函数,但你的 MATLAB 没装那个工具箱。解决方法是先addpath(genpath('codeTEC_L'))把整个目录加进路径,再which 函数名确认能不能找到。如果提示某个函数找不到,查一下它属于哪个工具箱,要么装工具箱,要么找替代实现。
4.2 现象:画出来的 TEC 曲线全是 NaN 或断成碎片
这多半是预处理阶段野值判据设得太严。3 * madVal这个阈值对干净数据合适,但如果你的数据本身噪声大,大量正常值会被误判成野值。解决办法是先画一下原始数据的直方图,看看分布范围,再决定阈值。也可以把判据从固定倍数改成百分位数,比如超过 99.5 百分位的才置 NaN,这样对不同噪声水平的数据更鲁棒。
4.3 现象:时间轴对不上,日变化出现在错误的地方
检查时间解析那一步。常见错误是把年积日(DOY)当成月日来解析,或者把 UT 和 LT 搞混。如果你的数据是年积日格式,用datetime(year, 1, 1) + days(doy - 1)来转换,别直接往datetime里塞。另外确认一下数据文件里的时间是整点还是带分钟,readmatrix读进来的数值列如果被截断,时间就会整体偏移。
4.4 现象:并行跑完结果跟串行不一致
parfor里如果用了随机数、或者循环体里修改了共享变量,结果就会跟串行不一样。电离层数据处理里常见的是在循环内做随机抽样或加噪声,这种操作在parfor里必须用RandStream给每个 worker 设独立种子。更稳妥的做法是把随机操作挪到循环外面,先生成好随机序列再传进去。
4.5 现象:批量出图跑到一半内存爆掉
MATLAB 的figure对象不手动关的话会一直占内存,循环里每画一张就多一份。解决办法就是前面说的close(f),或者用close all在每轮结束时统一清。如果图特别多,还可以考虑把数据先存成 MAT,另起一个脚本专门读数据出图,把处理和绘图拆成两个阶段,内存压力会小很多。
5. 进阶技巧:用 codeTEC_L.m 做扰动指数与事件分析
跑通基本流程之后,codeTEC_L.m真正有价值的地方在于它能当扰动分析的起点。电离层 TEC 的短期扰动(比如磁暴期间的 TEC 增强或耗空)是空间天气监测的核心指标之一,而扰动指数(如 DIX、ROTI)的计算并不复杂,关键是把背景场和观测场的对齐做扎实。
一个我常用的做法是:先用滑动中位数(窗口取 1 到 2 小时)算背景,再用观测减背景得到残差,最后对残差取滑动标准差,就得到一个简化的扰动指数。
% 滑动中位数背景(窗口 2 小时,按 30 秒采样即 240 点) bgWin = 240; tecBackground = movmedian(tecSmooth, bgWin, 'omitnan'); % 残差 tecRes = tecSmooth - tecBackground; % 滑动标准差作为扰动指数 distWin = 60; % 30 分钟窗口 tecIndex = movstd(tecRes, distWin, 'omitnan'); % 画扰动指数 figure; plot(timeVec, tecIndex(:, 1)); xlabel('UT'); ylabel('扰动指数'); title('单站 TEC 扰动指数'); grid on;这段代码里bgWin和distWin两个窗口长度是核心参数。背景窗口太短,会把真实的扰动当成背景减掉;太长,背景跟不上电离层的快速变化。经验上背景窗口取 1 到 2 小时比较平衡,扰动窗口取 30 到 60 分钟。如果你关注的是磁暴主相期间的快速变化,两个窗口都可以缩短到 15 到 30 分钟,但代价是噪声也会被放大。
另一个实用技巧是把扰动指数跟地磁指数(Kp、Dst)叠在一起看。把 Kp 按时间插值到 TEC 的时间轴上,然后双 y 轴画出来,扰动响应的时间滞后一目了然。
% 假设 kpTime 和 kpVal 是地磁 Kp 数据 kpInterp = interp1(kpTime, kpVal, timeVec, 'linear', 'extrap'); yyaxis left; plot(timeVec, tecIndex(:, 1)); ylabel('TEC 扰动指数'); yyaxis right; plot(timeVec, kpInterp); ylabel('Kp'); xlabel('UT'); title('TEC 扰动与 Kp 对比'); grid on;interp1的'extrap'选项让时间轴两端超出 Kp 数据范围的部分也能有值,不然两头会断掉。双 y 轴图在 MATLAB 里用yyaxis实现,注意左右轴的plot要分别调用,颜色会自动区分。
验证这套流程是否靠谱,最简单的办法是找一个已知的磁暴事件(比如 Kp 大于 6 的日期),拿当天的数据跑一遍,看扰动指数是不是在磁暴主相期间明显抬升。如果抬升时间跟 Kp 峰值对得上,说明窗口参数选得合理;如果扰动指数在平静日也一直很高,那就是背景窗口太短,把噪声当成了扰动。
从那以后我每次拿到一批新数据,都强制先跑一遍平静日的扰动指数,确认基线水平正常,再去看事件日的结果。这个习惯帮我挡掉过好几次因为数据段拼接错误导致的假扰动。希望帮到你。
本文还有配套的精品资源,点击获取