C语言 月相算法

mutmk8jj  于 2022-12-29  发布在  其他
关注(0)|答案(8)|浏览(285)

有没有人知道一个算法来计算月相或年龄在给定的日期或找到日期的新月/满月在给定的一年?
谷歌告诉我答案在一些天文学书籍中,但我真的不想买一整本书时,我只需要一页。

    • 更新日期:**

我应该更好地解释一下我关于谷歌搜索的说法,我确实找到了一些解决方案,这些方案只在一小段时间内有效(比如20世纪);和基于三角函数的解决方案,这比我想的要更昂贵。
S Lott在他的Python书中有几个算法可以计算给定年份的复活节,大多数算法不到10行代码,有些算法可以计算公历中的所有日期。找到3月的满月是找到复活节的关键,所以我认为应该有一个算法不需要三角函数,可以计算公历中的所有日期。

ibrsph3r

ibrsph3r1#

不久前我把一些代码移植到了Python中,我本打算直接链接到它,但结果发现它同时从网络上掉了下来,所以我不得不把它擦干净,重新上传,参见moon.py,它是从John Walker's moontool衍生而来的。
我也找不到一个参考资料来说明它在什么时间跨度上是准确的,但看起来作者们相当严谨。这意味着是的,它确实使用了trig,但我无法想象你会用它来做什么,这会使它在计算上受到限制。Python函数调用的开销可能比trig操作的成本还要多。计算机在计算上相当快。
代码中使用的算法来自以下来源:

**Meeus,Jean.《天文学算法》,里士满:威尔曼-贝尔出版社,1991年,国际标准书号0-943396-35-2。

必备品;如果你只买一本书,一定要买这本。算法是用数学方法提出的,而不是作为计算机程序,但是实现书中许多算法的源代码可以用QuickBasic,Turbo Pascal或C. Meeus分别向出版商订购,Meeus提供了许多计算的工作示例,这些示例对调试代码至关重要,并且经常提出在精度、速度、复杂度和长期(世纪和千年)有效性之间具有不同折衷的若干算法。

Duffett-Smith,Peter,《使用计算器的实用天文学》,第3版,剑桥:剑桥大学出版社,1981年。ISBN 0-521-28411-2。

尽管标题中有计算器一词;这是一个有价值的参考,如果你有兴趣在开发软件,计算行星的位置,轨道,Eclipse,等等。更多的背景信息比在Meeus,这有助于那些还不精通天文学学习经常混淆的术语。算法给出的是简单的,准确性比Meeus提供的,但适合于大多数实际工作。

mlmc2os5

mlmc2os52#

如果你像我一样,你会努力成为一个细心的程序员,所以当你看到散布在互联网上的随机代码声称要解决一个复杂的天文学问题,却不能解释为什么答案是正确的时,你会感到紧张。
你相信一定有权威的资料来源,如 * 书籍 *,其中包含仔细、完整的解决方案。例如:
《天文学算法》,里士满:威尔曼-贝尔出版社,1991年,国际标准书号0 - 943396 - 35 - 2。
Duffett-Smith,Peter,《使用计算器的实用天文学》,第3版,剑桥:剑桥大学出版社,1981年。ISBN 0 - 521 - 28411 - 2。
您可以信任广泛使用、经过良好测试的开源库,它们可以纠正错误(不像静态网页),下面是基于PyEphem库的Python解决方案,使用月相接口。

#!/usr/bin/python
import datetime
import ephem
from typing import List, Tuple

def get_phase_on_day(year: int, month: int, day: int):
  """Returns a floating-point number from 0-1. where 0=new, 0.5=full, 1=new"""
  #Ephem stores its date numbers as floating points, which the following uses
  #to conveniently extract the percent time between one new moon and the next
  #This corresponds (somewhat roughly) to the phase of the moon.

  #Use Year, Month, Day as arguments
  date = ephem.Date(datetime.date(year,month,day))

  nnm = ephem.next_new_moon(date)
  pnm = ephem.previous_new_moon(date)

  lunation = (date-pnm)/(nnm-pnm)

  #Note that there is a ephem.Moon().phase() command, but this returns the
  #percentage of the moon which is illuminated. This is not really what we want.

  return lunation

def get_moons_in_year(year: int) -> List[Tuple[ephem.Date, str]]:
  """Returns a list of the full and new moons in a year. The list contains tuples
of either the form (DATE,'full') or the form (DATE,'new')"""
  moons=[]

  date=ephem.Date(datetime.date(year,1,1))
  while date.datetime().year==year:
    date=ephem.next_full_moon(date)
    moons.append( (date,'full') )

  date=ephem.Date(datetime.date(year,1,1))
  while date.datetime().year==year:
    date=ephem.next_new_moon(date)
    moons.append( (date,'new') )

  #Note that previous_first_quarter_moon() and previous_last_quarter_moon()
  #are also methods

  moons.sort(key=lambda x: x[0])

  return moons

print(get_phase_on_day(2013,1,1))

print(get_moons_in_year(2013))

这将返回

0.632652265318

[(2013/1/11 19:43:37, 'new'), (2013/1/27 04:38:22, 'full'), (2013/2/10 07:20:06, 'new'), (2013/2/25 20:26:03, 'full'), (2013/3/11 19:51:00, 'new'), (2013/3/27 09:27:18, 'full'), (2013/4/10 09:35:17, 'new'), (2013/4/25 19:57:06, 'full'), (2013/5/10 00:28:22, 'new'), (2013/5/25 04:24:55, 'full'), (2013/6/8 15:56:19, 'new'), (2013/6/23 11:32:15, 'full'), (2013/7/8 07:14:16, 'new'), (2013/7/22 18:15:31, 'full'), (2013/8/6 21:50:40, 'new'), (2013/8/21 01:44:35, 'full'), (2013/9/5 11:36:07, 'new'), (2013/9/19 11:12:49, 'full'), (2013/10/5 00:34:31, 'new'), (2013/10/18 23:37:39, 'full'), (2013/11/3 12:49:57, 'new'), (2013/11/17 15:15:44, 'full'), (2013/12/3 00:22:22, 'new'), (2013/12/17 09:28:05, 'full'), (2014/1/1 11:14:10, 'new'), (2014/1/16 04:52:10, 'full')]
8i9zcol2

8i9zcol24#

还有pyephem — scientific-grade astronomy routines [PyPI],这是一个Python包,但是有computational guts in C,它 * 确实 * 表示
从-1369到+2950的精度〈0.05英寸。
使用表查找技术限制对三角函数的调用。

o2gm4chl

o2gm4chl5#

Pyphem默认使用坐标通用(UTC)时间。我想要一个程序,将生成一个满月列表,将是准确的太平洋时区。下面的代码将计算满月为给定的一年,然后调整使用ephem.localtime()方法来校准到所需的时区。它似乎也正确地说明了夏令时以及。感谢理查德,这个代码和他写的很相似。

#!/usr/bin/python
import datetime
import ephem
import os
import time

# Set time zone to pacific
os.environ['TZ'] = 'US/Pacific'
time.tzset()

print("Time zone calibrated to", os.environ['TZ'])

def get_full_moons_in_year(year):
    """
    Generate a list of full moons for a given year calibrated to the local time zone
    :param year: year to determine the list of full moons
    :return: list of dates as strings in the format YYYY-mm-dd
    """
    moons = []

    date = ephem.Date(datetime.date(year - 1, 12, 31))
    end_date = ephem.Date(datetime.date(year + 1, 1, 1))

    while date <= end_date:
        date = ephem.next_full_moon(date)

        # Convert the moon dates to the local time zone, add to list if moon date still falls in desired year
        local_date = ephem.localtime(date)
        if local_date.year == year:
            # Append the date as a string to the list for easier comparison later
            moons.append(local_date.strftime("%Y-%m-%d"))

    return moons

moons = get_full_moons_in_year(2015)
print(moons)

上面的代码将返回:

Time zone calibrated to US/Pacific
['2015-01-04', '2015-02-03', '2015-03-05', '2015-04-04', '2015-05-03', '2015-06-02', '2015-07-01', '2015-07-31', '2015-08-29', '2015-09-27', '2015-10-27', '2015-11-25', '2015-12-25']
qnzebej0

qnzebej06#

PyEphem现在被弃用-他们建议在新项目中使用**Skyfield astronomy library**而不是PyEphem。它的现代设计鼓励更好的Python代码,并使用NumPy来加速计算。

月相的定义是月球和太阳在黄道上的夹角,这个夹角的计算方法是月球和太阳的黄道经度之差。

结果是新月的Angular 为0°,上弦月为90°,满月为180°,下弦月为270°

代码取自此处

from skyfield.api import load
from skyfield.framelib import ecliptic_frame

ts = load.timescale()
t = ts.utc(2019, 12, 9, 15, 36)

eph = load('de421.bsp')
sun, moon, earth = eph['sun'], eph['moon'], eph['earth']

e = earth.at(t)
_, slon, _ = e.observe(sun).apparent().frame_latlon(ecliptic_frame)
_, mlon, _ = e.observe(moon).apparent().frame_latlon(ecliptic_frame)
phase = (mlon.degrees - slon.degrees) % 360.0

print('{0:.1f}'.format(phase))

产出

149.4
8hhllhi2

8hhllhi27#

我知道你在找Python,但是如果你能理解C#,有一个开源项目叫做Chronos XP,它做得很好。

zzoitvuj

zzoitvuj8#

如果不需要高精度,您可以随时(ab)使用阴历(或日月)日历类(例如,Microsoft .NET中的HijriCalendarChineseLunisolarCalendar)来计算任何日期的(近似)月相,作为日历的“星期几”属性,是阴历(或日月)日历日,* 始终对应于月相 *(例如,第1天是新月,第15天是满月,等等)

相关问题