明确目标:我们要生成什么?

根据物理海洋学的观测,海面高度通常被认为是一个高斯随机场。这意味着,如果我们想在频域中表达这个海面,我们需要生成一系列复数 $H_0$ 表示振幅,并且这些复数 $H_0$ 必须满足两个条件:

  1. 能量匹配:这些随机振幅的能量必须符合能量谱 $S(\mathbf{k})$
  2. 随机性:它们必须符合高斯分布(正态分布)。

推导符合条件的 $H_0$

处理第一个条件: 在信号处理中,频域中某个波数 $k$ 的复数振幅 $H_0(\mathbf{k})$ 的能量,等于它的模的平方的期望值,即

$$ \mathbb{E}\left[|H_0(\mathbf{k})|^2\right] $$

根据第一个条件,我们需要让这个期望值(能量)等于能量谱 $S(\mathbf{k})$

$$ \mathbb{E}\left[|H_0(\mathbf{k})|^2\right] = S(\mathbf{k}) $$

处理第二个条件: 现在引入一个复高斯随机数 $Z$ ,构造出符合正太分布的 $H_0(\mathbf{k})$ 为

$$ H_0(\mathbf{k}) = Z \sqrt{S(\mathbf{k})} $$

计算期望值,

$$ \mathbb{E}\left[|H_0(\mathbf{k})|^2\right] = \mathbb{E}\left[| Z \sqrt{S(\mathbf{k})} |^2\right] = \mathbb{E}\left[|Z|^2\right] S(\mathbf{k}) $$

再根据第一个条件,

$$ \mathbb{E}\left[|H_0(\mathbf{k})|^2\right] = \mathbb{E}\left[|Z|^2\right] S(\mathbf{k}) = S(\mathbf{k}) $$

由此,我们可知引入的 $Z$ 的期望值 $\mathbb{E}\left[|Z|^2\right]$ 必须为 1

最终符合条件的 $H_0$ 为

$$ H_0(\mathbf{k}) = Z \sqrt{S(\mathbf{k})} \quad,\text{其中} \mathbb{E}\left[|Z|^2\right] = 1 $$

构造复高斯随机数

我们通过计算机随机生成两个独立的、服从标准正态分布(均值为 0,方差为 1)的实数,记为 $\xi_r$ 和 $\xi_i$。即:

$$\mathbb{E}[\xi_r^2] = 1, \quad \mathbb{E}[\xi_i^2] = 1$$

我们将它们组合成一个复数:

$$ Z=\xi_r + i\xi_i $$

它的期望值是:

$$ \mathbb{E}\left[|Z|^2\right]=\mathbb{E}[\xi_r^2 + \xi_i^2] = \mathbb{E}[\xi_r^2] + \mathbb{E}[\xi_i^2] = 1 + 1 = 2 $$

这与我们的条件不符,为了把期望值从 2 降到 1,我们需要在前面乘以 $\frac{1}{\sqrt{2}}$ :

$$Z = \frac{1}{\sqrt{2}} \left(\xi_r + i\xi_i\right)$$

此时

$$ \mathbb{E}[|Z|^2] = 1 $$

这就得到了一个纯粹的、没有任何物理偏好的“白噪声”振幅。

代入式子,我们得到 $H_0$:

$$ H_0(\mathbf{k}) = \frac{1}{\sqrt{2}} \left(\xi_r + i\xi_i\right) \sqrt{S(\mathbf{k})} $$

离散化修复

在物理学中,$S(\mathbf{k})$ 的严谨叫法是功率谱密度 (Power Spectral Density, PSD)。 注意“密度”这两个字。就像物理上的质量等于密度乘以体积($m = \rho \times V$)一样,在波数域中,某个特定波数的绝对能量,等于能量密度乘以它所占据的面积

  • 在连续的数学推导中,总能量是积分:$E_{total} = \iint S(\mathbf{k}) dk_x dk_y$
  • 在计算机中,我们只能用离散的网格点来近似。 所以,在计算机中, $S(\mathbf{k})$ 代表的是当前网格点的能量密度,而一个离散网格点模拟的是物理现实中的一块连续面,因此,我们需要计算出一个网格点所代表的物理面积大小,才能计算出该网格点的绝对能量。

根据

,我们得到(根据构建坐标的方式可能有所不同):

$$ \Delta\mathbf{k}=\mathbf{k}_{n+1} - \mathbf{k}_{n} = \frac{2 \pi}{L} $$

其中 $L$ 为所模拟的物理区域大小。 则一个离散网格点所代表的物理面积大小为,

$$ S = \Delta\mathbf{k}^2 $$

代入式子,我们得 最终的 $H_0$:

$$ H_0(\mathbf{k}) = \frac{1}{\sqrt{2}} \left(\xi_r + i\xi_i\right) \sqrt{S(\mathbf{k}) \Delta\mathbf{k}^2 } $$

示例代码

HLSL
// 简单的伪随机数哈希函数 (Wang Hash)
uint WangHash(uint seed)
{
    seed = (seed ^ 61) ^ (seed >> 16);
    seed *= 9;
    seed = seed ^ (seed >> 4);
    seed *= 0x27d4eb2d;
    seed = seed ^ (seed >> 15);
    return seed;
}

// 获取 0 到 1 之间的均匀分布随机数
float RandomFloat(inout uint seed)
{
    seed = WangHash(seed);
    return float(seed) * (1.0 / 4294967296.0);
}

// Box-Muller 变换:将均匀分布转换为标准正态分布 (高斯分布)
float2 BoxMuller(float u1, float u2)
{
    u1 = max(u1, 1e-6); // 防止 log(0)
    float R = sqrt(-2.0 * log(u1));
    float Theta = 2.0 * PI * u2;
    return float2(R * cos(Theta), R * sin(Theta));
}

[numthreads(8, 8, 1)]
void MainCS(uint3 DispatchThreadId : SV_DispatchThreadID)
{
	// 略
	// 计算频谱
    float S_k = JONSWAP(k);
    
    // 计算振幅
    float dk = 2.0 * PI / Length;
    float amp = sqrt(S_k * dk * dk / 2.0);
	
	// 生成随机数 (使用坐标组合作为种子确保确定性)
    uint seed = WangHash(id.x + id.y * Size);
    uint seed2 = WangHash(seed);
    float2 xi = BoxMuller(RandomFloat(seed), RandomFloat(seed2));

	// h0
    float2 h0_k = xi * amp;
}
点击展开查看更多

版权声明

作者: Cheyne Xie

链接: https://chaim.eu.org/posts/f0ab9546/

许可证: CC BY-NC-SA 4.0

This work is licensed under a Creative Commons Attribution-NonCommercial-ShareAlike 4.0 International License. Please attribute the source, use non-commercially, and maintain the same license.

开始搜索

输入关键词搜索文章内容

↑↓
ESC
⌘K 快捷键