c# - 如何实现 Maxwell 的分布?
问题描述
我有以下问题需要解决(此文本是从俄语翻译的。所以,可能存在一些翻译问题):
...从正态分布中提取的另一种方法是从均匀分布 x1, x2 ∈ [0:0, 1:0) 中提取两个独立的随机数。然后应用以下变换:从具有零期望值和单位方差的正态分布中产生两个随机独立的数字 n 1、 n 2 。
要将分布参数更改为其他参数,例如预期值和方差,您应该将绘制的结果乘以并添加,即在上面的等式中,N(μ, σ) 是具有正态分布的随机变量具有期望值 μ 和方差 σ。
根据麦克斯韦分布,速度矢量v的每个分量(x、y 或 z)是来自具有零期望值和方差的正态分布的随机变量,其中 m 是分子的质量,T 是开尔文温度, k B是玻尔兹曼常数。
你的任务:为 300K 的 N 2氮分子绘制 10,000 个速度矢量。使用以下公式计算这些向量的平均长度,从而计算氮分子速度的平均值:
public class Maxwell
{
public double N1 { get; private set; }
public double N2 { get; private set; }
public void Compute(Random random)
{
double x1 = random.NextDouble();
double x2 = random.NextDouble();
N1 = Math.Sqrt(-2 * Math.Log(x1)) * Math.Cos(2 * Math.PI * x2);
N2 = Math.Sqrt(-2 * Math.Log(x1)) * Math.Sin(2 * Math.PI * x2);
}
}
public class Program
{
static void Main(string[] args)
{
Random r = new Random();
Maxwell m = new Maxwell();
m.Compute(r);
double n1 = m.N1;
double n2 = m.N2;
//.....?
}
}
我不明白如何从 n1 和 n2 实现 N(μ, σ),以及如何从那里得到向量v。
任何人都可以帮忙吗?
编辑:我已经根据Eric Lippert 的回答实现了它:
using System;
public class CommonDistributions
{
public static double Uniform(Random random)
{
return random.NextDouble();
}
static double Gaussian(Random random)
{
return Math.Sqrt(-2 * Math.Log(Uniform(random))) * Math.Cos(2 * Math.PI * Uniform(random));
}
public static double Gaussian(Random random, double mu, double sigma)
{
return sigma * Gaussian(random) + mu;
}
}
public class MaxwellBolzman
{
static double KB = 1.38064852e-23;
static double MaxwellVariance(double mass, double temperature)
{
return Math.Sqrt(KB * temperature / mass);
}
static double MaxwellComponent(Random random, double mass, double temperature)
{
double mu = 0.0;
double sigma = MaxwellVariance(mass, temperature);
return CommonDistributions.Gaussian(random, mu, sigma);
}
public static double Maxwell(Random random, double mass, double temperature)
{
double one = MaxwellComponent(random, mass, temperature);
double two = MaxwellComponent(random, mass, temperature);
double thr = MaxwellComponent(random, mass, temperature);
return Math.Sqrt(one * one + two * two + thr * thr);
}
}
public static class MainClass
{
public static void Main(String[] args)
{
Random random = new Random();
const int N = 10000;
const int T = 300;//300K
const double mass = 28.02;//28.02 g/mol
double sum = 0.0;
for (int i = 1; i < N; i++)
{
sum = sum + MaxwellBolzman.Maxwell(random, mass, T);
}
Console.WriteLine($"Maxwell-Boltzman = {sum/N}");
string str = string.Empty;
}
}
我不确定温度值和氮 2 的质量。
如果有人可以对代码发表评论,那就太好了。
解决方案
在这种情况下要做的事情是思考“假设我有一个魔术盒,它回答了我向它提出的特定问题;那个盒子的输入和输出会是什么?” 并编写一个实现该框的方法。
从最简单的盒子开始。没有输入,输出是一个介于 0 和 1 之间的均匀分布数:
static Random random = new Random();
static double Uniform() => random.NextDouble();
好的,现在我们的工具箱中有一个新工具。我们的下一个魔法盒子是什么?没有输入,输出是一个均值为 0 标准差为 1 的正态分布数:
static double StandardNormal() =>
Sqrt(-2 * Log(Uniform())) * Cos(2 * PI * Uniform());
我们还有另一个工具。我们可以用它构建什么?输入:均值和标准差,输出,具有该均值和标准差的正态分布数:
static double Normal(double mean, double sigma) =>
sigma * StandardNormal() + mean;
好的,现在我们需要什么?作为质量和温度函数的方差:
static double KB = 1.38064852e-23;
static double MaxwellVariance(double mass, double temperature) =>
Sqrt(KB * temperature / mass);
超级,我们正在前进。现在我们需要什么?输入是质量和温度,输出是单个随机麦克斯韦速度分量:
static double MaxwellComponent(double mass, double temperature) =>
Normal(0.0, MaxwellVariance(mass, temperature));
现在我们需要什么?表示向量的类型:
struct Vector
{
public double X { get; }
public double Y { get; }
public double Z { get; }
public Vector(double x, double y, double z)
{
this.X = x;
this.Y = y;
thiz.Z = z;
}
}
接下来我们需要什么?一个随机向量:
static Vector MaxwellVector(double mass, double temperature) =>
...
你能从这里拿走吗?接下来你需要什么?再次,继续将其分解为单行。不要花哨。编写您不理解的长代码没有任何奖励。
这里的技术是分而治之。有了这些问题,您几乎总是可以编写一个少于五行代码的方法,只计算一件事。那就这样做吧;每次只计算一件事,然后你的工具包中有一个新工具可以计算下一件事。此外,您有一组方法,其中每个方法 (1) 显然是正确的,因为它只有一行代码,并且 (2) 可测试!写一个测试套件!
更新:该问题已更新以实现其中一些想法,看起来还不错。还有一个关于温度和质量的后续问题。
温度看起来不错;300K。但是质量是完全错误的。说明说要使用一个分子的质量,但您输入的是一摩尔分子的质量。
请记住,“mol”就像“pair”或“dozen”。一对是两个东西,一打是十二个东西,一摩尔大约是 600000000000000000000000 个东西。显然,一个 N2 分子的重量不超过 28 克。相反,6000000000000000000000000 个 N2 分子重 28 克。
还要记住,质量和体积的公制单位是完全任意选择的。如果你把地球的周长除以 40 亿,做一个边长一样长的立方体,然后装满水,那就是 1 克的质量。
我们选择了与“mol”相关的值,因为它具有这样的性质:同种分子的 mol 的质量等于分子的原子量(以克为单位)。所以这些小盒子中有 18 个有 1 摩尔的水分子。使用摩尔质量只是一种方便,因为它使数字对我们的目的更“合理”;通常我们习惯于考虑一些克水,而不是一些水分子,但你的问题只涉及一万个分子,而不是一万克。因此,您要做的是将一摩尔的质量除以一摩尔中的物质数量,得到一个分子的质量,以克为单位。
接下来要做的是进行单位分析,以确定质量需要以克还是千克为单位!对于 KB,我们有 1.38E-23 的值,维基百科有用地指出,它的单位是焦耳每开尔文。我们如何使用它?我们取 KB*T/M 的平方根。平方根需要的单位是多少?它是速度的标准偏差,以米每秒为单位,所以我们需要KB*T/M
以米平方每秒为单位。
- KB 是焦耳每开尔文;T 是开尔文,
KB * T
焦耳的单位也是如此。 - 焦耳的单位是千克乘以平方米/秒平方。
- 因此,要获得米平方/秒平方,我们需要除以千克,而不是克。
所以你需要的是克/摩尔除以分子/摩尔得到克/分子,然后将其转换为千克/分子。
有道理? 养成对每个问题进行单元分析的习惯。当我在黑暗时代还是一名物理专业的学生时,这让我犯了很多错误。
旁白:说到单位分析,需要注意的是:您的文本摘录将标准差称为方差,但标准差实际上定义为方差的平方根。这种用法非常普遍,您应该从上下文中推断“方差”是否意味着“真正的方差”,或者在这种情况下是标准偏差。
也就是说,文本应该说“N(μ, σ) 是一个具有正态分布的随机变量,期望值 μ 和方差 σ 2。” 或者应该说“N(μ, σ) 是一个具有正态分布的随机变量,期望值为 μ,标准差为 σ。” 请注意这一点并防御性地阅读。
另外一个问题:您可能已经注意到我们表示分布的方式非常“笨拙”。感觉就像你必须做很多工作才能表示一些相当简单的东西。我目前的研究是概率语言,这使得这类工作非常简单。在概率语言中,我们将代表您的工作流程,如下所示:
IDistribution<double> Speed(double mass, double temp)
{
IDistribution<double> c =
Normal.Distribution(0.0, MaxwellVariance(mass, temp))
double x = sample c;
double y = sample c;
double z = sample c;
return Sqrt(x*x + y*y + z*z);
}
...
double mean = Speed(mass, temp).Mean(10000);
(如果这看起来像一个Task<T>
被替换为IDistribution<T>
和await
替换为的异步方法sample
,那是因为它是;异步和概率工作流都可以作为协程实现。)
如果您对概率语言的主题感兴趣,我有一个温和而冗长的介绍,从这里开始:https ://ericlippert.com/2019/01/31/fixing-random-part-1/
推荐阅读
- javascript - 使用 C# 我无法将密钥发送到角度标签
我得到这个错误元素 我已经尝试了一堆解决方案,比如隐式等待 - 这不起作用,文本字段可以通过鼠标单击但无法通过键盘访问,因此无法输入值但可以单击文本字段。
我也有这个解决方案
- r - 使用R调整skimr包中的火花图/直方图
- postgresql - 查询间隔日期Postgres更改如果月末
- powershell - 具有两个同名标题的导出 CSV
- .net - 如何在 Blazor 中将信息从上一页发送到当前页?
- python - docker-compose build 时 Docker miniconda3 设置错误
- testing - 在非 GUI 中运行脚本时负载测试卡住了
- html - 如何将用户输入的 HTML 发送到 R 函数
- php - 如何使用 Imagemagick(或 imagick php)将 alpha 通道附加到 TIFF(或 pdf)?
- r - 以另一列为条件重新编码 data.frame 中的列