建筑设计日照分析计算初探

在建筑设计过程中,特别是住宅区,日照计算对于我国寒冷地区来说,通常是一个必不可少的步骤。既然是计算,那必然会有方法和规律,本文将分步探讨建筑日照计算原理及其基于Rhino/Grasshopper的实现,内容大纲如下:

一、原理及相关约定
  1. 条件设定
  2. 名词约定
  3. 计算原理
二、太阳位置的计算
  1. 使用公式计算
  2. 使用已开源的代码库
  3. 使用Rhino自带太阳模拟系统
三、计算过程全解析
  1. 确定分析网格
  2. 得到日照矢量
  3. 发射射线检测
  4. 统计日照结果
  5. 提高运算速度

四、日照结果可视化
  1. 色块显示
  2. 求等时线
  3. 三维显示
五、山地日照的思路

一、原理及相关约定

1. 条件设定

在开始之前,我们先来约定一下,以下条件作为已知条件,不去深究:

  • 太阳光当作平行光
  • 在一年的周期内,太阳位置变化受到年份的影响忽略不计
  • 以北京所在位置为例进行计算,经纬度(116.19, 39.57)
  • 以下所有角度的度量单位均为弧度

2 名词约定

名词含义
分析网格取每一个网格的重点作为采样点,每个分析网格包含一系列采样点
采样点即观察点,用来发射反光线入射矢量的射线
连续日照时间在有效日照时段中,将按照这个时间长度来细分出多个光线入射矢量
光线入射矢量太阳在天空中的位置不同导致的太阳光

3. 计算原理

本文的日照计算原理为:根据日照相关的国家规范,求得在有效日照时段中,按照连续日照时间细分后的若干个光线入射矢量,在任意采样点沿着光线入射矢量的方向发射射线,如果这条射线打到参与计算的建筑体量中的任意一个,则这一个方向的日照无效,最后将有效的光线入射矢量的数量乘以连续日照时间可得到该采样点的日照累计时长。

二、太阳位置的计算

太阳在天空中的位置是以年为周期有规律出现的,主要受以下因素影响(参考):

  • 目标时间
  • 地球在绕日公转轨道的速度
  • 地球自转轴与公转轨道的夹角
  • 观测点的位置

我们先来看看我们在这一步需要计算什么?

来自百度图片

如上图所示,North向北,Up向上,角A为方位角,角h为高度角,角z为天顶角,角h和角互为余角,咱们这一步需要求出角A和角h,来确定太阳在天空中的位置。

1. 使用公式计算

使用公式计算着实复杂了些,公式有很多推导的版本,计算方法也不止一种,这里我来讲解一种(参考)这个计算方法来自美国国家海洋和大气管理局NOAA,不得不说,这些公式所引用的参量可谓“天文数字”,可以说完全看不懂,受篇幅的限制,这部分内容我写在另一篇文章太阳方位计算原理,感兴趣的朋友可以去查看,另外,也可以直接看我对这个过程做的代码笔记,这样可以更直观的了解这个过程。

2. 使用已开源的代码库

太阳方位位置计算我推荐一个suncalc代码库,以及它的具体计算方法。这个库是Javascript的实现,在Github上也能找到别的语言实现。具体使用过程我也做了笔记,感兴趣的朋友也可以查看。

3. 使用Rhino自带太阳模拟系统

如果是在Rhino/Grasshopper下实现太阳模拟,可以考虑使用Rhino自带的太阳系统,这个太阳模拟功能位于Rhino的太阳面板(如下图), RhinoCommon 的 Api public class Sun 定义Rhino.Render命名空间下。具体实现见——三、计算过程全解析的2。

4. 总结

这一步至关重要,当我们能够确定太阳在天空中的位置之后,后面的计算就相当简单了。对于这个过程我推荐使用代码库,或者使用我在太阳方位计算原理这篇文章内基于NOAA的计算方法所实现的代码,对于在Rhino/Grashopper平台的开发,推荐使用第三种方法。

三、计算过程全解析

1. 确定分析网格

分析网格用于确定日照分析采样点,以及后续的日照结果可视化,可以用很多方法创建分析网格,比如拾取参与计算的建筑物外包一个分析网格范围等。本文介绍一个简易的分析网格创建方法。

/* using Rhino.Geometry;
 * P 网格创建平面
 * X 网格在方向的数量
 * Y 网格在Y方向的数量
 * S 采样点间距
 */
Mesh.CreateFromPlane(P, new Interval(0, X * S), new Interval(0, Y * S), X, Y);

2. 得到日照矢量

通过查阅Rhino的相关文档得知,我们可以使用class Sun来模拟太阳,有两个地方需要注意,一是设置正确的时区sun.TimeZone = 8,二是DateTime 的 Kind 需要设置为DateTimeKind.Local。通过如下方法,我们可以得到一个List<Vector3d>,里边儿就装着一天中有效日照时段按照连续日照时间细分后所有太阳在天空中位置的矢量了。

/*
 * @param Lng 当地经度
 * @param Lat 当地纬度
 * @param Month 日照计算月份,在2012年1月的21日是大寒,12月的21日是冬至
 * @param Step 连续日照时间细分
 * @return V List<Vector3d> 一系列的太阳方位矢量
 */
private void RunScript(double Lng, double Lat, int Month, int Step, ref object V, ref object B)
{
  var vcts = new List<Vector3d>();
  var sun = new Sun();
  sun.TimeZone = 8;

  int div = (int) Math.Floor((decimal) 60 / Step);
  int m = 1;
  int start = 8;
  int end = 16;

  if (Month == 12)
  {
    m = 12;
    start = 9;
    end = 15;
  }

  for (int i = start; i < end; i++)
  {
    for(int j = 0; j < div; j++)
    {
      var date = new DateTime(2012, m, 21, i, j * (60 / div), 0, DateTimeKind.Local);
      sun.SetPosition(date, Lat, Lng);
      var vct = sun.Vector;
      vcts.Add(vct);
    }
  }
  V = vcts;
}

3. 发射射线检测

这一步是计算核心,我们将通过从采样点沿着太阳光线矢量发出的射线光束进行一次追踪,如果与参与计算的建筑网格有一次相交,那就判定这个采样点这一个时刻的光线被遮挡,否则这个采样点将得到这一时刻的光照。

首先设采样点位置为记作P(x0, y0, z0),光线方向记作D(m, n, p),则射线方程可写为点向式,也可写为参数式:

\[{x – x_0 \over m} = {y – y_0 \over n} = {z – z_0 \over p} = t\]
$$\begin{cases} x = mt + x_0 \\ y = nt + y_0 \\ z = pt + z_0 \end{cases} $$

为了减少运算量,我们通过三个步骤完成上述的一次验证:

① 光线与参与计算的建筑网格的包裹球相交运算

假设包裹球的中心为 O(x1, y1, z1),半径为r,那么有

\[(x – x_1)^2 + (y – y_1)^2 + (z – z_1)^2 = r^2\]

此式联立光线参数方程得:

\[(mt + x_0 – x_1)^2 + (nt + y_0 – y_1)^2 + (pt + z_0 – z_1)^2 = r^2\]

这是一个一元二次方程,t将会有无解,单解和双解三种情况。咱们的目的只是需要判断有没有解就行,无解则没交点,否则就有交点。这个式子化简得:

\[(m^2 + n^2 + p^2)t^2 + (2m(x_0 – x_1) + 2n(y_0 – y_1) + 2p(z_0 – z_1))t\]
\[ + (x_0 – x_1)^2 + (y_0 – y_1)^2 + (z_0 – z_1)^2 – r^2 = 0\]

方程形如:

\[f(x) = ax^2 + bx + c\]

只需判断:

\[\Delta = b^2 – 4ac\]

若上式Δ小于0则t无解,那么这个时刻的光线对于采样点O就不会被这栋楼影响,否则将会在这个时刻对采样点进行遮挡。

② 光线与参与计算的建筑网格的包裹盒相交运算
③ 光线与参与计算的每个建筑网格的三角面相交运算

4. 统计日照结果

5. 提高运算速度

四、日照结果可视化

1. 色块显示

2. 求等时线

3. 三维显示

五、山地日照的思路

guest
0 评论
Inline Feedbacks
View all comments