source

Python의 Haversine 공식(두 GPS 지점 사이의 방위 및 거리)

ittop 2023. 7. 16. 17:54
반응형

Python의 Haversine 공식(두 GPS 지점 사이의 방위 및 거리)

문제

저는 두 GPS 지점 사이의 거리와 방위를 어떻게 알 수 있는지 알고 싶습니다.

나는 haversine 거리에 대해 조사했습니다.누군가가 나에게 동일한 데이터를 사용하여 베어링도 찾을 수 있다고 말했습니다.


모든 것이 잘 작동하고 있지만, 베어링은 아직 제대로 작동하지 않습니다.베어링 출력은 음수이지만 0~360도 사이여야 합니다.

는 수평베어링을 ▁the▁should▁make합▁the다니야▁set▁data만.96.02166666666666다음과 같습니다.

Start point: 53.32055555555556, -1.7297222222222221
Bearing:  96.02166666666666
Distance: 2 km
Destination point: 53.31861111111111, -1.6997222222222223
Final bearing: 96.04555555555555

내 새 코드는 다음과 같습니다.

from math import *

Aaltitude = 2000
Oppsite  = 20000

lat1 = 53.32055555555556
lat2 = 53.31861111111111
lon1 = -1.7297222222222221
lon2 = -1.6997222222222223

lon1, lat1, lon2, lat2 = map(radians, [lon1, lat1, lon2, lat2])

dlon = lon2 - lon1
dlat = lat2 - lat1
a = sin(dlat/2)**2 + cos(lat1) * cos(lat2) * sin(dlon/2)**2
c = 2 * atan2(sqrt(a), sqrt(1-a))
Base = 6371 * c


Bearing = atan2(cos(lat1)*sin(lat2)-sin(lat1)*cos(lat2)*cos(lon2-lon1), sin(lon2-lon1)*cos(lat2))

Bearing = degrees(Bearing)
print ""
print ""
print "--------------------"
print "Horizontal Distance: "
print Base
print "--------------------"
print "Bearing: "
print Bearing
print "--------------------"


Base2 = Base * 1000
distance = Base * 2 + Oppsite * 2 / 2
Caltitude = Oppsite - Aaltitude

a = Oppsite/Base
b = atan(a)
c = degrees(b)

distance = distance / 1000

print "The degree of vertical angle is: "
print c
print "--------------------"
print "The distance between the Balloon GPS and the Antenna GPS is: "
print distance
print "--------------------"

다음은 Python 버전입니다.

from math import radians, cos, sin, asin, sqrt

def haversine(lon1, lat1, lon2, lat2):
    """
    Calculate the great circle distance in kilometers between two points 
    on the earth (specified in decimal degrees)
    """
    # convert decimal degrees to radians 
    lon1, lat1, lon2, lat2 = map(radians, [lon1, lat1, lon2, lat2])

    # haversine formula 
    dlon = lon2 - lon1 
    dlat = lat2 - lat1 
    a = sin(dlat/2)**2 + cos(lat1) * cos(lat2) * sin(dlon/2)**2
    c = 2 * asin(sqrt(a)) 
    r = 6371 # Radius of earth in kilometers. Use 3956 for miles. Determines return value units.
    return c * r

이 대답들의 대부분은 지구의 반지름을 "반올림"하는 것입니다.다른 거리 계산기(예: 지오피)와 비교하여 이러한 기능을 확인하면 이러한 기능이 해제됩니다.

이것은 잘 작동합니다.

from math import radians, cos, sin, asin, sqrt

def haversine(lat1, lon1, lat2, lon2):

      R = 3959.87433 # this is in miles.  For Earth radius in kilometers use 6372.8 km

      dLat = radians(lat2 - lat1)
      dLon = radians(lon2 - lon1)
      lat1 = radians(lat1)
      lat2 = radians(lat2)

      a = sin(dLat/2)**2 + cos(lat1)*cos(lat2)*sin(dLon/2)**2
      c = 2*asin(sqrt(a))

      return R * c

# Usage
lon1 = -103.548851
lat1 = 32.0004311
lon2 = -103.6041946
lat2 = 33.374939

print(haversine(lat1, lon1, lat2, lon2))

벡터화된 구현체도 있어 좌표에 스칼라 값 대신 4개의 NumPy 배열을 사용할 수 있습니다.

def distance(s_lat, s_lng, e_lat, e_lng):

   # Approximate radius of earth in km
   R = 6373.0

   s_lat = s_lat*np.pi/180.0
   s_lng = np.deg2rad(s_lng)
   e_lat = np.deg2rad(e_lat)
   e_lng = np.deg2rad(e_lng)

   d = np.sin((e_lat - s_lat)/2)**2 + np.cos(s_lat)*np.cos(e_lat) * np.sin((e_lng - s_lng)/2)**2

   return 2 * R * np.arcsin(np.sqrt(d))

Haversine 패키지를 사용해 볼 수 있습니다.

코드 예제:

from haversine import haversine

haversine((45.7597, 4.8422), (48.8567, 2.3508), unit='mi')

출력:

243.71209416020253

베어링 계산이 잘못되었습니다.입력을 an2로 전환해야 합니다.

bearing = atan2(sin(long2 - long1)*cos(lat2), cos(lat1)*sin(lat2) - sin(lat1)*cos(lat2)*cos(long2 - long1))
bearing = degrees(bearing)
bearing = (bearing + 360) % 360

이렇게 하면 올바른 방향으로 방향을 잡을 수 있습니다.

@Michael Dunn이 준 Haversine 공식의 NumPy 벡터화된 구현은 큰 벡터에 비해 10-50배 향상을 제공합니다.

from numpy import radians, cos, sin, arcsin, sqrt

def haversine(lon1, lat1, lon2, lat2):
    """
    Calculate the great circle distance between two points
    on the earth (specified in decimal degrees)
    """

    # Convert decimal degrees to radians:
    lon1 = np.radians(lon1.values)
    lat1 = np.radians(lat1.values)
    lon2 = np.radians(lon2.values)
    lat2 = np.radians(lat2.values)

    # Implementing the haversine formula:
    dlon = np.subtract(lon2, lon1)
    dlat = np.subtract(lat2, lat1)

    a = np.add(np.power(np.sin(np.divide(dlat, 2)), 2),
               np.multiply(np.cos(lat1),
                           np.multiply(np.cos(lat2),
                               np.power(np.sin(np.divide(dlon, 2)), 2))))

    c = np.multiply(2, np.arcsin(np.sqrt(a)))
    r = 6371

    return c*r

360°를 더하면 네거티브 베어링 문제를 해결할 수 있습니다.안타깝게도 포지티브 베어링의 경우 베어링이 360°보다 클 수 있습니다.이것은 모듈로 연산자에 적합한 후보이므로 대체로 라인을 추가해야 합니다.

Bearing = (Bearing + 360) % 360

당신 방법의 끝에.

빈센트와 대원 거리 계산의 차이를 참조하십시오.

이것은 실제로 거리를 두는 두 가지 방법을 제공합니다.그들은 Haversine과 Vincentys입니다.제가 조사한 결과 빈센트가 비교적 정확하다는 것을 알게 되었습니다.또한 가져오기 문을 사용하여 구현합니다.

atan2의 Y는 기본적으로 첫 번째 모수입니다.여기 설명서가 있습니다.올바른 베어링 각도를 얻으려면 입력을 전환해야 합니다.

bearing = atan2(sin(lon2-lon1)*cos(lat2), cos(lat1)*sin(lat2)-sin(lat1)*cos(lat2)*cos(lon2-lon1))
bearing = degrees(bearing)
bearing = (bearing + 360) % 360

다음은 이전 메시지의 코드와 Python의 두 점 사이의 나침반 방위를 기반으로 거리와 방위를 계산하는 두 가지 함수입니다(명확성을 위해 위도의 지리적 점에 대한 튜플 유형을 추가했습니다).두 가지 기능을 모두 테스트해보니 제대로 작동하는 것 같았습니다.

# Encoding: UTF-8
from math import radians, cos, sin, asin, sqrt, atan2, degrees

def haversine(pointA, pointB):

    if (type(pointA) != tuple) or (type(pointB) != tuple):
        raise TypeError("Only tuples are supported as arguments")

    lat1 = pointA[0]
    lon1 = pointA[1]

    lat2 = pointB[0]
    lon2 = pointB[1]

    # Convert decimal degrees to radians
    lat1, lon1, lat2, lon2 = map(radians, [lat1, lon1, lat2, lon2])

    # Haversine formula
    dlon = lon2 - lon1
    dlat = lat2 - lat1
    a = sin(dlat/2)**2 + cos(lat1) * cos(lat2) * sin(dlon/2)**2
    c = 2 * asin(sqrt(a))
    r = 6371 # Radius of earth in kilometers. Use 3956 for miles
    return c * r

def initial_bearing(pointA, pointB):

    if (type(pointA) != tuple) or (type(pointB) != tuple):
        raise TypeError("Only tuples are supported as arguments")

    lat1 = radians(pointA[0])
    lat2 = radians(pointB[0])

    diffLong = radians(pointB[1] - pointA[1])

    x = sin(diffLong) * cos(lat2)
    y = cos(lat1) * sin(lat2) -
        (sin(lat1) * cos(lat2) * cos(diffLong))

    initial_bearing = atan2(x, y)

    # Now we have the initial bearing but math.atan2 return values
    # from -180° to + 180° which is not what we want for a compass bearing
    # The solution is to normalize the initial bearing as shown below
    initial_bearing = degrees(initial_bearing)
    compass_bearing = (initial_bearing + 360) % 360

    return compass_bearing

pA = (46.2038, 6.1530)
pB = (46.449, 30.690)

print haversine(pA, pB)

print initial_bearing(pA, pB)

두 점 사이의 거리(지리적 좌표로 표시됨)를 측정하는 것이 목표라는 점을 고려하면 에서는 다음 세 가지 옵션을 선택할 수 있습니다.

  1. 하버신 공식

  2. GeoPy 측지선 거리 사용

  3. GeoPy 대원 거리 사용


옵션 1

Haversine 공식이 효과가 있을 것입니다.하지만, 그렇게 함으로써 하나는 지구를 구형으로 근사하고, 지구는 구형이 아니기 때문에 오류가 있다는 것을 유념하는 것이 중요합니다( 답변 참조).

Haversine 공식을 사용하기 위해서는 우선 지구의 반지름을 정의해야 합니다.이것은 그 자체로 약간의 논란을 일으킬 수도 있고요.다음 세 가지 출처를 고려할 때

는 6371 km라는 값을 지구의 반지름에 대한 기준으로 사용할 것입니다.

# Radius of the Earth
r = 6371.0

우리는 모듈을 활용할 것입니다.

반지름 후에 좌표로 이동하고, 수학의 삼각 함수를 사용하기 위해 좌표를 라디안으로 변환하는 것으로 시작합니다.이 경우 다음과 같이 가져오기 및 사용합니다.

# Import radians from the 'math' module
from math import radians

# Latitude and longitude for the first point (let's consider 40.000º and 21.000º)
lat1 = radians(40.000)
lon1 = radians(21.000)

# Latitude and longitude for the second point (let's consider 30.000º and 25.000º)
lat2 = radians(30.000)
lon2 = radians(25.000)

이제 Haversine 공식을 적용할 준비가 되었습니다.먼저, 1점의 경도를 2점의 경도로 뺍니다.

dlon = lon2 - lon1
dlat = lat2 - lat1

그리고 여기서 사용할 삼각함수가 몇 가지 있습니다. 더 구체적으로는 , , 및 입니다.우리는 또한 사용할 것입니다.

# Import sin, cos, atan2, and sqrt from the 'math' module
from math import sin, cos, atan2, sqrt

a = sin(dlat / 2)**2 + cos(lat1) * cos(lat2) * sin(dlon / 2)**2
c = 2 * atan2(sqrt(a), sqrt(1 - a))
d = r * c

그러면 인쇄를 통해 거리를 얻습니다.d.

도움이 될 수도 있지만, (Michael Dunn의 답변에서 영감을 받아) 모든 것을 함수로 모읍시다.

from math import radians, cos, sin, atan2, sqrt

def haversine(lon1, lat1, lon2, lat2):
    """
    Calculate the great-circle distance (in km) between two points
    using their longitude and latitude (in degrees).
    """
    # Radius of the Earth
    r = 6371.0

    # Convert degrees to radians
    # First point
    lat1 = radians(lat1)
    lon1 = radians(lon1)

    # Second point
    lat2 = radians(lat2)
    lon2 = radians(lon2)

    # Haversine formula
    dlon = lon2 - lon1
    dlat = lat2 - lat1
    a = sin(dlat / 2)**2 + cos(lat1) * cos(lat2) * sin(dlon / 2)**2
    c = 2 * atan2(sqrt(a), sqrt(1 - a))
    return r * c

옵션 2

하나는 GeoPy의 거리, 더 구체적으로, 를 사용할 것입니다.

결과는 km 또는 마일(출처) 모두에서 얻을 수 있습니다.

# Import Geopy's distance
from geopy import distance

wellington = (-41.32, 174.81)
salamanca = (40.96, -5.50)
print(distance.distance(wellington, salamanca).km) # If one wants it in miles, change `km` to `miles`

[Out]: 19959.6792674

옵션 3

하나는 GeoPy의 거리, 더 구체적으로, 를 사용할 것입니다.

결과는 km 또는 마일(출처) 모두에서 얻을 수 있습니다.

# Import Geopy's distance
from geopy import distance

newport_ri = (41.49008, -71.312796)
cleveland_oh = (41.499498, -81.695391)

print(distance.great_circle(newport_ri, cleveland_oh).miles) # If one wants it in km, change `miles` to `km`

[Out]: 536.997990696

주의:

  • 대원 거리는 종종 Haversine 공식을 사용하여 계산되기 때문에(Willem Hendriks가 언급했듯이) 옵션 1과 3은 비슷하지만 다른 반경을 사용합니다.

    • GeoPy의 Great-circle 거리는 지구의 구형 모델을 사용하며, 국제 측지학 및 지구 물리학 연합에 의해 정의된 평균 지구 반지름을 사용합니다.6371.0087714150598 kilometers거의. 6371.009 km(의 경우)WGS-84), 의 오류가 발생합니다.0.5%[출처].

Python에서 아래 구현을 사용할 수 있습니다.

import math

def haversine_distance(lat1, lon1, lat2, lon2, unit='K'):
r = 6371  # radius of the earth in kilometers
if unit == 'M':
    r = 3960  # radius of the earth in miles
dLat = math.radians(lat2 - lat1)
dLon = math.radians(lon2 - lon1)
a = math.sin(dLat / 2) * math.sin(dLat / 2) + \
    math.cos(math.radians(lat1)) * math.cos(math.radians(lat2)) * \
    math.sin(dLon / 2) * math.sin(dLon / 2)
c = 2 * math.atan2(math.sqrt(a), math.sqrt(1 - a))
distance = r * c
return distance

자세한 내용은 Haversine Formula에서 확인하실 수 있습니다.

언급URL : https://stackoverflow.com/questions/4913349/haversine-formula-in-python-bearing-and-distance-between-two-gps-points

반응형