球面上に均一にランダム分布する点群を生成する

はじめに

この記事では、球面上に均一に点を配置する2つの方法について解説します。具体的には、乱数を用いる方法と、黄金比を用いる方法を紹介します。これらの手法は、シミュレーションの初期値設定や3Dグラフィックスにおけるオブジェクト配置など、様々な場面で応用できます。

この記事を書いたひと

デジタルリアクタ合同会社 代表
機械学習・統計、数値計算などの領域を軸としたソフトウェアエンジニアリングを専門としています。スタートアップからグローバル企業まで、さまざまなスケールの企業にて、事業価値に直結する計算システムを設計・構築してきました。主に機械学習の応用分野において、出版・発表、特許取得等の実績があり、また、IT戦略やデータベース技術等の情報処理に関する専門領域の国家資格を複数保有しています。九州大学理学部卒業。日本ITストラテジスト協会正会員。

対象読者:

  • プログラミングの基礎知識(Python)がある方
  • シミュレーションや3Dグラフィックスに興味がある方
  • 数学的な概念(確率密度関数、累積分布関数、逆関数など)に抵抗がない方

記事のポイント:

  • 緯線の長さを考慮した確率密度関数に基づいた乱数生成による点の配置方法を解説
  • 黄金比(フィボナッチ数列)を利用した、より簡便な点の配置方法を紹介
  • それぞれの方法をPythonコードで実装し、結果を可視化

乱数を用いた球面上への均一な点の配置

球面上に点を均等に分布させる場合、緯度と経度を単純な乱数で決定する方法では不十分です。なぜなら、緯度によって緯線の長さが異なるため、点の密度に偏りが生じてしまうからです。均一な分布を得るためには、緯線の長さに比例した頻度で緯度を生成する必要があります。

確率密度関数と累積分布関数

話を簡単にするため、半径1の単位球面を考えます。緯度をt、経度をuとします。t[-\pi/2, \pi/2]u[-\pi, \pi]の範囲の値をとります。このとき、緯度tにおける緯線の長さは\cos(t)で表されます。

緯線の長さに比例した確率で点を生成するため、累積分布関数f(x)を考えます。t = \pi/2を起点とすると、f(x)\cos(t)の積分に比例し、以下のようになります。

f(x) = \frac{1}{2} \sin(x) + \frac{1}{2}

ここで、2つの\frac{1}{2}は規格化定数であり、tの範囲内で確率の総和を1にし、f(-\pi/2) = 0f(\pi/2) = 1を満たすように調整しています。

この累積分布関数をグラフで表すと、次のようになります。

累積分布関数の逆関数

次に、この累積分布関数の逆関数f^{-1}(x)を求めます。これにより、一様乱数から緯度tを生成できるようになります。逆関数は次のように表されます。

f^{-1}(x) =
\begin{cases}
- \sin^{-1}(1 - 2x) & (0 < x < 1) \\
\text{未定義} & (x \leq 0, x \geq 1)
\end{cases}

ここで、\sin^{-1}は逆正弦関数(アークサイン)を表します。xが0から1の範囲の一様乱数であることに注意してください。

この逆関数をグラフで表すと、次のようになります。

乱数を用いた点群の生成と可視化 (Pythonコード)

上記の逆関数を用いて緯度tを生成し、経度u[-\pi, \pi]の一様乱数とすることで、球面上の点を生成します。以下にPythonコードを示します。

import matplotlib.pyplot as plt
from mpl_toolkits.mplot3d import Axes3D
import random
import numpy as np

points = []
for i in range(10000):
    t = random.random()
    t = - np.arcsin(1-2*t)
    u = random.random() * 2 * np.pi - np.pi

    x = np.cos(t) * np.cos(u)
    y = np.cos(t) * np.sin(u)
    z = np.sin(t)
    points.append([x, y, z])
points = np.array(points)

fig = plt.figure(figsize=(15,15))
ax = Axes3D(fig)
ax.plot(points[:, 0], points[:,1], points[:, 2], "o", ms=2, mew=0.5)
plt.show()

このコードを実行すると、球面上に点が均一に分布している様子が確認できます。

黄金比を用いた球面上への点の配置

乱数を使わずに、黄金比を利用して球面上に点を配置する方法もあります。この方法は、ヒマワリの種の配列など、自然界に見られるフィボナッチ数列に基づいた配置方法です。

黄金比とフィボナッチ数列

黄金比は、(1 + \sqrt{5}) / 2 で表される無理数で、約1.618です。フィボナッチ数列は、隣り合う2つの数の和が次の数になる数列(1, 1, 2, 3, 5, 8...)です。黄金比とフィボナッチ数列は密接な関係があり、この性質を利用して点を配置します。

Pythonコードによる実装

以下に、黄金比を用いて球面状に点を配置するPythonコードを示します。

import numpy as np
import matplotlib.pyplot as plt
from mpl_toolkits.mplot3d import Axes3D

def fib(N):
    f = (np.sqrt(5)-1)/2
    arr = np.linspace(-N, N, N*2+1)
    theta = np.arcsin(arr/N)
    phi = 2*np.pi*arr*f
    x = np.cos(theta)*np.cos(phi)
    y = np.cos(theta)*np.sin(phi)
    z = np.sin(theta)
    return x, y, z

x, y, z = fib(10000)

fig = plt.figure(figsize=(15,15))
ax = Axes3D(fig)
ax.plot(x, y, z, "o", ms=2, mew=0.5)
plt.show()

このコードを実行すると、点が球面全体に比較的均一に配置されていることがわかります。

まとめ

本記事では、球面上に均一に点を配置する2つの方法を紹介しました。

手法の概要 特徴
乱数を用いた方法 緯線の長さを考慮した確率密度関数を使用。逆関数を求める必要がある。 点同士の距離はランダム。点が少ないと偏ることがある。
黄金比を用いた方法 フィボナッチ数列に基づく配置。比較的シンプルな計算で実現できる。 点同士の距離は均一。点が少なくても偏らない。

これらの方法は、以下のような様々な分野で応用することができます。

  • 分子動力学シミュレーション:原子の初期配置
  • 3Dモデリング:パーティクルの配置、オブジェクトの配置
  • 機械学習:データのサンプリング
  • コンピュータグラフィックス:テクスチャマッピング

これらの手法を活用することで、より現実的で効率的なシミュレーションやモデリングが可能となります。

お気軽にご相談ください!

弊社のデジタル技術を活用し、貴社のDXをサポートします。

基本的な設計や実装支援はもちろん、機械学習・データ分析・3D計算などの高度な技術が求められる場面でも、最適なソリューションをご提案します。

初回相談は無料で受け付けております。困っていること、是非お聞かせください。