模組:MoonXiu
外观
|
请对照以下删除理由判断本页是否具备执行快速删除的理据:
本页可能符合快速删除的標準而需删除,理由:
請勿移除本模板。如有異議,請在本模板下方加入 其他編者若認為本頁明顯不符合快速删除的标准,或者您已修正存在的問題,可去除此模板。 |
|
请对照以下删除理由判断本页是否具备执行快速删除的理据:
本页可能符合快速删除的標準而需删除,理由: 請勿移除本模板。如有異議,請在本模板下方加入 其他編者若認為本頁明顯不符合快速删除的标准,或者您已修正存在的問題,可去除此模板。 |
require('Module:Module wikitext')._addText('{{D|G3|G21|见[[U:12З4567/Wenlongtian调查]]}}')
local p = {}
-- ================= 宿度体系数据 =================
local SYSTEMS = {
huainan = {
name = "淮南子·黄道宿度",
origin = 0,
xiu = {
{"角",12},{"亢",9},{"氐",15},{"房",5},{"心",5},{"尾",18},{"箕",11},
{"斗",25},{"牛",7},{"女",11},{"虚",10},{"危",16},{"室",17},{"壁",9},
{"奎",16},{"娄",12},{"胃",14},{"昴",11},{"毕",16},{"觜",2},{"参",9},
{"井",33},{"鬼",4},{"柳",15},{"星",7},{"张",18},{"翼",18},{"轸",17}
}
},
dayan_ecl = {
name = "大衍历·黄道宿度",
origin = 0,
xiu = {
{"角",12.5},{"亢",9.5},{"氐",16},{"房",5.5},{"心",5.5},{"尾",18.5},{"箕",10.5},
{"斗",24},{"牛",7.5},{"女",11.5},{"虚",9.5},{"危",16.5},{"室",17},{"壁",9.5},
{"奎",17},{"娄",12.5},{"胃",14.5},{"昴",10.5},{"毕",16.5},{"觜",1.5},{"参",9.5},
{"井",32},{"鬼",3.5},{"柳",14.5},{"星",7.5},{"张",17.5},{"翼",18.5},{"轸",16.5}
}
},
dayan_equ = {
name = "大衍历·赤道宿度",
origin = 0,
xiu = {
{"角",12},{"亢",9},{"氐",15},{"房",5},{"心",5},{"尾",18},{"箕",11},
{"斗",25},{"牛",7},{"女",11},{"虚",10},{"危",16},{"室",17},{"壁",9},
{"奎",16},{"娄",12},{"胃",14},{"昴",11},{"毕",16},{"觜",2},{"参",9},
{"井",33},{"鬼",4},{"柳",15},{"星",7},{"张",18},{"翼",18},{"轸",17}
}
},
modern = {
name = "现代真黄道宿界(含岁差)",
origin = -28.0,
xiu = {
{"角",11.3},{"亢",9.0},{"氐",14.4},{"房",5.2},{"心",6.1},{"尾",19.0},{"箕",10.2},
{"斗",24.0},{"牛",7.8},{"女",11.0},{"虚",9.5},{"危",16.2},{"室",17.0},{"壁",8.8},
{"奎",15.5},{"娄",11.8},{"胃",13.5},{"昴",10.2},{"毕",15.8},{"觜",1.8},{"参",9.2},
{"井",31.5},{"鬼",3.8},{"柳",14.2},{"星",7.2},{"张",17.2},{"翼",17.8},{"轸",16.8}
}
}
}
-- ================= 工具函数 =================
local function norm360(x)
return x % 360
end
local function rad(d) return d * math.pi / 180 end
local function deg(r) return r * 180 / math.pi end
local function findXiu(pos, sys)
local acc = 0
for i, x in ipairs(sys.xiu) do
local w = x[2]
if pos >= acc and pos < acc + w then
return x[1], acc, w, i
end
acc = acc + w
end
local n = #sys.xiu
local x = sys.xiu[n]
return x[1], 365.25 - x[2], x[2], n
end
-- ================= 天文算法 (Meeus) =================
local function toJD(y, m, d, h)
if not y or not m or not d then error("年月日参数不能为空") end
local a = math.floor((14 - m) / 12)
local y1 = y + 4800 - a
local m1 = m + 12 * a - 3
return d + h/24 + math.floor((153 * m1 + 2) / 5) + 365 * y1 + math.floor(y1 / 4) - 32045.5
end
local function moonEcliptic(jdTT)
local T = (jdTT - 2451545.0) / 36525.0
local Lp = 218.3164477 + 481267.88123421 * T - 0.0015786 * T * T
local D = 297.8501921 + 445267.1114034 * T - 0.0018819 * T * T
local M = 357.5291092 + 35999.0502909 * T - 0.0001536 * T * T
local Mp = 134.9633964 + 477198.8675055 * T + 0.0087414 * T * T
local F = 93.2720950 + 483202.0175233 * T - 0.0036539 * T * T
local E = 1 - 0.002516 * T - 0.0000074 * T * T
local Lp_r, D_r, M_r, Mp_r, F_r = rad(norm360(Lp)), rad(norm360(D)), rad(norm360(M)), rad(norm360(Mp)), rad(norm360(F))
local sum = 0
sum = sum + 6288774 * math.sin(Mp_r)
sum = sum + 1274027 * math.sin(2*D_r - Mp_r)
sum = sum + 658314 * math.sin(2*D_r)
sum = sum + 213618 * math.sin(2*Mp_r)
sum = sum - 185116 * E * math.sin(M_r)
sum = sum - 114332 * math.sin(2*F_r)
sum = sum + 58793 * math.sin(2*D_r - 2*Mp_r)
sum = sum + 57066 * math.sin(2*D_r - M_r - Mp_r)
local A1 = rad(119.75 + 131.849 * T)
local A2 = rad(53.09 + 479264.290 * T)
sum = sum + 3958 * math.sin(A1)
sum = sum + 1962 * math.sin(Lp_r - F_r)
sum = sum + 318 * math.sin(A2)
local lon = norm360(Lp + sum / 1000000)
local lat_sum = 0
lat_sum = lat_sum + 5128122 * math.sin(F_r)
lat_sum = lat_sum + 280602 * math.sin(Mp_r + F_r)
lat_sum = lat_sum + 277693 * math.sin(Mp_r - F_r)
local lat = lat_sum / 1000000
local dist = 385000 - 20905 * math.cos(Mp_r)
return lon, lat, dist, {Lp=norm360(Lp), D=norm360(D), M=norm360(M), Mp=norm360(Mp), F=norm360(F), E=E}
end
-- ============== 新增:太阳黄经(简化) ==============
local function sunLongitude(jdTT)
local T = (jdTT - 2451545.0) / 36525.0
local M = 357.5291092 + 35999.0502909 * T - 0.0001536 * T * T
local Mr = rad(norm360(M))
local C = 1.9148 * math.sin(Mr) + 0.0200 * math.sin(2*Mr) + 0.0003 * math.sin(3*Mr)
local lambda = 280.46646 + 36000.76983 * T + C
return norm360(lambda)
end
-- ============== 新增:月相计算 ==============
local function moonPhase(jdTT)
local moon_lon = moonEcliptic(jdTT) -- 第一个返回值就是月亮黄经
local sun_lon = sunLongitude(jdTT)
local delta = norm360(moon_lon - sun_lon) -- 0~360
local synodic_day = delta / 360 * 29.53058867
local illum = (1 - math.cos(rad(delta))) / 2
-- 现代月相名称
local modern_name
if delta < 15 then
modern_name = "朔"
elseif delta < 50 then
modern_name = "朏"
elseif delta < 85 then
modern_name = "上弦前"
elseif delta < 105 then
modern_name = "上弦"
elseif delta < 165 then
modern_name = "望前"
elseif delta < 195 then
modern_name = "望"
elseif delta < 240 then
modern_name = "既望"
elseif delta < 265 then
modern_name = "下弦前"
elseif delta < 285 then
modern_name = "下弦"
elseif delta < 345 then
modern_name = "下弦后"
else
modern_name = "晦"
end
-- 西周月相(四分说 + 定点说)
local zhou_main, zhou_detail
if synodic_day < 7.5 then
zhou_main = "初吉"
if synodic_day < 1.5 then
zhou_detail = "朔"
elseif synodic_day < 3 then
zhou_detail = "哉生霸/朏"
else
zhou_detail = "初吉(余)"
end
elseif synodic_day < 15 then
zhou_main = "既生霸"
if synodic_day < 9 then
zhou_detail = "上弦"
elseif synodic_day < 13 then
zhou_detail = "既生霸"
else
zhou_detail = "旁生霸"
end
elseif synodic_day < 22.5 then
zhou_main = "既望"
if synodic_day < 16.5 then
zhou_detail = "望"
elseif synodic_day < 18 then
zhou_detail = "既望"
else
zhou_detail = "既望(余)"
end
else
zhou_main = "既死霸"
if synodic_day < 24 then
zhou_detail = "下弦"
elseif synodic_day < 27 then
zhou_detail = "既死霸"
else
zhou_detail = "晦/旁死霸"
end
end
return {
phase_angle = delta,
illum_frac = illum,
synodic_day = synodic_day,
phase_name_modern = modern_name,
phase_name_zhou = zhou_main,
phase_name_zhou_detail = zhou_detail
}
end
local function nutation(jdTT)
local T = (jdTT - 2451545.0) / 36525.0
local L = rad(280.4665 + 36000.7698 * T)
local Lp = rad(218.3165 + 481267.8813 * T)
local omega = rad(125.04452 - 1934.136261 * T)
local dpsi = -17.20 * math.sin(omega) - 1.32 * math.sin(2*L) - 0.23 * math.sin(2*Lp) + 0.21 * math.sin(2*omega)
local deps = 9.20 * math.cos(omega) + 0.57 * math.cos(2*L) + 0.10 * math.cos(2*Lp) - 0.09 * math.cos(2*omega)
return dpsi, deps
end
local function meanObliquity(jdTT)
local T = (jdTT - 2451545.0) / 36525.0
return 23.43929111 - 0.013004167 * T - 0.000000164 * T*T + 0.000000503 * T*T*T
end
local function ecl2equ(lon, lat, eps)
local lon_r, lat_r, eps_r = rad(lon), rad(lat), rad(eps)
local ra = math.atan2(math.sin(lon_r) * math.cos(eps_r) - math.tan(lat_r) * math.sin(eps_r), math.cos(lon_r))
local dec = math.asin(math.sin(lat_r) * math.cos(eps_r) + math.cos(lat_r) * math.sin(eps_r) * math.sin(lon_r))
return norm360(deg(ra)), deg(dec)
end
-- ================= 月离九道 / 月将 =================
local function moonPath(lat, lon)
if lat > 0 then
if lon > 0 and lon < 90 then return "青道" end
if lon >= 90 and lon < 180 then return "朱道" end
if lon >= 180 and lon < 270 then return "白道" end
return "黑道"
else
if lon > 0 and lon < 90 then return "黑道" end
if lon >= 90 and lon < 180 then return "白道" end
if lon >= 180 and lon < 270 then return "青道" end
return "朱道"
end
end
local JIANG = {"子","丑","寅","卯","辰","巳","午","未","申","酉","戌","亥"}
local function moonJiang(ra)
local idx = math.floor((norm360(ra) + 15) / 30) + 1
return JIANG[idx]
end
-- ================= 主计算 =================
local function compute(args)
local y = tonumber(args.year) or os.date("*t").year
local m = tonumber(args.month) or 1
local d = tonumber(args.day) or 1
local hh = tonumber(args.hour) or 0
local sysKey = args.system or "huainan"
local sys = SYSTEMS[sysKey] or SYSTEMS.huainan
local jd = toJD(y, m, d, hh)
local jdTT = jd + 69.184/86400
local lon0, lat0, dist0, aux = moonEcliptic(jdTT)
local dp, de = nutation(jdTT)
local epsMean = meanObliquity(jdTT)
local epsTrue = epsMean + de/3600
local lon = norm360(lon0 + dp/3600)
local lat = lat0
local ra, dec = ecl2equ(lon, lat, epsTrue)
local pos = norm360(lon - sys.origin)
local star, startDeg, width, idx = findXiu(pos, sys)
local inDeg = pos - startDeg
local quji = 90 - dec
local parallax = 8.794 / (dist0/6378.137)
local path = moonPath(lat, lon)
local jiang = moonJiang(ra)
-- =========== 新增:月相 ===========
local ph = moonPhase(jdTT)
return {
time_str = string.format("%04d-%02d-%02d %02d:00 UTC+8", y, m, d, hh),
system_key = sysKey,
system_name = sys.name,
jd = jd,
jd_tt = jdTT,
T = (jdTT - 2451545.0)/36525.0,
Lp = aux.Lp, D = aux.D, M = aux.M, Mp = aux.Mp, F = aux.F, E = aux.E,
lon_mean = lon0, lat_mean = lat0,
nut_dpsi = dp, nut_deps = de,
eps_mean = epsMean, eps_true = epsTrue,
lon = lon, lat = lat,
ra = ra/15,
ra_deg = ra,
dec = dec,
star = star,
star_index = idx,
xiu_start = startDeg,
xiu_width = width,
in_deg = inDeg,
quji = quji,
path = path,
obliq_angle = 5.1454,
jiang = jiang,
dist_km = dist0,
parallax_sec = parallax,
-- 月相字段
phase_angle = ph.phase_angle,
illum_frac = ph.illum_frac,
synodic_day = ph.synodic_day,
phase_name_modern = ph.phase_name_modern,
phase_name_zhou = ph.phase_name_zhou,
phase_name_zhou_detail = ph.phase_name_zhou_detail
}
end
-- ================= 信息框渲染 =================
local function row(label, val, bg)
bg = bg or "#ffffff"
return string.format(
'<div style="display:flex;border-bottom:1px solid #eaecf0;background:%s">'..
'<div style="width:96px;flex:none;padding:6px 8px;font-weight:bold;background:#f1f4f6;border-right:1px solid #eaecf0">%s</div>'..
'<div style="padding:6px 8px;flex:1">%s</div></div>', bg, label, val)
end
local function fmt(x, n) return string.format("%."..(n or 4).."f", x) end
local function renderFullBox(d)
local out = {}
table.insert(out, '<div style="width:300px;float:right;clear:right;margin:0 0 1em 1em;'..
'border:1px solid #a2a9b1;border-radius:10px;overflow:hidden;font-family:sans-serif;'..
'box-shadow:0 2px 6px rgba(0,0,0,.12);background:#fff;font-size:13px;line-height:1.5">')
table.insert(out, string.format(
'<div style="background:linear-gradient(90deg,#4a90d9,#6ab0ff);color:#fff;padding:10px 12px;'..
'font-weight:bold;text-align:center;font-size:15px">月宿推算 · %s</div>', d.time_str))
table.insert(out, string.format(
'<div style="padding:12px;text-align:center;background:#f8fbff;border-bottom:1px solid #eaecf0">'..
'<div style="font-size:18px;font-weight:bold;color:#1a3c6e">入【%s】宿</div>'..
'<div style="margin-top:4px">入宿距度 <b>%.2f°</b> · 去极度 <b>%.2f°</b></div>'..
'<div style="font-size:11px;color:#667">距星 %s · 体系:%s</div></div>',
d.star, d.in_deg, d.quji, d.star, d.system_name))
table.insert(out, row("计算参数",
string.format("历元 J2000 · 体系 %s<br/>JD %.5f · TT %.5f<br/>T=%.6f",
d.system_name, d.jd, d.jd_tt, d.T), "#fafcff"))
table.insert(out, row("岁差/章动",
string.format("平黄赤交角 %.4f°<br/>章动 Δψ=%.3f″ Δε=%.3f″<br/>真黄赤交角 %.4f°",
d.eps_mean, d.nut_dpsi, d.nut_deps, d.eps_true), "#f6f8fa"))
table.insert(out, row("月亮平坐标",
string.format("L′=%.4f° M′=%.4f°<br/>D=%.4f° M=%.4f° F=%.4f°<br/>E=%.6f",
d.Lp, d.Mp, d.D, d.M, d.F, d.E), "#fafcff"))
table.insert(out, row("月亮真坐标",
string.format("黄经 %.4f° · 黄纬 %.4f°<br/>赤经 %.4fʰ · 赤纬 %.4f°",
d.lon, d.lat, d.ra, d.dec), "#f6f8fa"))
table.insert(out, row("宿度判定",
string.format("第%d宿 %s<br/>宿界起点 %.2f° 宽 %.2f°<br/>入宿距度 %.3f°",
d.star_index, d.star, d.xiu_start, d.xiu_width, d.in_deg), "#fafcff"))
table.insert(out, row("月离九道",
string.format("通道:%s<br/>黄白交角 %.4f°<br/>月将:%s",
d.path, d.obliq_angle, d.jiang), "#f6f8fa"))
-- =========== 新增:月相行 ===========
table.insert(out, row("月相",
string.format("相位角 %.2f° · 照明率 %.1f%%<br/>距朔 %.2f 天<br/>现代:%s<br/>西周(四分说):%s<br/>细分:%s",
d.phase_angle, d.illum_frac*100, d.synodic_day,
d.phase_name_modern, d.phase_name_zhou, d.phase_name_zhou_detail), "#fafcff"))
table.insert(out, row("距离与视差",
string.format("地月距 %.1f km<br/>视差 %.2f″", d.dist_km, d.parallax_sec), "#f6f8fa"))
table.insert(out, '</div>')
return table.concat(out)
end
-- ================= 公开接口 =================
function p.moon(frame)
local d = compute(frame.args)
if frame.args.format == "fullbox" then
return renderFullBox(d)
elseif frame.args.format == "short" then
local phase = d.phase_name_modern or "—"
local synodic = d.synodic_day or 0
return string.format(
"月亮入【%s】宿,距度 %.2f°,去极度 %.2f°,%s,距朔 %.2f 天",
d.star, d.in_deg, d.quji, phase, synodic
)
else
return string.format("入【%s】宿 %.2f° / 去极 %.2f°", d.star, d.in_deg, d.quji)
end
end
function p.get(frame)
local d = compute(frame.args)
local key = frame.args.param or frame.args[1]
if key and d[key] ~= nil then
if type(d[key]) == "number" then
return fmt(d[key], 5)
end
return tostring(d[key])
end
return "未知参数:" .. tostring(key)
end
function p.getJD(frame)
local y = tonumber(frame.args.year) or os.date("*t").year
local m = tonumber(frame.args.month) or 1
local d = tonumber(frame.args.day) or 1
local hh = tonumber(frame.args.hour) or 0
return string.format("%.5f", toJD(y,m,d,hh))
end
return p