Skip to content

feat: add DistanceNoiseStd and FlipHitProbability to RayPerceptionSensor #6215

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 1 commit into
base: develop
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
14 changes: 14 additions & 0 deletions com.unity.ml-agents/CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,20 @@ and this project adheres to
[Semantic Versioning](http://semver.org/spec/v2.0.0.html).

## [Unreleased]

### Added
- **Sensors** – Two new noise parameters are now available on RayPerceptionSensorComponent:

| Parameter | Default | Description |
|-----------|---------|-------------|
| `DistanceNoiseStd` | `0` | Standard deviation (σ) of Gaussian noise added to HitFraction, which represents the normalized hit distance (ranging from 0 to 1). |
| `FlipHitProbability` | `0` | The probability of randomly flipping the HasHit boolean value (0 → 1 or 1 → 0). A value of 0 means no flipping occurs. |

Leaving both parameters at `0` reproduces the exact behaviour of previous releases.

### Fixed
- n/a

### Major Changes
#### com.unity.ml-agents / com.unity.ml-agents.extensions (C#)
- Upgraded to Inference Engine 2.2.1 (#6212)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -72,6 +72,10 @@ protected void OnRayPerceptionInspectorGUI(bool is3d)
EditorGUILayout.PropertyField(so.FindProperty("rayHitColor"), true);
EditorGUILayout.PropertyField(so.FindProperty("rayMissColor"), true);

// ───────── Parameters Noise ─────────
EditorGUILayout.PropertyField(so.FindProperty("m_DistanceNoiseStd"), true);
EditorGUILayout.PropertyField(so.FindProperty("m_FlipHitProbability"), true);

EditorGUI.indentLevel--;
if (EditorGUI.EndChangeCheck())
{
Expand Down
50 changes: 48 additions & 2 deletions com.unity.ml-agents/Runtime/Sensors/RayPerceptionSensor.cs
Original file line number Diff line number Diff line change
Expand Up @@ -254,6 +254,10 @@ public class RayPerceptionSensor : ISensor, IBuiltInSensor

bool m_UseBatchedRaycasts;

// ───────── Parameters Noise ─────────
float m_DistanceNoiseStd;
float m_FlipHitProb;

/// <summary>
/// Time.frameCount at the last time Update() was called. This is only used for display in gizmos.
/// </summary>
Expand All @@ -269,12 +273,16 @@ internal int DebugLastFrameCount
/// </summary>
/// <param name="name">The name of the sensor.</param>
/// <param name="rayInput">The inputs for the sensor.</param>
public RayPerceptionSensor(string name, RayPerceptionInput rayInput)
public RayPerceptionSensor(string name, RayPerceptionInput rayInput, float distanceNoiseStd, float flipHitProb)
{
m_Name = name;
m_RayPerceptionInput = rayInput;
m_UseBatchedRaycasts = rayInput.UseBatchedRaycasts;

// ───────── Parameters Noise ─────────
m_DistanceNoiseStd = distanceNoiseStd;
m_FlipHitProb = flipHitProb;

SetNumObservations(rayInput.OutputSize());

m_DebugLastFrameCount = Time.frameCount;
Expand Down Expand Up @@ -329,7 +337,20 @@ public int Write(ObservationWriter writer)
// For each ray, write the information to the observation buffer
for (var rayIndex = 0; rayIndex < numRays; rayIndex++)
{
m_RayPerceptionOutput.RayOutputs?[rayIndex].ToFloatArray(numDetectableTags, rayIndex, m_Observations);
var ro = m_RayPerceptionOutput.RayOutputs[rayIndex];

// Used to debug values
float before = ro.HitFraction;
bool hit0 = ro.HasHit;

// Aplly noise
ApplyNoise(ref ro);

// Debug Value
//if (before != ro.HitFraction) Debug.Log($"Ray {rayIndex} | dist {before} → {ro.HitFraction} | hit {hit0}→{ro.HasHit}");

m_RayPerceptionOutput.RayOutputs[rayIndex] = ro;
ro.ToFloatArray(numDetectableTags, rayIndex, m_Observations);
}

// Finally, add the observations to the ObservationWriter
Expand Down Expand Up @@ -666,5 +687,30 @@ int rayIndex

return rayOutput;
}

/// <summary>
/// Applies simulated noise to ray hit data to mimic real-world sensor or environmental conditions.
/// Includes Gaussian-like noise on hit distance and random flipping of the hit detection state.
/// </summary>
/// <param name="ro">Reference to the RayOutput object to modify with applied noise.</param>
void ApplyNoise(ref RayPerceptionOutput.RayOutput ro)
{
// Apply noise to the normalized hit distance if m_DistanceNoiseStd > 0
if (m_DistanceNoiseStd > 0f)
{
// Generate a random value in the range [-m_DistanceNoiseStd, m_DistanceNoiseStd]
// Add it to the original HitFraction and clamp the result between 0 and 1
ro.HitFraction = Mathf.Clamp01(
ro.HitFraction +
UnityEngine.Random.Range(-m_DistanceNoiseStd, m_DistanceNoiseStd));
}

// Randomly flip the hit detection state based on m_FlipHitProb
if (m_FlipHitProb > 0f && UnityEngine.Random.value < m_FlipHitProb)
{
// Invert the boolean HasHit value: true becomes false, and vice versa
ro.HasHit = !ro.HasHit;
}
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -180,6 +180,28 @@ public bool UseBatchedRaycasts
[SerializeField]
internal Color rayMissColor = Color.white;

// ───────── Parametes Noise ─────────
/// <summary>
/// Standard deviation of Gaussian noise added to the normalized ray distance.
/// A value of 0 means no noise is applied.
/// </summary>
[HideInInspector]
[SerializeField, Range(0f, 0.5f)]
[Header("Noise", order = 999)]
[Tooltip("Standard deviation of Gaussian noise added to the normalized ray distance (HitFraction varies from 0 to 1)")]
internal float m_DistanceNoiseStd;

/// <summary>
/// Probability of randomly flipping the HasHit bit (0 → 1 or 1 → 0).
/// This simulates sensor or detection errors in raycasting.
/// A value of 0 means no flipping occurs.
/// </summary>
[HideInInspector]
[SerializeField, Range(0f, 0.5f)]
[Tooltip("Probability of flipping the HasHit bit (0 → 1 or 1 → 0).")]
float m_FlipHitProbability;


[NonSerialized]
RayPerceptionSensor m_RaySensor;

Expand Down Expand Up @@ -223,7 +245,12 @@ public override ISensor[] CreateSensors()
{
var rayPerceptionInput = GetRayPerceptionInput();

m_RaySensor = new RayPerceptionSensor(m_SensorName, rayPerceptionInput);
m_RaySensor = new RayPerceptionSensor(
m_SensorName,
rayPerceptionInput,
m_DistanceNoiseStd,
m_FlipHitProbability
);

if (ObservationStacks != 1)
{
Expand Down
2 changes: 2 additions & 0 deletions docs/Learning-Environment-Design-Agents.md
Original file line number Diff line number Diff line change
Expand Up @@ -509,6 +509,8 @@ Both sensor components have several settings:
but if using custom models the left-to-right layout that matches the spatial
structuring can be preferred (e.g. for processing with conv nets).
- _Use Batched Raycasts_ (3D only) Whether to use batched raycasts. Enable to use batched raycasts and the jobs system.
- _Distance Noise Std_ This parameter controls the standard deviation (σ) of Gaussian noise added to HitFraction, a value representing the normalized hit distance along the ray. A value of 0 means no noise is applied. HitFraction ranges from 0 (no hit) to 1 (hit at maximum ray distance).
- _FlipHitProbability_ Sets the probability that the HasHit result will be flipped (e.g., hit becomes no hit, or vice versa). Useful for simulating sensor noise or unreliable detection..

In the example image above, the Agent has two `RayPerceptionSensorComponent3D`s.
Both use 3 Rays Per Direction and 90 Max Ray Degrees. One of the components had
Expand Down