我正在尝试对太阳系进行数值积分。我以前用普通的 Scheme 做过这个,现在我想用MIT 的非常有趣的 SCMUTILS-library来做这个。我做了什么:
- 我从喷气推进实验室获取了太阳系数据;即:太阳、水星、金星和地球在重心坐标中的质量、位置和速度。
- 我为微分方程编写了代码,这样系统中的每个物体(太阳、水星、金星、地球)都会以正确的方式被其他 3 个物体吸引。
- 我使用 SCMUTILS 通过数值积分运行模拟。
如果我用太阳 + 1 个其他行星运行模拟,它就可以工作。如果我尝试取太阳 + 2 个其他行星,它似乎会挂起。这很奇怪,因为几年前我用我自己自制的 Runge-Kutta 积分器用相同的数据运行了模拟,而且效果很好。
请注意,我在 MIT-Scheme 和数值积分方面很有名,我只想学习 SCMUTILS。我显然做错了什么,如果这个问题不能用 SCMUTILS 解决,我会感到惊讶。
另外,我不固定在我的代码上:如果有人可以在 SCMUTILS 中为我提供一个有效的实现,那么这也很好,只要我了解我在我的程序中做错了什么。我只想以惯用的方式使用 SCMUTILS ...
我的代码如下(大约 60 行有据可查)。感谢您对工作模拟的任何评论或改进。
;JPL-DE - Ephemerides from Jet Propulsion Laboratory http://ssd.jpl.nasa.gov
(define solar-system
(up (+ 0.0 (decoded-time->universal-time (make-decoded-time 0 0 0 1 1 2000 0))) ; January 1st 2000 at 0h0m0s UT
(up (up 1.3271244004193937e20 ; Sun mass * gravitational constant
(up -1068000648.30182 -417680212.56849295 30844670.2068709) ; Sun position (x,y,z) in meters in barycentric coordinates
(up 9.305300847631916 -12.83176670344807 -.1631528028381386)) ; Sun velocity (vx,vy,vz) in meters per second
(up 22031780000000. ; Mercurius
(up -22120621758.62221 -66824318296.10253 -3461601353.17608)
(up 36662.29236478603 -12302.66986781422 -4368.33605178479))
(up 324858592000000. ; Venus
(up -108573550917.8141 -3784200933.160055 6190064472.97799)
(up 898.4651054838754 -35172.03950794635 -532.0225582712421))
; (up 398600435436000. ; Earth
; (up -26278929286.8248 144510239358.6391 30228181.35935813)
; (up -29830.52803283506 -5220.465685407924 -.1014621798034465))
)))
(define (ss-time state) ; Select time from solar system state
(ref state 0))
(define (ss-planets state) ; Select up-tuple with all planets
(ref state 1))
(define (ss-planet state i) ; Select i-th planet in system (0: sun, 1: mercurius, 2: venus, 3: earth) (Note: the sun is also a "planet")
(ref (ss-planets state) i))
(define (GM planet) ; Select GM from planet (GM is gravitational constant times mass of planet)
(ref planet 0))
(define (position planet) ; Select position up-tuple (x,y,z) from planet
(ref planet 1))
(define (velocity planet) ; Select velocity up-tuple (vx,vy,vz) from planet
(ref planet 2))
(define ((dy/dt) state)
(define (gravitational-force on-planet by-planet) ; Calculate gravitational force on planet "on-planet" by "by-planet"
(if (equal? on-planet by-planet) ; Compare planets
(up 0.0 0.0 0.0) ; There is no force of a planet on itself
(let* ((r (- (position on-planet) (position by-planet))) ; Position of "on-planet" seen from "by-planet"
(d (abs r))) ; Distance between the two
(* -1.0 (GM by-planet) (/ r (* d d d)))))) ; Gravitational force is negatively directed, we divide by d^3 to cancel out r in nominator
(define (dy/dt-planet planet) ; Calculate dy/dt for a planet
(up 0.0 ; No change in GM
(velocity planet) ; Change in position is velocity
(* (s:generate (s:length (ss-planets state)) 'up (lambda (i) (gravitational-force planet (ss-planet state i)))) ; Calculate gravitation forces from
(s:generate (s:length (ss-planets state)) 'down (lambda (i) 1.0))))) ; all other planets, and sum them via inner product with down-tuple
(up 1.0 ; Timestep: dt/dt=1.0
(s:generate (s:length (ss-planets state)) 'up (lambda (i) (dy/dt-planet (ss-planet state i)))))) ; Calculate dy/dt for all planets
(define win (frame -150e9 150e9 -150e9 150e9 512 512)) ; Viewport: a square of 300e9 meters by 300e9 meters plotted in a 512 by 512 window
(define ((monitor-xy) state)
((s:elementwise (lambda (planet) (plot-point win (ref (position planet) 0) (ref (position planet) 1)))) (ss-planets state))) ; Plot X,Y (no Z) for planets
(define end ; Define end state
((evolve dy/dt) ; Run simulation
solar-system ; Starting state, Jan. 1st 2000 0h0m0s
(monitor-xy) ; Plot positions throughout simulation
(* 1.0 60 60) ; Timestep: 1 hour
(decoded-time->universal-time (make-decoded-time 0 0 0 1 1 2005 0))) ; Run for 5 years
)