首页 > 解决方案 > 如何实现 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 的质量。

如果有人可以对代码发表评论,那就太好了。

标签: c#probability-distribution

解决方案


在这种情况下要做的事情是思考“假设我有一个魔术盒,它回答了我向它提出的特定问题;那个盒子的输入和输出会是什么?” 并编写一个实现该框的方法

从最简单的盒子开始。没有输入,输出是一个介于 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/


推荐阅读