天体の位置を計算するパラメーターは、海上保安庁の海洋情報部から提供されている。
世界が世界ならブルマーが提供してくれるはず
海上保安庁が出している情報だけあって、目視観測が目的になっている。そのため、太陽、月、金星、火星、木星、土星、といった、観測しやすい天体が記載されている。
下の方の"コンピュータによる天体の位置計算式 (天測暦/天測略暦付録)"に計算方法のPDFや数値が書かれたTXTのリンクが有る。
平成21年から31年までの範囲のデータが有る。年末が近くなると翌年分のデータが提供される。
とりあえず手っ取り早く動作確認したかったので、値をソースコードに埋め込んでいる。
データのコピペが面倒だったので太陽と金星と火星のみ扱っている。
エクセルでグラフ化してみた。
各軸の符号は気にしないように。。。
計算結果は地球を中心とした極座標系で得られるので、直交座標系に変換し、惑星の位置は太陽との差を取る。
また、この図では$x = \sin(ra \div 12 \times \pi) \cos(dec \div 180 \times \pi) dist$のように計算しているが、これは地球の極軸の延長線上から見た形なので、公転面に対する自転軸の傾斜分、つぶれた形になっている。
static void Main(string[] args)
{
string[] names = new[] { "Sun", "Venus", "Mars", };
DateTimeOffset start = new DateTimeOffset(2019, 1, 1, 0, 0, 0, new TimeSpan());
DateTimeOffset end = new DateTimeOffset(2020, 1, 1, 0, 0, 0, new TimeSpan());
StringBuilder sb = new StringBuilder();
foreach (string name in names)
{
sb.Append("," + name + " ra");
sb.Append("," + name + " dec");
sb.Append("," + name + " dist");
}
sb.AppendLine();
for (int days = 0; start.AddDays(days) < end; days++)
{
DateTimeOffset date = start.AddDays(days);
sb.Append(date);
foreach (string name in names)
{
double ra, dec, dist;
if (!tryCalcCelestialPosition(name, date, out ra, out dec, out dist))
{
ra = dec = dist = double.NaN;
}
sb.Append("," + ra);
sb.Append("," + dec);
sb.Append("," + dist);
}
sb.AppendLine();
}
using (StreamWriter sw = new StreamWriter("./log.txt"))
{
sw.Write(sb.ToString().Replace(',', '\t'));
}
}
struct DataSet
{
public int a { get; private set; }
public int b { get; private set; }
public double[] RA { get; private set; }
public double[] Dec { get; private set; }
public double[] Dist { get; private set; }
public DataSet(int a, int b, double[] RA, double[] Dec, double[] Dist)
{
if (a >= b ||
RA.Length != Dec.Length ||
RA.Length != Dist.Length)
{
throw new ArgumentException();
}
this.a = a;
this.b = b;
this.RA = RA;
this.Dec = Dec;
this.Dist = Dist;
}
}
static bool tryCalcCelestialPosition(string name, DateTimeOffset date, out double RaHour, out double DecDeg, out double DistAu)
{
RaHour = DecDeg = DistAu = 0;
string key = name + date.UtcDateTime.Year;
if (!dict1.ContainsKey(key))
{
return (false);
}
double t = (date.UtcDateTime - new DateTime(date.UtcDateTime.Year, 1, 1)).TotalDays + 1
+ dict2[date.UtcDateTime.Year] / 86400.0;
foreach (DataSet set in dict1[key])
{
if (set.a > t || t > set.b)
{
continue;
}
double theta = Math.Acos((2 * t - (set.b + set.a)) / (set.b - set.a));
for (int i = 0; i < set.RA.Length; i++)
{
double cosNtheta = Math.Cos(theta * i);
RaHour += set.RA[i] * cosNtheta;
DecDeg += set.Dec[i] * cosNtheta;
DistAu += set.Dist[i] * cosNtheta;
}
return (true);
}
return (false);
}
static readonly Dictionary<int, int> dict2 = new Dictionary<int, int>()
{
{ 2019, 70 },
};
static readonly Dictionary<string, DataSet[]> dict1 = new Dictionary<string, DataSet[]>()
{
{ "Sun2019", new DataSet[] {
new DataSet(0, 121,
#region
new [] {
22.6964,
3.896948, -0.103656, 0.034727, 0.006648, -0.002283,
0.000073, 0.000064, -0.000002, 0.000012, 0.000053,
-0.000038, -0.000053, 0.000023, 0.000021, -0.000007,
-0.000003, 0.000002,
},
new []
{
-5.85509,
19.99447, 1.75027, -0.98562, 0.01226, 0.008,
-0.00368, 0.00067, 0.00016, 0.00014, 0.00022,
-0.00011, -0.00028, 0.00002, 0.00014, 0,
-0.00003, -0.00001,
},
new []
{
0.993121,
0.012666, 0.00229, -0.000646, -0.000043, 0.000016,
0.000005, 0.000013, -0.000004, 0.000005, -0.000008,
-0.000015, 0.000007, 0.000009, -0.000003, -0.000003,
0.000001, 0.000001,
}),
#endregion
new DataSet(120, 244,
#region
new []
{
6.599667,
4.13595, -0.040841, -0.040829, 0.005193, 0.003291,
-0.000422, -0.000118, 0.000049, 0.000017, 0.000012,
-0.000071, -0.000019, 0.00005, 0.00001, -0.000018,
-0.000007, 0.000006,
},
new []
{
17.17705,
-3.27497, -5.7942, 0.2083, 0.1602, -0.01044,
-0.00503, 0.00073, 0.00012, -0.00019, 0.00016,
0.00002, 0.00004, 0.00006, -0.00007, -0.00004,
0.00002, 0.00003,
},
new []
{
1.012388,
0.001199, -0.004187, -0.000056, 0.000106, 0.000004,
0.000004, 0.000005, -0.00001, 0.000001, -0.000012,
-0.000006, 0.000016, 0.000004, -0.000008, -0.000001,
0.000002, 0,
}),
#endregion
new DataSet(243, 366,
#region
new []
{
14.525213,
4.050617, 0.151517, 0.013548, -0.013395, -0.002113,
0.000297, 0.000215, 0.000008, 0.000002, -0.00004,
-0.000056, 0.000037, 0.000037, -0.000016, -0.000012,
0.000004, 0.000004,
},
new []
{
-10.58204,
-16.89248, 3.49425, 0.97511, -0.02577, -0.02312,
-0.00523, -0.00008, 0.00042, -0.00005, 0.00004,
0.00029, -0.00017, -0.00022, 0.00011, 0.00009,
-0.00003, -0.00002,
},
new []
{
0.994695,
-0.013897, 0.001825, 0.000724, -0.000027, -0.000017,
0.000005, -0.000009, -0.000007, -0.000002, -0.000011,
0.000011, 0.000013, -0.000007, -0.000006, 0.000003,
0.000001, -0.000001,
}),
#endregion
}
},
{ "Venus2019", new DataSet[] {
new DataSet(0, 121,
#region
new []
{
20.0894,
4.770818, -0.004287, -0.070212, 0.021819, 0.004282,
-0.001415, -0.000295, 0.000167, 0.000029, 0.000015,
-0.000067, -0.000014, 0.000039, 0.000002, -0.000012,
0.000002, 0.000004,
},
new []
{
-12.22805,
9.61427, 6.78204, -0.4148, -0.39134, 0.05256,
0.00901, -0.00365, -0.00038, 0.00048, -0.00006,
-0.00008, -0.00013, 0.00001, 0.0001, -0.00001,
-0.00002, 0.00001,
},
new []
{
1.054744,
0.411713, -0.018687, -0.002435, 0.000187, -0.0001,
0.000025, 0.000004, -0.000004, 0.000002, -0.000016,
-0.000006, 0.000015, 0.000003, -0.000006, -0.000001,
0.000001, 0.000001,
}),
#endregion
new DataSet(120, 244,
#region
new []
{
5.827986,
5.202986, 0.049994, -0.078962, -0.010601, 0.009797,
0.001418, -0.000796, -0.000175, 0.000089, 0.000027,
-0.000053, -0.000006, 0.000028, 0.000002, -0.000009,
-0.000003, 0.000003,
},
new []
{
13.89664,
2.88981, -8.86463, -0.43301, 0.42723, 0.03293,
-0.02073, -0.00349, 0.00152, 0.00036, -0.00001,
-0.00009, 0.00005, 0.00006, -0.00006, -0.00002,
0.00001, 0.00002,
},
new []
{
1.630704,
0.141151, -0.051406, -0.001594, 0.000519, 0.000048,
-0.000002, 0, -0.000008, 0.000001, -0.000015,
-0.000002, 0.000016, 0.000001, -0.000007, 0,
0.000002, 0,
}),
#endregion
new DataSet(243, 366,
#region
new []
{
15.923639,
5.14974, 0.151701, -0.031983, -0.034715, 0.000704,
0.003079, 0.000513, -0.000191, -0.000079, -0.000014,
-0.000036, 0.000012, 0.000026, -0.000003, -0.000008,
0, 0.000003,
},
new []
{
-12.22232,
-14.72841, 7.56495, 1.4717, -0.27205, -0.08298,
-0.00353, 0.00611, 0.00149, -0.00039, -0.00024,
0.00013, -0.00005, -0.0001, 0.00005, 0.00005,
-0.00001, -0.00001,
},
new []
{
1.533443,
-0.223213, -0.033985, 0.001937, -0.000248, -0.000017,
0.000017, -0.000005, -0.000006, -0.000002, -0.000015,
0.000006, 0.000015, -0.000003, -0.000006, 0.000001,
0.000001, 0,
}),
#endregion
}
},
{ "Mars2019", new DataSet[] {
new DataSet(0, 121,
#region
new []
{
2.564142,
2.658989, 0.06083, 0.000734, -0.002224, -0.000314,
0.000041, -0.00001, 0.000022, -0.000005, 0.000024,
0.000016, -0.000032, -0.000011, 0.000016, 0.000004,
-0.000003, -0.000001,
},
new []
{
13.61414,
12.62843, -1.85287, -0.26484, 0.01618, 0.00222,
0.00026, -0.00013, 0.0001, -0.00006, 0.00006,
0.00013, -0.00013, -0.00008, 0.00008, 0.00002,
-0.00003, -0.00001,
},
new []
{
1.75839,
0.497599, -0.012599, -0.004394, 0.000046, 0.000033,
-0.000005, 0.000012, 0.000005, 0.000001, 0.000007,
-0.000015, -0.000009, 0.000011, 0.000004, -0.000004,
-0.000001, 0.000001,
}),
#endregion
new DataSet(120, 244,
#region
new []
{
8.045234,
2.747163, -0.071382, -0.004923, 0.003287, 0.000004,
-0.000082, 0.000024, 0.000016, -0.000005, 0.000011,
-0.000023, -0.000017, 0.000018, 0.000009, -0.000007,
-0.000005, 0.000003,
},
new []
{
19.04418,
-7.60969, -2.37057, 0.21373, 0.01609, -0.00385,
0.00021, 0.00003, -0.00004, -0.00005, 0.00002,
0.00007, 0.00004, -0.00001, -0.00003, 0,
0.00001, 0,
},
new []
{
2.508586,
0.223481, -0.055137, -0.002149, 0.000199, 0.000011,
0.000001, 0.000008, -0.00001, -0.000001, -0.000007,
-0.000011, 0.000014, 0.000009, -0.000008, -0.000004,
0.000002, 0.000001,
}),
#endregion
new DataSet(243, 366,
#region
new []
{
13.162022,
2.519937, 0.052854, 0.014762, -0.000897, -0.000253,
-0.000019, 0.000007, -0.000014, -0.000002, -0.000015,
-0.000015, 0.000022, 0.000011, -0.000011, -0.000003,
0.000002, 0.000002,
},
new []
{
-5.57105,
-14.76437, 0.60721, 0.27608, 0.0074, 0.00011,
-0.00031, -0.00011, 0.00006, 0.00001, 0.00007,
0.00011, -0.00013, -0.00008, 0.00006, 0.00004,
-0.00001, -0.00001,
},
new []
{
2.485056,
-0.247831, -0.055639, 0.002496, 0.000414, -0.000007,
-0.000002, -0.000012, -0.000006, 0.000001, -0.000006,
0.000015, 0.00001, -0.000012, -0.000005, 0.000005,
0.000001, -0.000001,
}),
#endregion
}
},
};
プログラムを簡単にするために、1月0日からの経過日数をDateTimeOffsetの差、TimeSpan.TotalDaysで得ているが、うるう年やうるう秒の処理について問題があるかもしれない。
