☰
用Matlab完成测风塔风能资源评估:从数据清洗到发电量估算
2026/10/19 6:08:26 网站建设 项目流程

气象塔(风电行业里叫测风塔)出来的历史风力数据,看起来就是一堆时间和风速的表格,但真正能把它变成风能资源评估结论的人,并不算多。我刚接触这个领域的时候也犯过“拿数据就求平均”的错,结果被前辈按在工位上从头教了一遍:测风数据从传感器到报告之间,隔着一整条质量控制、统计建模、发电量估算的链路。这篇博文就把这个过程完整走一遍,用Matlab从导入、清洗气象塔历史风力数据开始,一直到平均风速、威布尔分布、风功率密度、风玫瑰图和年发电量估算,适合刚入行的风电开发工程师、新能源方向的研究生,以及所有想弄明白风能资源评估数据怎么变成决策依据的人。

1. 测风塔数据:风电项目选址的“底牌”

1.1 为什么风资源评估不能靠“拍脑袋”

做风电项目前期开发,设备的选型、机位的排布、投资收益的测算,几乎全部压在一个东西上:场址的风资源条件。一个风电场的投资规模动辄上亿,如果资源评估偏差10%,整个项目的收益率曲线都会明显偏移。而风资源评估最硬的数据来源,就是立在现场的气象塔实测数据——它比卫星反演、数值再分析网格更接近未来风机轮毂高度处的真实气流。

气象塔之所以叫“塔”,是因为它通常要立到计划风机轮毂高度附近,比如70米、90米、100米,塔身上在不同高度布置风速计、风向标、温度、气压传感器。数据采集器会连续记录风速、风向等要素,通常是10分钟一条记录。这个10分钟平均数据就是后续所有分析的原料。和测风塔数据相比,其他数据源可以作为参考或长期订正,但无法替代现场实测的地位。

这篇文章想讲清楚的核心,就是这批10分钟原始数据从“Excel表格”变成“资源评估结论”的完整过程。不管你是只写过几行Matlab的初学者,还是已经做过几个项目但想理顺流程的工程师,都可以照着下面的步骤走。

1.2 测风塔数据的构成与“一塔一年”行业惯例

拿到气象塔数据,先别急着写代码。先看清楚手里是什么。典型的测风塔数据文件,列结构大致是这样的:

字段含义典型单位/范围
time记录时间yyyy-mm-dd HH:MM:SS
ws70 / ws5070米、50米高度平均风速m/s,0~60
wd70 / wd5070米、50米高度风向°,0~360
temp空气温度°C
pres大气压力hPa
hum相对湿度%

行业里做风资源评估,默认的“起步数据”是一整年的完整测风记录,通常要求跨越四个季节,数据完整率不低于90%。为什么是一年?因为风资源有明显季节性,只有覆盖完整年周期的数据才能代表场址的真实水平。如果只有半年数据,评估结果会有明显的季节偏差。

数据本身也不是拿来就能用的。10分钟数据里常见的问题包括:传感器结冰导致的连续重复值、雷击或线路故障导致的野值、设备停机导致的缺测、风向标被塔影遮挡导致的错误风向。这些都在“数据处理”这一步解决。

2. 一次完整的风资源评估工作流:从测风塔到Matlab

2.1 工作流总览与每个环节的意义

我习惯把风能资源评估数据研究拆成八个环节:数据获取、数据导入、质量控制、数据订正与插补、统计特征分析、垂直外推、发电量估算、报告输出。其中数据获取靠现场设备和采集器完成,我们拿到手的是第二环节开始。质量控制是所有环节里最枯燥但又最重要的一步,直接决定后面所有统计数字的可信度。统计特征分析包括平均风速、风向频率、威布尔分布参数、风功率密度、湍流强度等,这些指标共同构成风资源评估报告的核心表。发电量估算则是在统计特征基础上,结合风机功率曲线计算机组理论发电量,再扣除尾流、利用率等损失,得出风电场层面的发电量预期。

从数据分析角度讲,Matlab做这批时序数据处理很顺手。内置的timetable、retime、wblfit这些函数,几行代码就能完成数据聚合和概率分布拟合,画出来的图也足够进报告。当然,用Python也能做同样的事,只是工具不同,分析逻辑完全一致,本文以Matlab为例。

2.2 环境准备与目录约定

工欲善其事,必先利其器。做数据研究之前,先把项目目录搭好。我自己的习惯是下面这套结构:

project_root/ ├── data/ │ ├── raw_data/ # 原始测风数据,只读不修改 │ └── processed_data/ # 清洗后的数据 ├── scripts/ # 分析脚本 ├── results/ # 统计结果表 └── figures/ # 输出图片

原始数据目录只放从现场拷贝回来的文件,保持“原样”,处理后的数据单独放,这样做的好处是数据可追溯。比如甲方问“这个异常值是不是删多了”,你可以随时回到原始文件重新检查。

Matlab版本建议R2019b以上,需要统计和机器学习工具箱,主要是为了用wblfit做威布尔分布拟合。没有这个工具箱也不慌,后面会给出一个备用的手动拟合方法。

2.3 检查文件与数据规模的第一个脚本

拿到数据目录后,先用一个最简单的脚本确认文件数量和格式:

clear; clc; rawDir = fullfile(pwd, 'data', 'raw_data'); files = dir(fullfile(rawDir, '*.csv')); fprintf('发现测风数据文件 %d 个\n', numel(files));

这一步看着简单,但很值得做。实际项目中,有时数据会按月拆成12个文件,有时一个文件包含全年,有时还混着不同塔的数据。先看清楚文件规模,再写批量导入逻辑,能避免很多不必要的返工。

3. 数据导入与清洗的实操细节:坏数据会让整个评估前功尽弃

3.1 批量导入CSV与时间戳解析

原始CSV文件的格式千差万别,有的列名是中文,有的时间格式是“2023-01-01 00:00”,有的是“2023/1/1 0:00”。我用统一的方式处理:先读入,再统一列名,最后把时间字符串解析成datetime类型。

opts = detectImportOptions(filename); opts.VariableNames = {'time','ws70','wd70','ws50','wd50','temp','pres','hum'}; raw = readtable(filename, opts); % 统一时间格式 raw.time = datetime(raw.time, 'InputFormat', 'yyyy-MM-dd HH:mm:ss'); raw = sortrows(raw, 'time');

如果遇到解析报错,多半是时间格式不一致,可以先检查一下时间字符串的规律:

% 查看前20个时间字符串 head(raw.time, 20)

时间解析这块,经验是“宁慢勿错”。有些CSV文件的时间列带时区后缀,或者包含“0:00”这种不补零的格式,统一处理之前必须先看清楚实际字符串格式。解析完成后,用diff检查时间间隔是否连续:

dt = diff(raw.time); fprintf('最小采样间隔:%s\n', char(min(dt))); fprintf('最大采样间隔:%s\n', char(max(dt)));

10分钟采样频率的数据,最小采样间隔应该是10分钟。如果最大间隔远远大于10分钟,说明存在缺测段,需要在后面重点处理。

3.2 质量控制逻辑:过滤野值、标记卡滞、记录完整率

质量控制是整个处理环节的“底线”。我的处理规则很简单,但每条都有明确依据:

检查项判断条件处理方式
负值/超量程风速<0或>60 m/s置为NaN
风向超范围风向<0或>360置为NaN
温度异常温度<-40℃或>60℃置为NaN
传感器卡滞连续12个以上记录完全相同置为NaN
相邻跳变相邻时刻风速变化>20 m/s且不回落按野值标记

代码实现方式并不复杂:

% 基础上下限过滤 valid1 = raw.ws70 >= 0 & raw.ws70 <= 60; valid2 = raw.wd70 >= 0 & raw.wd70 <= 360; valid3 = raw.temp > -40 & raw.temp < 60; % 连续重复值判断(传感器卡滞) dup = [false; diff(raw.ws70) == 0]; % 统计连续重复段长度 runLen = 0; dupRun = false(size(raw.ws70)); for i = 2:height(raw) if diff(raw.ws70(max(1,i-1):i)) == 0 runLen = runLen + 1; else runLen = 0; end if runLen >= 12 dupRun(i) = true; end end % 总体有效标记 valid = valid1 & valid2 & valid3; valid(dupRun) = false; % 无效值置NaN raw.ws70(~valid) = NaN; raw.wd70(~valid) = NaN; % 统计完整率 validRate = mean(valid) * 100; fprintf('数据完整率:%.2f%%\n', validRate);

这段逻辑里有个容易忽略的点:风速为0在物理上是可能出现的(无风天气),所以下限判断用“>=0”,不要写成“>0”,否则会把真实静风数据误删。风向判断也一样,0°代表北风,是有效值。

这里说个实操体会:质控处理不只是“删数据”,删掉的每一段都应该能解释原因。比如冬天塔上传感器结冰,风速数据会出现连续几小时完全相同的恒定值,这段数据被标为无效后,最好在报告里注明“冬季结冰导致传感器卡滞”。甲方、评审专家看报告时非常在意这些细节。

3.3 从10分钟原始数据到小时平均序列

原始数据是10分钟一条,做统计分析和后续发电量估算时,很多场景会用到小时平均风速。聚合方法用timetable的retime函数,一行代码的事。但这里有个陷阱:风向不能直接做算术平均。

0°到360°的边界是连在一起的,如果某个小时内有几条记录是350°、355°、0°、5°,算术平均值会算出个错误方向,比如用普通mean会得出约177°。正确做法是把风向转成u、v分量再平均:

TT = table2timetable(raw(:, {'time','ws70','wd70','temp','pres','hum'})); TT = rmmissing(TT); % 先删除含无效值的整行 % 将风向转为u、v分量 TT.u = TT.ws70 .* cosd(TT.wd70); TT.v = TT.ws70 .* sind(TT.wd70); % 聚合为小时平均 TT_hour = retime(TT, 'hourly', 'mean'); % 从u、v分量合成小时平均风向 TT_hour.wd70_avg = atan2d(TT_hour.v, TT_hour.u); TT_hour.wd70_avg(TT_hour.wd70_avg < 0) = TT_hour.wd70_avg(TT_hour.wd70_avg < 0) + 360;

聚合这块还有一个容易被忽略的业务规则:一个小时内,如果有效10分钟记录太少,算出来的小时平均值是不可信的。行业里常见要求是每小时至少要有4条有效记录才保留该小时平均,否则标记为NaN。实现上可以用retime加“聚合函数”,也可以简单用movsum统计窗口内有效值数量再筛选。这一步保证了后面每个小时风速都有“足够的观测支撑”。

提示:风向平均值算出来后,如果要切回360°制表示,务必处理负值,否则会出现风向-5°这种看起来就不严谨的数值。

4. 风能分析的三个硬指标:平均风速、威布尔分布与风功率密度

4.1 平均风速与垂直外推

风速统计最基础的就是平均风速。直接对小时序列求均值即可:

meanSpeed = mean(TT_hour.ws70, 'omitnan'); maxSpeed = max(TT_hour.ws70);

但实际评估中,测风塔测风高度不一定是未来风机轮毂高度,比如塔高70米,风机轮毂高度100米。这时候需要做垂直外推。工程上最常用的是幂指数公式:

[ v_2 = v_1 \left( \frac{h_2}{h_1} \right)^{\alpha} ]

其中α是风切变指数。如果你在现场70米和50米两个高度都测了风速,可以用实测数据估算α:

% 由50米和70米高度风速估算风切变指数 alpha = log(meanSpeed70 / meanSpeed50) / log(70 / 50); % 外推到100米 meanSpeed100 = meanSpeed70 * (100 / 70) ^ alpha;

如果手里只有单层测风数据,就用行业经验值α=1/7(约0.143)。但注意,这个经验值属于“海上或平坦地形近似值”,复杂地形下用实测两层风速算own alpha会更靠谱。切变指数也直接反映大气稳定性,夜间稳定层结下切变很强,这些都是估算轮毂高度风速时的细节,但很影响最终结果。

4.2 威布尔分布拟合:比“平均值”更有信息量

风资源的概率分布特征,行业标准做法是用两参数威布尔分布来描述。风速概率密度函数:

[ f(v) = \frac{k}{A} \left( \frac{v}{A} \right)^{k-1} e^{-(v/A)^k} ]

A是尺度参数,和平均风速正相关;k是形状参数,决定分布形态。一般在陆上风电场,k值落在1.5~3之间,k越大说明风速变化越集中,风资源越稳定。

Matlab里拟合很简单:

speedValid = TT_hour.ws70(~isnan(TT_hour.ws70)); params = wblfit(speedValid); A_fit = params(1); k_fit = params(2); % 校验:用A和k反推理论平均风速,与直接均值对比 meanTheory = A_fit * gamma(1 + 1 / k_fit); fprintf('拟合均值=%.2f m/s,实测均值=%.2f m/s\n', meanTheory, mean(speedValid, 'omitnan'));

如果理论均值与实测均值差得比较多,说明样本分布并不完全符合威布尔模型,可能是数据清洗不彻底,或者存在极端工况,有必要回去检查质控步骤。

为什么说威布尔参数比平均风速“更有信息量”?因为平均风速相同,不代表风速分布相同。A=6.5、k=2的场址,与A=6.5、k=3的场址,年均风速一样,但高风速段的累计频率差异明显,风机在高风速段发的电更多,同样的平均风资源,后者等效发电小时可能高出不少。只看平均风速完全看不出这种差异。

没有统计工具箱时也可以手动拟合威布尔参数,较简单的方法是矩估计:

[ k \approx \left( \frac{\sigma}{\bar{v}} \right)^{-1.086} ]

然后用均值与k反推出A。这个估计精度对工程初判够用,但正式报告还是建议用最大似然法。

4.3 风功率密度:衡量资源“质量”的关键参数

风功率密度(WPD)是判断风资源等级的核心指标,公式:

[ WPD = \frac{1}{2} \rho v^3 ]

注意,正确的算法是用逐时风速三次方的平均值,而不是“平均风速的三次方”,两者差距很大。因为风速的三次方对高风速段非常敏感,用平均风速的三次方会系统性低估风功率密度。

空气密度ρ也要用实测数据计算,简单方式是用理想气体公式:

% 用温度、气压估算空气密度(kg/m³) rho = TT_hour.pres ./ (287.05 .* (TT_hour.temp + 273.15)); % 风功率密度 WPD = 0.5 * mean(rho .* TT_hour.ws70 .^ 3, 'omitnan');

打个比方,平均值是“账面上的资源”,风功率密度才是“真正能装进口袋的能量”。我经手的一个模拟项目里,两个场址平均风速只差0.3 m/s,但风功率密度差距达到80 W/m²,直接决定了机型的IEC等级选择。评估报告里WPD是一个绕不开的硬数据。

提示:WPD对极端风速很敏感,质控如果没做干净,一个被保留下来的野值就足以让全年WPD明显偏高。算WPD之前务必确保所有风速超过合理阈值的记录都已经被标为NaN。

5. 风向与风玫瑰:别让“平均值”掩盖方向信息

5.1 风向数据的“0°/360°边界陷阱”

风向是圆周数据,它的统计处理与风速很不一样。前面聚合小时数据的时候已经提醒过风向平均的问题。做扇区统计时同样要小心,最典型的是0°和360°其实是一个方向,但数值上差了360。

处理方式简单粗暴:先把360°统一改成0°:

wd = TT_hour.wd70_avg; wd(wd >= 360) = 0;

然后做16扇区划分。16扇区就是每22.5°一个区间。用histcounts时要注意边缘误差,我的习惯是让0°严格落在第一个扇区中心,而不是边界:

edges = -11.25:22.5:348.75; [~, ~, binIdx] = histcounts(wd, edges); freq = accumarray(binIdx, 1) / numel(wd) * 100;

5.2 用Matlab绘制风玫瑰与扇区频率表

风玫瑰图是表达风向和风速频率的标准方式。Matlab可以用极坐标直方图快速画:

figure; polarhistogram(deg2rad(wd), 16, 'FaceColor', [0.2 0.6 0.9]); title('风向频率玫瑰图');

但更严谨的报告用图,我一般会自己画扇区柱状图,这样速度、频率、平均风速可以按扇区统计清楚,做出来的扇区频率表长这样:

扇区风向区间频率占比扇区平均风速
N348.75°~11.25°22.3%6.8 m/s
NNE11.25°~33.75°8.7%6.2 m/s
............

从这张表能直观看出主风向。实际项目中,主风向落在哪几个扇区,直接决定风机排布方式和自动偏航控制策略。

5.3 主导风向对风机排布与尾流评估的影响

风玫瑰图不只是“画出来好看”,它直接影响微观选址。在主导风向上,风机之间需要拉开距离,否则前排风机产生的尾流会明显降低下风向风机的来流风速。行业经验是主风向间距通常要留到8~10倍叶轮直径,垂直主风方向可以稍密一些。评估阶段从测风塔数据分析出主导风向,是风机排布的第一手依据。

同时,测风塔自身也会产生塔影遮挡。塔身对下风向的传感器有尾流干扰,如果发现某个扇区的风速系统性偏低,且该扇区和塔身位置吻合,这部分数据要在风资源评估中标记为“塔影影响扇区”,必要时剔除或修正。这点在现场踏勘和数据分析里都容易被忽略。

6. 从数据到决策:功率曲线插值、容量系数与年发电量估算

6.1 用功率曲线把风速换算成出力

资源分析做到这一步,终于要和“电”挂钩了。方法是把小时平均风速序列,代入某机型标准功率曲线,得到每小时的输出功率。

以某2MW主流陆上机型为例,切入风速3 m/s,额定风速约11 m/s,切出风速25 m/s。功率曲线文件通常包含风速列和功率列:

pc = readtable('power_curve.csv'); % 假设功率曲线列为 wind_speed 和 power_kw powerEst = interp1(pc.wind_speed, pc.power_kw, TT_hour.ws70, 'linear', 0); % 空气密度修正 rho_actual = mean(rho, 'omitnan'); powerEst = powerEst .* (rho_actual / 1.225);

interp1的最后一个参数0表示:风速低于切入风速或高于切出风速时,输出功率按0处理。这一步比手动if判断干净很多,也避免数组维数不匹配。

小时功率序列求和,就是理论发电量:

annualEnergy = sum(powerEst) / 1000; % kWh -> MWh fprintf('年理论发电量:%.0f MWh\n', annualEnergy);

需要注意的是,用小时平均风速估算发电量,相对用10分钟数据存在一定偏差。风速的瞬时波动在高风速段带来的发电增量会被平均掉,工程初判阶段可以用小时数据,但正式评估报告通常建议用10分钟数据或分钟级数据。这是方法精度问题,分析流程本身完全一致。

6.2 容量系数:外行人也能看懂的选址指标

容量系数CF,定义是年发电量除以机组额定功率×全年小时数:

[ CF = \frac{E_{annual}}{P_{rated} \times 8760} ]

如果某2MW机组理论年发电量为500万kWh,那么:

ratedPower = 2e3; % kW CF = annualEnergy * 1000 / (ratedPower * 8760); fprintf('容量系数:%.3f\n', CF);

容量系数0.25~0.35是陆上风电场常见的区间。低于0.2的项目,投资收益压力会非常大;高于0.35的项目,在资源评估报告里就是相当优质了。我习惯在报告里同时给出等效满发小时数,比如容量系数0.27约等于等效满发2365小时,这个说法对投资决策者更直观。

6.3 尾流与利用率修正的实际经验

需要提醒的是:前面算的是单机理论发电量,不等于风电场实际发电量。整场发电量还要做一系列折减,常见折减项如下:

折减项典型范围备注
尾流损失5%~15%机群排布越密,尾流越大
场用电与输配电损耗2%~4%集电线路、变压器损耗
叶片污染与功率曲线偏差3%~8%污垢、结冰、制造公差
停机维护与非计划损失3%~8%检修、电网限电、故障

假设尾流8%、损耗3%、维护5%,合计折减约15%,则整场年发电量约为单机估算值乘机位数再乘0.85。做评估时如果把单机理论发电量直接乘台数,会被评审专家一眼看穿,这是报告里最常见的低级错误。我在经手的模拟项目X里,就亲自把“乐观版”和“稳健版”两套发电量都算过一遍,实际运维数据证明稳健版更接近真实值。

7. 实操中绕不开的几个坑:切塔、补缺与季节偏差

7.1 检测时间断点:数据完整性问题

数据处理完成后,一定要检查时间序列中有没有断点。设备停机、采集器重启、卡恢复都可能造成几小时甚至几天的数据缺口。一张全年时间间隔检查表就能看出问题:

dtHour = minutes(diff(TT_hour.time)); gapIdx = find(dtHour > 90); % 大于1.5小时视为缺口 for i = 1:length(gapIdx) fprintf('缺口:%s 到 %s,历时 %.1f 小时\n', ... TT_hour.time(gapIdx(i)), TT_hour.time(gapIdx(i)+1), dtHour(gapIdx(i))); end

现实中出现缺口不可怕,可怕的是不对缺口做说明。还有些项目会遇到“切塔”情况:测风塔因为台风倒了,重新立塔后继续测,中间缺了两个月。这种情况,缺口前后的数据原则上是两个数据集,是否拼接使用要很慎重。

7.2 缺测补插:能补的补,不能补的硬着头皮也不能补

很多人拿到缺测数据,第一反应是用线性插值填满。我的原则是:短缺口(2小时以内)可以补,长缺口不能补。原因是风速序列的持续性和随机性没法用线性模型真实还原,强行补出一段“看起来连续”的数据,实际上是在给评估结论注入虚假信心。

Matlab里可以用fillmissing配合MaxGap控制补插范围:

TT_hour.ws70 = fillmissing(TT_hour.ws70, 'linear', 'MaxGap', hours(2));

这一步把短缺口补上,长缺口保持NaN,在报告里明确写出“数据完整率92%,其中缺失部分未做人工插补”。完整率是底,补插是权宜。如果完整率都不到80%,建议直接考虑延长测风周期,而不是靠插值硬凑一年。

7.3 季节代表性与长期订正

最后一个大坑是季节代表性。假设项目方只提供了3月到10月的测风数据,这段时期平均风速通常低于全年平均(因为少了冬春大风季),直接把8个月数据说成年平均,结果会系统性偏低。反之只有冬季数据,结果会偏高。

解决思路是结合长期再分析数据,把短期实测数据和长期参考数据建立相关关系,将短期统计修正到长期平均水平,这就是行业里说的“长期订正”或“代表性订正”。具体实现涉及相关分析、线性回归甚至概率映射,是一套独立的分析流程,这篇文章不展开了,但作为风能资源评估数据分析的一部分,它必须出现在报告的方法论说明里。

提示:任何风资源评估报告都应该包含“数据时段与代表性”说明,清晰写明实测数据覆盖的时间范围、完整率、缺测原因及订正方法,这是专业性的直接体现。

我自己现在拿到一份风资源评估报告,第一眼看的不是那行平均风速,而是“数据完整率”和“质控过程描述”这两栏。只要这两栏写得潦草,后面算得再精细我都会打个问号。测风塔数据研究这件事,90%的功夫其实花在把数据处理干净、把逻辑讲清楚上,Matlab代码只是把分析过程落地的工具。哪怕只是刚接触数据分析的读者,从这份流程入手,也能避开我最开始踩过的那些坑。

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询