<jupyter_start><jupyter_text>DescriptionThis Notebook provides an example of using the EDC API to request laser ranging data. It is adapted from the examples at https://edc.dgfi.tum.de/en/api/doc/python/ . Configuring the account to use laser ranging data from the EDC TUM service. You need an account, it can be created for free at https://edc.dgfi.tum.de/en/register/.<jupyter_code>from getpass import getpass
url = 'https://edc.dgfi.tum.de/api/v1/'
username = 'jonglez' # Modify with your own username
password = getpass(prompt='Enter EDC API password for account {}'.format(username)) # You will get prompted for your password<jupyter_output>Enter EDC API password for account jonglez ·······<jupyter_text>Listing the satellites available in the service<jupyter_code>import requests
import json

args = {}
""" required options """
args['username'] = username
args['password'] = password
args['action'] = 'list-satellites'

""" optional options """
args['status'] = 'present'

""" send request as method POST """
response = requests.post(url, data=args)

if response.status_code == 200:
	""" convert json string in python list """
	data = json.loads(response.text)
	print(json.dumps(data, indent=4, sort_keys=True))
else:
	print(response.status_code)
	print(response.text)<jupyter_output>[
    {
        "bin_size": null,
        "ext": "a11",
        "norad_number": null,
        "np_indicator": "2",
        "satellite_id": "0000100",
        "satellite_name": "apollo11",
        "sic_code": "0100",
        "status": "present"
    },
    {
        "bin_size": null,
        "ext": "l17",
        "norad_number": null,
        "np_indicator": "2",
        "satellite_id": "0000101",
        "satellite_name": "luna17",
        "sic_code": "0101",
        "status": "present"
    },
    {
        "bin_size": null,
        "ext": "a14",
        "norad_number": null,
        "np_indicator": "2",
        "satellite_id": "0000102",
        "satellite_name": "apollo14",
        "sic_code": "0102",
        "status": "present"
    },
    {
        "bin_size": null,
        "ext": "a15",
        "norad_number": null,
        "np_indicator": "2",
        "satellite_id": "0000103",
        "satellite_name": "apollo15",
        "sic_code": "0103",
        "status": "present"
    },
    [...]<jupyter_text>Getting information about Technosat, which bears the COSPAR ID 1704205. See the available satellites at https://edc.dgfi.tum.de/en/satellites/, or in the JSON list printed above.<jupyter_code>cosparId = '1704205' 

args = {}
""" required options """
args['username'] = username
args['password'] = password
args['action'] = 'satellite-info'

""" optional options """
args['satellite_id'] = cosparId
#args['satellite_name'] = 'technosat'

""" send request as method POST """
response = requests.post(url, data=args)

if response.status_code == 200:
	""" convert json string in python list """
	data = json.loads(response.text)	
	for key in data.keys():
		print(key,':',data[key])
else:
	print(response.status_code)
	print(response.text)<jupyter_output>status : present
np_indicator : 3
satellite_name : technosat
end_date : None
bin_size : 15
nice_name : Technosat
start_date : None
satellite_id : 1704205
ext : tec
launch_date : 2017-07-14
sic_code : 6203
norad_number : 42829
decay_date : None<jupyter_text>Listing the ground stations.<jupyter_code>args = {}
""" required options """
args['username'] = username
args['password'] = password
args['action'] = 'list-stations'

""" optional options """
args['active'] = 'yes'

""" send request as method POST """
response = requests.post(url, data=args)

if response.status_code == 200:
	""" convert json string in python list """
	data = json.loads(response.text)
	print(json.dumps(data, indent=4, sort_keys=True))
else:
	print(response.status_code)
	print(response.text)<jupyter_output>[
    {
        "active": "yes",
        "code": "GLSL",
        "datacenter": "EDC",
        "latitude": "50.3633",
        "longitude": "30.4961",
        "site": "Golosiiv, Ukraine",
        "station_id": "1824"
    },
    {
        "active": "yes",
        "code": "MAIL",
        "datacenter": "EDC",
        "latitude": "38.6849",
        "longitude": "66.94309",
        "site": "Maidanak 1, Uzbekistan",
        "station_id": "1864"
    },
    {
        "active": "yes",
        "code": "KOML",
        "datacenter": "EDC",
        "latitude": "50.69461",
        "longitude": "136.74383",
        "site": "Komsomolsk-na-Amure, Russia",
        "station_id": "1868"
    },
    {
        "active": "yes",
        "code": "SIML",
        "datacenter": "EDC",
        "latitude": "44.4128",
        "longitude": "33.9931",
        "site": "Simeiz, Ukraine",
        "station_id": "1873"
    },
    {
        "active": "yes",
        "code": "MDVS",
        "datacenter": "EDC",
        "latitude[...]<jupyter_text>Getting detailed information about a ground station<jupyter_code>args = {}
""" required options """
args['username'] = username
args['password'] = password
args['action'] = 'station-info'
args['station_id'] = '7080'

""" send request as method POST """
response = requests.post(url, data=args)

if response.status_code == 200:
	""" convert json string in python list """
	data = json.loads(response.text)	
	for key in data.keys():
		print(key,':',data[key])
else:
	print(response.status_code)
	print(response.text)<jupyter_output>datacenter : CDDIS
code : MDOL
longitude : 255.9848
site : McDonald Observatory, Texas
station_id : 7080
latitude : 30.6802
secondary_name : <NAME>
primary_name : <NAME>
secondary_mail : <EMAIL>
primary_mail : <EMAIL>
active : yes<jupyter_text>Searching for datasets corresponding to the user criteria, from December 1st 2018 to December 9th 2018. In this case, the Normal Point Data (NPT) is requested. More information on the different data formats for laser ranging: https://edc.dgfi.tum.de/en/data/<jupyter_code>args = {}
""" required options """
args['username'] = username
args['password'] = password
args['action'] = 'data-query'
args['data_type'] = 'NPT' # Normal pointing data

""" optional options """
args['start_data_date'] = '2018-12-0%'
args['end_data_date'] = '2018-12-0%'
args['satellite'] = cosparId
#args['provider'] = 'COD'
#args['station'] = '78403501'

""" send request as method POST """
response = requests.post(url, data=args)

if response.status_code == 200:
	""" convert json string in python list """
	data = json.loads(response.text)
	print(json.dumps(data, indent=4, sort_keys=True))
else:
	print(response.status_code)
	print(response.text)<jupyter_output>[
    {
        "end_data_date": "2018-12-01 12:39:55",
        "errors": "",
        "id": "1790842",
        "incoming_date": "2018-12-02 23:24:34",
        "incoming_filename": "7825_technosat_20181201_12_00.NPT",
        "observations": "6",
        "satellite": "1704205",
        "start_data_date": "2018-12-01 12:35:00",
        "station": "78259001",
        "status": "valid",
        "version": "00",
        "wavelength": "532.10"
    },
    {
        "end_data_date": "2018-12-01 13:53:35",
        "errors": "",
        "id": "1790375",
        "incoming_date": "2018-12-01 14:02:16",
        "incoming_filename": "7237_technosat_crd_20181201_13_00.npt",
        "observations": "7",
        "satellite": "1704205",
        "start_data_date": "2018-12-01 13:51:00",
        "station": "72371901",
        "status": "valid",
        "version": "00",
        "wavelength": "532.000"
    },
    {
        "end_data_date": "2018-12-01 14:12:12",
        "errors": "",
        "id": "1790437"[...]<jupyter_text>Getting more information about a specific dataset<jupyter_code>args = {}
""" required options """
args['username'] = username
args['password'] = password
args['action'] = 'data-info'
args['id'] = '1790842' # The first returned dataset from the query above
args['data_type'] = 'NPT'

""" send request as method POST """
response = requests.post(url, data=args)

if response.status_code == 200:
	""" convert json string in python list """
	data = json.loads(response.text)	
	for key in data.keys():
		print(key,':',data[key])
else:
	print(response.status_code)
	print(response.text)<jupyter_output>status : valid
satellite : 1704205
errors : 
version : 00
incoming_date : 2018-12-02 23:24:34
start_data_date : 2018-12-01 12:35:00
end_data_date : 2018-12-01 12:39:55
incoming_filename : 7825_technosat_20181201_12_00.NPT
station : 78259001
observations : 6
wavelength : 532.10
id : 1790842<jupyter_text>Downloading the dataset.References for the CRD NPT format: * https://ilrs.cddis.eosdis.nasa.gov/data_and_products/data/npt/index.html* https://ilrs.cddis.eosdis.nasa.gov/docs/2018/crd_v2.00h-4e.pdf<jupyter_code>args = {}
""" required options """
args['username'] = username
args['password'] = password
args['action'] = 'data-download'
args['id'] = '1790842'
args['data_type'] = 'NPT'

""" send request as method POST """
response = requests.post(url, data=args)

if response.status_code == 200:
	""" convert json string in python list """
	data = json.loads(response.text)
	print(json.dumps(data, indent=4, sort_keys=True))
else:
	print(response.status_code)
	print(response.text)<jupyter_output>[
    "H1 CRD  1 2018 12 02 04",
    "H2 STL3       7825 90 01  4",
    "H3 technosat   1704205 6203   042829 0 1",
    "H4  1 2018 12 01 12 35 00 2018 12 01 12 39 55  0 0 0 0 1 0 2 0",
    "C0 0 532.10 IDAA IDAB IDAJ IDAV",
    "C1 0 IDAB Nd-YAG 1064.00 0.00 20.00 12.0 0.00 1",
    "C2 0 IDAJ CSPAD 532.00 20.00 11.0 100.0 ECL 12.0 2.00 90.0 0.1 Manual",
    "C3 0 IDAV TrueTime_XLi TrueTime_OCXO MRCS NA 0.2322",
    "20 45304.419250999999 918.05 293.13 24.1 0",
    "20 45331.103251000000 918.05 293.13 24.1 0",
    "20 45355.130234999997 918.05 293.09 24.5 0",
    "20 45384.537235000003 918.05 293.04 24.6 0",
    "20 45405.072235000000 918.06 293.00 24.7 0",
    "20 45425.072235000000 918.06 292.97 24.7 0",
    "20 45445.074235000000 918.06 292.96 24.8 0",
    "20 45465.074235000000 918.06 292.94 24.8 0",
    "20 45485.075234999997 918.05 292.93 24.6 0",
    "20 45505.076235000000 918.05 292.91 24.8 0",
    "20 45532.685234999997 918.06 292.90 24.9 0",
    "20 45554.432235000000 918.05 [...]<jupyter_text>In the example dataset above, we can see information headers about the satellite and the ground station (H1 to H4), then configuration data for the laser system (C0 to C3), and then several data fields:* 20: meteorological record. It can be used to model the laser propagation in the atmosphere (delay, attenuation, etc.)* 40: calibration record* 11: normal point range data* 50: session statistics recordMore details about the normal point data:* The second field (ex: 45503.67) is the measurement time, given in seconds of day* The third field is the time-of-flight ($TOF$). This value directly gives the satellite range $r$ by multiplying by the speed of light $c$: $r = c * TOF / 2$ * The fifth field is the type of epoch event. It tells how is the measurement time defined:    * 1: at spacecraft bounce time    * 2: at ground transmit time (the most common)The following below browses the data file and prints the measurement time and satellite range.<jupyter_code>c = 299792458 # m/s

currentLine = ''
i = 0
n = len(data)

while (not currentLine.startswith('H4')) and i < n: # Reading lines until the H4 header
    currentLine = data[i]
    i += 1
    
lineData = currentLine.split() # Reading day in H4 header
y = int(lineData[2])
m = int(lineData[3])
d = int(lineData[4])
from datetime import datetime
from datetime import timedelta
measurementDay = datetime(y, m, d)

while (not currentLine.startswith('11')) and i < n: # Reading lines until the start of normal point data
    currentLine = data[i]
    i += 1

while currentLine.startswith('11') and i < n: # Reading until the end of normal point data
    lineData = currentLine.split()
    timeOfDay = float(lineData[1])
    timeOfFlight = float(lineData[2])
    timestampType = int(lineData[4])
    
    r = c * timeOfFlight / 2
    
    if timestampType == 1:
        transmitTime = measurementDay + timedelta(seconds=(timeOfDay - timeOfFlight/2))
    else:
        transmitTime = measurementDay + timedelta(seconds=timeOfDay)
            
    bounceTime = transmitTime + timedelta(seconds=timeOfFlight/2)
    receiveTime = bounceTime + timedelta(seconds=timeOfFlight/2)
    
    print('Transmit time: {}, receive time: {}'.format(transmitTime, receiveTime))
    print('Time of flight: {} milliseconds, satellite range: {} kilometers'.format(timeOfFlight*1000, r/1000))
    print('')
    
    currentLine = data[i]
    i += 1<jupyter_output>Transmit time: 2018-12-01 12:38:23.671869, receive time: 2018-12-01 12:38:23.678335
Time of flight: 6.465817421 milliseconds, satellite range: 969.2016488104053 kilometers

Transmit time: 2018-12-01 12:38:36.688536, receive time: 2018-12-01 12:38:36.695476
Time of flight: 6.940238973 milliseconds, satellite range: 1040.3156504115327 kilometers

Transmit time: 2018-12-01 12:38:48.888536, receive time: 2018-12-01 12:38:48.895942
Time of flight: 7.40570114 milliseconds, satellite range: 1110.0866739870012 kilometers

Transmit time: 2018-12-01 12:39:06.638536, receive time: 2018-12-01 12:39:06.646648
Time of flight: 8.111399748 milliseconds, satellite range: 1215.8682341367505 kilometers

Transmit time: 2018-12-01 12:39:21.621869, receive time: 2018-12-01 12:39:21.630597
Time of flight: 8.727827808999999 milliseconds, satellite range: 1308.268475930432 kilometers

Transmit time: 2018-12-01 12:39:37.171869, receive time: 2018-12-01 12:39:37.181253
Time of flight: 9.383209968 milliseconds, s[...]
{'fraction_non_alphanumeric': 0.1430983847283407, 'fraction_numerical': 0.11328928046989721, 'mean_word_length': 3.6266983695652173, 'pattern_counts': {'":': 90, '<': 35, '<?xml version=': 0, '>': 32, 'https://': 7, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 2, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'chain_length': '9', 'dir': 'jupyter-structured-clean-dedup', 'id': '292370', 'license': 'Apache-2.0', 'n_tokens_mistral': 5787, 'n_tokens_neox': 4657, 'n_words': 1258, 'path': '01-EDC-API-example.ipynb', 'repo_name': 'GorgiAstro/laser-orbit-determination', 'size': '13653'}