{ "cells": [ { "cell_type": "markdown", "metadata": {}, "source": [ "# Tutorial 21: Ground Segment and CCSDS\n", "\n", "This tutorial explains how to format spacecraft telemetry using the CCSDS (Consultative Committee for Space Data Systems) standard for ground-to-satellite communication.\n", "\n", "## 1. CCSDS Space Packet\n", "Every CCSDS Space Packet consists of a 6-byte Primary Header followed by the Packet Data Field. The header defines the Application Process ID (APID), packet type, sequence flags, and sequence count." ] }, { "cell_type": "code", "execution_count": 7, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "Full Packet (hex): 0123c02a00074121999a41a1999a\n", "Header (hex): 0123c02a0007\n", "Total Packet Length: 14 bytes\n" ] } ], "source": [ "from opengnc.ground_segment.ccsds import SpacePacket, PacketType, SequenceFlags\n", "import numpy as np\n", "\n", "# 1. Create a Space Packet\n", "# APID: 0x123 (291), Sequence Count: 42\n", "packet = SpacePacket(\n", " apid=0x123, \n", " packet_type=PacketType.TELEMETRY, \n", " seq_count=42\n", ")\n", "\n", "# 2. Append some payload data (two float32 values)\n", "# CCSDS standards use Big-Endian (Network Byte Order)\n", "payload = np.array([10.1, 20.2], dtype='>f4').tobytes()\n", "packet.data = payload\n", "\n", "# 3. Pack the full packet to binary\n", "raw_bytes = packet.pack()\n", "print(f\"Full Packet (hex): {raw_bytes.hex()}\")\n", "print(f\"Header (hex): {raw_bytes[:6].hex()}\")\n", "print(f\"Total Packet Length: {len(raw_bytes)} bytes\")" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## 2. Telemetry Decommutation\n", "The `decom` module handles extracting fields from binary telemetry streams based on a parameter map. We use the `DecomEngine` to convert the raw octets back into engineering units." ] }, { "cell_type": "code", "execution_count": 8, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "Decommutated Telemetry (Big-Endian): {'voltage': 10.100000381469727, 'current': 20.200000762939453}\n", "Measured Voltage: 10.10 V\n", "Measured Current: 20.20 A\n" ] } ], "source": [ "from opengnc.ground_segment.decom import DecomEngine\n", "\n", "# Define the structure of the data inside the CCSDS packet data field\n", "# 'f' corresponds to a 32-bit float (4 bytes)\n", "parameter_config = [\n", " {\"name\": \"voltage\", \"data_type\": \"f\", \"offset\": 0, \"scale\": 1.0},\n", " {\"name\": \"current\", \"data_type\": \"f\", \"offset\": 4, \"scale\": 1.0}\n", "]\n", "\n", "# Initialize the DecomEngine\n", "engine = DecomEngine.from_dict(parameter_config)\n", "\n", "# Extract data from the packed bytes (skipping the 6-byte CCSDS header)\n", "data_field = raw_bytes[6:]\n", "results = engine.decommutate(data_field)\n", "\n", "print(f\"Decommutated Telemetry (Big-Endian): {results}\")\n", "print(f\"Measured Voltage: {results['voltage']:.2f} V\")\n", "print(f\"Measured Current: {results['current']:.2f} A\")" ] } ], "metadata": { "kernelspec": { "display_name": "Python 3", "language": "python", "name": "python3" }, "language_info": { "codemirror_mode": { "name": "ipython", "version": 3 }, "file_extension": ".py", "mimetype": "text/x-python", "name": "python", "nbconvert_exporter": "python", "pygments_lexer": "ipython3", "version": "3.10.11" } }, "nbformat": 4, "nbformat_minor": 4 }