Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to plot the field of view of an Earth-Observation satellite when close to the poles using basemap?

I am trying to draw the maximum (theoretical) field of view of a satellite along its orbit. I am using Basemap, on which I want to plot different positions along the orbit (with scatter), and I would like to add the whole field of view using the tissot method (or equivalent). The code below works fine until the latitude reaches about 75 degrees North, on a 300km altitude orbit. Beyond which the code outputs a ValueError: "ValueError: undefined inverse geodesic (may be an antipodal point)"

import matplotlib.pyplot as plt
from mpl_toolkits.basemap import Basemap
import math

earth_radius = 6371000.  # m
fig = plt.figure(figsize=(8, 6), edgecolor='w')
m = Basemap(projection='cyl', resolution='l',
            llcrnrlat=-90, urcrnrlat=90,
            llcrnrlon=-180, urcrnrlon=180)

# draw the coastlines on the empty map
m.drawcoastlines(color='k')

# define the position of the satellite
position = [300000., 75., 0.]  # altitude, latitude, longitude

# radius needed by the tissot method
radius = math.degrees(math.acos(earth_radius / (earth_radius + position[0])))
m.tissot(position[2], position[1], radius, 100, facecolor='tab:blue', alpha=0.3)
m.scatter(position[2], position[1], marker='*', c='tab:red')

plt.show()

To be noted that the code works fine at the south pole (latitude lower than -75). I know it's a known bug, is there a known workaround for this issue? Thanks for your help!

like image 928
Flo Avatar asked Jan 22 '26 23:01

Flo


1 Answers

What you found is some of Basemap's limitations. Let's switch to Cartopy for now. The working code will be different but not much.

import matplotlib.pyplot as plt
import cartopy.crs as ccrs
import math

earth_radius = 6371000.
position = [300000., 75., 0.]   # altitude (m), lat, long
radius = math.degrees(math.acos(earth_radius / (earth_radius + position[0])))
print(radius)  # in subtended degrees??

fig = plt.figure(figsize=(12,8))

img_extent = [-180, 180, -90, 90]

# here, cartopy's' `PlateCarree` is equivalent with Basemap's `cyl` you use
ax = fig.add_subplot(1, 1, 1, projection = ccrs.PlateCarree(), extent = img_extent)

# for demo purposes, ...
# let's take 1 subtended degree = 112 km on earth surface (*** you set the value as needed ***)
ax.tissot(rad_km=radius*112, lons=position[2], lats=position[1], n_samples=64, \
             facecolor='red', edgecolor='black', linewidth=0.15, alpha = 0.3)

ax.coastlines(linewidth=0.15)
ax.gridlines(draw_labels=False, linewidth=1, color='blue', alpha=0.3, linestyle='--')
plt.show()

With the code above, the resulting plot is:

enter image description here

Now, if we use Orthographic projection, (replace relevant line of code with this)

ax = fig.add_subplot(1, 1, 1, projection = ccrs.Orthographic(central_longitude=0.0, central_latitude=60.0))

you get this plot:

enter image description here

like image 150
swatchai Avatar answered Jan 24 '26 11:01

swatchai



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!