Newer
Older
""" NASA EOS mission specific data
References:
1. MODIS Command, Telemetry, Science and Engineering Description,
Document Number 151840, May 1997, Appendix C
https://directreadout.sci.gsfc.nasa.gov/documents/satellite_gen/MODIS_UG.pdf
"""
from typing import Union
from enum import Enum
from dataclasses import dataclass
class PktType(Enum):
Day = 0
Night = 1
Eng1 = 2
Eng2 = 3
class CalType(Enum):
SD = 0
SRCA = 1
BB = 2
Space = 3
class CalMode(Enum):
Radiometric = 0
Spatial = 1
Spectral = 2
NonCal = 3
@dataclass
class CalSource:
type: CalType
mode: CalMode
frame_count: int
@dataclass
class EarthSource:
frame_count: int
packets_per_scan = {
"day": 3032,
"night": 326,
}
def _caltype(p):
v = p.data[0] >> 5 & 0x3
if v > 3:
return None
return CalType(v)
def _calmode(p):
v = p.data[0] >> 3 & 0x3
if v > 3:
return None
return CalMode(v)
return (bytes(p.secondary_header)[8] & 0x1) + 1
def _pkttype(p):
v = bytes(p.secondary_header)[8] >> 4 & 0x7
if v > 3:
return None
return PktType(v)
x = int.from_bytes(b"\x00\x00" + p.data[:2], "big")
return x >> 4 & 0x3F
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
def _earth_frame_count(p):
x = int.from_bytes(b"\x00\x00" + p.data[:2], "big")
return x >> 4 & 0x7FF
@dataclass
class Info:
type: str
packet_type: PktType
mirror_side: int
scancount: int
source: Union[EarthSource, CalSource]
def info(p):
tp = _pkttype(p)
source = None
type = "engr"
if tp in (PktType.Day, PktType.Night):
if p.data[0] & 0b10000000 == 0:
type = "earthdata"
source = EarthSource(frame_count=_earth_frame_count(p))
else:
type = "cal"
source = CalSource(
type=_caltype(p),
mode=_calmode(p),
frame_count=_earth_frame_count(p),
)
return Info(type, tp, _mirrorside(p), _scancount(p), source)
"""Return a tuple that will maintain order for this packet in a stream of
MODIS data. Intended to be used as a key func for sorting.
Packets are sorted in the order defined in _sort_indexes.
"""
frame_sort = 0
i = info(p)
if i.type == "earthdata":
type_idx = 5
frame_sort = i.source.frame_count
elif i.type == "cal":
type_idx = i.source.type.value
frame_sort = i.source.frame_count
else:
type_idx = 6 if i.type == PktType.Eng1 else 7
return (p.stamp, 64, type_idx, frame_sort, int(p.is_last()))