etsi_its_messages v3.5.0
Loading...
Searching...
No Matches
cdd_setters_common.h
Go to the documentation of this file.
1// SPDX-License-Identifier: MIT
2// Copyright Institute for Automotive Engineering (ika), RWTH Aachen University
3
8
9#ifndef ETSI_ITS_MSGS_UTILS_IMPL_CDD_CDD_SETTERS_COMMON_H
10#define ETSI_ITS_MSGS_UTILS_IMPL_CDD_CDD_SETTERS_COMMON_H
11
14#include <GeographicLib/UTMUPS.hpp>
15#include <array>
16#include <cmath>
17#include <cstdint>
18#include <cstring>
19#include <type_traits>
20
27template <typename StationId>
28inline void setStationId(StationId& station_id, const uint32_t id_value) {
29 throwIfOutOfRange(id_value, StationId::MIN, StationId::MAX, "StationId");
30 station_id.value = id_value;
31}
32
39template <typename StationType>
40inline void setStationType(StationType& station_type, const uint8_t value) {
41 throwIfOutOfRange(value, StationType::MIN, StationType::MAX, "StationType");
42 station_type.value = value;
43}
44
53inline void setTimestampITS(
54 TimestampIts& timestamp_its, const uint64_t unix_nanosecs,
55 const uint16_t n_leap_seconds = etsi_its_msgs::LEAP_SECOND_INSERTIONS_SINCE_2004.rbegin()->second) {
56 uint64_t t_its = unix_nanosecs * 1e-6 + (uint64_t)(n_leap_seconds * 1e3) - etsi_its_msgs::UNIX_SECONDS_2004 * 1e3;
57 throwIfOutOfRange(t_its, TimestampIts::MIN, TimestampIts::MAX, "TimestampIts");
58 timestamp_its.value = t_its;
59}
60
67inline void setLatitude(Latitude& latitude, const double deg) {
68 int64_t angle_in_10_micro_degree = (int64_t)std::round(deg * 1e7);
69 throwIfOutOfRange(angle_in_10_micro_degree, Latitude::MIN, Latitude::MAX, "Latitude");
70 latitude.value = angle_in_10_micro_degree;
71}
72
79inline void setLongitude(Longitude& longitude, const double deg) {
80 int64_t angle_in_10_micro_degree = (int64_t)std::round(deg * 1e7);
81 throwIfOutOfRange(angle_in_10_micro_degree, Longitude::MIN, Longitude::MAX, "Longitude");
82 longitude.value = angle_in_10_micro_degree;
83}
84
91inline void setAltitudeValue(AltitudeValue& altitude, const double value) {
92 int64_t alt_in_cm = (int64_t)std::round(value * 1e2);
93 if (alt_in_cm >= AltitudeValue::MIN && alt_in_cm <= AltitudeValue::MAX) {
94 altitude.value = alt_in_cm;
95 } else if (alt_in_cm < AltitudeValue::MIN) {
96 altitude.value = AltitudeValue::MIN;
97 } else if (alt_in_cm > AltitudeValue::MAX) {
98 altitude.value = AltitudeValue::MAX;
99 }
100}
101
110inline void setAltitude(Altitude& altitude, const double value) {
111 altitude.altitude_confidence.value = AltitudeConfidence::UNAVAILABLE;
112 setAltitudeValue(altitude.altitude_value, value);
113}
114
121inline void setSpeedValue(SpeedValue& speed, const double value) {
122 auto speed_val = std::round(value * 1e2);
123 throwIfOutOfRange(speed_val, SpeedValue::MIN, SpeedValue::MAX, "SpeedValue");
124 speed.value = static_cast<decltype(speed.value)>(speed_val);
125}
126
133inline void setSpeedConfidence(SpeedConfidence& speed_confidence, const double value) {
134 auto speed_conf = std::round(value * 1e2 * etsi_its_msgs::ONE_D_GAUSSIAN_FACTOR);
135 if (speed_conf < SpeedConfidence::MIN && speed_conf > 0.0){
136 speed_conf = SpeedConfidence::MIN;
137 } else if (speed_conf >= SpeedConfidence::OUT_OF_RANGE || speed_conf <= 0.0) {
138 speed_conf = SpeedConfidence::UNAVAILABLE;
139 }
140 speed_confidence.value = static_cast<decltype(speed_confidence.value)>(speed_conf);
141}
142
152inline void setSpeed(Speed& speed, const double value, const double confidence = std::numeric_limits<double>::infinity()) {
153 setSpeedConfidence(speed.speed_confidence, confidence);
154 setSpeedValue(speed.speed_value, value);
155}
156
163template <typename AccelerationMagnitudeValue>
164inline void setAccelerationMagnitudeValue(AccelerationMagnitudeValue& accel_mag_value, const double value) {
165 auto accel_mag = std::round(value * 1e1);
166 throwIfOutOfRange(accel_mag, AccelerationMagnitudeValue::MIN, AccelerationMagnitudeValue::MAX, "AccelerationMagnitudeValue");
167 accel_mag_value.value = static_cast<decltype(accel_mag_value.value)>(accel_mag);
168}
169
176template <typename AccelerationConfidence>
177inline void setAccelerationMagnitudeConfidence(AccelerationConfidence& accel_mag_confidence, const double value) {
178 auto accel_mag_conf = std::round(value * 1e1 * etsi_its_msgs::ONE_D_GAUSSIAN_FACTOR);
179 if (accel_mag_conf < AccelerationConfidence::MIN && accel_mag_conf > 0.0){
180 accel_mag_conf = AccelerationConfidence::MIN;
181 } else if (accel_mag_conf >= AccelerationConfidence::OUT_OF_RANGE || accel_mag_conf <= 0.0) {
182 accel_mag_conf = AccelerationConfidence::UNAVAILABLE;
183 }
184 accel_mag_confidence.value = static_cast<decltype(accel_mag_confidence.value)>(accel_mag_conf);
185}
186
196template<typename AccelerationMagnitude>
197inline void setAccelerationMagnitude(AccelerationMagnitude& accel_mag, const double value,
198 const double confidence = std::numeric_limits<double>::infinity()) {
199 setAccelerationMagnitudeConfidence(accel_mag.acceleration_confidence, confidence);
200 setAccelerationMagnitudeValue(accel_mag.acceleration_magnitude_value, value);
201}
202
209template <typename AccelerationConfidence>
210inline void setAccelerationConfidence(AccelerationConfidence& accel_confidence, const double value) {
211 auto accel_conf = std::round(value * 1e1 * etsi_its_msgs::ONE_D_GAUSSIAN_FACTOR);
212 if (accel_conf < AccelerationConfidence::MIN && accel_conf > 0.0){
213 accel_conf = AccelerationConfidence::MIN;
214 } else if (accel_conf >= AccelerationConfidence::OUT_OF_RANGE || accel_conf <= 0.0) {
215 accel_conf = AccelerationConfidence::UNAVAILABLE;
216 }
217 accel_confidence.value = static_cast<decltype(accel_confidence.value)>(accel_conf);
218}
219
231template <typename T>
232inline void setReferencePosition(T& ref_position, const double latitude, const double longitude,
233 const double altitude = AltitudeValue::UNAVAILABLE) {
234 setLatitude(ref_position.latitude, latitude);
235 setLongitude(ref_position.longitude, longitude);
236 if (altitude != AltitudeValue::UNAVAILABLE) {
237 setAltitude(ref_position.altitude, altitude);
238 } else {
239 ref_position.altitude.altitude_value.value = AltitudeValue::UNAVAILABLE;
240 ref_position.altitude.altitude_confidence.value = AltitudeConfidence::UNAVAILABLE;
241 }
242 // TODO: set confidence values
243}
244
257template <typename T>
258inline void setFromUTMPosition(T& reference_position, const gm::PointStamped& utm_position, const int zone,
259 const bool northp) {
260 std::string required_frame_prefix = "utm_";
261 if (utm_position.header.frame_id.rfind(required_frame_prefix, 0) != 0) {
262 throw std::invalid_argument("Frame-ID of UTM Position '" + utm_position.header.frame_id +
263 "' does not start with required prefix '" + required_frame_prefix + "'!");
264 }
265 double latitude, longitude;
266 try {
267 GeographicLib::UTMUPS::Reverse(zone, northp, utm_position.point.x, utm_position.point.y, latitude, longitude);
268 } catch (GeographicLib::GeographicErr& e) {
269 throw std::invalid_argument(e.what());
270 }
271 setReferencePosition(reference_position, latitude, longitude, utm_position.point.z);
272}
273
282template <typename HeadingValue>
283inline void setHeadingValue(HeadingValue& heading, const double value) {
284 int64_t deg = (int64_t)std::round(value * 1e1);
285 throwIfOutOfRange(deg, HeadingValue::MIN, HeadingValue::MAX, "HeadingValue");
286 heading.value = deg;
287}
288
295template<typename HeadingConfidence>
296inline void setHeadingConfidence(HeadingConfidence& heading_confidence, const double value) {
297 auto heading_conf = std::round(value * 1e1 * etsi_its_msgs::ONE_D_GAUSSIAN_FACTOR);
298 if (heading_conf < HeadingConfidence::MIN && heading_conf > 0.0){
299 heading_conf = HeadingConfidence::MIN;
300 } else if (heading_conf >= HeadingConfidence::OUT_OF_RANGE || heading_conf <= 0.0) {
301 heading_conf = HeadingConfidence::UNAVAILABLE;
302 }
303 heading_confidence.value = static_cast<decltype(heading_confidence.value)>(heading_conf);
304}
305
316template <typename Heading, typename HeadingConfidence = decltype(Heading::heading_confidence)>
317void setHeadingCDD(Heading& heading, const double value, double confidence = std::numeric_limits<double>::infinity()) {
318 setHeadingConfidence(heading.heading_confidence, confidence);
319 setHeadingValue(heading.heading_value, value);
320}
321
329template <typename YawRate, typename YawRateValue = decltype(YawRate::yaw_rate_value), typename YawRateConfidence = decltype(YawRate::yaw_rate_confidence)>
330inline void setYawRateCDD(YawRate& yaw_rate, const double value,
331 double confidence = std::numeric_limits<double>::infinity()) {
332 double yaw_rate_in_001_degrees = value * 100.0;
333 // limit value range
334 if (yaw_rate_in_001_degrees < YawRateValue::MIN) {
335 yaw_rate_in_001_degrees = YawRateValue::MIN; // MIN should be NEGATIVE_OUT_OF_RANGE, but CAM only has MIN
336 } else if (yaw_rate_in_001_degrees > YawRateValue::MAX - 1) {
337 yaw_rate_in_001_degrees = YawRateValue::MAX - 1; // MAX - 1 should be POSITIVE_OUT_OF_RANGE, but CAM only has MAX
338 }
339
340 yaw_rate.yaw_rate_value.value = static_cast<decltype(yaw_rate.yaw_rate_value.value)>(yaw_rate_in_001_degrees);
341
342 double yaw_rate_std = confidence;
343 if(yaw_rate_std == std::numeric_limits<double>::infinity()) {
344 yaw_rate.yaw_rate_confidence.value = YawRateConfidence::UNAVAILABLE;
345 } else {
346 yaw_rate_std *= etsi_its_msgs::ONE_D_GAUSSIAN_FACTOR;
347 // How stupid is this?!
348 static const std::map<double, uint8_t> confidence_map = {
349 {0.01, YawRateConfidence::DEG_SEC_000_01},
350 {0.05, YawRateConfidence::DEG_SEC_000_05},
351 {0.1, YawRateConfidence::DEG_SEC_000_10},
352 {1.0, YawRateConfidence::DEG_SEC_001_00},
353 {5.0, YawRateConfidence::DEG_SEC_005_00},
354 {10.0, YawRateConfidence::DEG_SEC_010_00},
355 {100.0, YawRateConfidence::DEG_SEC_100_00},
356 {std::numeric_limits<double>::infinity(), YawRateConfidence::OUT_OF_RANGE},
357 };
358 for(const auto& [thresh, conf_val] : confidence_map) {
359 if (yaw_rate_std <= thresh) {
360 yaw_rate.yaw_rate_confidence.value = conf_val;
361 break;
362 }
363 }
364 }
365}
366
375template <typename SemiAxisLength>
376inline void setSemiAxis(SemiAxisLength& semi_axis_length, const double length) {
377 double semi_axis_length_val = std::round(length * etsi_its_msgs::OneCentimeterHelper<SemiAxisLength>::value * 1e2);
378 if(semi_axis_length_val < SemiAxisLength::MIN) {
379 semi_axis_length_val = SemiAxisLength::MIN;
380 } else if(semi_axis_length_val >= SemiAxisLength::OUT_OF_RANGE) {
381 semi_axis_length_val = SemiAxisLength::OUT_OF_RANGE;
382 }
383 semi_axis_length.value = static_cast<uint16_t>(semi_axis_length_val);
384}
385
394template <typename PosConfidenceEllipse>
395inline void setPosConfidenceEllipse(PosConfidenceEllipse& position_confidence_ellipse, const double semi_major_axis,
396 const double semi_minor_axis, const double orientation) {
397 setSemiAxis(position_confidence_ellipse.semi_major_confidence, semi_major_axis);
398 setSemiAxis(position_confidence_ellipse.semi_minor_confidence, semi_minor_axis);
399 setHeadingValue(position_confidence_ellipse.semi_major_orientation, orientation);
400}
401
411inline std::tuple<double, double, double> confidenceEllipseFromCovMatrix(const std::array<double, 4>& covariance_matrix, const double object_heading) {
412
413 if(std::abs(covariance_matrix[1] - covariance_matrix[2]) > 1e-6) {
414 throw std::invalid_argument("Covariance matrix is not symmetric");
415 }
416 double trace = covariance_matrix[0] + covariance_matrix[3];
417 double determinant = covariance_matrix[0] * covariance_matrix[3] - covariance_matrix[1] * covariance_matrix[1];
418 if (determinant <= 0 || covariance_matrix[0] <= 0) {
419 // https://sites.math.northwestern.edu/~clark/285/2006-07/handouts/pos-def.pdf:
420 // Therefore, a necessary and sufficient condition for the quadratic form of a symmetric 2 × 2 matrix
421 // to be positive definite is for det(A) > 0 and a > 0
422 throw std::invalid_argument("Covariance matrix is not positive definite");
423 }
424 double eigenvalue1 = trace / 2 + std::sqrt(trace * trace / 4 - determinant);
425 double eigenvalue2 = trace / 2 - std::sqrt(trace * trace / 4 - determinant);
426 double semi_major_axis = std::sqrt(eigenvalue1) * etsi_its_msgs::TWO_D_GAUSSIAN_FACTOR;
427 double semi_minor_axis = std::sqrt(eigenvalue2) * etsi_its_msgs::TWO_D_GAUSSIAN_FACTOR;
428 // object_heading - orientation of the ellipse, as WGS84 has positive angles to the right
429 double orientation = object_heading - 0.5 * std::atan2(2 * covariance_matrix[1], covariance_matrix[0] - covariance_matrix[3]);
430 orientation = orientation * 180 / M_PI; // Convert to degrees
431 // Normalize to [0, 180)
432 // Not to 0, 360, as the ellipse is symmetric and the orientation is defined as the angle between the semi-major axis and the x-axis
433 orientation = std::fmod(orientation + 180, 180);
434 while (orientation < 0) {
435 orientation += 180;
436 }
437 while (orientation >= 180) {
438 orientation -= 180;
439 }
440 return std::make_tuple(semi_major_axis, semi_minor_axis, orientation);
441}
442
452inline std::tuple<double, double, double> confidenceEllipseFromWGSCovMatrix(const std::array<double, 4>& covariance_matrix) {
453 // The resulting ellipse is the same as if the cov matrix was given in vehicle coordinates
454 // and the object heading was set to 0.0
455 return confidenceEllipseFromCovMatrix(covariance_matrix, 0.0);
456}
457
467template <typename PosConfidenceEllipse>
468inline void setPosConfidenceEllipse(PosConfidenceEllipse& position_confidence_ellipse, const std::array<double, 4>& covariance_matrix, const double object_heading){
469 auto [semi_major_axis, semi_minor_axis, orientation] = confidenceEllipseFromCovMatrix(covariance_matrix, object_heading);
470 setPosConfidenceEllipse(position_confidence_ellipse, semi_major_axis, semi_minor_axis, orientation);
471}
472
482template <typename PosConfidenceEllipse>
483inline void setWGSPosConfidenceEllipse(PosConfidenceEllipse& position_confidence_ellipse, const std::array<double, 4>& covariance_matrix){
484 auto [semi_major_axis, semi_minor_axis, orientation] = confidenceEllipseFromWGSCovMatrix(covariance_matrix);
485 setPosConfidenceEllipse(position_confidence_ellipse, semi_major_axis, semi_minor_axis, orientation);
486}
487
488#endif // ETSI_ITS_MSGS_UTILS_IMPL_CDD_CDD_SETTERS_COMMON_H
void setLongitude(Longitude &longitude, const double deg)
Set the Longitude object.
void setAccelerationConfidence(AccelerationConfidence &accel_confidence, const double value)
Set the Acceleration Confidence object.
void setPosConfidenceEllipse(PosConfidenceEllipse &position_confidence_ellipse, const double semi_major_axis, const double semi_minor_axis, const double orientation)
Set the Pos Confidence Ellipse object.
void setSpeedValue(SpeedValue &speed, const double value)
Set the SpeedValue object.
void setTimestampITS(TimestampIts &timestamp_its, const uint64_t unix_nanosecs, const uint16_t n_leap_seconds=etsi_its_msgs::LEAP_SECOND_INSERTIONS_SINCE_2004.rbegin() ->second)
Set the TimestampITS object.
void setSpeedConfidence(SpeedConfidence &speed_confidence, const double value)
Set the Speed Confidence object.
void setStationId(StationId &station_id, const uint32_t id_value)
Set the Station Id object.
std::tuple< double, double, double > confidenceEllipseFromCovMatrix(const std::array< double, 4 > &covariance_matrix, const double object_heading)
Gets the values needed to set a confidence ellipse from a covariance matrix.
void setAccelerationMagnitudeValue(AccelerationMagnitudeValue &accel_mag_value, const double value)
Set the Acceleration Magnitude Value object.
void setSemiAxis(SemiAxisLength &semi_axis_length, const double length)
Set the Semi Axis length.
void setStationType(StationType &station_type, const uint8_t value)
Set the Station Type.
void setAltitude(Altitude &altitude, const double value)
Set the Altitude object.
void setYawRateCDD(YawRate &yaw_rate, const double value, double confidence=std::numeric_limits< double >::infinity())
Set the Yaw Rate object.
void setFromUTMPosition(T &reference_position, const gm::PointStamped &utm_position, const int zone, const bool northp)
Set the ReferencePosition from a given UTM-Position.
void setHeadingConfidence(HeadingConfidence &heading_confidence, const double value)
Set the Heading Confidence object.
void setSpeed(Speed &speed, const double value, const double confidence=std::numeric_limits< double >::infinity())
Set the Speed object.
void setAccelerationMagnitudeConfidence(AccelerationConfidence &accel_mag_confidence, const double value)
Set the AccelerationMagnitude Confidence object.
void setWGSPosConfidenceEllipse(PosConfidenceEllipse &position_confidence_ellipse, const std::array< double, 4 > &covariance_matrix)
Set the Pos Confidence Ellipse object.
void setAccelerationMagnitude(AccelerationMagnitude &accel_mag, const double value, const double confidence=std::numeric_limits< double >::infinity())
Set the AccelerationMagnitude object.
void setAltitudeValue(AltitudeValue &altitude, const double value)
Set the AltitudeValue object.
void setHeadingCDD(Heading &heading, const double value, double confidence=std::numeric_limits< double >::infinity())
Set the Heading object.
void setHeadingValue(HeadingValue &heading, const double value)
Set the HeadingValue object.
void setLatitude(Latitude &latitude, const double deg)
Set the Latitude object.
void setReferencePosition(T &ref_position, const double latitude, const double longitude, const double altitude=AltitudeValue::UNAVAILABLE)
Sets the reference position in the given ReferencePostion object.
std::tuple< double, double, double > confidenceEllipseFromWGSCovMatrix(const std::array< double, 4 > &covariance_matrix)
Gets the values needed to set a confidence ellipse from a covariance matrix.
Sanity-check functions etc.
void throwIfOutOfRange(const T1 &val, const T2 &min, const T2 &max, const std::string val_desc)
Throws an exception if a given value is out of a defined range.
Definition checks.h:23
File containing constants that are used in the context of ETIS ITS Messages.
const std::map< uint64_t, uint16_t > LEAP_SECOND_INSERTIONS_SINCE_2004
std::map that stores all leap second insertions since 2004 with the corresponding unix-date of the in...
Definition constants.h:22