ARTICLE DETAIL

资讯详情

深耕网站视觉设计与运营推广的一线实战洞察。

基于Matlab的测风塔数据处理与风资源评估全流程指南

基于Matlab的测风塔数据处理与风资源评估全流程指南 1. 测风塔数据为什么不能直接算从原始序列到投资结论的偏差来源我第一次拿到测风塔的历史风力数据时心里想的是“这不就是一堆风速风向嘛Excel里拉个平均值就完事了”。后来被做风资源评估的前辈指着报告里的风功率密度问了一句“你这空气密度用的多少”我才意识到测风塔数据的处理远不是求个平均那么简单。先把这个内容的定位说清楚这是一篇面向风电前期开发、风资源评估入门者以及要做气象时序数据分析的Matlab用户的实操笔记。核心场景是——你手里有一台或多台测风塔的长期连续观测数据通常是10分钟平均序列需要用Matlab完成数据导入、质量检验、缺测处理、风资源参数计算最后输出一组能支撑投资决策的关键指标。为什么强调“支撑投资决策”因为测风塔数据最终要换算成发电量、容量系数再换算成度电成本。数据质控做不做到位直接决定一个风电场项目的收益测算偏乐观还是偏保守。行业里有个粗略共识如果测风数据里夹杂着大量传感器结冰、雷击失效、仪器故障产生的野值而不做任何处理平均风速的偏差很容易超过10%而风功率密度和风速的三次方成正比这个偏差传导到发电量估算上可能就是每年上百万度的差距。所以我常跟人说测风塔数据分析的第一原则不是“算”而是“审”。审数据的完整性、一致性、物理合理性。先把脏数据挑出去再来谈均值、威布尔参数、湍流强度这些指标。这篇文章就把这套流程完整走一遍从文件导入到最终指标输出附带可以直接改改用的Matlab代码块。适合两类人看一类是刚入行、手里有数据但不知道怎么下手的工程师另一类是做科研课题、需要从气象塔数据里提取特征指标的研究生。2. 气象塔数据长什么样字段口径、时间戳规范与Matlab导入实操2.1 测风塔的观测体系与数据文件形态先花点篇幅讲清楚测风塔本身的观测结构。一座典型测风塔会在多个高度安装风速计、风向标常见的是10m、30m、50m、70m、80m、100m这样的布置组合具体根据风机轮毂高度设计。风电场前期测风一般持续至少一年满一整年覆盖四季才能拿到可靠的风资源结论但实际项目里也有测风三个月就启动评估的——那种情况必须在报告里明确说明不确定性。仪器层面风速计用得最多的是杯式风速计现在超声波风速计也越来越多。杯式的优点是便宜、皮实缺点是结冰工况下表现糟糕轴承磨损后会出现“风速值异常偏低甚至卡死”的情况。超声波没有转动部件但价格更高极端低温下也可能出现异常尖峰。所以你会发现测风数据里的脏数据不是随机噪声而是有规律的——冬季凌晨的持续零值大概率是结冰个别时间点的超大风速大概率是传感器受雷击或线路干扰。数据记录器数据采集器的输出文件常见格式是Campbell、Vaisala等厂家的专用格式但交付给分析工程师的时候通常已经导出为CSV或Excel。我接过最多的就是CSV表头长这样Timestamp, WS_80m, WD_80m, WS_50m, WD_50m, WS_30m, WD_30m, Temp_2m, Pressure_hPa 2023-01-01 00:00, 8.25, 214.3, 7.61, 211.8, 6.12, 205.4, -3.2, 981.2 2023-01-01 00:10, 7.98, 209.7, 7.32, 207.2, 5.94, 203.1, -3.5, 981.5这个表看起来简单但里面有几个坑时间戳格式到底带不带时区是本地时间还是UTC风速单位是m/s还是节风向是度还是方位角字符串温度是摄氏度还是开尔文我会在拿到的第一时间确认这些元信息。2.2 用detectImportOptions规避导入时的隐性错误很多人在Matlab里读CSV直接用readtable(data.csv)大多数时候没问题但遇到两类情况会翻车一是表头里有中文字段或特殊字符二是时间列被自动识别成了datetime之外的类型。我建议用detectImportOptions先让Matlab自动侦察一遍格式再手动确认关键字段稳妥得多。% 数据导入完整脚本 % 先用detectImportOptions让Matlab识别格式再按需修改 opts detectImportOptions(tower_data.csv); % 确认时间列格式避免被读成文本或数值 opts setvartype(opts, Timestamp, datetime); opts setvaropts(opts, Timestamp, InputFormat, yyyy-MM-dd HH:mm:ss); % 读取数据 data readtable(tower_data.csv, opts); % 将时间列设为行时间后续做时序分析更方便 data.Properties.VariableNames ... {Timestamp, WS80, WD80, WS50, WD50, WS30, WD30, Temp, Pres}; t data.Timestamp;这段代码里值得注意的setvartype和setvaropts是一对组合拳前者把列类型强行指定为datetime后者告诉Matlab这个时间字符串的解析格式。如果CSV里的时间戳是2023/01/01 00:00InputFormat要改成yyyy/MM/dd HH:mm如果是带时区的ISO格式情况就更复杂一点建议先把字符串切割出前半段再解析。你可能问我为什么不用readmatrix、load这些函数因为它们处理不了混合类型的表格式数据。测风数据是文本列时间戳数值列风速风向混在一起readtable是唯一能保真导入的方案。旧版Matlab用dataset或tblread的写法现在是真不推荐了维护性太差。2.3 时间戳乱象时区、夏令时与丢采样时刻时间戳处理是整个导入阶段最容易被低估的环节。我遇到过不止一次测风塔数据里时间戳是当地标准时间但现场运维记录风机发电量用的是UTC8两边对不上相关系数拉了半天数据对不齐最后发现差了8个小时。所以第一步先确认时区有没有写进文件名或配套的说明文档里没有就直接问数据提供方。第二个大坑是夏令时。国内项目基本没有这个问题但如果数据来自海外项目尤其欧洲、北美夏令时切换会导致春秋两季各出现一次“时间重复一小时”和“时间缺失一小时”。Matlab的datetime类型对时区处理有一套规则建议在处理这类数据时显式指定时区t.TimeZone UTC08:00; % 国内项目通常是北京时间不过要提醒一句如果原始数据里没有时区信息你强行给datetime对象设置时区Matlab只会把它当成“无时区的墙上时钟时间”来显示并不会自动做转换。真要转换得用TimeZone赋值的方式把墙上时间解释成某个时区的时间再tzoffset换算。这块水很深大多数人用不到但知道有这回事就够了。还有一类时间戳乱象是掉采样。数据采集器偶尔会因为信道拥堵、存储卡问题漏记某几个10分钟窗口。导入之后第一步就要检查时间序列是否连续常见的检查方法是计算相邻时间戳的差值看有没有超过正常的采样间隔10分钟600秒% 检查时间连续性 dt minutes(diff(t)); gapIdx find(dt 10); % 找到间隔超过10分钟的位置 fprintf(共发现 %d 处缺测间隔最大间隔 %.1f 分钟\n, ... length(gapIdx), max(dt) / 10 * 10);这一步做完你对这批数据的“健康状况”就有数了。缺测率如果超过10%后续结论的不确定性就要写得特别重。3. 数据清洗第一步野值剔除、缺测统计与一致性检查的工程做法3.1 物理合理性检验用阈值圈出明显不可能的数值数据导入完成后正式进入清洗环节。我会按三个层次来做物理合理性、时间一致性、空间一致性。物理合理性最直接——风速不可能是负数也不可能是200m/s风向必须在0°到360°之间气温在中国的测风塔数据里不应该出现60°C。这些判断不依赖任何统计方法就是物理常识。用Matlab的isoutlier函数可以快速找到异常值但我不建议直接全自动剔除因为测风数据的异常往往是有物理成因的盲目按统计阈值删可能把真实的大风事件误杀。% 物理合理性检验 validWS data.WS80 0 data.WS80 60; % 风速0-60 m/s validWD data.WD80 0 data.WD80 360; % 风向0-360度 validTemp data.Temp -50 data.Temp 45; % 气温物理范围 validIdx validWS validWD validTemp; fprintf(物理合理性检验通过 %d / %d (%.1f%%)\n, ... sum(validIdx), height(data), 100 * mean(validIdx));注意0m/s的风速要不要剔除取决于你的项目背景。如果测风塔位于内陆平原长时段持续0风速几乎可以肯定是传感器故障但如果塔在复杂山地山谷里的静风时段是真实存在的。我做这类判断时会去看风向数据——如果风速为0的同时风向也在乱跳大概率是仪器问题因为真实静风时风向标会因为失去驱动力而自由漂移这两者同时发生才能判定为故障。阈值定多少也讲究。60m/s的下限在哪里强台风登陆时的10分钟平均风速可能超过50m/s如果项目地在东南沿海硬编码60可能会导致台风过程数据被错误保留或剔除。更稳妥的方式是结合当地气象历史极值来定上限比如查一下近50年国家气象站的最大风速记录再加一点余量。3.2 结冰、雷击、传感器卡涩如何识别有“故事”的野值物理合理性检验解决了“明显不可能”的问题但测风数据里还有一种更难处理的坏数据数值上合理、物理上不可能。典型例子是传感器结冰。杯式风速计结冰后叶片被冻住但数据采集器会输出一个稳定的低值比如持续几个小时风速恒为1.2m/s风向完全不变化。从单点看1.2m/s完全在合理范围内但从时间序列看这种“死死的一条直线”绝不是真实大气过程。识别方法有两个思路一是滑动窗口内的标准差趋近于零二是风速风向同时长时间不变。我用的是后者因为更直观。10分钟平均风速序列中如果连续6个点1小时风速变化小于0.1m/s风向变化小于5°基本可以判定传感器处于卡涩或冻结状态% 检测长时间稳定不变的数据块疑似结冰/卡涩 window 6; % 1小时窗口 n height(data); frozenFlag false(n, 1); for i window:n wsSeg data.WS80(i-window1:i); wdSeg data.WD80(i-window1:i); if range(wsSeg) 0.1 range(wdSeg) 5 frozenFlag(i-window1:i) true; end end这个逻辑对复杂地形要慎用——山谷风转换时刻风速可能在一个小时内非常平稳风向也可能稳定朝一个方向吹。所以我把这类判据当作“疑似标记”最后会人工抽查而不是直接全部剔除。雷击和电磁干扰产生的是另一个极端瞬间出现一个巨大的尖峰比如80m/s或500°的风向角。这类数据在物理合理性检验阶段就会被拦截但也有尖峰恰好落在合理范围内的比如干扰信号叠加出28m/s这种值。我的做法是看相邻点的变化率真实的10分钟平均风速序列中相邻点风速跳变超过10m/s的场景极其罕见一旦出现大概率是干扰。3.3 缺测与无效数据的占比统计一份诚实报告的基础清洗做完立刻统计数据有效率和缺测率的分布这是整个清洗环节最重要的产出之一。行业惯例是测风数据完整率不低于98%如果达不到就要在风资源评估报告里说明原因并评估对结果的影响。完整率按高度分别统计因为不同高度的传感器故障概率不一样。% 统计各高度数据有效率 heights {WS30, WS50, WS80}; for i 1:length(heights) col heights{i}; validCnt sum(~isnan(data.(col)) validPhysical); fprintf(%s 有效数据%d / %d (%.2f%%)\n, ... col, validCnt, n, 100 * validCnt / n); end关于缺测数据要不要插补我的经验是能不做就不做。测风数据缺测的原因五花八门如果只是因为存储卡问题缺了几个小时插补的意义不大但如果是冬季结冰连续缺测两周这一段缺失正好落在全年大风季直接忽略会导致年均风速偏低。插补方案一般有两种一是用塔上其他高度的风速通过风切变关系推算出缺失高度二是用邻近参考测风塔或长期再分析数据建立回归关系来补齐。无论哪种都要在报告里明确标注“该时段为插补数据”不能混在实测序列里当真实数据用。4. 风资源评估核心指标风玫瑰、Weibull拟合、湍流强度与发电量估算4.1 平均风速和风功率密度先把三次方的威力讲清楚清洗后的数据才能真正用于指标计算。第一个指标是平均风速这个简单直接mean就行。但风资源评估的核心指标不是平均风速而是风功率密度Wind Power Density公式是[ WPD \frac{1}{2} \rho \overline{v^3} ]注意这里用的是风速三次方的平均值不是平均风速的三次方。这两个数值差别巨大。举个例子风速序列里如果有1%的时间吹25m/s的大风它对v³均值的贡献可能超过20%的份额。大风时段对风资源贡献极大所以平均风速相同、风速分布不同的两个场址发电量可能差出一截。空气密度ρ则根据测风塔上实测气温和气压计算公式是[ \rho \frac{P}{R \cdot T} ]其中P是气压(Pa)R是干空气比气体常数287.05 J/(kg·K)T是开尔文温度。Matlab代码% 计算空气密度和风功率密度 T_K data.Temp 273.15; % 摄氏度转开尔文 P_Pa data.Pres * 100; % hPa转Pa rho P_Pa ./ (287.05 * T_K); % 逐时刻空气密度 % 风速三次方平均 v3_mean mean(data.WS80 .^ 3); WPD 0.5 * mean(rho) * v3_mean; % W/m² fprintf(平均风速%.2f m/s风功率密度%.2f W/m²\n, ... mean(data.WS80), WPD);很多入门教程直接拿1.225kg/m³的标准空气密度代入计算这在海平面、15°C条件下没问题但青藏高原上的空气密度只有0.8左右误差直接干到30%以上。所以只要测风塔上有温压传感器就一定要用实测数据修正。4.2 风玫瑰图用极坐标直方图看清主风向风向频率分析是风资源评估的必出图件。风玫瑰图展示的是各个风向扇区通常16或12个扇区内风速出现的频率分布帮助判断机位排布和尾流影响方向。Matlab里可以用polarhistogram直接画极坐标直方图但我想给一个更符合风资源行业习惯的做法计算各扇区频率然后画成极坐标柱状图。% 风向扇区统计16扇区 edges 0:22.5:360; wd data.WD80; wd(wd 360) 0; % 处理360°边界 [counts, ~] histcounts(wd, edges); freq counts / sum(counts) * 100; % 画风玫瑰图 figure; polaraxes; hold on; for i 1:length(counts) theta deg2rad(edges(i) 11.25); % 扇区中心角度 r freq(i); polarplot([theta theta], [0 r], LineWidth, 4, Color, [0.2 0.4 0.8]); end这里有个小细节风向数据里如果出现360°要归到0°扇区否则histcounts会把360°单独分一档导致统计多出个空扇区。另外风向扇区只统计有效风速对应的风向——风速为0时风向数据没有意义建议先筛选WS80 0.5再统计。4.3 Weibull分布拟合用两个参数概括一整年风况风资源的概率分布通常用双参数Weibull分布描述[ f(v) \frac{k}{A}\left(\frac{v}{A}\right)^{k-1} \exp\left(-\left(\frac{v}{A}\right)^k\right) ]其中A是尺度参数与平均风速正相关k是形状参数控制分布的峰度一般在1.5到3之间。拟合方法有极大似然估计、矩估计等。Matlab自带wblfit函数可以直接拟合但要注意Matlab的Weibull参数定义和风资源领域的定义是A尺度和B形状所以返回的第二个参数就是k值。% Weibull分布拟合 ws data.WS80(~isnan(data.WS80) data.WS80 0); [A_wbl, k_wbl] wblfit(ws); fprintf(Weibull参数A%.3f m/s, k%.3f\n, A_wbl, k_wbl); % 验证拟合效果画出频率直方图和拟合曲线 figure; histogram(ws, 0:0.5:max(ws), Normalization, pdf, FaceAlpha, 0.3); hold on; v 0:0.1:max(ws); pdf_fit (k_wbl / A_wbl) * (v / A_wbl).^(k_wbl - 1) .* exp(-(v / A_wbl).^k_wbl); plot(v, pdf_fit, r-, LineWidth, 2);拟合完成后一定要画图看一眼不要只输出参数。k值的经验范围是1.5~3如果拟合出来的k超过4很可能数据里混入了大量重复值或经过平滑处理。A值则可以通过平均风速粗略验证Weibull分布的平均风速理论值是(A \cdot \Gamma(11/k))把这个算出来和实测平均风速对比偏差应该在1%以内大偏差说明拟合过程有问题或者数据本身不服从Weibull假设。4.4 湍流强度一个被很多人算错的指标湍流强度Turbulence Intensity, TI定义为10分钟时段内风速标准差与平均风速之比。它直接影响风机的疲劳载荷等级选择所以是风资源评估报告里的必填项。问题在于很多初学者拿10分钟平均序列去算TI——用10分钟平均风速的标准差除以10分钟平均风速。这算出来的是“风速逐时变率”根本不是湍流强度数值会小一个量级。正确的做法是用原始高频采样数据比如1Hz或0.5Hz采集的瞬时风速来算每个10分钟段内的标准差和平均值再求比值。但现实情况是很多项目交付的CSV里只有10分钟平均序列没有原始高频数据。这时候能做什么只能明确标注“本报告TI基于10分钟平均序列估算结果仅供参考”或者用一些经验模型来推测。如果你手里有原始高频数据用Matlab按10分钟窗口切片计算TI% 假设high_freq_data包含1Hz风速数据按10分钟窗口计算TI ws_hf high_freq_data.WS; % 高频风速序列 t_hf high_freq_data.Time; edges_hf datetime(2023, 1, 1, 0, 0, 0):minutes(10):datetime(2024, 1, 1, 0, 0, 0); TI_10min zeros(length(edges_hf)-1, 1); for i 1:length(edges_hf)-1 idx t_hf edges_hf(i) t_hf edges_hf(i1); seg ws_hf(idx); if length(seg) 500 % 有效样本数足够 TI_10min(i) std(seg) / mean(seg); else TI_10min(i) NaN; end endTI平均值的工程经验是沿海平坦地形可能只有0.08~0.12复杂山地可能超过0.15~0.20。IEC标准把湍流等级分为A高湍流TI0.16参考值、B中湍流0.14、C低湍流0.12这个分级直接影响风机的选型安全性。4.5 垂直风切变把低层风速外推到轮毂高度测风塔上装了多个高度的风速计就是为了研究风速随高度的变化。工程上最常用的是幂律模型[ \frac{v_2}{v_1} \left(\frac{h_2}{h_1}\right)^\alpha ]α就是风切变指数平坦地形通常在0.1~0.2之间复杂地形可能更高。用不同高度的同步风速数据拟合α公式是[ \alpha \frac{\ln(v_2/v_1)}{\ln(h_2/h_1)} ]Matlab实现时按时间点逐点计算然后取中位数或按风速分区统计。注意不能取所有点的简单平均值因为低风速时段α波动很大夜间的α通常比白天大夜间边界层稳定风速梯度大所以更科学的做法是分风速段统计α或者分昼夜统计。% 计算风切变指数基于80m和50m风速 validPair data.WS80 3 data.WS50 3; % 只统计风速大于3m/s的情况 alpha log(data.WS80(validPair) ./ data.WS50(validPair)) / log(80 / 50); % 得到轮毂高度90m的风速外推 WS90 data.WS80 .* (90 / 80).^median(alpha);为什么要避开低风速段因为低风速下仪器的测量误差和大气层结的影响都会被放大算出来的α没有代表性。我一般把阈值设在3~4m/s低于这个风速段的α直接忽略。4.6 发电量估算功率曲线、空气密度修正与折减系数风资源指标的最终归宿是发电量。常用的估算思路是把测风高度风速外推到轮毂高度然后将轮毂高度风速频率分布从Weibull拟合得到或直接用实测直方图乘以风机功率曲线再乘以全年小时数8760就得到理论年发电量AEP。风机功率曲线给出的是标准空气密度通常1.225kg/m³下的出力-风速关系实际空气密度不同需要修正。因为风功率正比于空气密度所以修正方式是把风速轴做一个等效变换(v_{eq} v \cdot (\rho / \rho_0)^{1/3})再用等效风速查功率曲线。代码思路如下% AEP估算 % 假设pc_v是功率曲线风速数组pc_p是对应功率 rho0 1.225; rho_actual mean(rho); % 实测平均空气密度 % 轮毂高度风速序列 WS_hub data.WS80 .* (90 / 80).^median(alpha); WS_eq WS_hub .* (rho_actual / rho0).^(1/3); % 用等效风速查功率曲线 P_out interp1(pc_v, pc_p, WS_eq, linear, 0); % 理论年发电量kWh AEP_gross sum(P_out) * 10 / 1000 * 8760 / n; % 10分钟间隔折算年 % 扣除尾流损失、停机维护、电气损耗等 lossFactor 0.85; % 综合折减系数 AEP_net AEP_gross * lossFactor; fprintf(理论年发电量%.2f GWh折减后%.2f GWh\n, ... AEP_gross / 1e6, AEP_net / 1e6);折减系数是行业里的关心重点尾流损失、叶片污染、停机维护、电气损耗、低温停机等都要逐项估算。这里给0.85只是示意实际项目要分项列出依据。如果你对某台风机的功率曲线不确定可以直接去风机厂家官网下载公开的功率曲线数据通常是Excel或PDF。5. 搞定数据后的最后一个坑结果校验、报告输出与长期修正5.1 交叉校验用再分析数据或邻近气象站验证测风数据合理性算完一堆指标后先别急着写报告。我习惯做一步交叉校验把测风塔的月度平均风速或风向玫瑰图和一个独立的长期数据源对比。国内可以就近找国家气象站的公开数据或者用再分析资料。找长期参考站的时候注意三点距离别太远50km以内比较理想、地形特征不要太悬殊、海拔别差太大。如果测风塔和参考站的变化趋势一致说明测风塔数据基本可信如果趋势相悖就要回看是不是时间戳对齐出了问题或者测风塔某个传感器从一开始就不准。5.2 报告输出的基本盘把每一步都留下可追溯的记录风资源评估报告的数据部分至少要包含以下内容各高度数据有效率统计表、逐月平均风速和风功率密度表、风向频率和风能频率表、Weibull参数及拟合图、湍流强度分级统计、风切变指数和轮毂高度外推结果、最终AEP及折减明细。我的习惯是清洗参数和阈值全写在代码注释里输出一份带版本号的数据处理日志这样半年后有人问起“这批数据当时怎么处理的”不用翻聊天记录一份日志全说清楚。数据处理日志的模板大概是原始文件名称和行数、时间范围、时区、采样间隔、清洗规则和剔除数据量、插补规则和插补数据量、最终有效数据量、每个计算指标对应的Matlab脚本名称和运行时间。这个习惯在你同时处理多个测风塔数据时救命我见过太多同事到了汇报前夜还在翻哪个脚本生成的是哪版结果。5.3 从测风期到长期代表年为什么一年测风数据还需要“订正”最后一个要讲透的点是长期订正。测风塔测风一年但这一年的风况未必等于长期平均风况。如果测风期恰好是一个偏枯风年直接拿这一年数据算出来的发电量就会偏低。所以行业标准做法是选取一个长期参考站至少20年数据建立测风期同步数据之间的回归关系MCP方法再把长期参考站的多年均风况映射到测风塔位置。这样算出来的才是长期代表年发电量。Matlab里MCP最常用的方法是线性回归% MCP长期订正简单线性回归法 % ref是长期参考站测风期风速target是测风塔同期风速 % ref_long是参考站长期多年平均风速序列 p polyfit(ref, target, 1); % 回归系数 target_long polyval(p, ref_long); % 订正后的长期平均风速 % 用长期订正风速重新算发电量MCP的回归拟合度R²低于0.7基本不可用说明两个站点的相关性太弱强行订正反而引入更大不确定性。复杂地形下MCP误差很大可能需要考虑使用Mesoscale模拟数据或CFD微尺度模型做统计订正但这已经超出测风塔数据本身的分析范畴了。多提一句现在的很多项目已经开始用中尺度再分析数据和机器学习方法做风资源评估但测风塔实测数据依然是所有方法的“锚点”——再好的模型没有地基校准都是空中楼阁。所以这一套Matlab处理流程无论技术怎么演进都是风资源工程师的基本功。我在实际项目里做得最多的不是算法调优而是反复用不同的可视化方式去“看”数据。plot一下原始序列找尖峰画个histogram看分布形态叠几个高度风速曲线查一致性——高效的清洗离不开对数据的敏感度而这种敏感度的建立就是一次次盯着图看出来的。所以不论你用的是Matlab还是别的工具别急着追求花哨的模型先把数据看明白后面的每个结论都会站得更稳。
返回列表