用.NET模拟天体运动

用.NET模拟天体运动

这将是一篇罕见而偏极客的文章。

我上大学时就见过一些模拟太阳系等天体运动的软件和网站,觉得非常酷炫,比如这个(http://www.astronoo.com/en/articles/positions-of-the-planets.html): 

其酷炫之处不仅在于天体运动轨迹能画出美妙的弧线,更重要的是其运动规律完全由万有引力定律产生,不需要对其运动轨迹进行编程。所有天体受其它天体的合力,然后按照其加速度运行。只需一个起始坐标和起始速度,就能坐下来欣赏画面。

我从大学毕业后就一直对这个抱有深厚兴趣,工作第一年时我就用 C++做过一版;后来我负责公司前端工作,又用 jscanvas又做了一个重制版;由于近期爆发的 .NET“革命”,我近期又用 C#.NET再次重制了一版。

需要的数学知识

由于是程序看数学知识,此处我将使用代码来表示公式。

  • 万有引力,该力 F与两个天体的质量 m1m2成正比,如距离 r的平方成反比,用代码表示为: F=m1*m2*G/r^2

  • 牛顿第二定律,加速度 a等于合力 F除以质量 m,用代码表示为: a=F/m

  • 速度 v与加速度 a以及时间 t的关系,用代码表示为: v=a*t

  • 距离 s与速度 v以及时间 t的关系,用代码表示为: s=v*t

这里面的所有知识都已经在高中物理提过了,但有两点需要注意:

  • 所有的力、加速度、速度以及距离都需要分为 x轴和 y轴两个分量;

  • 所有的时间 t实际上是小段时间 dt,程序将循环模拟小段时间累加起来,来模拟天体运动。

核心代码

天体类:

class Star
{public LinkedList<Vector2> PositionTrack = new LinkedList<SharpDX.Vector2>();public double Px, Py, Vx, Vy;public double Mass;public float Size => (float)Math.Log(Mass) * 2;public Color Color = Color.Black;public void Move(double step){Px += Vx * step;Py += Vy * step;PositionTrack.AddFirst(new Vector2((float)Px, (float)Py));if (PositionTrack.Count > 1000){PositionTrack.RemoveLast();}}
}

注意,我没指定大小 Size,直接给值为其质量的对数乘 2,另外注意我使用了一个 PositionTrack的 链表来存储其运动轨迹。

万有引力、加速度、速度计算

void Step()
{foreach (var s1 in Stars){// star velocity// F = G * m1 * m2 / r^2// F has a direction:double Fdx = 0;double Fdy = 0;const double Gm1 = 100.0f;     // G*s1.mvar ttm = StepDt * StepDt; // t*t/s1.mforeach (var s2 in Stars){if (s1 == s2) continue;var rx = s2.Px - s1.Px;var ry = s2.Py - s1.Py;var rr = rx * rx + ry * ry;var r = Math.Sqrt(rr);var f = Gm1 * s2.Mass / rr;var fdx = f * rx / r;var fdy = f * ry / r;Fdx += fdx;Fdy += fdy;}// Ft = ma    -> a = Ft/m// v  = at    -> v = Ftt/mvar dvx = Fdx * ttm;var dvy = Fdy * ttm;s1.Vx += dvx;s1.Vy += dvy;}foreach (var star in Stars){star.Move(StepDt);}
}

注意其中有个 foreach循环,它将一一计算每个天体对某天体的力,然后通过累加的方式求出合力,最后依照合力计算加速度和速度。如果使用 gmp等高精度计算库,该循环将存在性能热点,因此可以将这个 foreach改成 Parallel.For加 lock的方式修改合力 Fdx和 Fdy,可以提高性能( C++的代码就是这样写的)。

绘图代码

public void Draw(DeviceContext ctx)
{ctx.Clear(Color.DarkGray);using var solidBrash = new SolidColorBrush(ctx, Color.White);float allHeight = ctx.Size.Height;float allWidth = ctx.Size.Width;float scale = allHeight / 100.0f;foreach (var star in Stars){using var radialBrush = new RadialGradientBrush(ctx, new RadialGradientBrushProperties{Center = Vector2.Zero,RadiusX = 1.0f,RadiusY = 1.0f,}, new SharpDX.Direct2D1.GradientStopCollection(ctx, new[]{new GradientStop{ Color = Color.White, Position = 0f},new GradientStop{ Color = star.Color, Position = 1.0f},}));ctx.Transform =Matrix3x2.Scaling(star.Size) *Matrix3x2.Translation(((float)star.Px + 50) * scale + (allWidth - allHeight) / 2, ((float)star.Py + 50) * scale);ctx.FillEllipse(new Ellipse(Vector2.Zero, 1, 1), radialBrush);ctx.Transform =Matrix3x2.Translation(allHeight / 2 + (allWidth - allHeight) / 2, allHeight / 2);foreach (var line in star.PositionTrack.Zip(star.PositionTrack.Skip(1))){ctx.DrawLine(line.First * scale, line.Second * scale, solidBrash, 1.0f);}}ctx.Transform = Matrix3x2.Identity;
}

注意我在绘图代码逻辑中做了一些矩阵变换,我把所有逻辑做成了窗体分辨率无关的,假定屏幕长和宽的较小值为 100,然后左上角坐标为 -50,-50,右下角坐标为 50,50

星系模拟

太阳、地球和月亮

这是最容易想到了,地球绕太阳转,月亮绕地球转,创建代码如下:

public static StarSystem CreateSolarEarthMoon()
{var solar = new Star{Px = 0, Py = 0,Vx = 0.6, Vy = 0,Mass = 1000,Color = Color.Red,};// Earthvar earth = new Star{Px = 0, Py = -41,Vx = -5, Vy = 0,Mass = 100,Color = Color.Blue,};// Moonvar moon = new Star{Px = 0, Py = -45,Vx = -10, Vy = 0,Mass = 10,};return new StarSystem(new List<Star> { solar, earth, moon });
}

注意所有数据都没使用真实数字模拟(不然地球绕太阳转一圈需要 365天才能看完????),运行效果如下: 

从轨迹可以看出,由于太阳引力的作用,地球会转着太阳转,但也同样由于地球和月球引力的作用,太阳也在以微小的角度在“公转”。

扩展

如果将太阳质量翻倍( 1000-> 2000),会是何种效果呢?

可见这样一来,由于引力太大,导致地球速度变快,月亮就被地球“甩”出去了,然后地球轨道也变成了实实在在的椭圆。

双子星

宇宙中存在这样一种星系,它的两颗恒星互相围绕对方转,也可以模拟出来: 

注意两个天体在接近时速度会变快,远离时速度会变慢,这是由于万有引力与距离平方成反比决定的。

扩展N星系统

static IEnumerable<Star> CreateStars(int N)
{for (var i = 0; i < N; ++i){double angle = 1.0f * i / N * Math.PI * 2;double R = 45;double M = 10000 * 2 / (N * Math.Sqrt(N) * Math.Log(N));double v = 5;double px = R * Math.Sin(angle);double py = R * -Math.Cos(angle);double vx = v * Math.Cos(angle);double vy = v * Math.Sin(angle);yield return new Star{Px = px,Py = py,Vx = vx,Vy = vy,Mass = M,};}
}

通过精密的数学计算,可以让任意多的天体组织为系统,如将 3当作 N传入函数,即可组织为“三星系统”,运行效果如下: 

注意,超过 2星的系统都不稳定(因此“三星系统”也不稳定),转过两圈之后所有天体由于 double类型的误差已经累积到不可逆转的程度,“三星系统”会慢慢崩溃解体。

看看四星系统,命运也差不多(又比“三星”稍稳定,需要等待好几圈才崩溃): 

展望与总结

由于误差是 double类型的精度限制而累积的,在 C++中我可以使用 gmp、 mpir、 mpfr等高精度计算库来模拟计算,性能也非常高。我之前使用 C++和 mpirboost配合,可以让四星系统稳定运行长达 15分钟不崩溃,还能在我的 WindowsPhone(????)上流畅运行。

之前有人将 mpir移植到了 .NET,但不支持 .NETCore(https://github.com/wezeku/Mpir.NET),有人将 mpfr移植到了 .NET(https://github.com/emphasis87/mpfr.NET/pull/5), .NETCore可以运行,但有坑爹的 bug,我提了 PR,但作者似乎没心思Merge????。

大小数计算在天文、地震、天气、海洋等科研领域有不可取代的作用,我挺希望 .NET能提供一个高性能、高精度的小数计算库,如 BigFloat。有人会问 .NET4.0不是提供了 BigInteger吗?难道不够?是真不够!整数计算和小数计算不完全一样,性能这一关就过不去。但在 .NETCore中这个问题官方似乎没有太大动力去做,我在 github上找到了几个相关 issue,都是 open状态:

  • https://github.com/dotnet/corefx/issues/17267

  • https://github.com/dotnet/corefxlab/issues/2635

本文中涉及的所有完整、可运行代码都已经上传到我的 github博客,各位可以自行下载:https://github.com/sdcb/blog-data/tree/master/2019/20191214-simulate-planet-movement-using-dotnet

喜欢的朋友 请关注我的微信公众号:【DotNet骚操作】

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/312662.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

01 手把手带你构建大规模分布式服务--高并发、高可用架构系列,高质量原创好文!...

作者&#xff1a;丁浪&#xff0c;目前在创业公司担任高级技术架构师。曾就职于阿里巴巴大文娱和蚂蚁金服。具有丰富的稳定性保障&#xff0c;全链路性能优化的经验。架构师社区特邀嘉宾&#xff01;阅读本&#xff08;系列&#xff09;文章&#xff0c;你将会收获&#xff1a;…

如何正确的探索 Microsoft Ignite The Tour

Microsoft Ignite The Tour 是一年一度微软为全球开发者、IT专家、安全专家以及数据专家提供的为期两天&#xff0c;包含众多核心产品的实践性技术培训。2019.12.10-2019.12.11 已经在北京国家会议中心胜利闭幕&#xff0c;我作为一名Speaker 参与了两门课程的分享&#xff0c;…

Leetcode贪心 种花问题

You have a long flowerbed in which some of the plots are planted, and some are not. However, flowers cannot be planted in adjacent plots. Given an integer array flowerbed containing 0’s and 1’s, where 0 means empty and 1 means not empty, and an integer n…

回顾这一年,我沉默良久

今天是一个特殊的日子&#xff0c;因为还有一周就2024了。 回忆 我骑着我心爱的小电驴慢悠悠的走在下班的路上&#xff0c;看着万家灯火&#xff0c;匆匆而过的行人和那开着三轮车的摊贩们与城管斗智斗勇。 我陷入了回忆&#xff1f; 回忆着今年的进程&#xff0c;先是裁员…

Cookie、session、token对比

Cookiecookie 是一个非常具体的东西&#xff0c;指的就是浏览器里面能永久存储的一种数据&#xff0c;仅仅是浏览器实现的一种数据存储功能。cookie由服务器生成&#xff0c;发送给浏览器&#xff0c;浏览器把cookie以kv形式保存到某个目录下的文本文件内&#xff0c;下一次请求…

Leetcode贪心 验证回文字符串

Given a string s, return true if the s can be palindrome after deleting at most one character from it. 思路 用头尾指针遍历原字符串&#xff0c;但碰到所指不相同时&#xff0c;需要退出循环记录此书指针的位置。分别去除两个指针上的内容&#xff0c;查看删除一个字符…

使用ASP.NET Core 3.x 构建 RESTful API - 4.1 面向外部的Model

Entity Framework Core 使用的 Entity Model 是用来表示数据库里面的记录的。 而面向外部的 model 则表示了要传输的东西。这类 model 有时候叫做 Dto&#xff0c;有时候叫做 ViewModel。 举一个例子&#xff0c;人员的Entity Model如下&#xff1a; 最后一个字段表示人员的出生…

特意向大家推荐.NET技术圈一些优秀开发者的公众号

在互联网技术飞速发展的今天&#xff0c;各种技术席卷而来&#xff0c;总是让人感觉压力山大。作为.NET开发者&#xff0c;我们该如何刷新自己&#xff0c;实现价值的提升呢&#xff1f;2019年.NET中国开发者峰会之后&#xff0c;我们汇总了.NET技术圈一些优秀开发者的公众号&a…

ASP.NET Core on K8S深入学习(11)K8S网络知多少

Photo &#xff1a;Kubernetes文 | Edison Zhou本文已加入《.NET Core on K8S 学习与实践系列文章索引目录》&#xff0c;点击查看阅读更多容器化相关文章&#xff0c;希望对你有所帮助&#xff01;Kubernetes网络模型我们都知道Kubernetes作为容器编排引擎&#xff0c;它有一个…

Leetcode动态规划 不同路径

A robot is located at the top-left corner of a m x n grid (marked ‘Start’ in the diagram below). The robot can only move either down or right at any point in time. The robot is trying to reach the bottom-right corner of the grid (marked ‘Finish’ in the…

Amazon、Linux基金会开发边缘网络交换器操作系统

Amazon、Linux基金会和5家网络业者上周宣布边缘网络交换器操作系统项目DENT&#xff0c;可能冲击开发专属操作系统的网络晶片及设备业者。DENT希望集结网络设备制造商&#xff0c;系统整合商及晶片厂商&#xff0c;为分散式厂区、远端办公室、分公司及零售业开发解构式网络交换…

fit、transform与fit_transform

fit(x) 是对x进行训练 transform(y) 是将模型直接应用于y fit_transform(x) 是对x进行训练后再将模型应用于x x_test加fit&#xff0c;pca x_test不加fit -4 1 0.8855240762093011 0.6501925545571245 0.7678583153832128 -4 3 0.8855236186606635 0.6508344030808729 0.76817…

多库操作:多个数据库的动态切换(一)

▼更多精彩推荐&#xff0c;上午11点到达▼在平时的开发中&#xff0c;受到传统模式的影响&#xff0c;我们都是习惯了单一的数据库表操作&#xff0c;把数据都建到一个库里边&#xff0c;然后进行增删改查&#xff0c;这个是很经典的开发模式。但是随着项目开发&#xff0c;总…

SMOTE/SMOTEEN 处理不平衡数据集

imblearn包 from imblearn.over_sampling import SMOTE from imblearn.combine import SMOTEENN代码 smo SMOTE(random_state42) x_train, y_train smo.fit_sample(x_train, y_train)smo SMOTEENN(random_state42) x_train, y_train smo.fit_sample(x_train, y_train)

超燃| 2019 中国.NET 开发者峰会视频发布

首届 .NET Conf China 2019 年&#xff0c;注定会是 .NET Core 社区发展的关键一年&#xff0c;诸多重大事件在这一年发生&#xff01;正如大家所期待的那样&#xff0c;刷新中国 .NET 社区的年度盛会——2019 中国 .NET 开发者峰会&#xff08;.NET Conf China 2019&#xff0…

Lingo优化模型概述

注意事项 lingo中变量默认是非负的示例 model: max 2*x1 3*x2; 2*x1 x2 < 8; 4*x1 3*x2 < 15; end数组型变量 集合段、数据段、目标与约束段、计算段、初始段和子模型段 model: sets: s/1..10/:x; endsetsdata: x 1 2 3 4 5 6 7 8 9 10; enddatamin sum(s(i):x…

刷新.NET

.NET Core 发布的那一天起&#xff0c;它在完成自我刷新的过程&#xff0c;一切为了适应未来&#xff0c;云原生。不仅仅跨平台那么简单。.NET Core 未来发展路线我们发现跳过了.NET Core 4.X 避免了和目前.NET Framework4.X命名上的混乱&#xff0c;明年直接命名为了.NET 5 &a…

XGBClassifier()特征选择

clf XGBClassifier() clf.fit(x_train, y_train) importances clf.feature_importances_ # print(importances) indices np.argsort(importances)[::-1] # print(indices)

如何备份和还原您的Kubernetes集群资源和持久卷?

众所周知&#xff0c;Kubernetes可以协调连接在一起&#xff0c;作为一个工作单元&#xff0c;形成高可用性的计算机集群。Kubernetes包含许多抽象概念&#xff0c;这些抽象概念允许将容器化的应用程序部署到集群中&#xff0c;而无需将它们附加到单独的机器上。简而言之&#…

sklearn评价指标

机器学习中&#xff0c;常见的评价指标如下&#xff1a; 准确率&#xff08;Accuracy&#xff09; 精确率&#xff08;Precision&#xff09; 灵敏度&#xff08;Sensitivity&#xff09;&#xff0c;即召回率&#xff08;Recall&#xff09; 特异度&#xff08;Specificity&am…