Python

Pythonで霧・ミストをシミュレーションする方法

Python

どうも、月見(@Suzuka14144156)です。

今回は、Pythonで霧をシミュレーションする方法を解説します。

この記事のゴール

以下のGIFを得られます。

以下を想定してシミュレーション

  • 重力が-Y方向に9.8m/s2
  • 風が、平均0、標準偏差が10m/sでXY方向に吹く

風が吹くと、四隅に霧は集まりやすいことが、分かります。

どのくらいの風が吹くと霧が浮遊しやすいかなど、探索することができるようになります。

環境の構築

今回は、Anacondaを用います。

以下の記事を参考にしてください。

今回使うライブラリは、Anacondaをインストールすれば、自動でインストールされます。

Pythonで霧をシミュレーションする方法

Pythonで霧をシミュレーションするためのコード。

import numpy as np
import matplotlib.pyplot as plt
import matplotlib.animation as animation

# Simulation parameters
num_particles = 1000  # Number of fog particles
particle_size = 0.01  # Size of each particle
dt = 0.01             # Time step
g = np.array([0, -9.81])  # Acceleration due to gravity
v_mean = np.array([0.0, 0.0])  # Mean wind velocity
v_std = np.array([10.0, 10.0])   # Standard deviation of wind velocity

# Set up initial particle positions and velocities
x = np.random.uniform(low=-1.0, high=1.0, size=(num_particles, 2))
v = np.random.normal(loc=v_mean, scale=v_std, size=(num_particles, 2))

# Set up plot
fig, ax = plt.subplots()
ax.set_xlim(-1.0, 1.0)
ax.set_ylim(-1.0, 1.0)

# Define animation function
def update(frame):
    # Update particle positions
    x_new = x + v*dt
    
    # Apply gravity
    v_new = v + g*dt
    
    # Apply random wind velocity
    v_new += np.random.normal(loc=0.0, scale=particle_size, size=(num_particles, 2))
    
    # Reflect off walls
    x_new[(x_new[:, 0] < -1.0) | (x_new[:, 0] > 1.0), 0] = x[(x_new[:, 0] < -1.0) | (x_new[:, 0] > 1.0), 0]
    v_new[(x_new[:, 0] < -1.0) | (x_new[:, 0] > 1.0), 0] = -v[(x_new[:, 0] < -1.0) | (x_new[:, 0] > 1.0), 0]
    x_new[(x_new[:, 1] < -1.0) | (x_new[:, 1] > 1.0), 1] = x[(x_new[:, 1] < -1.0) | (x_new[:, 1] > 1.0), 1]
    v_new[(x_new[:, 1] < -1.0) | (x_new[:, 1] > 1.0), 1] = -v[(x_new[:, 1] < -1.0) | (x_new[:, 1] > 1.0), 1]
    
    # Update positions and velocities
    x[:] = x_new[:]
    v[:] = v_new[:]
    
    # Update scatter plot
    ax.clear()
    ax.scatter(x[:, 0], x[:, 1], s=particle_size*1000)
    ax.set_xlim(-1.0, 1.0)
    ax.set_ylim(-1.0, 1.0)

# Create animation
ani = animation.FuncAnimation(fig, update, frames=100, interval=50)

# Save animation to file
ani.save('fog_simulation.gif', writer='imagemagick')

解説

  • このコードは、Pythonで空気中に浮遊する霧をシミュレーションし、霧の大きさを任意で可変できること、そしてそれに応じて重力と気流の影響を計算できる、2DのGIFを出力としたシミュレーションです。

このシミュレーションでは、NumPyを使用して、空気中の水分子のランダムな配置を生成しています。この配置に対して、重力と風による影響を考慮して、水分子を移動させ、新しい配置を生成し、これを繰り返すことで霧のシミュレーションを行います。

そして、Matplotlibのanimationモジュールを使用して、これらの配置を連続的に表示し、GIFアニメーションとして保存することができます。

境界条件

  • 壁の衝突による反射:空気中を浮遊する霧の粒子は、壁に衝突すると反射します。この反射によって、霧の粒子は壁から跳ね返されます。
  • 重力による落下:霧の粒子は、重力の影響を受けて下向きに加速されます。このため、霧の粒子は床に向かって落下していきます。
  • 風による移動:風は、霧の粒子を風向きに押し流す力を持っています。このため、霧の粒子は風向きに移動し、風の強さに応じて速度が変化します。

次に、particle_sizeが何に寄与するか解説します。

np.random.normalの中のscaleの値を決定するのにparticle_sizeが用いられます。

この値が大きいほど、分散が大きくなります。

np.random.normalは、正規分布に従う乱数を生成する関数です。この関数のパラメータの一つであるscaleは、生成する乱数の分散を指定するものです。具体的には、平均値を0とした正規分布における標準偏差を表します。

例えば、scale=1.0と指定すると、平均値を0とした正規分布における標準偏差が1.0となります。つまり、生成される乱数は平均値の周りに集中し、その分布の幅が狭くなります。一方、scale=2.0と指定すると、分散が4.0となり、乱数の分布がより広がります。

したがって、np.random.normalで生成される乱数のばらつきを調整するために、scaleパラメータを調整することができます。

Pythonで霧をシミュレーションした結果

風の平均速さ0m/s,標準偏差1m/sの場合

風のばらつきが、1m/s程度では、重力によって-Y方向に霧が落ちていくことが分かります。

風の平均速さ0m/s,標準偏差5m/sの場合

風の平均速さ0m/s,標準偏差10m/sの場合

霧が空気中で浮遊する様子を見ていきます。

霧が浮遊するには、上昇気流が必要です。

なぜなら、上昇気流(y方向)の気流があると-y方向の重力を打ち消しあい、長時間浮遊していられるためです。

y方向の風の平均速1m/s,標準偏差1m/sの場合

y方向の風の平均2m/s,標準偏差1m/sの場合

風速が、2mを超えてくると最初浮き上がり、徐々に重力に負ける様子が分かります。

Pythonで流体を勉強する方法

私は、以下の本で勉強しましたので、参考にしてみてください。

created by Rinker
¥4,180 (2025/01/14 16:50:39時点 楽天市場調べ-詳細)

Udemy

Udemyはオンライン講座です。

一度購入すれば、ずっと閲覧できるのでオススメです。

Pythonの基礎を学びたい方は、以下の口座がオススメです。

現役シリコンバレーエンジニアが教えるPython 3 入門 + 応用 +アメリカのシリコンバレー流コードスタイル
現役シリコンバレーエンジニアが教えるPython入門!応用では、データ解析、データーベース、ネットワーク、暗号化、並列化、テスト、インフラ自動化、キューイングシステム、非同期処理など盛り沢山の内容です!

まとめ

Pythonで霧をシミュレーションする方法について解説しました。

Pythonを使えば、比較的簡単に実装することができます。

コメント

タイトルとURLをコピーしました