Code covered by the BSD License  

Highlights from
Moon Position

image thumbnail
from Moon Position by James Tursa
moonpos calculates moon position accurate to 10 arcsec. Based on Astronomical Algorithms, Meeus

moonpos(varargin)
% moonpos calculates moon position from Astronomical Algorithms, Jean Meeus
%******************************************************************************
% 
%  MATLAB (R) is a trademark of The Mathworks (R) Corporation
% 
%  Function:    moonpos
%  Filename:    moonpos.c
%  Programmer:  James Tursa
%  Version:     1.1
%  Date:        April 7, 2009
%  Copyright:   (c) 2009 by James Tursa, All Rights Reserved
%
%  This code uses the BSD License:
%
%  Redistribution and use in source and binary forms, with or without 
%  modification, are permitted provided that the following conditions are 
%  met:
%
%     * Redistributions of source code must retain the above copyright 
%       notice, this list of conditions and the following disclaimer.
%     * Redistributions in binary form must reproduce the above copyright 
%       notice, this list of conditions and the following disclaimer in 
%       the documentation and/or other materials provided with the distribution
%      
%  THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 
%  AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 
%  IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 
%  ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE 
%  LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 
%  CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 
%  SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 
%  INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 
%  CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 
%  ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 
%  POSSIBILITY OF SUCH DAMAGE.
% 
%  moonpos calculates the moon position using the method in the book
%  Astronomical Algorithms by Jean Meeus, Chapter 45, pp 307 - 313. The
%  algorithm used is accurate to about 10 arcsec in longitude and 4 arcsec
%  in latitude according to the book, although the time range is not
%  mentioned. The periodic terms used in this algorithm are based on the
%  Chapront ELP-2000/82 lunar theory, including the later improvements by
%  Chapront. The results of this theory are referred to the mean equinox
%  of date, but moonpos converts these to the apparent geocentric position
%  of the moon referred to the true equinox of date.
% 
%  Building:
% 
%  moonpos requires that a mex routine be built (one time only). This
%  process is typically self-building the first time you call the function
%  as long as you have the files moonpos.m and moonpos.c in the same
%  directory somewhere on the MATLAB path. If you need to manually build
%  the mex function, here are the commands:
%
%  >> mex -setup
%    (then follow instructions to select a C / C++ compiler of your choice)
%  >> mex moonpos.c
%
%  If you have an older version of MATLAB, you may need to use this command:
%
%  >> mex -DDEFINEMWSIZE moonpos.c
% 
%  Syntax
% 
%  B = moonpos(A)
%  B = moonpos(A,S1)
%  B = moonpos(A,S1,S2,...)
% 
%  Description
% 
%  A = a Nx1 or 1xN double vector containing the date values. By default,
%      the data is expected to be in Serial Date Number format, but this
%      can be changed to Julian Day, Modified Julian Day, Reduced Julian
%      Day, or Truncated Julian Day with optional strings (see below).
%
%    = a Nx6 double date matrix, where each row is a full date vector
%      specifying year, month, day, hours, minutes, seconds in that order.
%      Dates must be compatible with the MATLAB datenum function.
%
%    = a Nx3 double date matrix, where each row is a partial date vector
%      specifying year, month, and day in that order. Dates must be
%      compatible with the MATLAB datenum function.
%
%    = a NxM character array containing dates that are compatible with the
%      datenum function.
%
%      For the last three cases the datenum function is called automatically
%      by moonpos to convert the dates to SDN format.
%
%  B = a NxM double vector containing the moon position data. By default a
%      Nx3 vector is returned where the three columns are right ascension (rad),
%      declination (rad), and distance (km), but this can be changed with
%      optional strings (see below). Output is true-of-date from earth
%      center.
%
%  Sn = Optional string argument(s) that alter input and output settings. You
%       can specify more than one optional string. They are processed left to
%       right and are case insensitive. If you specify mutually exclusive
%       options (such as 'jd' and 'rjd'), the rightmost option will prevail.
%
%       'julian' or 'julian day' or 'jd'
%       = Input vector A is in Julian Day format. i.e., the interval of time
%         in days and fractions of a day since January 1, 4713 BC Greenwich noon
%
%       'reduced julian day' or 'reduced' or 'rjd'
%       = Input vector A is in Reduced Julian Day format, RJD = JD - 2400000.
%
%       'modified julian day' or 'modified' or 'mjd'
%       = Input vector A is in Modified Julian Day format, MJD = JD - 2400000.5
%
%       'truncated julian day' or 'truncated' or 'tjd'
%       = Input vector A is in Truncated Julian Day format, TJD = JD - 2440000.5
%
%       'radec'
%       = Output is Nx3 matrix in right ascension, declination, distance format
%         in units of radians, radians, kilometers (this is the default).
%         But note that you can change the units of the angles or distance
%         (see below), and you can add the x, y, z cartesian output at the
%         same time with the 'xyz' option and get a Nx6 matrix result.
%
%       'xyz'
%       = Output is Nx3 matrix with x, y, z cartesian coordinates. Note
%         that this can be specified in addition to 'radec' if you want
%         a Nx6 matrix output with both data sets present. The order in
%         which the 'radec' and 'xyz' options appear in the argument list
%         determines the order in which the output appears in the result.
%
%       'feet' or 'ft'
%       = Output distances will be in feet instead of km.
%
%       'meter' or 'meters' or 'm'
%       = Output distances will be in meters instead of km.
%
%       'degree' or 'degrees' or 'deg'
%       = Output angles will be in degrees instead of radians.
%
%       'hms'
%       = Output right ascension will be in hh.mmsss... format.
%
%       'dms'
%       = Output declination will be in dd.mmsss... format.
%
%       'nutationlow'
%       = Use the slightly lower precision nutation formulae at the bottom
%         of page 132 instead of the full TABLE 21.A terms.
%
%  Examples
%  
%  >> format long
%  >> x = moonpos(2448724.5,'jd') % The example on pages 312-313 of the book
% 
%  You must build the mex routine before you can use moonpos.
%  Attempting to do so now ...
% 
%  Found file moonpos.c in C:\Program Files\MATLAB\R2006a\work\moonpos.c
% 
%  Now attempting to compile ...
%  (If prompted, please press the Enter key and then select any C/C++
%  compiler that is available, such as lcc.)
% 
%  mex('C:\Program Files\MATLAB\R2006a\work\moonpos.c')
% 
%  moonpos.c 
%  C:\Program Files\MATLAB\R2006a\work\moonpos.c(202) : error C2065: 'mwSize' : undeclared identifier 
%  C:\Program Files\MATLAB\R2006a\work\moonpos.c(202) : error C2146: syntax error : missing ';' before identifier 'i' 
%    :
%  (a list of over 200 compile errors)
%    :
%  C:\Program Files\MATLAB\R2006a\work\moonpos.c(405) : warning C4244: '=' : conversion from 'double' to 'int', possible loss of data 
%  C:\Program Files\MATLAB\R2006a\work\moonpos.c(408) : error C2100: illegal indirection 
%  
%  C:\PROGRAM FILES\MATLAB\R2006A\BIN\MEX.PL: Error: Compile of 'C:\Program Files\MATLAB\R2006a\work\moonpos.c' failed. 
% 
%  Well, *that* didn't work ... this is often caused on older versions
%  of MATLAB that do not have the typedef mwSize defined. So now we will
%  attempt to compile it by manually defining mwSize ...
% 
%  mex('-DDEFINEMWSIZE','C:\Program Files\MATLAB\R2006a\work\moonpos.c')
%   
%  Success!
%  mex moonpos.c build completed ... attempting to call this moonpos.
% 
% x =
%   1.0e+005 *
%    0.00002350757329   0.00000240303299   3.68409684525585
%
%  There are several things to note about the previous example. First, of
%  course, is the long list of errors the first time it was run. This is
%  because the MATLAB API for R2006a does not have the typedef for mwSize.
%  A try-catch logic accounts for this, however, and then manually defines
%  the mwSize for another compile try, and the second time it is a success.
%  This process is all automated, so don't worry if you get a bunch of
%  errors the very first time you try this function ... they can safely be
%  ignored as long as you get the Success message.
%
%  The second thing to note is that the return results are in radians, but
%  a glance at the book shows the results in degrees and hms & dms. Before
%  you start converting this result by hand to do the compare, realize that
%  moonpos will do this for you. Just select the 'hms' and 'dms' options:
%
%  >> x = moonpos(2448724.5,'jd','hms','dms')
%  x =
%  1.0e+005 *
%   0.00008584523366   0.00013460611349   3.68409684525585
%
%  The results given in the book are:
%  RA  = 8h 58m 45.2s
%  DEC = 13deg 46' 06"
%  DELTA = 368409.7 (corrected from errata, early editions are incorrect)
%
%  So the results of moonpos match the book. Also note that the 2nd time
%  moonpos was run there were no compile error messages because the mex
%  file has already been built.
%
%  Several of the values in early editions of the book are incorrect. They
%  have been corrected with errata of later editions. The corrections are:
%
%   http://www.willbell.com/MATH/AA-First%20Ed.%20Errata.pdf
%   http://www.willbell.com/MATH/AA-Second%20Ed.%20Errata.pdf
%
%   Sigma r = -16590875
%   Delta   =  385000.56 - 16590.875 = 368409.7
%   pi      =  arcsine(6378.14 / 368409.7) = 0.991990 = 0deg 59' 31".2
%
%  Some more examples:
%
%  % Request x,y,z output instead of ra,dec,delta (results will be in km)
%  >> x = moonpos(2448724.5,'jd','xyz')
%  x =
%    1.0e+005 *
%    -2.51640151355659   2.54391554623140   0.87680481376215
%
%  % Request x,y,z output in feet instead km
%  >> x = moonpos(2448724.5,'jd','xyz','feet')
%  x =
%    1.0e+008 *
%    -8.25591047754786   8.34617961362006   2.87665621313040
%
%  % Request both ra,dec,delta and x,y,z output, with angles in degrees and
%  % distances in meters
%  >> x = moonpos(2448724.5,'jd','radec','deg','xyz','m')
%  x =
%    1.0e+008 *
%    Columns 1 through 4 
%     0.00000134688474   0.00000013768365   3.68409684525585  -2.51640151355659
%    Columns 5 through 6 
%     2.54391554623140   0.87680481376215
%
%  % Request both ra,dec,delta and x,y,z output, with angles in degrees and
%  % distances in meters, but this time list the x,y,z first
%  >> x = moonpos(2448724.5,'jd','xyz','radec','deg','m')
%  x =
%    1.0e+008 *
%    Columns 1 through 4 
%    -2.51640151355659   2.54391554623140   0.87680481376215   0.00000134688474
%    Columns 5 through 6 
%     0.00000013768365   3.68409684525585
%
%  % Request position for a string date, with right ascension output in
%  % hours, minutes, seconds, and declination output in degrees, minutes,
%  % seconds. Note that we don't have to specify a time format with this
%  % example since the result of the datenum function (called in the
%  % background) is a Serial Date Number, which is the default for moonpos.
%  >> x = moonpos('01-Jan-2000','hms','dms')
%  x =
%    1.0e+005 *
%    0.00014263869309  -0.00008592808456   4.00927160087148
%
%  % Plot the radial distance of the moon for the year 2009
%  >> t = datenum('01-Jan-2009'):datenum('31-Dec-2009');
%  >> x = moonpos(t);
%  >> plot(t,x(:,3));
%  >> title('2009 Moon Radial Distance from Earth');
%  >> ylabel('km');
%  >> dateaxis('x',12);
%
%**************************************************************************

function varargout = moonpos(varargin)
mname = mfilename;
disp(' ');
disp(['You must build the mex routine before you can use ' mname '.']);
disp('Attempting to do so now ...');
disp(' ');
mfull = mfilename('fullpath');
cname = [mfull '.c'];
if( isempty(dir(cname)) )
    disp(['Cannot find the file ' mname '.c in the same directory as the']);
    disp(['file ' mname '.m. Please ensure that they are in the same']);
    disp('directory and try again. The following file was not found:');
    disp(' ');
    disp(cname);
    disp(' ');
    error(['Unable to compile ' mname '.c']);
else
    disp(['Found file ' mname '.c in ' cname]);
    disp(' ');
    disp('Now attempting to compile ...');
    disp('(If prompted, please press the Enter key and then select any C/C++');
    disp('compiler that is available, such as lcc.)');
    disp(' ');
    disp(['mex(''' cname ''')']);
    disp(' ');
    try
        mex(cname,'-output',mfull);
        disp('Success!');
        disp(['mex ' mname '.c build completed ... attempting to call this ' mname '.']);
        disp(' ');
    catch
        disp(' ');
        disp('Well, *that* didn''t work ... this is often caused on older versions');
        disp('of MATLAB that do not have the typedef mwSize defined. So now we will');
        disp('attempt to compile it by manually defining mwSize ...');
        disp(' ');
        try
            disp(' ');
            disp(['mex(''-DDEFINEMWSIZE'',''' cname ''')']);
            disp(' ');
            mex('-DDEFINEMWSIZE',cname,'-output',mfull);
            disp('Success!');
            disp(['mex ' mname '.c build completed ... attempting to call this ' mname '.']);
            disp(' ');
        catch
            disp('Hmmm ... That didn''t work either.');
            disp(' ');
            disp('The mex command failed. This may be because you have already run');
            disp('mex -setup and selected a non-C compiler, such as Fortran. If this');
            disp('is the case, then rerun mex -setup and select a C/C++ compiler.');
            disp(' ');
            error(['Unable to compile ' mname '.c']);
        end
    end
    [varargout{1:nargout}] = moonpos(varargin{:});
end
end

Contact us at files@mathworks.com