satdump/plugins/xrit_support/xrit/processor/calib.h

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