satdump/plugins/metopsg_support/metopsg/module_metopsg_instruments.cpp
2025-11-21 22:04:51 +01:00

365 lines
No EOL
15 KiB
C++

#include "module_metopsg_instruments.h"
#include "common/calibration.h"
#include "common/ccsds/ccsds_aos/demuxer.h"
#include "common/ccsds/ccsds_aos/vcdu.h"
#include "common/repack.h"
#include "common/tracking/tle.h"
#include "common/utils.h"
#include "core/resources.h"
#include "image/bowtie.h"
#include "image/image.h"
#include "image/io.h"
#include "image/processing.h"
#include "imgui/imgui.h"
#include "init.h"
#include "logger.h"
#include "metopsg.h"
#include "nlohmann/json_utils.h"
#include "products/image/channel_transform.h"
#include "utils/stats.h"
#include <filesystem>
#include <fstream>
#include <string>
#include "products/dataset.h"
#include "products/image_product.h"
#include "products/punctiform_product.h"
namespace metopsg
{
namespace instruments
{
MetOpSGInstrumentsDecoderModule::MetOpSGInstrumentsDecoderModule(std::string input_file, std::string output_file_hint, nlohmann::json parameters)
: satdump::pipeline::base::FileStreamToFileStreamModule(input_file, output_file_hint, parameters)
{
ignore_integrated_tle = parameters.contains("ignore_integrated_tle") ? parameters["ignore_integrated_tle"].get<bool>() : false;
metimage_bowtie = parameters.contains("metimage_bowtie") ? parameters["metimage_bowtie"].get<bool>() : false;
fsfsm_enable_output = false;
}
void MetOpSGInstrumentsDecoderModule::process()
{
uint8_t cadu[1024];
// 3-MI TODOREWORK
{
std::string directory = d_output_file_hint.substr(0, d_output_file_hint.rfind('/')) + "/3MI";
if (!std::filesystem::exists(directory))
std::filesystem::create_directories(directory);
threemi_reader.directory = directory;
}
// Demuxers
ccsds::ccsds_aos::Demuxer demuxer_vcid9(884, false);
ccsds::ccsds_aos::Demuxer demuxer_vcid10(884, false);
ccsds::ccsds_aos::Demuxer demuxer_vcid13(884, false);
ccsds::ccsds_aos::Demuxer demuxer_vcid14(884, false);
ccsds::ccsds_aos::Demuxer demuxer_vcid15(884, false);
ccsds::ccsds_aos::Demuxer demuxer_vcid16(884, false);
// Setup Admin Message
{
std::string directory = d_output_file_hint.substr(0, d_output_file_hint.rfind('/')) + "/Admin Messages";
if (!std::filesystem::exists(directory))
std::filesystem::create_directory(directory);
admin_msg_reader.directory = directory;
}
std::vector<uint8_t> metop_scids;
while (should_run())
{
// Read buffer
read_data(cadu, 1024);
// Parse this transport frame
ccsds::ccsds_aos::VCDU vcdu = ccsds::ccsds_aos::parseVCDU(cadu);
if (vcdu.spacecraft_id == METOPSG_A1_SCID || vcdu.spacecraft_id == METOPSG_A2_SCID || vcdu.spacecraft_id == METOPSG_A3_SCID || //
vcdu.spacecraft_id == METOPSG_B1_SCID || vcdu.spacecraft_id == METOPSG_B2_SCID || vcdu.spacecraft_id == METOPSG_B3_SCID)
metop_scids.push_back(vcdu.spacecraft_id);
if (vcdu.vcid == 9) // NAVATT
{
std::vector<ccsds::CCSDSPacket> ccsdsFrames = demuxer_vcid9.work(cadu);
// for (ccsds::CCSDSPacket &pkt : ccsdsFrames)
// logger->critical("APID %d LEN %d", pkt.header.apid, pkt.payload.size() + 6);
}
else if (vcdu.vcid == 13) // MWS
{
std::vector<ccsds::CCSDSPacket> ccsdsFrames = demuxer_vcid13.work(cadu);
for (ccsds::CCSDSPacket &pkt : ccsdsFrames)
mws_reader.work(pkt);
}
else if (vcdu.vcid == 14) // 3-MI
{
std::vector<ccsds::CCSDSPacket> ccsdsFrames = demuxer_vcid14.work(cadu);
for (ccsds::CCSDSPacket &pkt : ccsdsFrames)
threemi_reader.work(pkt);
}
else if (vcdu.vcid == 15) // Sentinel-5
{
std::vector<ccsds::CCSDSPacket> ccsdsFrames = demuxer_vcid15.work(cadu);
for (ccsds::CCSDSPacket &pkt : ccsdsFrames)
sentinel5_reader.work(pkt);
}
else if (vcdu.vcid == 16) // METimage
{
std::vector<ccsds::CCSDSPacket> ccsdsFrames = demuxer_vcid16.work(cadu);
for (ccsds::CCSDSPacket &pkt : ccsdsFrames)
metimage_reader.work(pkt);
}
else if (vcdu.vcid == 10) // Admin Messages
{
std::vector<ccsds::CCSDSPacket> ccsdsFrames = demuxer_vcid10.work(cadu);
for (ccsds::CCSDSPacket &pkt : ccsdsFrames)
if (pkt.header.apid == 577)
admin_msg_reader.work(pkt);
}
}
cleanup();
int scid = satdump::most_common(metop_scids.begin(), metop_scids.end(), 0);
metop_scids.clear();
std::string sat_name = "Unknown MetOp-SG";
if (scid == METOPSG_A1_SCID)
sat_name = "MetOp-SG-A1";
else if (scid == METOPSG_A2_SCID)
sat_name = "MetOp-SG-A2";
else if (scid == METOPSG_A3_SCID)
sat_name = "MetOp-SG-A3";
else if (scid == METOPSG_B1_SCID)
sat_name = "MetOp-SG-B1";
else if (scid == METOPSG_B2_SCID)
sat_name = "MetOp-SG-B2";
else if (scid == METOPSG_B3_SCID)
sat_name = "MetOp-SG-B3";
int norad = 0;
if (scid == METOPSG_A1_SCID)
norad = METOPSG_A1_NORAD;
else if (scid == METOPSG_A2_SCID)
norad = METOPSG_A2_NORAD;
else if (scid == METOPSG_A3_SCID)
norad = METOPSG_A3_NORAD;
else if (scid == METOPSG_B1_SCID)
norad = METOPSG_B1_NORAD;
else if (scid == METOPSG_B2_SCID)
norad = METOPSG_B2_NORAD;
else if (scid == METOPSG_B3_SCID)
norad = METOPSG_B3_NORAD;
// Products dataset
satdump::products::DataSet dataset;
dataset.satellite_name = sat_name;
dataset.timestamp = satdump::get_median(metimage_reader.timestamps);
std::optional<satdump::TLE> satellite_tle; // TODOREWORK = admin_msg_reader.tles.get_from_norad(norad);
if (!satellite_tle.has_value() || ignore_integrated_tle)
satellite_tle = satdump::db_tle->get_from_norad_time(norad, dataset.timestamp);
// Satellite ID
{
logger->info("----------- Satellite");
logger->info("NORAD : " + std::to_string(norad));
logger->info("Name : " + sat_name);
}
// Sentinel-5
{
sentinel5_status = SAVING;
std::string directory = d_output_file_hint.substr(0, d_output_file_hint.rfind('/')) + "/Sentinel-5";
if (!std::filesystem::exists(directory))
std::filesystem::create_directory(directory);
logger->info("----------- Sentinel-5");
for (int i = 0; i < sentinel5_reader.nchannels; i++)
{
std::string name = "num_" + std::to_string(i + 1);
auto img = sentinel5_reader.getChannel(i, name);
image::save_png(img, directory + "/" + name + ".png");
}
dataset.products_list.push_back("Sentinel-5");
sentinel5_status = DONE;
}
// MWS
{
mws_status = SAVING;
std::string directory = d_output_file_hint.substr(0, d_output_file_hint.rfind('/')) + "/MWS";
if (!std::filesystem::exists(directory))
std::filesystem::create_directory(directory);
mws_reader.correlate();
logger->info("----------- MWS");
logger->info("Lines : " + std::to_string(mws_reader.lines[0])); // TODOREWORK
satdump::products::ImageProduct mws_products;
mws_products.instrument_name = "metopsg_mws";
mws_products.set_proj_cfg_tle_timestamps(loadJsonFile(resources::getResourcePath("projections_settings/metopsg_a_mws.json")), satellite_tle, mws_reader.timestamps[0]);
for (int i = 0; i < 24; i++)
{
mws_products.images.push_back({i, "MWS-" + std::to_string(i + 1), std::to_string(i + 1), mws_reader.getChannel(i), 16, //
i < 2 ? satdump::ChannelTransform().init_none() : satdump::ChannelTransform().init_affine(16, 1, 0, 0)});
// mws_products.set_channel_unit(i, i < 3 ? CALIBRATION_ID_REFLECTIVE_RADIANCE : CALIBRATION_ID_EMISSIVE_RADIANCE);
// mws_products.set_channel_wavenumber(i, calib_coefs[sat_name]["channels"][i]["wavnb"]);
}
mws_products.save(directory);
dataset.products_list.push_back("MWS");
mws_status = DONE;
}
// METimage
{
metimage_status = SAVING;
std::string directory = d_output_file_hint.substr(0, d_output_file_hint.rfind('/')) + "/METimage";
if (!std::filesystem::exists(directory))
std::filesystem::create_directory(directory);
logger->info("----------- METimage");
logger->info("Segments : " + std::to_string(metimage_reader.segments)); // TODOREWORK
satdump::products::ImageProduct metimage_products;
metimage_products.instrument_name = "metimage";
metimage_products.set_proj_cfg_tle_timestamps(loadJsonFile(resources::getResourcePath("projections_settings/metopsg_a_metimage.json")), satellite_tle, metimage_reader.timestamps);
const float ch_offsets[20] = {
0, //
-6, //
-15, //
-23, //
-34, //
-26, //
-35, //
-26, //
-23, //
-24, //
-21, //
-16, //
-12, //
-8, //
0, // TODO
-18, //
-24, //
0, // TODO
-28, //
0, // TODO
};
// BowTie values
const float alpha = 1.0 / 1.8;
const float beta = 0.58333;
const long scanHeight_500 = 24;
for (int i = 0; i < 20; i++)
{
int vii = metimage_reader.out_ch_n[i];
auto img = metimage_reader.getChannel(i);
if (metimage_bowtie)
img = image::bowtie::correctGenericBowTie(img, 1, scanHeight_500, alpha, beta);
metimage_products.images.push_back({i, "METimage-" + std::to_string(vii), std::to_string(vii), img, 16, //
satdump::ChannelTransform().init_affine(1, 1, ch_offsets[i], 0)});
// mws_products.set_channel_unit(i, i < 3 ? CALIBRATION_ID_REFLECTIVE_RADIANCE : CALIBRATION_ID_EMISSIVE_RADIANCE);
// mws_products.set_channel_wavenumber(i, calib_coefs[sat_name]["channels"][i]["wavnb"]);
}
metimage_products.set_proj_cfg_tle_timestamps(loadJsonFile(resources::getResourcePath("projections_settings/metopsg_a_metimage.json")), satellite_tle, metimage_reader.timestamps);
metimage_products.save(directory);
dataset.products_list.push_back("METimage");
metimage_status = DONE;
}
// Admin Messages
{
admin_msg_status = DONE;
logger->info("----------- Admin Message");
logger->info("Count : " + std::to_string(admin_msg_reader.count));
}
dataset.save(d_output_file_hint.substr(0, d_output_file_hint.rfind('/')));
}
void MetOpSGInstrumentsDecoderModule::drawUI(bool window)
{
ImGui::Begin("MetOp-SG Instruments Decoder", NULL, window ? 0 : NOWINDOW_FLAGS);
if (ImGui::BeginTable("##metopsginstrumentstable", 3, ImGuiTableFlags_Borders | ImGuiTableFlags_RowBg))
{
ImGui::TableNextRow();
ImGui::TableSetColumnIndex(0);
ImGui::Text("Instrument");
ImGui::TableSetColumnIndex(1);
ImGui::Text("Lines / Frames");
ImGui::TableSetColumnIndex(2);
ImGui::Text("Status");
ImGui::TableNextRow();
ImGui::TableSetColumnIndex(0);
ImGui::Text("METimage");
ImGui::TableSetColumnIndex(1);
ImGui::TextColored(style::theme.green, "%d", metimage_reader.segments);
ImGui::TableSetColumnIndex(2);
drawStatus(metimage_status);
ImGui::TableNextRow();
ImGui::TableSetColumnIndex(0);
ImGui::Text("MWS");
ImGui::TableSetColumnIndex(1);
ImGui::TextColored(style::theme.green, "%d", mws_reader.lines[0]);
ImGui::TableSetColumnIndex(2);
drawStatus(mws_status);
ImGui::TableNextRow();
ImGui::TableSetColumnIndex(0);
ImGui::Text("3MI");
ImGui::TableSetColumnIndex(1);
ImGui::TextColored(style::theme.green, "%d", threemi_reader.img_n);
ImGui::TableSetColumnIndex(2);
drawStatus(threemi_status);
ImGui::TableNextRow();
ImGui::TableSetColumnIndex(0);
ImGui::Text("Sentinel-5");
ImGui::TableSetColumnIndex(1);
ImGui::TextColored(style::theme.green, "%d", sentinel5_reader.total_packets);
ImGui::TableSetColumnIndex(2);
drawStatus(sentinel5_status);
ImGui::TableNextRow();
ImGui::TableSetColumnIndex(0);
ImGui::Text("Admin Messages");
ImGui::TableSetColumnIndex(1);
ImGui::TextColored(style::theme.green, "%d", admin_msg_reader.count);
ImGui::TableSetColumnIndex(2);
drawStatus(admin_msg_status);
ImGui::EndTable();
}
drawProgressBar();
ImGui::End();
}
std::string MetOpSGInstrumentsDecoderModule::getID() { return "metopsg_instruments"; }
std::shared_ptr<satdump::pipeline::ProcessingModule> MetOpSGInstrumentsDecoderModule::getInstance(std::string input_file, std::string output_file_hint, nlohmann::json parameters)
{
return std::make_shared<MetOpSGInstrumentsDecoderModule>(input_file, output_file_hint, parameters);
}
} // namespace instruments
} // namespace metopsg