Program Listing for File ground_station.cc¶
↰ Return to documentation for file (agents/ground_station.cc)
#include "lupnt/agents/ground_station.h"
#include <initializer_list>
#include <stdexcept>
#include "lupnt/core/asset_factory.h"
#include "lupnt/core/error.h"
#include "lupnt/dynamics/surface_dynamics.h"
#include "lupnt/interfaces/yaml.h"
namespace lupnt {
namespace {
Real ReadRequiredReal(const Config& config, std::initializer_list<const char*> keys) {
for (const char* key : keys) {
if (config[key]) return config[key].as<Real>();
}
throw std::runtime_error(
fmt::format("GroundStation config missing required field {}", *keys.begin()));
}
Real ReadOptionalReal(const Config& config, std::initializer_list<const char*> keys,
Real fallback) {
for (const char* key : keys) {
if (config[key]) return config[key].as<Real>();
}
return fallback;
}
BodyId ReadBodyId(const Config& config, BodyId fallback) {
if (config["body_id"]) return static_cast<BodyId>(config["body_id"].as<int>());
if (!config["body"]) return fallback;
std::string body = config["body"].as<std::string>();
auto body_id = enum_cast<BodyId>(body);
if (!body_id) throw std::runtime_error(fmt::format("Unknown body '{}'", body));
return *body_id;
}
spice::GroundStationSpiceData MakeGroundStationData(const std::string& name,
double latitude_deg, double longitude_deg,
double altitude_m,
BodyId body_id = BodyId::EARTH) {
BodyData body_data = GetBodyData(body_id);
LatLonAlt lla(Vec3(latitude_deg, longitude_deg, altitude_m), body_data.fixed_frame);
Cart3 position = LatLonAltToCart(lla, body_data.R, body_data.flattening);
spice::GroundStationSpiceData data;
data.name = name;
data.body_id = body_id;
data.frame = enum_name(body_data.fixed_frame);
data.position_m = position.head(3).cast<double>();
data.latitude_deg = latitude_deg;
data.longitude_deg = longitude_deg;
data.altitude_m = altitude_m;
return data;
}
} // namespace
GroundStation::GroundStation(Config& config) : AgentWithDynamics() {
ConfigureFromConfig(config);
}
GroundStation::GroundStation(const spice::GroundStationSpiceData& gs_data) : AgentWithDynamics() {
ConfigureFromData(gs_data);
}
GroundStation GroundStation::FromSpice(Real t_tai, const std::string& station_name, BodyId center,
const std::string& ref_frame,
const std::string& ab_correction) {
return GroundStation(
spice::GetGroundStationDataSpice(t_tai, station_name, center, ref_frame, ab_correction));
}
GroundStation GroundStation::FromSpice(Real t_tai, int station_id, BodyId center,
const std::string& ref_frame,
const std::string& ab_correction) {
return GroundStation(
spice::GetGroundStationDataSpice(t_tai, station_id, center, ref_frame, ab_correction));
}
void GroundStation::ConfigureFromConfig(Config& config) {
config_ = config;
if (config["name"])
SetName(config["name"].as<std::string>());
else
SetName(GetId());
if (config["frequency"]) SetFrequency(config["frequency"].as<Real>());
if (config["spice_kernel"]) {
spice::LoadSpiceKernel(config["spice_kernel"].as<std::string>());
}
if (config["spice_kernels"]) {
for (const auto& kernel : config["spice_kernels"]) {
spice::LoadSpiceKernel(kernel.as<std::string>());
}
}
BodyId body_id = ReadBodyId(config, BodyId::EARTH);
Real epoch = ReadOptionalReal(config, {"epoch", "t_tai"}, 0.0);
std::string ref_frame
= config["spice_frame"] ? config["spice_frame"].as<std::string>() : "ITRF93";
std::string ab_correction
= config["ab_correction"] ? config["ab_correction"].as<std::string>() : "NONE";
if (config["spice_name"]) {
auto gs_data = spice::GetGroundStationDataSpice(epoch, config["spice_name"].as<std::string>(),
body_id, ref_frame, ab_correction);
ConfigureFromData(gs_data);
return;
}
if (config["spice_id"]) {
auto gs_data = spice::GetGroundStationDataSpice(epoch, config["spice_id"].as<int>(), body_id,
ref_frame, ab_correction);
ConfigureFromData(gs_data);
return;
}
Real latitude_deg = ReadRequiredReal(config, {"latitude_deg", "latitude"});
Real longitude_deg = ReadRequiredReal(config, {"longitude_deg", "longitude"});
Real altitude_m = ReadRequiredReal(config, {"altitude_m", "altitude"});
ConfigureFromData(MakeGroundStationData(GetName(), latitude_deg.val(), longitude_deg.val(),
altitude_m.val(), body_id));
}
void GroundStation::ConfigureFromData(const spice::GroundStationSpiceData& gs_data) {
ConfigureFromCartesian(gs_data.name, gs_data.position_m.cast<Real>(), gs_data.body_id);
latitude_ = gs_data.latitude_deg;
longitude_ = gs_data.longitude_deg;
altitude_ = gs_data.altitude_m;
naif_id_ = gs_data.naif_id;
spice_frame_ = gs_data.frame;
}
void GroundStation::ConfigureFromCartesian(const std::string& name, const Vec3& position_m,
BodyId body_id) {
SetName(name);
body_id_ = body_id;
SetBodyId(body_id_);
BodyData body_data = GetBodyData(body_id_);
frame_ = body_data.fixed_frame;
Cart3 position(position_m, frame_);
LatLonAlt lla = CartToLatLonAlt(position, body_data.R, body_data.flattening);
latitude_ = lla(0);
longitude_ = lla(1);
altitude_ = lla(2);
Cart6 state(position_m, Vec3::Zero(), frame_);
SetState(state);
SetDynamics(MakePtr<StaticDynamics>());
SetAttitude(Attitude(Vec4(1.0, 0.0, 0.0, 0.0), Vec3::Zero(), frame_));
}
REGISTER_FACTORY_CLASS(Agent, GroundStation)
} // namespace lupnt