[postgis-users] Solar azimuth calculator
Bruce Rindahl
bruce.rindahl at gmail.com
Sat Apr 17 07:11:15 PDT 2021
Here it is in psql. Doesn't need PostGIS. Fun little exercise.
CREATE OR REPLACE FUNCTION public.solarazelev(
obs_time timestamp with time zone,
latitude numeric,
longitude numeric,
alt numeric)
RETURNS TABLE(azimuth numeric, elevation numeric)
LANGUAGE 'plpgsql'
AS $BODY$
DECLARE copyright varchar :=
' Programed by Darin C.Koblick 2 / 17 / 2009
Darin C.Koblick 4 / 16 / 2013 Vectorized for Speed
Allow for MATLAB Datevec input in
addition to a UTC string.
Cleaned up comments and code to
avoid warnings in MATLAB editor.
Kevin Godden 9/1/2020 Ported from Matlab to C++, tried
to change as little as possible.
this is a non-vectorised port.
Bruce Rindahl 4/17/2021 Ported to PostgreSQL
--------------------------------------------------------------------------
Copyright(c) 2010, Darin Koblick
All rights reserved.
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.';
DECLARE M_PI numeric := pi();
DECLARE jd numeric := to_char(obs_time,'J')::numeric;
DECLARE d numeric := jd - 2451543.5;
-- Keplerian Elements for the Sun(geocentric)
DECLARE w numeric := 282.9404 + 4.70935e-5*d; -- (longitude of
perihelion degrees)
-- a = 1.000000; % (mean distance, a.u.)
DECLARE e numeric := 0.016709 - 1.151e-9*d; -- (eccentricity)
DECLARE M numeric := mod(356.0470 + 0.9856002585*d, 360.0); -- (mean
anomaly degrees)
DECLARE L numeric := w + M; -- (Sun's mean longitude degrees)
DECLARE oblecl numeric := 23.4393 - 3.563e-7*d; -- (Sun's obliquity of
the ecliptic)
-- auxiliary angle
DECLARE EE numeric := M + (180 / M_PI)*e*sin(M*(M_PI / 180))*(1 +
e*cos(M*(M_PI / 180)));
-- rectangular coordinates in the plane of the ecliptic(x axis toward
perhilion)
DECLARE x numeric := cos(EE*(M_PI / 180)) - e;
DECLARE y numeric := sin(EE*(M_PI / 180))*sqrt(1 - pow(e, 2));
-- find the distance and true anomaly
DECLARE r numeric := sqrt(pow(x,2) + pow(y,2));
-- Is this y,x or x,y? opposite from Excel - use C++ version
DECLARE v numeric := atan2(y, x)*(180 / M_PI);
-- find the longitude of the sun
DECLARE lon numeric := v + w;
-- compute the ecliptic rectangular coordinates
DECLARE xeclip numeric := r*cos(lon*(M_PI / 180));
DECLARE yeclip numeric := r*sin(lon*(M_PI / 180));
DECLARE zeclip numeric := 0.0;
--rotate these coordinates to equitorial rectangular coordinates
DECLARE xequat numeric := xeclip;
DECLARE yequat numeric := yeclip*cos(oblecl*(M_PI / 180)) + zeclip *
sin(oblecl*(M_PI / 180));
DECLARE zequat numeric := yeclip*sin(23.4406*(M_PI / 180)) + zeclip *
cos(oblecl*(M_PI / 180));
-- convert equatorial rectangular coordinates to RA and Decl:
DECLARE RR numeric := sqrt(pow(xequat, 2) + pow(yequat, 2) +
pow(zequat, 2)) - (Alt / 149598000); -- roll up the altitude correction
DECLARE RA numeric := atan2(yequat, xequat)*(180 / M_PI);
DECLARE delta numeric := asin(zequat / RR)*(180 / M_PI);
DECLARE UTH numeric := date_part('hour',obs_time)
+ date_part('minute',obs_time)/60
+ date_part('second',obs_time) /3600
- extract( timezone from now())/3600;
-- Calculate local siderial time
DECLARE GMST0 numeric := mod(L + 180, 360.0) / 15;
DECLARE SIDTIME numeric := GMST0 + UTH + Longitude / 15;
-- Replace RA with hour angle HA
DECLARE HA numeric := (SIDTIME*15 - RA);
-- convert to rectangular coordinate system
DECLARE XX numeric := cos(HA*(M_PI / 180))*cos(delta*(M_PI / 180));
DECLARE YY numeric := sin(HA*(M_PI / 180))*cos(delta*(M_PI / 180));
DECLARE z numeric := sin(delta*(M_PI / 180));
-- rotate this along an axis going east - west.
DECLARE xhor numeric := XX*cos((90 - Latitude)*(M_PI / 180)) -
z*sin((90 - Latitude)*(M_PI / 180));
DECLARE yhor numeric := YY;
DECLARE zhor numeric := XX*sin((90 - Latitude)*(M_PI / 180)) +
z*cos((90 - Latitude)*(M_PI / 180));
-- Find the h and AZ
DECLARE Az numeric := round((atan2(yhor, xhor)*(180 / M_PI) +
180)::numeric,3);
DECLARE El numeric := round((asin(zhor)*(180 / M_PI))::numeric,3);
BEGIN
RETURN QUERY select Az,El;
END
$BODY$;
On Thu, Apr 15, 2021, 1:46 PM Bruce Rindahl <bruce.rindahl at gmail.com> wrote:
> Here is the code for it in c:
>
>
> https://www.ridgesolutions.ie/index.php/2020/01/14/c-code-to-estimate-solar-azimuth-and-elevation-given-gps-position-and-time/
>
>
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://lists.osgeo.org/pipermail/postgis-users/attachments/20210417/0e7e1b7f/attachment.html>
More information about the postgis-users
mailing list