mirror of
https://github.com/SatDump/SatDump
synced 2026-08-13 17:47:30 -04:00
256 lines
No EOL
12 KiB
C++
256 lines
No EOL
12 KiB
C++
#pragma once
|
|
|
|
/**
|
|
* @file calib.h
|
|
* @brief Generic xRIT calibration parsing
|
|
*/
|
|
|
|
#include "logger.h"
|
|
#include "products/image_product.h"
|
|
#include "utils/string.h"
|
|
#include "xrit/xrit_file.h"
|
|
|
|
namespace satdump
|
|
{
|
|
namespace xrit
|
|
{
|
|
/**
|
|
* @brief Most xRIT missions use the standard calibration header. This
|
|
* function parses it to insert calibration information on the channel.
|
|
*
|
|
* TODOREWORK This will most probably get moved over to each, and maybe load up wavelengths from files??
|
|
* Also quite... crappy?
|
|
*
|
|
* @param pro product to work on
|
|
* @param image_data_function_record xRIT calibration header
|
|
* @param channel instrument channel ID
|
|
* @param instrument_id the actual instrument channel ID
|
|
*/
|
|
inline void addCalibrationInfoFunc(satdump::products::ImageProduct &pro, ImageDataFunctionRecord *image_data_function_record, std::string channel, std::string instrument_id)
|
|
{
|
|
if (image_data_function_record)
|
|
{
|
|
if (instrument_id == "goesn_imager" && std::stoi(channel) > 0 && std::stoi(channel) <= 5)
|
|
{
|
|
const float goesn_imager_wavelength_table[5] = {
|
|
630, 3900, 6480, 10700, 13300,
|
|
};
|
|
|
|
pro.set_channel_wavenumber(pro.images.size() - 1, 1e7 / goesn_imager_wavelength_table[std::stoi(channel) - 1]);
|
|
}
|
|
else if (instrument_id == "abi" && channel.find_first_not_of("0123456789") == std::string::npos && std::stoi(channel) > 0 && std::stoi(channel) <= 16)
|
|
{
|
|
const float goes_abi_wavelength_table[16] = {
|
|
470, 640, 860, 1380, 1610, 2260, 3900, 6190, 6950, 7340, 8500, 9610, 10350, 11200, 12300, 13300,
|
|
};
|
|
|
|
pro.set_channel_wavenumber(pro.images.size() - 1, 1e7 / goes_abi_wavelength_table[std::stoi(channel) - 1]);
|
|
}
|
|
else if (instrument_id == "ahi" && std::stoi(channel) > 0 && std::stoi(channel) <= 16)
|
|
{
|
|
const float hima_ahi_wavelength_table[16] = {
|
|
470, 510, 640, 860, 1600, 2300, 3900, 6200, 6900, 7300, 8600, 9600, 10400, 11200, 12400, 13300,
|
|
};
|
|
|
|
pro.set_channel_wavenumber(pro.images.size() - 1, 1e7 / hima_ahi_wavelength_table[std::stoi(channel) - 1]);
|
|
}
|
|
else if (instrument_id == "ami")
|
|
{
|
|
double wavelength_nm = std::stod(channel.substr(2, channel.size() - 1)) * 100;
|
|
pro.set_channel_wavenumber(pro.images.size() - 1, 1e7 / wavelength_nm);
|
|
}
|
|
else
|
|
pro.set_channel_wavenumber(pro.images.size() - 1, -1);
|
|
|
|
// if (instrument_id == "ahi")
|
|
// printf("Channel %s\n%s\n", channel.c_str(), image_data_function_record->datas.c_str());
|
|
|
|
auto lines = splitString(image_data_function_record->datas, '\n');
|
|
if (lines.size() < 4)
|
|
{
|
|
lines = splitString(image_data_function_record->datas, '\r');
|
|
if (lines.size() < 4)
|
|
{
|
|
logger->error("Error parsing calibration info into lines!");
|
|
return;
|
|
}
|
|
}
|
|
|
|
// for (int i = 0; i < lines.size(); i++)
|
|
// logger->critical("%d => %s", i, lines[i].c_str());
|
|
|
|
if (lines[0].find("HALFTONE:=") != std::string::npos)
|
|
{
|
|
// GOES xRIT modes
|
|
if (instrument_id == "goesn_imager" || instrument_id == "abi")
|
|
{
|
|
if (lines[1] == "_NAME:=toa_lambertian_equivalent_albedo_multiplied_by_cosine_solar_zenith_angle")
|
|
{
|
|
std::vector<std::pair<int, float>> lut;
|
|
for (size_t i = 3; i < lines.size(); i++)
|
|
{
|
|
int val;
|
|
float valo;
|
|
if (sscanf(lines[i].c_str(), "%d:=%f", &val, &valo) == 2)
|
|
lut.push_back({val, valo});
|
|
}
|
|
|
|
nlohmann::json calib_cfg = pro.get_calibration_raw();
|
|
|
|
calib_cfg[channel] = lut;
|
|
pro.set_calibration("generic_xrit", calib_cfg);
|
|
pro.set_channel_unit(pro.images.size() - 1, CALIBRATION_ID_ALBEDO);
|
|
}
|
|
else if (lines[1] == "_NAME:=toa_brightness_temperature")
|
|
{
|
|
std::vector<std::pair<int, float>> lut;
|
|
for (size_t i = 3; i < lines.size(); i++)
|
|
{
|
|
int val;
|
|
float valo;
|
|
if (sscanf(lines[i].c_str(), "%d:=%f", &val, &valo) == 2)
|
|
lut.push_back({val, valo});
|
|
}
|
|
|
|
nlohmann::json calib_cfg = pro.get_calibration_raw();
|
|
|
|
calib_cfg[channel] = lut;
|
|
pro.set_calibration("generic_xrit", calib_cfg);
|
|
pro.set_channel_unit(pro.images.size() - 1, CALIBRATION_ID_EMISSIVE_RADIANCE);
|
|
}
|
|
}
|
|
|
|
// GK-2A xRIT modes
|
|
if (instrument_id == "ami")
|
|
{
|
|
int bits_for_calib = 8;
|
|
if (lines[0].find("HALFTONE:=9") != std::string::npos)
|
|
bits_for_calib = 9;
|
|
else if (lines[0].find("HALFTONE:=10") != std::string::npos)
|
|
bits_for_calib = 10;
|
|
else if (lines[0].find("HALFTONE:=11") != std::string::npos)
|
|
bits_for_calib = 11;
|
|
else if (lines[0].find("HALFTONE:=12") != std::string::npos)
|
|
bits_for_calib = 12;
|
|
else if (lines[0].find("HALFTONE:=13") != std::string::npos)
|
|
bits_for_calib = 13;
|
|
else if (lines[0].find("HALFTONE:=14") != std::string::npos)
|
|
bits_for_calib = 14;
|
|
|
|
if (lines[2] == "_UNIT:=ALBEDO(%)")
|
|
{
|
|
std::vector<std::pair<int, float>> lut;
|
|
for (size_t i = 3; i < lines.size(); i++)
|
|
{
|
|
int val;
|
|
float valo;
|
|
if (sscanf(lines[i].c_str(), "%d:=%f", &val, &valo) == 2)
|
|
lut.push_back({val, valo / 100.0});
|
|
}
|
|
|
|
nlohmann::json calib_cfg = pro.get_calibration_raw();
|
|
|
|
calib_cfg["bits_for_calib"][channel] = bits_for_calib;
|
|
calib_cfg["to_complete"] = true;
|
|
|
|
calib_cfg[channel] = lut;
|
|
pro.set_calibration("generic_xrit", calib_cfg);
|
|
pro.set_channel_unit(pro.images.size() - 1, CALIBRATION_ID_ALBEDO);
|
|
}
|
|
else if (lines[2] == "_UNIT:=KELVIN")
|
|
{
|
|
std::vector<std::pair<int, float>> lut;
|
|
for (size_t i = 3; i < lines.size(); i++)
|
|
{
|
|
int val;
|
|
float valo;
|
|
if (sscanf(lines[i].c_str(), "%d:=%f", &val, &valo) == 2)
|
|
lut.push_back({val, valo});
|
|
}
|
|
|
|
nlohmann::json calib_cfg = pro.get_calibration_raw();
|
|
|
|
calib_cfg["bits_for_calib"][channel] = bits_for_calib;
|
|
calib_cfg["to_complete"] = true;
|
|
|
|
calib_cfg[channel] = lut;
|
|
pro.set_calibration("generic_xrit", calib_cfg);
|
|
pro.set_channel_unit(pro.images.size() - 1, CALIBRATION_ID_EMISSIVE_RADIANCE);
|
|
}
|
|
}
|
|
|
|
// Himawari xRIT modes
|
|
if (instrument_id == "ahi")
|
|
{
|
|
int bits_for_calib = 8;
|
|
bool lut_has_1023 = false, lut_has_4095 = false, lut_has_16383 = false;
|
|
if (lines[2].find("_UNIT:=PERCENT") != std::string::npos || lines[2].find("_UNIT:=ALBEDO(%)") != std::string::npos)
|
|
{
|
|
std::vector<std::pair<int, float>> lut;
|
|
for (size_t i = 3; i < lines.size(); i++)
|
|
{
|
|
int val;
|
|
float valo;
|
|
if (sscanf(lines[i].c_str(), "%d:=%f", &val, &valo) == 2)
|
|
{
|
|
lut.push_back({val, valo / 100.0});
|
|
lut_has_1023 |= (val == 1023);
|
|
lut_has_4095 |= (val == 4095);
|
|
lut_has_16383 |= (val == 16383);
|
|
}
|
|
}
|
|
|
|
if (lut_has_1023)
|
|
bits_for_calib = 10;
|
|
if (lut_has_4095)
|
|
bits_for_calib = 12;
|
|
if (lut_has_16383)
|
|
bits_for_calib = 14;
|
|
|
|
nlohmann::json calib_cfg = pro.get_calibration_raw();
|
|
|
|
calib_cfg["bits_for_calib"][channel] = bits_for_calib;
|
|
calib_cfg["to_complete"] = true;
|
|
|
|
calib_cfg[channel] = lut;
|
|
pro.set_calibration("generic_xrit", calib_cfg);
|
|
pro.set_channel_unit(pro.images.size() - 1, CALIBRATION_ID_ALBEDO);
|
|
}
|
|
else if (lines[2].find("_UNIT:=KELVIN") != std::string::npos)
|
|
{
|
|
std::vector<std::pair<int, float>> lut;
|
|
for (size_t i = 3; i < lines.size(); i++)
|
|
{
|
|
int val;
|
|
float valo;
|
|
if (sscanf(lines[i].c_str(), "%d:=%f", &val, &valo) == 2)
|
|
{
|
|
lut.push_back({val, valo});
|
|
lut_has_1023 |= (val == 1023);
|
|
lut_has_4095 |= (val == 4095);
|
|
lut_has_16383 |= (val == 16383);
|
|
}
|
|
}
|
|
|
|
if (lut_has_1023)
|
|
bits_for_calib = 10;
|
|
if (lut_has_4095)
|
|
bits_for_calib = 12;
|
|
if (lut_has_16383)
|
|
bits_for_calib = 14;
|
|
|
|
nlohmann::json calib_cfg = pro.get_calibration_raw();
|
|
|
|
calib_cfg["bits_for_calib"][channel] = bits_for_calib;
|
|
calib_cfg["to_complete"] = true;
|
|
|
|
calib_cfg[channel] = lut;
|
|
pro.set_calibration("generic_xrit", calib_cfg);
|
|
pro.set_channel_unit(pro.images.size() - 1, CALIBRATION_ID_EMISSIVE_RADIANCE);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
} // namespace xrit
|
|
} // namespace satdump
|