0.3.0
Loading...
Searching...
No Matches
Troposphere.cpp
Go to the documentation of this file.
1// This file is part of INSTINCT, the INS Toolkit for Integrated
2// Navigation Concepts and Training by the Institute of Navigation of
3// the University of Stuttgart, Germany.
4//
5// This Source Code Form is subject to the terms of the Mozilla Public
6// License, v. 2.0. If a copy of the MPL was not distributed with this
7// file, You can obtain one at https://mozilla.org/MPL/2.0/.
8
9#include "Troposphere.hpp"
10
13#include "util/Logger.hpp"
14
16#include "Models/GPT.hpp"
17
22
23namespace NAV
24{
25
26const char* to_string(TroposphereModel troposphereZhdModel)
27{
28 switch (troposphereZhdModel)
29 {
31 return "None";
33 return "Saastamoinen";
35 return "GPT2";
37 return "GPT3";
39 break;
40 }
41 return "";
42}
43
44const char* to_string(MappingFunction mappingFunction)
45{
46 switch (mappingFunction)
47 {
49 return "None";
51 return "Cosecant(elevation)";
53 return "GMF";
55 return "NMF";
57 return "VMF(GPT2)";
59 return "VMF(GPT3)";
61 break;
62 }
63 return "";
64}
65
66namespace
67{
68
69AtmosphereModels MappingFunctionDefaults(MappingFunction mappingFunction)
70{
71 switch (mappingFunction)
72 {
74 return { .pressureModel = PressureModel::ISA,
75 .temperatureModel = TemperatureModel::ISA,
76 .waterVaporModel = WaterVaporModel::ISA };
78 return { .pressureModel = PressureModel::ISA,
79 .temperatureModel = TemperatureModel::ISA,
80 .waterVaporModel = WaterVaporModel::ISA };
82 return { .pressureModel = PressureModel::ISA,
83 .temperatureModel = TemperatureModel::ISA,
84 .waterVaporModel = WaterVaporModel::ISA };
86 return { .pressureModel = PressureModel::GPT2,
87 .temperatureModel = TemperatureModel::GPT2,
88 .waterVaporModel = WaterVaporModel::GPT2 };
90 return { .pressureModel = PressureModel::GPT3,
91 .temperatureModel = TemperatureModel::GPT3,
92 .waterVaporModel = WaterVaporModel::GPT3 };
95 break;
96 }
97 return { .pressureModel = PressureModel::None,
98 .temperatureModel = TemperatureModel::None,
99 .waterVaporModel = WaterVaporModel::None };
100}
101
102/// @brief Returns the default atmosphere model, mapping function and mapping function atmosphere model for the given troposphere model
103/// @param troposphereModel Troposphere model to give the defaults for
104/// @return Tuple of <atmosphere model, mapping function, mapping function atmosphere model>
105std::tuple<AtmosphereModels, MappingFunction, AtmosphereModels> ModelDefaults(TroposphereModel troposphereModel)
106{
107 switch (troposphereModel)
108 {
110 return { AtmosphereModels{ .pressureModel = PressureModel::ISA,
111 .temperatureModel = TemperatureModel::ISA,
112 .waterVaporModel = WaterVaporModel::ISA },
114 MappingFunctionDefaults(MappingFunction::GMF) };
116 return { AtmosphereModels{ .pressureModel = PressureModel::GPT2,
117 .temperatureModel = TemperatureModel::GPT2,
118 .waterVaporModel = WaterVaporModel::GPT2 },
120 MappingFunctionDefaults(MappingFunction::VMF_GPT2) };
122 return { AtmosphereModels{ .pressureModel = PressureModel::GPT3,
123 .temperatureModel = TemperatureModel::GPT3,
124 .waterVaporModel = WaterVaporModel::GPT3 },
126 MappingFunctionDefaults(MappingFunction::VMF_GPT3) };
129 break;
130 }
131
132 return { AtmosphereModels{ .pressureModel = PressureModel::None,
133 .temperatureModel = TemperatureModel::None,
134 .waterVaporModel = WaterVaporModel::None },
136 MappingFunctionDefaults(MappingFunction::None) };
137}
138
139} // namespace
140
141bool ComboTroposphereModel(const char* label, TroposphereModelSelection& troposphereModelSelection, float width)
142{
143 bool changed = false;
144
145 const float BUTTON_WIDTH = 25.0F * gui::NodeEditorApplication::windowFontRatio();
146
147 std::string mapFuncPreview;
148 if (troposphereModelSelection.zwdMappingFunction.first != std::get<1>(ModelDefaults(troposphereModelSelection.zwdModel.first))
149 || troposphereModelSelection.zhdMappingFunction.first != std::get<1>(ModelDefaults(troposphereModelSelection.zhdModel.first)))
150 {
151 mapFuncPreview = fmt::format(" + {}", troposphereModelSelection.zhdMappingFunction.first);
152
153 if (troposphereModelSelection.zhdMappingFunction.first != troposphereModelSelection.zwdMappingFunction.first)
154 {
155 mapFuncPreview += fmt::format(" | {}", troposphereModelSelection.zwdMappingFunction.first);
156 }
157 }
158
159 ImGui::SetNextItemWidth(width - BUTTON_WIDTH - 2 * ImGui::GetStyle().ItemInnerSpacing.x);
160 if (gui::widgets::EnumCombo(fmt::format("##{}", label).c_str(),
161 troposphereModelSelection.zhdModel.first,
162 troposphereModelSelection.zwdModel.first,
163 mapFuncPreview.c_str()))
164 {
165 std::tie(troposphereModelSelection.zhdModel.second,
166 troposphereModelSelection.zhdMappingFunction.first,
167 troposphereModelSelection.zhdMappingFunction.second) = ModelDefaults(troposphereModelSelection.zhdModel.first);
168 std::tie(troposphereModelSelection.zwdModel.second,
169 troposphereModelSelection.zwdMappingFunction.first,
170 troposphereModelSelection.zwdMappingFunction.second) = ModelDefaults(troposphereModelSelection.zwdModel.first);
171 changed = true;
172 }
173 ImGui::SameLine();
174 if (ImGui::Button(fmt::format("...##{}", label).c_str(), ImVec2(BUTTON_WIDTH, 0)))
175 {
176 ImGui::OpenPopup(fmt::format("{} Popup", label).c_str());
177 }
178 if (ImGui::BeginPopup(fmt::format("{} Popup", label).c_str()))
179 {
180 const float ATMOSPHERE_COMBO_WIDTH = 95.0F * gui::NodeEditorApplication::windowFontRatio();
181 if (ImGui::BeginTable(fmt::format("{} Table", label).c_str(), 5))
182 {
183 ImGui::TableSetupColumn("", ImGuiTableColumnFlags_WidthFixed);
184 ImGui::TableSetupColumn("", ImGuiTableColumnFlags_WidthFixed);
185 ImGui::TableSetupColumn("Pressure", ImGuiTableColumnFlags_WidthFixed);
186 ImGui::TableSetupColumn("Temperature", ImGuiTableColumnFlags_WidthFixed);
187 ImGui::TableSetupColumn("Water vapor", ImGuiTableColumnFlags_WidthFixed);
188 ImGui::TableHeadersRow();
189
190 ImGui::TableNextColumn();
191 ImGui::TextUnformatted("ZHD model");
192 ImGui::TableNextColumn();
193 ImGui::SetNextItemWidth(width);
194 if (gui::widgets::EnumCombo(fmt::format("##{} ZHD - Combo", label).c_str(), troposphereModelSelection.zhdModel.first))
195 {
196 std::tie(troposphereModelSelection.zhdModel.second,
197 troposphereModelSelection.zhdMappingFunction.first,
198 troposphereModelSelection.zhdMappingFunction.second) = ModelDefaults(troposphereModelSelection.zhdModel.first);
199 changed = true;
200 }
201 if (troposphereModelSelection.zhdModel.first == TroposphereModel::None) { ImGui::BeginDisabled(); }
202 ImGui::TableNextColumn();
203 ImGui::SetNextItemWidth(ATMOSPHERE_COMBO_WIDTH);
204 changed |= ComboPressureModel(fmt::format("##{} ZHD - Pressure", label).c_str(), troposphereModelSelection.zhdModel.second.pressureModel);
205 ImGui::TableNextColumn();
206 ImGui::SetNextItemWidth(ATMOSPHERE_COMBO_WIDTH);
207 changed |= ComboTemperatureModel(fmt::format("##{} ZHD - Temperature", label).c_str(), troposphereModelSelection.zhdModel.second.temperatureModel);
208 ImGui::TableNextColumn();
209 ImGui::SetNextItemWidth(ATMOSPHERE_COMBO_WIDTH);
210 changed |= ComboWaterVaporModel(fmt::format("##{} ZHD - Water vapor", label).c_str(), troposphereModelSelection.zhdModel.second.waterVaporModel);
211 if (troposphereModelSelection.zhdModel.first == TroposphereModel::None) { ImGui::EndDisabled(); }
212
213 ImGui::TableNextColumn();
214 ImGui::TextUnformatted("ZWD model");
215 ImGui::TableNextColumn();
216 ImGui::SetNextItemWidth(width);
217 if (gui::widgets::EnumCombo(fmt::format("##{} ZWD - Combo", label).c_str(), troposphereModelSelection.zwdModel.first))
218 {
219 std::tie(troposphereModelSelection.zwdModel.second,
220 troposphereModelSelection.zwdMappingFunction.first,
221 troposphereModelSelection.zwdMappingFunction.second) = ModelDefaults(troposphereModelSelection.zwdModel.first);
222 changed = true;
223 }
224 if (troposphereModelSelection.zwdModel.first == TroposphereModel::None) { ImGui::BeginDisabled(); }
225 ImGui::TableNextColumn();
226 ImGui::SetNextItemWidth(ATMOSPHERE_COMBO_WIDTH);
227 changed |= ComboPressureModel(fmt::format("##{} ZWD - Pressure", label).c_str(), troposphereModelSelection.zwdModel.second.pressureModel);
228 ImGui::TableNextColumn();
229 ImGui::SetNextItemWidth(ATMOSPHERE_COMBO_WIDTH);
230 changed |= ComboTemperatureModel(fmt::format("##{} ZWD - Temperature", label).c_str(), troposphereModelSelection.zwdModel.second.temperatureModel);
231 ImGui::TableNextColumn();
232 ImGui::SetNextItemWidth(ATMOSPHERE_COMBO_WIDTH);
233 changed |= ComboWaterVaporModel(fmt::format("##{} ZWD - Water vapor", label).c_str(), troposphereModelSelection.zwdModel.second.waterVaporModel);
234 if (troposphereModelSelection.zwdModel.first == TroposphereModel::None) { ImGui::EndDisabled(); }
235
236 if (troposphereModelSelection.zhdModel.first == TroposphereModel::None) { ImGui::BeginDisabled(); }
237 ImGui::TableNextColumn();
238 ImGui::TextUnformatted("Mapping function ZHD");
239 ImGui::TableNextColumn();
240 ImGui::SetNextItemWidth(width);
241 if (gui::widgets::EnumCombo(fmt::format("##{} MapZHD - Combo", label).c_str(), troposphereModelSelection.zhdMappingFunction.first))
242 {
243 troposphereModelSelection.zhdMappingFunction.second = MappingFunctionDefaults(troposphereModelSelection.zhdMappingFunction.first);
244 changed = true;
245 }
246 if (troposphereModelSelection.zhdModel.first != TroposphereModel::None
247 && troposphereModelSelection.zhdMappingFunction.first == MappingFunction::None) { ImGui::BeginDisabled(); }
248 ImGui::TableNextColumn();
249 ImGui::SetNextItemWidth(ATMOSPHERE_COMBO_WIDTH);
250 changed |= ComboPressureModel(fmt::format("##{} MapZHD - Pressure", label).c_str(), troposphereModelSelection.zhdMappingFunction.second.pressureModel);
251 ImGui::TableNextColumn();
252 ImGui::SetNextItemWidth(ATMOSPHERE_COMBO_WIDTH);
253 changed |= ComboTemperatureModel(fmt::format("##{} MapZHD - Temperature", label).c_str(), troposphereModelSelection.zhdMappingFunction.second.temperatureModel);
254 ImGui::TableNextColumn();
255 ImGui::SetNextItemWidth(ATMOSPHERE_COMBO_WIDTH);
256 changed |= ComboWaterVaporModel(fmt::format("##{} MapZHD - Water vapor", label).c_str(), troposphereModelSelection.zhdMappingFunction.second.waterVaporModel);
257 if (troposphereModelSelection.zhdModel.first == TroposphereModel::None
258 || troposphereModelSelection.zhdMappingFunction.first == MappingFunction::None) { ImGui::EndDisabled(); }
259
260 if (troposphereModelSelection.zwdModel.first == TroposphereModel::None) { ImGui::BeginDisabled(); }
261 ImGui::TableNextColumn();
262 ImGui::TextUnformatted("Mapping function ZWD");
263 ImGui::TableNextColumn();
264 ImGui::SetNextItemWidth(width);
265 if (gui::widgets::EnumCombo(fmt::format("##{} MapZWD - Combo", label).c_str(), troposphereModelSelection.zwdMappingFunction.first))
266 {
267 troposphereModelSelection.zwdMappingFunction.second = MappingFunctionDefaults(troposphereModelSelection.zwdMappingFunction.first);
268 changed = true;
269 }
270 if (troposphereModelSelection.zwdModel.first != TroposphereModel::None
271 && troposphereModelSelection.zwdMappingFunction.first == MappingFunction::None) { ImGui::BeginDisabled(); }
272 ImGui::TableNextColumn();
273 ImGui::SetNextItemWidth(ATMOSPHERE_COMBO_WIDTH);
274 changed |= ComboPressureModel(fmt::format("##{} MapZWD - Pressure", label).c_str(), troposphereModelSelection.zwdMappingFunction.second.pressureModel);
275 ImGui::TableNextColumn();
276 ImGui::SetNextItemWidth(ATMOSPHERE_COMBO_WIDTH);
277 changed |= ComboTemperatureModel(fmt::format("##{} MapZWD - Temperature", label).c_str(), troposphereModelSelection.zwdMappingFunction.second.temperatureModel);
278 ImGui::TableNextColumn();
279 ImGui::SetNextItemWidth(ATMOSPHERE_COMBO_WIDTH);
280 changed |= ComboWaterVaporModel(fmt::format("##{} MapZWD - Water vapor", label).c_str(), troposphereModelSelection.zwdMappingFunction.second.waterVaporModel);
281 if (troposphereModelSelection.zwdModel.first == TroposphereModel::None
282 || troposphereModelSelection.zwdMappingFunction.first == MappingFunction::None) { ImGui::EndDisabled(); }
283
284 ImGui::EndTable();
285 }
286
287 ImGui::EndPopup();
288 }
289
290 ImGui::SameLine(0.0F, ImGui::GetStyle().ItemInnerSpacing.x);
291 std::string labelStr = label;
292 ImGui::TextUnformatted(labelStr.substr(0, labelStr.find('#')).c_str());
293
294 return changed;
295}
296
297ZenithDelay calcTroposphericDelayAndMapping(const InsTime& insTime, const Eigen::Vector3d& lla_pos, double elevation, double /* azimuth */,
298 const TroposphereModelSelection& troposphereModels, [[maybe_unused]] const std::string& nameId)
299{
300 if (troposphereModels.zhdModel.first == TroposphereModel::None
301 && troposphereModels.zwdModel.first == TroposphereModel::None) { return {}; }
302
303 if (lla_pos(2) < -1000 || lla_pos(2) > 1e4 || std::isnan(elevation))
304 {
305 LOG_TRACE("{}: Not calculating tropospheric delay, due to altitude being invalid: {}m", nameId, lla_pos(2));
306 return {};
307 }
308
309 enum : uint8_t
310 {
311 ZHD,
312 ZWD,
313 ZHDMapFunc,
314 ZWDMapFunc,
315 COUNT,
316 };
317
318 const std::array<std::reference_wrapper<const AtmosphereModels>, COUNT> atmosphereModels = {
319 troposphereModels.zhdModel.second,
320 troposphereModels.zwdModel.second,
321 troposphereModels.zhdMappingFunction.second,
322 troposphereModels.zwdMappingFunction.second,
323 };
324 std::array<double, COUNT> pressure{}; // Total barometric pressure in [millibar]
325 std::array<double, COUNT> temperature{}; // Absolute temperature in [K]
326 std::array<double, COUNT> waterVapor{}; // Partial pressure of water vapour in [hPa]
327
328 GPT2output gpt2outputs;
329 GPT3output gpt3outputs;
330 // UTC->GPST
331 auto epoch_temp = InsTime(insTime) + std::chrono::duration<long double>(insTime.leapGps2UTC());
332 double mjd = static_cast<double>(epoch_temp.toMJD().mjd_day) + static_cast<double>(epoch_temp.toMJD().mjd_frac);
333
334 if (troposphereModels.zhdModel.first == TroposphereModel::GPT2
335 || troposphereModels.zwdModel.first == TroposphereModel::GPT2
336 || troposphereModels.zhdMappingFunction.first == MappingFunction::VMF_GPT2
337 || troposphereModels.zwdMappingFunction.first == MappingFunction::VMF_GPT2
338 || std::ranges::any_of(atmosphereModels,
339 [](const auto& model) { return model.get().pressureModel == PressureModel::GPT2
340 || model.get().temperatureModel == TemperatureModel::GPT2
341 || model.get().waterVaporModel == WaterVaporModel::GPT2; }))
342 {
343 // LOG_DATA("{}: Calculating GPT2 parameters", nameId);
344 gpt2outputs = GPT2_param(mjd, lla_pos);
345 }
346
347 if (troposphereModels.zhdModel.first == TroposphereModel::GPT3
348 || troposphereModels.zwdModel.first == TroposphereModel::GPT3
349 || troposphereModels.zhdMappingFunction.first == MappingFunction::VMF_GPT3
350 || troposphereModels.zwdMappingFunction.first == MappingFunction::VMF_GPT3
351 || std::ranges::any_of(atmosphereModels,
352 [](const auto& model) { return model.get().pressureModel == PressureModel::GPT3
353 || model.get().temperatureModel == TemperatureModel::GPT3
354 || model.get().waterVaporModel == WaterVaporModel::GPT3; }))
355 {
356 // LOG_DATA("{}: Calculating GPT3 parameters", nameId);
357 gpt3outputs = GPT3_param(mjd, lla_pos);
358 }
359
360 // LOG_DATA("{}: Calculating Atmosphere parameters ZHD=({},{}) ZWD=({},{}) [el={}°, pos={} {} {}]", nameId,
361 // troposphereModels.zhdModel.first, troposphereModels.zhdMappingFunction.first,
362 // troposphereModels.zwdModel.first, troposphereModels.zwdMappingFunction.first,
363 // rad2deg(elevation), rad2deg(lla_pos(0)), rad2deg(lla_pos(1)), lla_pos(2));
364 for (size_t i = 0; i < COUNT; i++)
365 {
366 bool alreadyCalculated = false;
367 for (size_t j = 0; j < i; j++)
368 {
369 if (atmosphereModels.at(i).get().pressureModel == atmosphereModels.at(j).get().pressureModel)
370 {
371 pressure.at(i) = pressure.at(j);
372 alreadyCalculated = true;
373 break;
374 }
375 }
376
377 if (!alreadyCalculated)
378 {
379 if (atmosphereModels.at(i).get().pressureModel == PressureModel::GPT2)
380 {
381 pressure.at(i) = gpt2outputs.p;
382 }
383 else if (atmosphereModels.at(i).get().pressureModel == PressureModel::GPT3)
384 {
385 pressure.at(i) = gpt3outputs.p;
386 }
387 else
388 {
389 pressure.at(i) = calcTotalPressure(lla_pos(2), atmosphereModels.at(i).get().pressureModel);
390 }
391 }
392 // LOG_DATA("{}: [{}]: {} - p {} [millibar] (Total barometric pressure) - value {}", nameId, i, atmosphereModels.at(i).get().pressureModel,
393 // pressure.at(i), alreadyCalculated ? "reused" : "calculated");
394
395 alreadyCalculated = false;
396 for (size_t j = 0; j < i; j++)
397 {
398 if (atmosphereModels.at(i).get().temperatureModel == atmosphereModels.at(j).get().temperatureModel)
399 {
400 temperature.at(i) = temperature.at(j);
401 alreadyCalculated = true;
402 break;
403 }
404 }
405
406 if (!alreadyCalculated)
407 {
408 if (atmosphereModels.at(i).get().temperatureModel == TemperatureModel::GPT2)
409 {
410 temperature.at(i) = gpt2outputs.T;
411 }
412 else if (atmosphereModels.at(i).get().temperatureModel == TemperatureModel::GPT3)
413 {
414 temperature.at(i) = gpt3outputs.T;
415 }
416 else
417 {
418 temperature.at(i) = atmosphereModels.at(i).get().temperatureModel.calcAbsoluteTemperature(lla_pos(2));
419 }
420 }
421 // LOG_DATA("{}: [{}]: {} - T {} [K] (Absolute temperature) - value {}", nameId, i, atmosphereModels.at(i).get().temperatureModel,
422 // temperature.at(i), alreadyCalculated ? "reused" : "calculated");
423
424 alreadyCalculated = false;
425 for (size_t j = 0; j < i; j++)
426 {
427 if (atmosphereModels.at(i).get().waterVaporModel == atmosphereModels.at(j).get().waterVaporModel)
428 {
429 waterVapor.at(i) = waterVapor.at(j);
430 alreadyCalculated = true;
431 break;
432 }
433 }
434
435 // Partial pressure of water vapour in [millibar] - RTKLIB ch. E.5, p. 149 specifies 70%
436 if (!alreadyCalculated)
437 {
438 if (atmosphereModels.at(i).get().waterVaporModel == WaterVaporModel::GPT2)
439 {
440 waterVapor.at(i) = gpt2outputs.e;
441 }
442 else if (atmosphereModels.at(i).get().waterVaporModel == WaterVaporModel::GPT3)
443 {
444 waterVapor.at(i) = gpt3outputs.e;
445 }
446 else
447 {
448 waterVapor.at(i) = calcWaterVaporPartialPressure(temperature.at(i), 0.7, atmosphereModels.at(i).get().waterVaporModel);
449 }
450 }
451 // LOG_DATA("{}: [{}]: {} - e {} [millibar] (Partial pressure of water vapour) - value {}", nameId, i,
452 // atmosphereModels.at(i).get().waterVaporModel, waterVapor.at(i), alreadyCalculated ? "reused" : "calculated");
453 }
454
455 double zhd = 0.0;
456 switch (troposphereModels.zhdModel.first)
457 {
461 zhd = calcZHD_Saastamoinen(lla_pos, pressure[ZHD]);
462 break;
465 break;
466 }
467
468 double zwd = 0.0;
469 switch (troposphereModels.zwdModel.first)
470 {
472 zwd = calcZWD_Saastamoinen(temperature[ZWD], waterVapor[ZWD]);
473 break;
475 zwd = asknewet(waterVapor[ZWD], gpt2outputs.Tm, gpt2outputs.la);
476 break;
478 zwd = asknewet(waterVapor[ZWD], gpt3outputs.Tm, gpt3outputs.la);
479 break;
482 break;
483 }
484
485 double zhdMappingFactor = 1.0;
486 switch (troposphereModels.zhdMappingFunction.first)
487 {
489 zhdMappingFactor = calcTropoMapFunc_cosecant(elevation);
490 break;
492 zhdMappingFactor = calcTropoMapFunc_GMFH(mjd, lla_pos, elevation);
493 break;
495 zhdMappingFactor = calcTropoMapFunc_NMFH(insTime, lla_pos, elevation);
496 break;
498 zhdMappingFactor = vmf1h(gpt2outputs.ah, mjd, lla_pos(0), lla_pos(2), M_PI / 2.0 - elevation);
499 break;
501 zhdMappingFactor = vmf1h(gpt3outputs.ah, mjd, lla_pos(0), lla_pos(2), M_PI / 2.0 - elevation);
502 break;
505 break;
506 }
507
508 double zwdMappingFactor = 1.0;
509 switch (troposphereModels.zwdMappingFunction.first)
510 {
512 zwdMappingFactor = calcTropoMapFunc_cosecant(elevation);
513 break;
515 zwdMappingFactor = calcTropoMapFunc_GMFW(mjd, lla_pos, elevation);
516 break;
518 zwdMappingFactor = calcTropoMapFunc_NMFW(lla_pos, elevation);
519 break;
521 zwdMappingFactor = vmf1w(gpt2outputs.aw, M_PI / 2.0 - elevation);
522 break;
524 zwdMappingFactor = vmf1w(gpt3outputs.aw, M_PI / 2.0 - elevation);
525 break;
528 break;
529 }
530 // LOG_DATA("{}: el = {}, ZHD = {}, ZWD = {}, ZHDMF = {}, ZWDMF = {}", nameId, elevation, zhd, zwd, zhdMappingFactor, zwdMappingFactor);
531
532 return { .ZHD = zhd,
533 .ZWD = zwd,
534 .zhdMappingFactor = zhdMappingFactor,
535 .zwdMappingFactor = zwdMappingFactor };
536}
537
538double tropoErrorVar(double dpsr_T, double elevation)
539{
540 constexpr double ERR_SAAS = 0.3; // Saastamoinen model error std [m] (maximum zenith wet delay - formulas with worst possible values)
541
542 return dpsr_T == 0.0 ? 0.0 : std::pow(ERR_SAAS / (std::sin(elevation) + 0.1), 2);
543}
544
545void to_json(json& j, const AtmosphereModels& obj)
546{
547 j = json{
548 { "pressureModel", obj.pressureModel },
549 { "temperatureModel", obj.temperatureModel },
550 { "waterVaporModel", obj.waterVaporModel },
551 };
552}
553
554void from_json(const json& j, AtmosphereModels& obj)
555{
556 if (j.contains("pressureModel")) { j.at("pressureModel").get_to(obj.pressureModel); }
557 if (j.contains("temperatureModel") && !j.at("temperatureModel").is_number()) { j.at("temperatureModel").get_to(obj.temperatureModel); }
558 if (j.contains("waterVaporModel")) { j.at("waterVaporModel").get_to(obj.waterVaporModel); }
559}
560
562{
563 j = json{
564 { "zhdModel", obj.zhdModel },
565 { "zwdModel", obj.zwdModel },
566 { "zhdMappingFunction", obj.zhdMappingFunction },
567 { "zwdMappingFunction", obj.zwdMappingFunction },
568 };
569}
570
572{
573 if (j.contains("zhdModel")) { j.at("zhdModel").get_to(obj.zhdModel); }
574 if (j.contains("zwdModel")) { j.at("zwdModel").get_to(obj.zwdModel); }
575 if (j.contains("zhdMappingFunction")) { j.at("zhdMappingFunction").get_to(obj.zhdMappingFunction); }
576 if (j.contains("zwdMappingFunction")) { j.at("zwdMappingFunction").get_to(obj.zwdMappingFunction); }
577}
578
579} // namespace NAV
Cosecant tropospheric mapping function.
Combo representing an enumeration.
nlohmann::json json
json namespace
Global Mapping Function (GMF)
GPT2/3 (Global Pressure and Temperature) models.
Utility class for logging to console and file.
#define LOG_TRACE
Detailled info to trace the execution of the program. Should not be called on functions which receive...
Definition Logger.hpp:65
Niell Mapping Function.
Saastamoinen troposphere correction model.
Troposphere Models.
The class is responsible for all time-related tasks.
Definition InsTime.hpp:710
constexpr uint16_t leapGps2UTC() const
Returns the current number of leap seconds (offset GPST to UTC)
Definition InsTime.hpp:942
@ None
No temperature model.
@ ISA
ICAO Standard Atmosphere.
static float windowFontRatio()
Ratio to multiply for GUI window elements.
bool EnumCombo(const char *label, T &enumeration, size_t startIdx=0)
Combo representing an enumeration.
Definition EnumCombo.hpp:30
void to_json(json &j, const Node &node)
Converts the provided node into a json object.
Definition Node.cpp:990
@ ISA
ICAO Standard Atmosphere.
Definition Pressure.hpp:27
@ None
No pressure model.
Definition Pressure.hpp:25
bool ComboTroposphereModel(const char *label, TroposphereModelSelection &troposphereModelSelection, float width)
Shows a ComboBox and button for advanced configuration to select the troposphere models.
@ COUNT
Amount of items in the enum.
MappingFunction
Available Mapping Functions.
@ COUNT
Amount of items in the enum.
@ NMF
Niell Mapping Function (NMF)
@ None
Mapping Function turned off (= 1)
@ GMF
Global Mapping Function (GMF)
@ Cosecant
Cosecant of elevation.
@ VMF_GPT2
Vienna Mapping Function based on the GPT2 grid.
@ VMF_GPT3
Vienna Mapping Function based on the GPT3 grid.
const char * to_string(gui::widgets::PositionWithFrame::ReferenceFrame refFrame)
Converts the enum to a string.
double calcTotalPressure(double altitudeMSL, PressureModel pressureModel)
Calculates the total pressure.
Definition Pressure.cpp:45
double calcTropoMapFunc_GMFH(double mjd, const Eigen::Vector3d &lla_pos, double elevation)
Calculates the Global Mapping Function (GMF) for the hydrostatic delay.
Definition GMF.cpp:75
double calcTropoMapFunc_GMFW(double mjd, const Eigen::Vector3d &lla_pos, double elevation)
Calculates the Global Mapping Function (GMF) for the wet delay.
Definition GMF.cpp:140
double calcZWD_Saastamoinen(double T, double e)
Calculates the tropospheric zenith wet delay with the Saastamoinen model.
double calcZHD_Saastamoinen(const Eigen::Vector3d &lla_pos, double p)
Calculates the tropospheric zenith hydrostatic delay with the Saastamoinen model.
double tropoErrorVar(double dpsr_T, double elevation)
Calculates the tropospheric error variance.
double asknewet(const double &e, const double &Tm, const double &la)
This subroutine determines the zenith wet delay.
Definition GPT.cpp:587
double vmf1w(const double &aw, const double &zd)
mapping functions with height correction
@ ISA
ICAO Standard Atmosphere.
@ None
Water vapor model turned off.
bool ComboWaterVaporModel(const char *label, WaterVaporModel &waterVaporModel)
Shows a ComboBox to select the water vapor model.
double calcWaterVaporPartialPressure(double temp, double humidity_rel, WaterVaporModel waterVaporModel)
Calculates the partial pressure of water vapor.
void from_json(const json &j, Node &node)
Converts the provided json object into a node object.
Definition Node.cpp:1007
ZenithDelay calcTroposphericDelayAndMapping(const InsTime &insTime, const Eigen::Vector3d &lla_pos, double elevation, double, const TroposphereModelSelection &troposphereModels, const std::string &nameId)
Calculates the tropospheric zenith hydrostatic and wet delays and corresponding mapping factors.
TroposphereModel
Available Troposphere delay models.
@ COUNT
Amount of items in the enum.
@ None
Troposphere Model turned off.
@ Saastamoinen
Saastamoinen model.
double calcTropoMapFunc_NMFH(const InsTime &epoch, const Eigen::Vector3d &lla_pos, double elevation)
Calculates the Niell Mapping Function (NMF) for the hydrostatic delay.
GPT2output GPT2_param(const double &mjd, const Eigen::Vector3d &lla_pos)
Determine pressure, temperature, temperature lapse rate, mean temperature of the water vapor,...
Definition GPT.cpp:22
bool ComboTemperatureModel(const char *label, TemperatureModel &temperatureModel)
Shows a ComboBox to select the temperature model.
double calcTropoMapFunc_cosecant(double elevation)
Calculates the mapping factor as cosecant of the elevation.
Definition Cosecant.cpp:16
double calcTropoMapFunc_NMFW(const Eigen::Vector3d &lla_pos, double elevation)
Calculates the Niell Mapping Function (NMF) for the wet delay.
double vmf1h(const double &ah, const double &dmjd, const double &dlat, const double &ht, const double &zd)
mapping functions with height correction
GPT3output GPT3_param(const double &mjd, const Eigen::Vector3d &lla_pos)
Determine pressure, temperature, temperature lapse rate, mean temperature of the water vapor,...
Definition GPT.cpp:254
bool ComboPressureModel(const char *label, PressureModel &pressureModel)
Shows a ComboBox to select the pressure model.
Definition Pressure.cpp:40
Atmospheric model selection for temperature, pressure and water vapor.
TemperatureModel temperatureModel
Temperature model.
PressureModel pressureModel
Pressure model.
WaterVaporModel waterVaporModel
WaterVapor model.
GPT2 output parameters.
Definition GPT.hpp:24
double ah
hydrostatic mapping function coefficient at zero height (VMF1) (vector of length nstat)
Definition GPT.hpp:30
double e
water vapor pressure in [hPa] (vector of length nstat)
Definition GPT.hpp:29
double Tm
mean temperature of the water vapor in [degrees Kelvin] (vector of length nstat)
Definition GPT.hpp:28
double la
water vapor decrease factor (vector of length nstat)
Definition GPT.hpp:32
double T
temperature in [degrees Celsius] (vector of length nstat)
Definition GPT.hpp:26
double p
p pressure in [hPa] (vector of length nstat)
Definition GPT.hpp:25
double aw
wet mapping function coefficient (VMF1) (vector of length nstat)
Definition GPT.hpp:31
GPT3 output parameters.
Definition GPT.hpp:38
Collection of troposphere model selections.
std::pair< MappingFunction, AtmosphereModels > zwdMappingFunction
Mapping function ZWD, atmosphere models.
std::pair< TroposphereModel, AtmosphereModels > zwdModel
Troposphere ZWD model, atmosphere models.
std::pair< TroposphereModel, AtmosphereModels > zhdModel
Troposphere ZHD model, atmosphere models.
std::pair< MappingFunction, AtmosphereModels > zhdMappingFunction
Mapping function ZHD, atmosphere models.
Zenith delays and mapping factors.