python 利用天文学根据我的位置生成Eclipse条件

n53p2ov0  于 2023-02-02  发布在  Python
关注(0)|答案(1)|浏览(146)

这是一个天文学家的问题。
我是一名业余天文摄影师,希望开发一个个人脚本来帮助我拍摄明年的日全食。我正在开发一个Python脚本来自动化我的摄影,这样我就可以在我的数码单反相机点击的同时,用自己的眼睛欣赏Eclipse。这是我目前开发的脚本。这个脚本使用digicamcontrol来控制相机。
现在,在脚本中,我刚刚开发了基于月食的偏食相位(第一次接触,C1)和以UTC表示的月食时间(以及我自己的PC)的自动化。如果我不能连接到互联网,并根据我的位置得到Eclipse的确切时间呢?我希望能够生成这些时间。有没有一个更有效的方法来利用这项任务的天文学?提前感谢。

import digiCamControlPython as dccp
import time
from datetime import datetime
from astropy.time import Time 

local_time = Time.now()

utc_time_now = local_time.utc

def PartialEclipse(start_time:str, end_time:str):
    camera = dccp.Camera()
    camera.setIso(100)
    camera.setShutterspeed("1/50")
    camera.setFolder(r"C:\Users\My_Name\Pictures\digiCamControl")
    
    # Set the target capture time in astropy time format
    partial_eclipse_start = Time(start_time, format='isot')
    partial_eclipse_end = Time(end_time, format='isot')

    # Wait until the capture time
    while utc_time_now < partial_eclipse_start:
        time.sleep(1)

    # Start capturing images
    while utc_time_now < partial_eclipse_end:
        camera.capture()
        time.sleep(30)  # Capture an image every 30 seconds
        
PartialEclipse("2024-04-08T17:12:13", "2024-04-08T18:29:24") #times of partial eclipse start and T-15s before totality

编辑:如果有人看过这个问题,我确实在这方面取得了一些进展。

import numpy as np
import astropy.units as u
from astropy.coordinates import solar_system_ephemeris, AltAz, EarthLocation, SkyCoord
from astropy.coordinates import get_body, get_moon, get_sun
from astropy.time import Time

myLocation = EarthLocation(lat=26*u.deg, lon=-80*u.deg, height=0*u.m)

# set the time step (how often to check for a solar eclipse in seconds)
time_step = 3600 # 1 hour

# set the number of days to check for a solar eclipse
num_days = 365

# set the start and end times to check for a solar eclipse
start_time = Time.now()
end_time = start_time + num_days * u.day

# initialize a list to store the times of a solar eclipse
eclipse_times = []

# loop over the desired time range, checking for a solar eclipse every time_step seconds
with solar_system_ephemeris.set('jpl'):
  for t in np.arange(start_time.unix, end_time.unix, time_step):
    time = Time(t, format='unix')
    moon = get_body('moon', time, myLocation)
    sun = get_body('sun', time, myLocation)
    sun_coord = SkyCoord(sun.ra, sun.dec, sun.distance, frame='icrs')
    moon_coord = SkyCoord(moon.ra, moon.dec, moon.distance, frame='icrs')
    
    # check if the angular separation between the moon and sun is close to zero
    angular_separation = moon_coord.separation(sun_coord)
    if angular_separation < 0.6 * u.deg: #elongation where the partial eclipse begins
      eclipse_times.append(time)

# print the times of the next solar eclipse
if len(eclipse_times) > 0:
  print("The next solar eclipse is at: ", eclipse_times[0].iso)
else:
  print("No solar eclipses found in the specified time range.")
iq3niunx

iq3niunx1#

我认为你的方法非常好!如果你想在不使用更多计算能力的情况下提高开始时间预测的准确性,你可以使用scipy.optimize.root_scalar来优化你找到的开始时间。
在下面的解决方案中,我定义了一个名为distance_contact()的函数,它的根表示Eclipse的开始。如果太阳和月亮几乎不接触,这个函数为零;如果它们分开,这个函数为正;如果它们重叠,这个函数为负。然后我定义了一个时间网格,时间步长为1小时,类似于您的代码。并将其传递给这个函数来搜索Eclipse,然后找到distance_contanct为负的第一个时间,并使用该时间和之前的时间步长作为scipy.optimize.root_scalar的搜索空间。
此外,我没有使用0.6 * u.deg作为Eclipse发生的间隔距离,而是计算了太阳和月亮的角半径,作为distance_contact的时间参数,以使预测尽可能准确。

import numpy as np
import scipy.optimize
import astropy.units as u
import astropy.time
import astropy.constants
import astropy.coordinates

def distance_contact(
        location: astropy.coordinates.EarthLocation,
        time: astropy.time.Time,
        eclipse_type: str,
) -> u.Quantity:

    radius_sun = astropy.constants.R_sun
    radius_moon = 1737.4 * u.km

    coordinate_sun = astropy.coordinates.get_sun(time)
    coordinate_moon = astropy.coordinates.get_moon(time)

    frame_local = astropy.coordinates.AltAz(obstime=time, location=location)

    alt_az_sun = coordinate_sun.transform_to(frame_local)
    alt_az_moon = coordinate_moon.transform_to(frame_local)

    angular_radius_sun = np.arctan2(radius_sun, coordinate_sun.distance).to(u.deg)
    angular_radius_moon = np.arctan2(radius_moon, coordinate_moon.distance).to(u.deg)

    if eclipse_type == 'total':
        separation_max = angular_radius_moon - angular_radius_sun
    elif eclipse_type == 'partial':
        separation_max = angular_radius_moon + angular_radius_sun
    else:
        raise ValueError("Unknown eclipse type")

    return (alt_az_moon.separation(alt_az_sun).deg * u.deg) - separation_max

def calc_time_start(
        location: astropy.coordinates.EarthLocation,
        time_search_start: astropy.time.Time,
        time_search_stop: astropy.time.Time,
        eclipse_type: str = 'partial'
) -> astropy.time.Time:

    astropy.coordinates.solar_system_ephemeris.set("jpl")

    # If we're only looking for a partial eclipse, we can accept a coarser search grid
    if eclipse_type == "partial":
        step = 1 * u.hr
    elif eclipse_type == "total":
        step = 1 * u.min
    else:
        raise ValueError("Unknown eclipse type")

    # Define a grid of times to search for eclipses
    time = astropy.time.Time(np.arange(time_search_start, time_search_stop, step=step))

    # Find the times that are during an eclipse
    mask_eclipse = distance_contact(location=location, time=time, eclipse_type=eclipse_type) < 0

    # Find the index of the first time that an eclipse is occuring
    index_start = np.argmax(mask_eclipse)

    # Search around that time to find when the eclipse actually starts
    time_eclipse_start = scipy.optimize.root_scalar(
        f=lambda t: distance_contact(location, astropy.time.Time(t, format="unix"), eclipse_type=eclipse_type).value,
        bracket=[time[index_start - 1].unix, time[index_start].unix],
    ).root
    time_eclipse_start = astropy.time.Time(time_eclipse_start, format="unix").isot

    return time_eclipse_start

def test_calc_time_start():

    time_start = calc_time_start(
        location=astropy.coordinates.EarthLocation(lat=26*u.deg, lon=-80*u.deg, height=0*u.m),
        time_search_start=astropy.time.Time.now(),
        time_search_stop=astropy.time.Time.now() + 1 * u.yr,
        eclipse_type='partial',
    )
    print(time_start)

其输出:

2023-10-14T15:58:16.910

奇怪的是,这个预测与timeanddate.com的预测相差了大约40秒,我还不知道为什么他们的预测不同,也许他们使用了不同的星历表?

相关问题