# How many hours each day is Mars reachable by 2 of the 3 DSN complexes?

NASA communicates with spacecraft beyond Earth orbit using the Deep Space Network, which has three complexes: Canberra, Australia; Goldstone, California; and Madrid, Spain.

There are many spacecraft on or around Mars, and occasionally two of the complexes are used at the same time for Mars craft. In the screenshot below, we see the following Mars spacecraft communicating the Madrid and Goldstone complexes:

• M01O = Mars Odyssey
• MRO = Mars Reconnaissance Orbiter
• MVN = MAVEN = Mars Atmosphere and Volatile Evolution
• MCOB = Mars Cubesat One B
• MSL = Curiosity rover from the Mars Science Laboratory
• MOM = Mars Orbiter Mission (India)

MMS, NHPC, and STA are not Mars missions.

How common (in hours per day, or a fraction, or percent) are two of the DSN complexes in a position to communicate with Mars? If the answer varies with the orbits of the two planets, please elaborate.

Related:

Here is a quick answer for today. It varies as Earth and Mars move in their orbits. This script can be adjusted to other dates or bodies.

I've used the Python package Skyfield but you can extract the same elevation angles from Horizons, they both are using one of the late Development Ephemerides

Today Madrid-Goldstone have about 4 hours of observing with Mars 10 degrees above the horizon, and Goldstone-Canbera have a little less than 2 hours. Next week or next month it will be different.

10 degrees is an arbitrary limit and usually one would like to be higher than that. I have not checked about hardware limits. Both the sky noise increases and side lobes will pick up more ground noise (both are thermal noise) as you get closer to the horizon. Would be worse for a very weak signal in very deep space like the Voyagers or New Horizons.

For more on noise see the DESCANSO series document Low-Noise Systems in the Deep Space Network

## From Horizons

Use this pattern or similar, use ftp or save to disk right from the web page:

## From Python/Skyfield

class Site(object):
def __init__(self, name, latlon):
self.name   = name
self.latdeg = latlon[0]
self.londeg = latlon[1]

info  = (('Goldstone', (35.426667, -116.89)), ('Madrid', (40.429167, -4.249167)),
('Canbera', (-35.401389, 148.981667)))

import numpy as np
import matplotlib.pyplot as plt
from skyfield.api import Topos, Loader, EarthSatellite

halfpi, pi, twopi = [f*np.pi for f in (0.5, 1, 2)]

earth   = data['earth']
mars    = data['mars']

print earth.at(ts.now()).position.km   # for no reason at all

hours    = np.linspace(0, 24, 24*12+1)  # 24 hours in 5 minute steps
time     = ts.utc(2018, 12, 6, hours)   # 2018-12-6

sites = [Site(*thing) for thing in info]

for site in sites:
site.topo = earth + Topos(longitude_degrees=site.londeg,
latitude_degrees =site.latdeg )
alt, az, dist  = site.topo.at(time).observe(mars).apparent().altaz()

pairs     = [(sites[i%3], sites[(i+1)%3]) for i in range(3)]
pairnames = [(a.name, b.name) for (a, b) in pairs]

if True:
plt.figure()
fs = 16

plt.subplot(2, 1, 1)

for site in sites:
plt.plot(hours, degs*site.elevation)
plt.plot(hours, np.zeros_like(hours), '-k', linewidth=2)
plt.plot(hours, 10+np.zeros_like(hours), '-k', linewidth=1)
plt.text( 0.2, 51, 'Goldstone', fontsize=fs)
plt.text(16.5, 45, 'Canbera', fontsize=fs)
plt.xlim(0, 24)
plt.ylabel('elevation (degs)', fontsize=fs)

plt.subplot(2, 1, 2)

for s0, s1 in pairs:
ok = (degs * s0.elevation > 10) & (degs * s1.elevation > 10)
plt.plot(hours, ok)
plt.ylim(-0.1, 1.25)
plt.xlabel('hours UTC', fontsize=fs)
plt.ylabel('both evelations > 10 degs', fontsize=fs)
plt.xlim(0, 24)

plt.text(16.5, 1.05, 'Goldstone-Canbera', fontsize=fs)

plt.suptitle('DSN sees Mars 06-Dec-2018', fontsize=fs)
plt.show()


update: Here is the calendar year 2018. The Boolean plots are the envelopes for Mars elevation at both sites above 10 degrees. The color plots are Mars elevation angle for each site.

class Site(object):
def __init__(self, name, latlon):
self.name   = name
self.latdeg = latlon[0]
self.londeg = latlon[1]

info  = (('Goldstone', (35.426667, -116.89)), ('Madrid', (40.429167, -4.249167)),
('Canbera', (-35.401389, 148.981667)))

import numpy as np
import matplotlib.pyplot as plt
from skyfield.api import Topos, Loader, EarthSatellite

halfpi, pi, twopi = [f*np.pi for f in (0.5, 1, 2)]

earth   = data['earth']
mars    = data['mars']

print earth.at(ts.now()).position.km   # for no reason at all

hours    = np.linspace(0, 24, 24*12+1)  # 24 hours in 5 minute steps
days     = np.arange(0, 367, 2)

sites = [Site(*thing) for thing in info]
names = [site.name for site in sites]

for site in sites:
site.topo = earth + Topos(longitude_degrees=site.londeg,
latitude_degrees =site.latdeg )

pairs     = [(sites[i%3], sites[(i+1)%3]) for i in range(3)]
pairnames = [(s0.name, s1.name) for (s0, s1) in pairs]

big_okays = []
big_elevs = []
for day in days:
time     = ts.utc(2018, 1, day, hours)   # 2018-12-6

elevs = []
for site in sites:
site.topo = earth + Topos(longitude_degrees=site.londeg,
latitude_degrees =site.latdeg )
alt, az, dist  = site.topo.at(time).observe(mars).apparent().altaz()
elevs.append(np.maximum(0, site.elevation))
big_elevs.append(elevs)

okays = []
for s0, s1 in pairs:
okays.append(ok)

big_okays.append(okays)

big_okays = np.array(big_okays)
new_okays = np.moveaxis(big_okays, 1, 0)

big_elevs = np.array(big_elevs)
new_elevs = np.moveaxis(big_elevs, 1, 0)

if True:
xlims = [hours[0], hours[-1]]
ylims = [days[0],  days[-1]]
ylims = [days[-1],  days[0]]
extent = sum([xlims, ylims], [])
plt.figure()
for i, (ok, pnames) in enumerate(zip(new_okays, pairnames)):
plt.subplot(3, 1, i+1)
plt.imshow(ok, origin='upper', extent=extent, aspect=1./25)
title = '{}-{}'.format(*pnames)
plt.title(title, fontsize=16)
if i == 2:
plt.xlabel('hours', fontsize=16)
plt.ylabel('days', fontsize=16)
plt.suptitle('DSN two-sites Mars both elevs > 10deg', fontsize=16)
plt.show()

if True:
xlims  = [hours[0], hours[-1]]
ylims  = [days[0],  days[-1]]
ylims  = [days[-1],  days[0]]
extent = sum([xlims, ylims], [])
levels = [20, 40, 60, 80]
plt.figure()
for i, (elev, name) in enumerate(zip(new_elevs, names)):
plt.subplot(3, 1, i+1)
plt.imshow(degs*elev, origin='upper', extent=extent,
vmin=0, vmax=90, aspect=1./25)
plt.colorbar()
plt.contour(degs*elev, levels=levels, extent=extent,
origin='upper', colors='k', aspect=1./25)
title = '{}'.format(name)
plt.title(title, fontsize=16)
if i == 2:
plt.xlabel('hours', fontsize=16)
plt.ylabel('days', fontsize=16)
plt.suptitle('DSN elevation of Mars (degs), \n levels = 20, 40, 60, 80',
fontsize=16)
plt.show()

• The graphs look much better now with 24 hours and 365 days axis scales. Thanks a lot! – Uwe Dec 6 '18 at 13:58
• @Uwe thanks! I just found out how to do it stackoverflow.com/q/53647191/3904031 – uhoh Dec 6 '18 at 13:59
• May I use and modify these skripts to see how it looks over a marsian year or the full time interval until Mars and Earth return to the same constellation? – Uwe Dec 7 '18 at 11:14
• @Uwe yes please do, I would be extremely happy if someone used something I posted ;-) ping me here or in chat if any questions. It's faster if you don't use as many steps in days and hours. Skyfield is pure python and each point in time costs a lot right now. For developing, use smaller time arrays, it makes it a lot faster. – uhoh Dec 7 '18 at 11:19