Skip to content

Commit ce7ceae

Browse files
msz-raiprybicki
andauthored
Improve radar clustering with variable separation on distance ranges (still CPU only) (#260)
* Add ranged separation for distance and radial speed * Add missing static_asset for structs * Introduce rgl_radar_separations_t * Follow math convention (a < b < c) Co-authored-by: Piotr Rybicki <[email protected]> * Review changes * Add validation to the radarScopes * Fix clusters merging check * Fix iteration and required field list * Add clustering test * Add more test cases * Review changes --------- Co-authored-by: Piotr Rybicki <[email protected]>
1 parent 4411255 commit ce7ceae

File tree

11 files changed

+352
-73
lines changed

11 files changed

+352
-73
lines changed

include/rgl/api/core.h

Lines changed: 63 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -61,6 +61,12 @@ typedef struct
6161
float value[2];
6262
} rgl_vec2f;
6363

64+
#ifndef __cplusplus
65+
static_assert(sizeof(rgl_vec2f) == 2 * sizeof(float));
66+
static_assert(std::is_trivial_v<rgl_vec2f>);
67+
static_assert(std::is_standard_layout_v<rgl_vec2f>);
68+
#endif
69+
6470
/**
6571
* Three consecutive 32-bit floats.
6672
*/
@@ -71,6 +77,8 @@ typedef struct
7177

7278
#ifndef __cplusplus
7379
static_assert(sizeof(rgl_vec3f) == 3 * sizeof(float));
80+
static_assert(std::is_trivial_v<rgl_vec3f>);
81+
static_assert(std::is_standard_layout_v<rgl_vec3f>);
7482
#endif
7583

7684
/**
@@ -81,6 +89,12 @@ typedef struct
8189
int32_t value[3];
8290
} rgl_vec3i;
8391

92+
#ifndef __cplusplus
93+
static_assert(sizeof(rgl_vec3i) == 3 * sizeof(int32_t));
94+
static_assert(std::is_trivial_v<rgl_vec3i>);
95+
static_assert(std::is_standard_layout_v<rgl_vec3i>);
96+
#endif
97+
8498
/**
8599
* Row-major matrix with 3 rows and 4 columns of 32-bit floats.
86100
* Right-handed coordinate system.
@@ -90,6 +104,45 @@ typedef struct
90104
float value[3][4];
91105
} rgl_mat3x4f;
92106

107+
#ifndef __cplusplus
108+
static_assert(sizeof(rgl_mat3x4f) == 3 * 4 * sizeof(float));
109+
static_assert(std::is_trivial_v<rgl_mat3x4f>);
110+
static_assert(std::is_standard_layout_v<rgl_mat3x4f>);
111+
#endif
112+
113+
/**
114+
* Radar parameters applied at a given distance range.
115+
*/
116+
typedef struct
117+
{
118+
/**
119+
* The beginning distance range for the parameters.
120+
*/
121+
float begin_distance;
122+
/**
123+
* The end range distance for the parameters.
124+
*/
125+
float end_distance;
126+
/**
127+
* The maximum distance difference to create a new radar detection (in simulation units).
128+
*/
129+
float distance_separation_threshold;
130+
/**
131+
* The maximum radial speed difference to create a new radar detection (in simulation units)
132+
*/
133+
float radial_speed_separation_threshold;
134+
/**
135+
* The maximum azimuth difference to create a new radar detection (in radians).
136+
*/
137+
float azimuth_separation_threshold;
138+
} rgl_radar_scope_t;
139+
140+
#ifndef __cplusplus
141+
static_assert(sizeof(rgl_radar_separations_t) == 5 * sizeof(float));
142+
static_assert(std::is_trivial_v<rgl_radar_separations_t>);
143+
static_assert(std::is_standard_layout_v<rgl_radar_separations_t>);
144+
#endif
145+
93146
/**
94147
* Represents on-GPU Mesh that can be referenced by Entities on the Scene.
95148
* Each Mesh can be referenced by any number of Entities on different Scenes.
@@ -699,19 +752,24 @@ RGL_API rgl_status_t rgl_node_points_from_array(rgl_node_t* node, const void* po
699752
/**
700753
* Creates or modifies RadarPostprocessPointsNode.
701754
* The Node processes point cloud to create radar-like output.
702-
* The point cloud is reduced by clustering input based on hit-point distance and hit-point azimuth.
755+
* The point cloud is reduced by clustering input based on hit-point attributes: distance, radial speed and azimuth.
756+
* Some radar parameters may vary for different distance ranges, as radars may employ multiple frequency bands.
757+
* For this reason, the configuration allows the definition of multiple radar scopes of parameters on the assumption that:
758+
* - in case of scopes that overlap, the first matching one will be used
759+
* - if the point is not within any of the radar scopes, it will be rejected
703760
* The output consists of the collection of one point per cluster (the closest to the azimuth and elevation center).
704761
* Graph input: point cloud
705762
* Graph output: point cloud
706763
* @param node If (*node) == nullptr, a new Node will be created. Otherwise, (*node) will be modified.
707-
* @param distance_separation The maximum distance difference to create a new radar cluster (in simulation units).
708-
* @param azimuth_separation The maximum azimuth difference to create a new radar cluster (in radians).
764+
* @param radar_scopes Array of radar scopes of parameters. See `rgl_radar_scope_t` for more details.
765+
* @param radar_scopes_count Number of elements in the `radar_scopes` array.
709766
* @param ray_azimuth_step The azimuth step between rays (in radians).
710767
* @param ray_elevation_step The elevation step between rays (in radians).
711768
* @param frequency The frequency of the radar (in Hz).
712769
*/
713-
RGL_API rgl_status_t rgl_node_points_radar_postprocess(rgl_node_t* node, float distance_separation, float azimuth_separation,
714-
float ray_azimuth_step, float ray_elevation_step, float frequency);
770+
RGL_API rgl_status_t rgl_node_points_radar_postprocess(rgl_node_t* node, const rgl_radar_scope_t* radar_scopes,
771+
int32_t radar_scopes_count, float ray_azimuth_step,
772+
float ray_elevation_step, float frequency);
715773

716774
/**
717775
* Creates or modifies FilterGroundPointsNode.

src/api/apiCore.cpp

Lines changed: 25 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -1049,31 +1049,44 @@ void TapeCore::tape_node_points_from_array(const YAML::Node& yamlNode, PlaybackS
10491049
state.nodes.insert({nodeId, node});
10501050
}
10511051

1052-
RGL_API rgl_status_t rgl_node_points_radar_postprocess(rgl_node_t* node, float distance_separation, float azimuth_separation,
1053-
float ray_azimuth_step, float ray_elevation_step, float frequency)
1052+
RGL_API rgl_status_t rgl_node_points_radar_postprocess(rgl_node_t* node, const rgl_radar_scope_t* radar_scopes,
1053+
int32_t radar_scopes_count, float ray_azimuth_step,
1054+
float ray_elevation_step, float frequency)
10541055
{
10551056
auto status = rglSafeCall([&]() {
1056-
RGL_API_LOG("rgl_node_points_radar_postprocess(node={}, distance_separation={}, azimuth_separation={})", repr(node),
1057-
distance_separation, azimuth_separation);
1058-
1059-
CHECK_ARG(distance_separation > 0);
1060-
CHECK_ARG(azimuth_separation > 0);
1057+
RGL_API_LOG("rgl_node_points_radar_postprocess(node={}, radar_scopes={}, ray_azimuth_step={}, ray_elevation_step={}, "
1058+
"frequency={})",
1059+
repr(node), repr(radar_scopes, radar_scopes_count), ray_azimuth_step, ray_elevation_step, frequency);
1060+
CHECK_ARG(radar_scopes != nullptr);
1061+
CHECK_ARG(radar_scopes_count > 0);
10611062
CHECK_ARG(ray_azimuth_step > 0);
10621063
CHECK_ARG(ray_elevation_step > 0);
1064+
CHECK_ARG(frequency > 0);
1065+
1066+
for (int i = 0; i < radar_scopes_count; ++i) {
1067+
CHECK_ARG(radar_scopes[i].begin_distance >= 0);
1068+
CHECK_ARG(radar_scopes[i].end_distance >= 0);
1069+
CHECK_ARG(radar_scopes[i].distance_separation_threshold >= 0);
1070+
CHECK_ARG(radar_scopes[i].radial_speed_separation_threshold >= 0);
1071+
CHECK_ARG(radar_scopes[i].azimuth_separation_threshold >= 0);
1072+
CHECK_ARG(radar_scopes[i].end_distance >= radar_scopes[i].begin_distance);
1073+
}
10631074

1064-
createOrUpdateNode<RadarPostprocessPointsNode>(node, distance_separation, azimuth_separation, ray_azimuth_step,
1065-
ray_elevation_step, frequency);
1075+
createOrUpdateNode<RadarPostprocessPointsNode>(
1076+
node, std::vector<rgl_radar_scope_t>{radar_scopes, radar_scopes + radar_scopes_count}, ray_azimuth_step,
1077+
ray_elevation_step, frequency);
10661078
});
1067-
TAPE_HOOK(node, distance_separation, azimuth_separation, ray_azimuth_step, ray_elevation_step, frequency);
1079+
TAPE_HOOK(node, TAPE_ARRAY(radar_scopes, radar_scopes_count), radar_scopes_count, ray_azimuth_step, ray_elevation_step,
1080+
frequency);
10681081
return status;
10691082
}
10701083

10711084
void TapeCore::tape_node_points_radar_postprocess(const YAML::Node& yamlNode, PlaybackState& state)
10721085
{
10731086
auto nodeId = yamlNode[0].as<TapeAPIObjectID>();
10741087
rgl_node_t node = state.nodes.contains(nodeId) ? state.nodes.at(nodeId) : nullptr;
1075-
rgl_node_points_radar_postprocess(&node, yamlNode[1].as<float>(), yamlNode[2].as<float>(), yamlNode[3].as<float>(),
1076-
yamlNode[4].as<float>(), yamlNode[5].as<float>());
1088+
rgl_node_points_radar_postprocess(&node, state.getPtr<const rgl_radar_scope_t>(yamlNode[1]), yamlNode[2].as<int32_t>(),
1089+
yamlNode[3].as<float>(), yamlNode[4].as<float>(), yamlNode[5].as<float>());
10771090
state.nodes.insert({nodeId, node});
10781091
}
10791092

src/graph/NodesCore.hpp

Lines changed: 15 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -369,7 +369,11 @@ struct FromArrayPointsNode : IPointsNode, INoInputNode
369369
void enqueueExecImpl() override {}
370370

371371
// Point cloud description
372-
bool isDense() const override { return false; }
372+
bool isDense() const override
373+
{
374+
// If point cloud doesn't contain IS_HIT field we assume all points are hits.
375+
return !fieldData.contains(RGL_FIELD_IS_HIT_I32);
376+
}
373377
bool hasField(rgl_field_t field) const override { return fieldData.contains(field); }
374378
size_t getWidth() const override { return width; }
375379
size_t getHeight() const override { return 1; }
@@ -470,7 +474,8 @@ struct GaussianNoiseDistanceNode : IPointsNodeSingleInput
470474
struct RadarPostprocessPointsNode : IPointsNodeSingleInput
471475
{
472476
using Ptr = std::shared_ptr<RadarPostprocessPointsNode>;
473-
void setParameters(float distanceSeparation, float azimuthSeparation, float rayAzimuthStepRad, float rayElevationStepRad,
477+
478+
void setParameters(const std::vector<rgl_radar_scope_t>& radarScopes, float rayAzimuthStepRad, float rayElevationStepRad,
474479
float frequency);
475480

476481
// Node
@@ -494,32 +499,33 @@ struct RadarPostprocessPointsNode : IPointsNodeSingleInput
494499
arrayMgr);
495500
HostPinnedArray<Field<DISTANCE_F32>::type>::Ptr distanceInputHost = HostPinnedArray<Field<DISTANCE_F32>::type>::create();
496501
HostPinnedArray<Field<AZIMUTH_F32>::type>::Ptr azimuthInputHost = HostPinnedArray<Field<AZIMUTH_F32>::type>::create();
502+
HostPinnedArray<Field<RADIAL_SPEED_F32>::type>::Ptr radialSpeedInputHost =
503+
HostPinnedArray<Field<RADIAL_SPEED_F32>::type>::create();
497504
HostPinnedArray<Field<ELEVATION_F32>::type>::Ptr elevationInputHost = HostPinnedArray<Field<ELEVATION_F32>::type>::create();
498505
DeviceAsyncArray<Vector<3, thrust::complex<float>>>::Ptr outBUBRFactorDev =
499506
DeviceAsyncArray<Vector<3, thrust::complex<float>>>::create(arrayMgr);
500507
HostPinnedArray<Vector<3, thrust::complex<float>>>::Ptr outBUBRFactorHost =
501508
HostPinnedArray<Vector<3, thrust::complex<float>>>::create();
502509

503-
float distanceSeparation;
504-
float azimuthSeparation;
505510
float rayAzimuthStepRad;
506511
float rayElevationStepRad;
507512
float frequency;
508513

514+
std::vector<rgl_radar_scope_t> radarScopes;
509515

510516
// RGL related members
511517
std::mutex getFieldDataMutex;
512518
mutable CacheManager<rgl_field_t, IAnyArray::Ptr> cacheManager;
513519

514520
struct RadarCluster
515521
{
516-
RadarCluster(Field<RAY_IDX_U32>::type index, float distance, float azimuth, float elevation);
522+
RadarCluster(Field<RAY_IDX_U32>::type index, float distance, float azimuth, float radialSpeed, float elevation);
517523
RadarCluster(RadarCluster&& other) noexcept = default;
518524
RadarCluster& operator=(RadarCluster&& other) noexcept = default;
519525

520-
void addPoint(Field<RAY_IDX_U32>::type index, float distance, float azimuth, float elevation);
521-
inline bool isCandidate(float distance, float azimuth, float distanceSeparation, float azimuthSeparation) const;
522-
inline bool canMergeWith(const RadarCluster& other, float distanceSeparation, float azimuthSeparation) const;
526+
void addPoint(Field<RAY_IDX_U32>::type index, float distance, float azimuth, float radialSpeed, float elevation);
527+
inline bool isCandidate(float distance, float azimuth, float radialSpeed, const rgl_radar_scope_t& separations) const;
528+
inline bool canMergeWith(const RadarCluster& other, const std::vector<rgl_radar_scope_t>& radarScopes) const;
523529
void takeIndicesFrom(RadarCluster&& other);
524530
Field<RAY_IDX_U32>::type findDirectionalCenterIndex(const Field<AZIMUTH_F32>::type* azimuths,
525531
const Field<ELEVATION_F32>::type* elevations) const;
@@ -528,6 +534,7 @@ struct RadarPostprocessPointsNode : IPointsNodeSingleInput
528534
std::vector<Field<RAY_IDX_U32>::type> indices;
529535
Vector<2, Field<DISTANCE_F32>::type> minMaxDistance;
530536
Vector<2, Field<AZIMUTH_F32>::type> minMaxAzimuth;
537+
Vector<2, Field<RADIAL_SPEED_F32>::type> minMaxRadialSpeed;
531538
Vector<2, Field<ELEVATION_F32>::type> minMaxElevation; // For finding directional center only
532539
};
533540
};

0 commit comments

Comments
 (0)