01 风坡夹角的定义

风向与坡向夹角的余弦值和坡度正弦值的乘积.

02 说明

计算风坡夹角需要使用到ERA5-Land再分析资料的u10(横向上风的分量)和v10(纵向上风的分量)(ps: 计算风速wind使用勾股定理u10 ^ 2 + v10 ^ 2再对结果开方即可),坡向坡度可以通过DEM进行计算(利用ArcGIS/QGIS等).

2.1 u10和v10的定义

u10全称为10 metre U wind componentv10全称是10 metre V wind component

ERA5-Land官方文档的定义是:



附官方文档链接:

u10v10

从上面的描述中可以知道:u10实际上就是东西向的风分量朝移动的速度,v10是南北向的风分量朝移动的速度。

而根据气象学上关于风的定义,例如东风表示风从东边吹过来,所以是朝正西方向移动的风,某种程度上可以说这个定义与上述的u10v10的定义刚好相反,前者是从哪边吹过来,后者是朝哪边吹过去。因此后续进行计算时尤其需要注意正负号的关系。

关于风向,应该计算为0-360范围(类似地,东风的风向为90°),具体如下:

2.2 u10和v10的下载

下载:ERA5-Land每小时产品下载

2.2.1 选择下载的变量

2.2.2 选择下载的时间

2.2.3 选择地理范围和下载格式

2.2.4 下载

2.3 DEM的下载

对于DEM的下载已经坡向坡度的计算较为简单,此处略

03计算

3.1 风向的计算

关于风行的定义前文已经提及,这里着重说明计算的逻辑。

由于气象学上风向的逻辑与ERA5-Land的u10和v10的逻辑正好相反,譬如:

u10 v10
东风 10m/s -10 m/s 0 m/s
北风 5 m/s 0 m/s -5 m/s
西风 8 m/s 8 m/s 0 m/s
正西南风 2m/s $\sqrt{2}$ m/s $\sqrt{2}$ m/s
正东南风 6 m/s $-3\sqrt{2}$ m/s $3\sqrt{2}$ m/s

其他风就不一一列举。

因此为了方便数学上关于向量的计算,提前将u10v10添上负号,其负号的两个横纵变量在笛卡尔xy坐标系上的合分量的指向就是正确的风向了。

也就是说,利用arctan($\frac{-v}{-u}$)反算夹角即可得到风向。

代码如下:

import numpy as np

def cal_wind_direction(u, v):
# 计算来向向量 (-u, -v) 的数学角度 -- (来向向量: 风吹来的方向, 例如北风是从北边吹来的,所以来向向量的方向是正北)
wind_dir_rad = np.arctan2(-v, -u) # 参数顺序为 y=-v, x=-u
"""
这里是对于np.arctan2(y, x)是传入一个向量(x, y), 计算其与向量(1, 0)(该向量与X轴正方向一致,此处坐标均为数学坐标系/二维笛卡尔坐标系)的夹角,
夹角范围为(-180, 180), 若为一二象限即是正,若为三四象限即为负,这与数学上的逆时针为正角顺时针为负角一致.
此外,
此处的u和v,首先解释u表示风吹向东边的速度;v表示风吹向北边的速度;(负号表示与定义方向相反)
由上面可以知道, u表示x轴方向上的分速度, v表示y轴方向上的分速度;
基于u和v可以计算出风运动的方向和速度,速度这里我们暂时不管,但是对于风运动的方向,显然与向量(u, v)的方向一致;
但是风运动的方向和向量(u, v)的方向都是表示风往哪个方向吹或者风要吹到哪里去;这与风向的定义正好相反,例如:
北风表示从北边吹来的风,所以是吹往南边的风,假定风速是1m/s,那么u=0,v=-1m/s(由v的定义知往南吹与定义方向相反所以添上负号).
如果直接传入arctan2(-1, 0),那么实际上得到的是向量(0, -1)的方向与向量(1, 0)方向上的夹角.
但是我们应该是需要得到向量(0, 1)的方向与向量(1, 0)方向上的夹角.
大家自行体会为什么需要添上负号,本质就是u和v定义正方向是风吹向的方向,而风向定义的方向是风来时或者从哪里吹来的方向--方向刚好相反
""" # 将弧度转换为度数 [-pi, pi] ==> [-180, 180]
wind_dir_deg = np.degrees(wind_dir_rad) # 转换为地理角度(正北为0°,顺时针旋转)
wind_dir_geo = (90 - wind_dir_deg) % 360
"""
根据arctan2的定义知,其输出是指风向向量(当你输入是-u, -v时符合风向定义)与向量(1, 0)方向或者说x轴正方向之间的夹角
但是风向的定义北风为0°,如此顺时针旋转到360度回到正北.两个夹角的定义不相同, 需要进行换算
""" return wind_dir_geo

ps:函数内有两个需要注意的就是np.arctan2的输入和输出,由于我们计算出来的夹角是需要在0-360°,普通的np.arctan函数只能计算一个周期Π即范围是[$\frac{-Π}{2}$, $\frac{Π}{2}$],因此需要使用np.arctan2

  1. 其输入是先y(对应-v10)后x(对应-u10),注意参数的顺序
  2. 其输出是[-Π,Π],夹角(即为下方的src_angle)表示为向量(x, y)(即(-u10, -v10))与x轴正方向上的(1, 0)之间的夹角,按照数学逻辑逆时针为正(即在x轴上方的向量为正),顺时针为负(x轴下方的向量为负),换算为气象学上的风向为dst_angle = (90 - src_angle) % 360,其中dst_angle为气象学的风向角度值(0-360,0表示北风)。注意此处的%不同编程语言的运算逻辑在负数的取余上存在区别,因此注意使用其他语言计算时的区别(目前仅适用于python)。

我们尝试计算一些示例(风向完全依据cal_wind_direction函数输入下方u10v10计算得到):

u10 v10 风向(°)
东风 10m/s -10 m/s 0 m/s 90
北风 5 m/s 0 m/s -5 m/s 0
西风 8 m/s 8 m/s 0 m/s 270
正西南风 2m/s $\sqrt{2}$ m/s $\sqrt{2}$ m/s 225
正东南风 6 m/s $-3\sqrt{2}$ m/s $3\sqrt{2}$ m/s 135

3.2 风向和坡向夹角的计算

坡向的计算通过GIS软件例如ArcGIS即可实现,此处不再赘述.

风向和坡向的夹角范围为0-180,因此计算为:

# 计算风向和坡向的夹角
theta_diff = np.abs(wind_dir - aspect)
theta = np.minimum(theta_diff, 360 - theta_diff)

3.3 计算风坡夹角/风效因子

# 计算风坡夹角
ws_angle = np.cos(np.radians(theta)) * np.sin(np.radians(slope))

这是具体函数(函数内部的cal_wind_direction为自定义函数,具体见3.1内容):

import rasterio as rio
import numpy as np def cal_wind_slope_angle(out_path, u10_path, v10_path, aspect_path, slope_path):
"""
基于u10和v10计算风向, 基于风向和坡向、坡度计算风坡夹角
风坡夹角: 风向与坡向夹角的余弦值和坡度正弦值的乘积
:param out_path: 风坡夹角的输出路径
:param u10_path: u10的输入路径
:param v10_path: v10的输入路径
:param aspect_path: 坡向的输入路径
:param slope_path: 坡度的输入路径
:return: None
""" # 读取经纬向风速,坡向坡度
with rio.open(u10_path) as f:
u10 = f.read(1, masked=True) # 读取第一个波段
meta = f.meta
"""
.meta返回当前tiff文件的元数据, 包括格格式(GTiff)、数据类型(dtype)、无效值(nodata)、行列数和波段数(width,height,count),
坐标参考系(crs)、仿射参数(transform)
示例:
{'driver': 'GTiff',
'dtype': 'float32',
'nodata': nan,
'width': 129,
'height': 133,
'count': 1,
'crs': CRS.from_wkt('GEOGCS["unknown",DATUM["unknown",SPHEROID["unknown",6367470,0]],PRIMEM["Greenwich",0],UNIT["degree",0.0174532925199433,AUTHORITY["EPSG","9122"]],AXIS["Latitude",NORTH],AXIS["Longitude",EAST]]'),
'transform': Affine(0.1, 0.0, 97.30000000000001,
0.0, -0.1, 34.4)}
"""
with rio.open(v10_path) as f:
v10 = f.read(1, masked=True)
with rio.open(aspect_path) as f:
aspect = f.read(1, masked=True)
with rio.open(slope_path) as f:
slope = f.read(1, masked=True) # 计算风向
wind_dir = cal_wind_direction(u10, v10)
# 计算风向和坡向的夹角
theta_diff = np.abs(wind_dir - aspect)
theta = np.minimum(theta_diff, 360 - theta_diff)
# 计算风坡夹角
ws_angle = np.cos(np.radians(theta)) * np.sin(np.radians(slope)) with rio.open(out_path, 'w', **meta) as f:
f.write(ws_angle, 1)

使用示例:

# @Author  : ChaoQiezi
# @Time : 2025/4/21 下午10:12
# @Email : chaoqiezi.one@qq.com
# @Wechat : GIS茄子
# @FileName: wind_slope_angle_cal """
This script is used to 基于ERA5的u和v风向计算风向角度(0~360),再利用风向和坡度坡向计算风坡夹角. 风坡夹角: 风向与坡向夹角的余弦值和坡度正弦值的乘积.
"""
import os.path import numpy as np
from numpy import arctan2, pi
from datetime import datetime
from dateutil.relativedelta import relativedelta
from rasterio.plot import show from Src.utils import cal_wind_direction, cal_wind_slope_angle # 准备
out_dir = r'E:\Datasets\Objects\PrecipitationDownscaling\wind_slope_angle'
slope_dir = r"E:\Datasets\Objects\PrecipitationDownscaling\Slope"
aspect_dir = r"E:\Datasets\Objects\PrecipitationDownscaling\Aspect"
u10_dir = r'E:\Datasets\Objects\PrecipitationDownscaling\u10'
v10_dir = r'E:\Datasets\Objects\PrecipitationDownscaling\v10'
res_folder_name = '1km'
start_date = datetime(2019, 1, 1)
end_date = datetime(2023, 12, 31)
out_dir = os.path.join(out_dir, res_folder_name)
if not os.path.exists(out_dir):
os.makedirs(out_dir) rd = relativedelta(end_date, start_date)
month_range = rd.years * 12 + rd.months + 1
for cur_month in range(month_range):
cur_date = start_date + relativedelta(months=cur_month)
cur_slope_path = os.path.join(slope_dir, 'slope_{}.tif'.format(res_folder_name))
cur_aspect_path = os.path.join(aspect_dir, 'aspect_{}.tif'.format(res_folder_name))
cur_u10_path = os.path.join(u10_dir, res_folder_name, 'u10_{}{:02}_{}.tif'.format(
cur_date.year, cur_date.month, res_folder_name))
cur_v10_path = os.path.join(v10_dir, res_folder_name, 'v10_{}{:02}_{}.tif'.format(
cur_date.year, cur_date.month, res_folder_name))
cur_out_filename = 'ws_angle_{}{:02}_{}.tif'.format(cur_date.year, cur_date.month, res_folder_name)
cur_out_path = os.path.join(out_dir, cur_out_filename)
cal_wind_slope_angle(cur_out_path, cur_u10_path, cur_v10_path, cur_aspect_path, cur_slope_path)
print('处理: {}'.format(cur_out_filename))
print('处理完成.')

若对博客存在疑虑或存在问题瑕疵,交流欢迎关注微信公众号:GIS茄子,或者邮箱联系(推荐 | chaoqiezi.one@qq.com).

本文由博客一文多发平台 OpenWrite 发布!

Python:风坡夹角/风效因子的计算的更多相关文章

  1. Python之NumPy实践之数组和矢量计算

    Python之NumPy实践之数组和矢量计算 1. NumPy(Numerical Python)是高性能科学技术和数据分析的基础包. 2. NumPy的ndarray:一种对位数组对象.NumPy最 ...

  2. 雷达无线电系列(三)经典CFAR算法门限因子alpha计算(matlab)

    前言 本文汇集CA.SO.GO.OS.杂波图等恒虚警算法的门限因子求解方法及其函数 1,CA-CFAR [非常简单,可以直接求解] %% 均值恒虚警_门限因子计算公式 %% 版本:v1 %% 时间:2 ...

  3. 【401】Python 求合数的所有质数因子

    对于这样的一个题目来说,出看来,可能会想到判断是否为质数,但其实并不需要. 只要按照从2开始遍历,只要遇到可以整除的就是想要的质数,理由是,如果遇到合数的话,那么在此之前一定会遇到这个合数的质因子,因 ...

  4. 利用Python进行数据分析(9) pandas基础: 汇总统计和计算

    pandas 对象拥有一些常用的数学和统计方法.   例如,sum() 方法,进行列小计:   sum() 方法传入 axis=1 指定为横向汇总,即行小计:   idxmax() 获取最大值对应的索 ...

  5. [python]沪深龙虎榜数据进一步处理,计算日后5日的涨跌幅

    沪深龙虎榜数据进一步处理,计算日后5日的涨跌幅 事前数据: 前面处理得到的csv文件 文件名前加入“[wait]”等待程序处理 python代码从雅虎股票历史数据api获取数据,计算后面5日的涨跌幅 ...

  6. python读取es中的所有数据并计算md5然后进行持久化

    #!/usr/bin/python import threading import json import time from elasticsearch import Elasticsearch f ...

  7. Python中类的声明,使用,属性,实例属性,计算属性及继承,重写

    Python中的类的定义以及使用: 类的定义: 定义类 在Python中,类的定义使用class关键字来实现 语法如下: class className: "类的注释" 类的实体 ...

  8. [读书笔记] Python数据分析 (四) 数组和矢量计算

    Numpy:高性能计算和数学分析的基础包 ndarray, 一个具有矢量算术运算和复杂广播能力的快速且节省空间的多维数组 用于对数组数据进行快速运算的标准数学函数 用于读写磁盘数据的工具和用于操作内存 ...

  9. Python datetime time 等时间 日期 之间的计算和相互转化

    from datetime import datetime, date, timedelta, timezone from time import time, ctime, localtime, st ...

  10. Python实例讲解 -- 获取本地时间日期(日期计算)

    1. 显示当前日期: print time.strftime('%Y-%m-%d %A %X %Z',time.localtime(time.time())) 或者 你也可以用: print list ...

随机推荐

  1. Flask之初始

    一.简介 Flask是一个基于Python实现的Web开发'微'框架 官方文档: http://flask.pocoo.org/docs/0.12/中文文档: http://docs.jinkan.o ...

  2. 鸿蒙运动项目开发:封装超级好用的 RCP 网络库(中)—— 错误处理,会话管理与网络状态检测篇

    鸿蒙核心技术##运动开发## Remote Communication Kit(远场通信服务) 在上篇中,我们介绍了 RCP 网络库的核心功能,包括请求参数的封装.响应内容的转换以及拦截器与日志记录机 ...

  3. AI大模型应用开发-用LangChain构建PAL应用:SQL的生成与执行

    PAL(Program-Aided Language models) 思想成为大模型 Agent 领域的重要范式.核心思路是 LLM 只负责语言任务,复杂的逻辑/计算交由程序执行. 通过合理设计 pr ...

  4. 揭秘如何用Monaco Editor打造功能强大的日志查看器

    Monaco Editor 是一个基于浏览器的代码编辑器,由 Microsoft 开发,是 Visual Studio Code 的核心编辑器组件.为用户提供了一个功能丰富.性能优异的代码编辑环境,常 ...

  5. 袋鼠云数栈DTinsight与10家信创厂家完成产品兼容互认证,携手共建信创生态圈

    信创产业是国家数据安全.网络安全的基础,也是"新基建"的重要内容,它将成为拉动经济发展的重要抓手之一.随着国际竞争形势发生新的变化,力争掌握核心科技的"自主可控" ...

  6. Flink Watermark示例

    Watermark简介 在 Apache Flink 中,水印(Watermark) 是一种用于处理事件时间(Event Time)流数据的机制.它代表了流处理系统中对事件时间进度的理解,用来标识数据 ...

  7. Django+DRF 实战:自定义异常处理流程

    一.DRF 异常处理流程 DRF 默认异常处理流程 DRF默认的异常处理流程如下: 当异常发生时,会自动调用rest_framework.views.exception_handler 函数来处理异常 ...

  8. 前端开发系列009-基础篇之JavaScript内置Math

    本文介绍JavaScript中的内置对象Math,以及Math的常用方法. 一.Math简单介绍 ECMAScript为我们提供了一个专门处理数学计算的内置对象--Math对象.Math对象提供了很多 ...

  9. dpkg 安装 依赖不全的软件

    sudo dpkg -i netease-cloud-music_1.0.0-2_amd64_ubuntu16.04.deb sudo apt-get -f -y install sudo dpkg ...

  10. 对称加密 & 非对称加密

    简介 其实网上的人讲的很好了 最著名的非对称加密在HTTPS/HTTP中实现 参考链接 https://zhuanlan.zhihu.com/p/43789231 https://blog.csdn. ...