Skip to content

Commit 9fbb408

Browse files
committed
[#1164] Fix NormalVectorAngleDispersion scalar sampling
Update NormalVectorAngleDispersion to draw scalar phi/theta samples instead of one-element NumPy arrays. The previous size=1 calls caused magnitude generation to fail when round() received an ndarray. Add a regression test that records the np.random.normal() calls and verifies the dispersion uses scalar sample arguments while still producing a normalized output vector and valid sigma magnitudes.
1 parent 56ef110 commit 9fbb408

2 files changed

Lines changed: 39 additions & 2 deletions

File tree

src/utilities/MonteCarlo/Dispersions.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -301,8 +301,8 @@ def generate(self, sim=None):
301301
meanPhi = vectorSphere[1] # Nominal phi
302302
meanTheta = vectorSphere[2] # Nominal theta
303303

304-
phiRnd = np.random.normal(meanPhi, self.phiStd, 1)
305-
thetaRnd = np.random.normal(meanTheta, self.thetaStd, 1)
304+
phiRnd = np.random.normal(meanPhi, self.phiStd)
305+
thetaRnd = np.random.normal(meanTheta, self.thetaStd)
306306

307307
self.phiBounds = [meanPhi + self.phiBoundsOffNom[0], meanPhi + self.phiBoundsOffNom[1]]
308308
self.thetaBounds = [meanTheta + self.thetaBoundsOffNom[0], meanTheta + self.thetaBoundsOffNom[1]]

src/utilities/MonteCarlo/_UnitTests/test_controller.py

Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@
2222
from Basilisk.utilities import simHelpers
2323
from Basilisk.utilities.MonteCarlo.Controller import SimulationExecutor, SimulationParameters
2424
from Basilisk.utilities.MonteCarlo.Dispersions import (
25+
NormalVectorAngleDispersion,
2526
NormalVectorDispersion,
2627
UniformDispersion,
2728
UniformVectorAngleDispersion
@@ -193,6 +194,42 @@ def record_uniform(lower_bound, upper_bound):
193194
assert np.allclose(uniform_calls[1], expected_theta_bounds)
194195

195196

197+
def test_normal_vector_angle_dispersion_uses_scalar_angle_samples(monkeypatch):
198+
"""Verify normal angle dispersions draw scalar angle samples."""
199+
sim = DummySimulation()
200+
vector_path = "get_DynModel().scObject.hub.unitVector"
201+
sim.get_DynModel().scObject.hub.unitVector = np.array([
202+
[1.0], [1.0], [1.0]
203+
]) # [-]
204+
phi_std = 0.02 # [rad]
205+
theta_std = 0.03 # [rad]
206+
normal_calls = []
207+
208+
def record_normal(mean, standard_deviation):
209+
normal_calls.append((mean, standard_deviation))
210+
return mean
211+
212+
monkeypatch.setattr(np.random, "normal", record_normal)
213+
214+
dispersion = NormalVectorAngleDispersion(
215+
vector_path,
216+
phiStd=phi_std,
217+
thetaStd=theta_std,
218+
phiBoundsOffNom=[-0.1, 0.1],
219+
thetaBoundsOffNom=[-0.1, 0.1]
220+
)
221+
dispersed_vector = dispersion.generate(sim)
222+
223+
nominal_vector = sim.get_DynModel().scObject.hub.unitVector
224+
nominal_vector = nominal_vector / np.linalg.norm(nominal_vector)
225+
nominal_spherical = dispersion.cart2Spherical(nominal_vector)
226+
227+
assert np.isclose(np.linalg.norm(dispersed_vector), 1.0)
228+
assert np.allclose(normal_calls[0], [nominal_spherical[1], phi_std])
229+
assert np.allclose(normal_calls[1], [nominal_spherical[2], theta_std])
230+
assert dispersion.getDispersionMag() == [r"0.0 $\sigma$", r"0.0 $\sigma$"]
231+
232+
196233
def test_normal_vector_dispersion_uses_configured_statistics():
197234
"""Verify normal vector dispersions retain mean and standard deviation."""
198235
sim = DummySimulation()

0 commit comments

Comments
 (0)