PHPで月齢を計算

(1/1)
月齢 (げつれい) とは、直前の朔(新月)の瞬間を "0" として、そこからの経過日数を表す数字だ。
月齢は、太陽と月の位置関係から計算できる。今回は、PHP で月の視黄経を算出するプログラムを作り、指定した月から 3 ヶ月分の月齢一覧を求めることを目標にする。

サンプル・プログラムの実行例

PHPで月齢を計算

サンプル・プログラム

準備:外部クラスなど

0026: //計算期間(月)
0027: define('CALC_TERM', 3);
0028: 
0029: //世界時からの時差
0030: define('UTCDIFF', 9);
0031: 
0032: //暦計算クラス
0033: require_once('pahooCalendar.php');

あらかじめ、計算期間(月)と世界時からの時差を定数として定義しておく。

月齢、月の視半径、各種カレンダー計算は、ユーザークラス "pahooCalendar" に用意したメソッド群を利用する。
そこで、クラスファイル "pahooCalendar.php" を  require_once  し、オブジェクトを生成する。

解説:月の視黄経の算出

月の位置と月齢

0688: // 月の位置計算 ===========================================================
0689: /**
0690:  * 月の黄経計算(視黄経)
0691:  * @param double $jy 2000.0からの経過年数
0692:  * @return double 月の黄経(視黄経)
0693: */
0694: function __longitude_moon($jy) {
0695:     $am  = 0.0006 * sin(deg2rad($this->__angle( 54.0 + 19.3  * $jy)));
0696:     $am += 0.0006 * sin(deg2rad($this->__angle( 71.0 +  0.2  * $jy)));
0697:     $am += 0.0020 * sin(deg2rad($this->__angle( 55.0 + 19.34 * $jy)));
0698:     $am += 0.0040 * sin(deg2rad($this->__angle(119.5 +  1.33 * $jy)));
0699:     $rm_moon  = 0.0003 * sin(deg2rad($this->__angle(280.0   + 23221.3    * $jy)));
0700:     $rm_moon += 0.0003 * sin(deg2rad($this->__angle(161.0   +    40.7    * $jy)));
0701:     $rm_moon += 0.0003 * sin(deg2rad($this->__angle(311.0   +  5492.0    * $jy)));
0702:     $rm_moon += 0.0003 * sin(deg2rad($this->__angle(147.0   + 18089.3    * $jy)));
0703:     $rm_moon += 0.0003 * sin(deg2rad($this->__angle( 66.0   +  3494.7    * $jy)));
0704:     $rm_moon += 0.0003 * sin(deg2rad($this->__angle( 83.0   +  3814.0    * $jy)));
0705:     $rm_moon += 0.0004 * sin(deg2rad($this->__angle( 20.0   +   720.0    * $jy)));
0706:     $rm_moon += 0.0004 * sin(deg2rad($this->__angle( 71.0   +  9584.7    * $jy)));
0707:     $rm_moon += 0.0004 * sin(deg2rad($this->__angle(278.0   +   120.1    * $jy)));
0708:     $rm_moon += 0.0004 * sin(deg2rad($this->__angle(313.0   +   398.7    * $jy)));
0709:     $rm_moon += 0.0005 * sin(deg2rad($this->__angle(332.0   +  5091.3    * $jy)));
0710:     $rm_moon += 0.0005 * sin(deg2rad($this->__angle(114.0   + 17450.7    * $jy)));
0711:     $rm_moon += 0.0005 * sin(deg2rad($this->__angle(181.0   + 19088.0    * $jy)));
0712:     $rm_moon += 0.0005 * sin(deg2rad($this->__angle(247.0   + 22582.7    * $jy)));
0713:     $rm_moon += 0.0006 * sin(deg2rad($this->__angle(128.0   +  1118.7    * $jy)));
0714:     $rm_moon += 0.0007 * sin(deg2rad($this->__angle(216.0   +   278.6    * $jy)));
0715:     $rm_moon += 0.0007 * sin(deg2rad($this->__angle(275.0   +  4853.3    * $jy)));
0716:     $rm_moon += 0.0007 * sin(deg2rad($this->__angle(140.0   +  4052.0    * $jy)));
0717:     $rm_moon += 0.0008 * sin(deg2rad($this->__angle(204.0   +  7906.7    * $jy)));
0718:     $rm_moon += 0.0008 * sin(deg2rad($this->__angle(188.0   + 14037.3    * $jy)));
0719:     $rm_moon += 0.0009 * sin(deg2rad($this->__angle(218.0   +  8586.0    * $jy)));
0720:     $rm_moon += 0.0011 * sin(deg2rad($this->__angle(276.5   + 19208.02   * $jy)));
0721:     $rm_moon += 0.0012 * sin(deg2rad($this->__angle(339.0   + 12678.71   * $jy)));
0722:     $rm_moon += 0.0016 * sin(deg2rad($this->__angle(242.2   + 18569.38   * $jy)));
0723:     $rm_moon += 0.0018 * sin(deg2rad($this->__angle(  4.1   +  4013.29   * $jy)));
0724:     $rm_moon += 0.0020 * sin(deg2rad($this->__angle( 55.0   +    19.34   * $jy)));
0725:     $rm_moon += 0.0021 * sin(deg2rad($this->__angle(105.6   +  3413.37   * $jy)));
0726:     $rm_moon += 0.0021 * sin(deg2rad($this->__angle(175.1   +   719.98   * $jy)));
0727:     $rm_moon += 0.0021 * sin(deg2rad($this->__angle( 87.5   +  9903.97   * $jy)));
0728:     $rm_moon += 0.0022 * sin(deg2rad($this->__angle(240.6   +  8185.36   * $jy)));
0729:     $rm_moon += 0.0024 * sin(deg2rad($this->__angle(252.8   +  9224.66   * $jy)));
0730:     $rm_moon += 0.0024 * sin(deg2rad($this->__angle(211.9   +   988.63   * $jy)));
0731:     $rm_moon += 0.0026 * sin(deg2rad($this->__angle(107.2   + 13797.39   * $jy)));
0732:     $rm_moon += 0.0027 * sin(deg2rad($this->__angle(272.5   +  9183.99   * $jy)));
0733:     $rm_moon += 0.0037 * sin(deg2rad($this->__angle(349.1   +  5410.62   * $jy)));
0734:     $rm_moon += 0.0039 * sin(deg2rad($this->__angle(111.3   + 17810.68   * $jy)));
0735:     $rm_moon += 0.0040 * sin(deg2rad($this->__angle(119.5   +     1.33   * $jy)));
0736:     $rm_moon += 0.0040 * sin(deg2rad($this->__angle(145.6   + 18449.32   * $jy)));
0737:     $rm_moon += 0.0040 * sin(deg2rad($this->__angle( 13.2   + 13317.34   * $jy)));
0738:     $rm_moon += 0.0048 * sin(deg2rad($this->__angle(235.0   +    19.34   * $jy)));
0739:     $rm_moon += 0.0050 * sin(deg2rad($this->__angle(295.4   +  4812.66   * $jy)));
0740:     $rm_moon += 0.0052 * sin(deg2rad($this->__angle(197.2   +   319.32   * $jy)));
0741:     $rm_moon += 0.0068 * sin(deg2rad($this->__angle( 53.2   +  9265.33   * $jy)));
0742:     $rm_moon += 0.0079 * sin(deg2rad($this->__angle(278.2   +  4493.34   * $jy)));
0743:     $rm_moon += 0.0085 * sin(deg2rad($this->__angle(201.5   +  8266.71   * $jy)));
0744:     $rm_moon += 0.0100 * sin(deg2rad($this->__angle( 44.89  + 14315.966  * $jy)));
0745:     $rm_moon += 0.0107 * sin(deg2rad($this->__angle(336.44  + 13038.696  * $jy)));
0746:     $rm_moon += 0.0110 * sin(deg2rad($this->__angle(231.59  +  4892.052  * $jy)));
0747:     $rm_moon += 0.0125 * sin(deg2rad($this->__angle(141.51  + 14436.029  * $jy)));
0748:     $rm_moon += 0.0153 * sin(deg2rad($this->__angle(130.84  +   758.698  * $jy)));
0749:     $rm_moon += 0.0305 * sin(deg2rad($this->__angle(312.49  +  5131.979  * $jy)));
0750:     $rm_moon += 0.0348 * sin(deg2rad($this->__angle(117.84  +  4452.671  * $jy)));
0751:     $rm_moon += 0.0410 * sin(deg2rad($this->__angle(137.43  +  4411.998  * $jy)));
0752:     $rm_moon += 0.0459 * sin(deg2rad($this->__angle(238.18  +  8545.352  * $jy)));
0753:     $rm_moon += 0.0533 * sin(deg2rad($this->__angle( 10.66  + 13677.331  * $jy)));
0754:     $rm_moon += 0.0572 * sin(deg2rad($this->__angle(103.21  +  3773.363  * $jy)));
0755:     $rm_moon += 0.0588 * sin(deg2rad($this->__angle(214.22  +   638.635  * $jy)));
0756:     $rm_moon += 0.1143 * sin(deg2rad($this->__angle(  6.546 +  9664.0404 * $jy)));
0757:     $rm_moon += 0.1856 * sin(deg2rad($this->__angle(177.525 +   359.9905 * $jy)));
0758:     $rm_moon += 0.2136 * sin(deg2rad($this->__angle(269.926 +  9543.9773 * $jy)));
0759:     $rm_moon += 0.6583 * sin(deg2rad($this->__angle(235.700 +  8905.3422 * $jy)));
0760:     $rm_moon += 1.2740 * sin(deg2rad($this->__angle(100.738 +  4133.3536 * $jy)));
0761:     $rm_moon += 6.2887 * sin(deg2rad($this->__angle(134.961 +  4771.9886 * $jy + $am)));
0762: 
0763:     return $rm_moon + $this->__angle(218.3161 + 4812.67881 * $jy);
0764: }
0765: 
0766: /**
0767:  * 月の黄経計算(視黄経)
0768:  * @param int $year, $month, $day  グレゴリオ暦による年月日
0769:  * @param double $hour, $min, $sec 時分秒(世界時)
0770:  * @return double 月の黄経(視黄経)
0771: */
0772: function longitude_moon($year$month$day$hour$min$sec) {
0773:     $jy = $this->Gregorian2JY($year$month$day$hour$min$sec);
0774: 
0775:     return $this->__longitude_moon($jy);
0776: }

計算式は『日の出・日の入りの計算』(長沢工=著)による。

解説:月齢の算出

1007: /**
1008:  * 月齢を求める(視黄経)
1009:  * @param int $year, $month, $day  グレゴリオ暦による年月日
1010:  * @param double $hour, $min, $sec 時分秒(世界時)
1011:  * @return double 月齢(視黄経)
1012: */
1013: function moon_age($year$month$day$hour$min$sec) {
1014:     $jd0 = $this->Gregorian2JD($year$month$day$hour$min$sec) + (9 / 24);
1015:     $tm1 = floor($jd0);
1016:     $tm2 = $jd0 - $tm1;
1017: 
1018:     //繰り返し計算によって朔の時刻を計算
1019:     //誤差が±1.0 sec以内になったら打ち切る
1020:     $lc = 1;
1021:     $delta_t1 = 0;
1022:     $delta_t2 = 1;
1023:     while (($delta_t1 + abs($delta_t2)) > (1.0 / 86400.0)) {
1024:         $jd = $tm1 + $tm2;
1025:         list($year$month$day$hour$min$sec) = $this->JD2Gregorian($jd);
1026:         $longitude_sun  = $this->longitude_sun($year$month$day$hour$min$sec);
1027:         $longitude_moon = $this->longitude_moon($year$month$day$hour$min$sec);
1028: 
1029:         //Δλ=λmoon-λsun
1030:         $delta_rm = $longitude_moon - $longitude_sun;
1031: 
1032:         //ループ1回目 で $delta_rm < 0.0 の場合には引き込み範囲に入るよう補正
1033:         if ($lc == 1 && $delta_rm < 0) {
1034:             $delta_rm = $this->__angle($delta_rm);
1035:         //春分の近くで朔がある場合 ( 0 ≦λsun≦ 20 ) で、月の黄経λmoon≧300 の
1036:         //場合には、Δλ= 360.0 - Δλ と計算して補正
1037:         } else if ($longitude_sun >= 0 && $longitude_sun <= 20 && $longitude_moon >= 300) {
1038:             $delta_rm = $this->__angle($delta_rm);
1039:             $delta_rm = 360 - $delta_rm;
1040:         //Δλの引き込み範囲 ( ±40°) を逸脱した場合には補正
1041:         } else if (abs($delta_rm) > 40.0) {
1042:             $delta_rm = $this->__angle($delta_rm);
1043:         }
1044: 
1045:         //時刻引数の補正値 Δt
1046:         $delta_t1  = floor($delta_rm * 29.530589 / 360.0);
1047:         $delta_t2  = $delta_rm * 29.530589 / 360.0;
1048:         $delta_t2 -= $delta_t1;
1049: 
1050:         //時刻引数の補正
1051:         $tm1 = $tm1 - $delta_t1;
1052:         $tm2 = $tm2 - $delta_t2;
1053:         if ($tm2 < 0) {
1054:             $tm2++;
1055:             $tm1--;
1056:         }
1057: 
1058:         //ループ回数が15回になったら、初期値 tm を tm-26
1059:         if ($lc == 15 && abs($delta_t1 + $delta_t2) > (1.0 / 86400.0)) {
1060:             $tm1 = floor($jd0 - 26);
1061:             $tm2 = 0;
1062:             //初期値を補正したにも関わらず振動を続ける場合は、
1063:             //初期値を答えとして返して強制的にループを抜け出して異常終了
1064:         } else if ($lc > 30 && abs($delta_t1 + $delta_t2) > (1.0 / 86400.0)) {
1065:             $tm1 = $jd0;
1066:             $tm2 = 0;
1067:             break;
1068:         }
1069:         $lc++;
1070:     }
1071: 
1072:     //時刻引数を合成
1073:     $ma = $jd0 - ($tm2 + $tm1);
1074:     if ($ma > 30)   $ma -= 30;
1075:     return $ma;
1076: }

太陽と月の黄経が一致した瞬間が「(新月)」、月が太陽より 90 度東にきた瞬間を「上弦」、月と太陽が 180 度離れた瞬間を「(満月)」、月が太陽より 90 度西にきた瞬間を「下弦」と定義されている。
ここから、月齢を求めるためには、「PHP で二十四節気一覧を作成」で紹介した太陽の視黄経と、今回作成した 月の視黄経の差分を計算することにする。

Wikipedia には月齢を求める簡易式が掲載されているが、それより今回のプログラムの方が正確である。

活用例

月齢=今日の月・現在の月=」(みんなの知識 ちょっと便利帳)では、このサンプル・プログラムを活用し、月の写真を使って月齢を表示するようにしている。ありがとうございます。

参考書籍

表紙 日の出・日の入りの計算
著者 長沢工
出版社 地人書館
サイズ 単行本
発売日 1999年12月
価格 1,620円(税込)
rakuten
ISBN 9784805206348
 

参考サイト

(この項おわり)
header