99 lines
3.3 KiB
Python
99 lines
3.3 KiB
Python
|
|
#!/usr/bin/env python3
|
||
|
|
"""Configuration propagation and bounded-size contracts for bilateral v2."""
|
||
|
|
|
||
|
|
from pathlib import Path
|
||
|
|
import sys
|
||
|
|
import unittest
|
||
|
|
|
||
|
|
|
||
|
|
CODE_ROOT = Path(__file__).resolve().parents[1]
|
||
|
|
sys.path.insert(0, str(CODE_ROOT))
|
||
|
|
|
||
|
|
from experiments.executors import _bilateral_scenario_and_config # noqa: E402
|
||
|
|
from experiments.plan import build_trial_plan, load_document # noqa: E402
|
||
|
|
from experiments.rng import named_seed_record # noqa: E402
|
||
|
|
|
||
|
|
|
||
|
|
CONFIG_ROOT = CODE_ROOT / "config" / "experiments"
|
||
|
|
|
||
|
|
|
||
|
|
def bilateral_trial():
|
||
|
|
return {
|
||
|
|
"method": {"method_id": "proposed_energy"},
|
||
|
|
"trajectory": {
|
||
|
|
"trajectory_id": "unit_contact",
|
||
|
|
"family": "contact_roundtrip",
|
||
|
|
"duration_s": 0.8,
|
||
|
|
"contact_probe_fraction": 0.01,
|
||
|
|
},
|
||
|
|
"factors": {
|
||
|
|
"map_policy": "source_stamped",
|
||
|
|
"network_profile": {
|
||
|
|
"forward_delay_s": 0.04,
|
||
|
|
"return_delay_s": 0.08,
|
||
|
|
"forward_jitter_s": 0.003,
|
||
|
|
"return_jitter_s": 0.004,
|
||
|
|
"forward_packet_loss": 0.01,
|
||
|
|
"return_packet_loss": 0.02,
|
||
|
|
},
|
||
|
|
"haptic_profile": {
|
||
|
|
"feedback_strength": 0.25,
|
||
|
|
"energy_min": 0.0,
|
||
|
|
"energy_max": 0.3,
|
||
|
|
"energy_initial": 0.1,
|
||
|
|
},
|
||
|
|
# A direct factor must override the coupled profile.
|
||
|
|
"forward_delay_s": 0.02,
|
||
|
|
"energy_initial": 0.12,
|
||
|
|
},
|
||
|
|
"seeds": named_seed_record(7, {"test": "bilateral-v2"}),
|
||
|
|
}
|
||
|
|
|
||
|
|
|
||
|
|
class BilateralCalibrationV2Test(unittest.TestCase):
|
||
|
|
def test_haptic_and_network_factors_reach_simulation_config(self):
|
||
|
|
scenario, config = _bilateral_scenario_and_config(bilateral_trial())
|
||
|
|
self.assertEqual(scenario.map_policy, "source_stamped")
|
||
|
|
self.assertEqual(config.feedback_strength, 0.25)
|
||
|
|
self.assertEqual(config.energy_min, 0.0)
|
||
|
|
self.assertEqual(config.energy_max, 0.3)
|
||
|
|
self.assertEqual(config.energy_initial, 0.12)
|
||
|
|
self.assertEqual(config.forward_delay_s, 0.02)
|
||
|
|
self.assertEqual(config.feedback_delay_s, 0.08)
|
||
|
|
self.assertEqual(config.forward_jitter_s, 0.003)
|
||
|
|
self.assertEqual(config.return_jitter_s, 0.004)
|
||
|
|
self.assertEqual(config.forward_packet_loss, 0.01)
|
||
|
|
self.assertEqual(config.return_packet_loss, 0.02)
|
||
|
|
|
||
|
|
def test_v2_grids_are_directional_and_bounded(self):
|
||
|
|
energy = build_trial_plan(
|
||
|
|
load_document(CONFIG_ROOT / "bilateral_calibration_v2_energy.json")
|
||
|
|
)
|
||
|
|
network = build_trial_plan(
|
||
|
|
load_document(CONFIG_ROOT / "bilateral_calibration_v2_network.json")
|
||
|
|
)
|
||
|
|
self.assertEqual(energy["pair_count"], 36)
|
||
|
|
self.assertEqual(energy["trial_count"], 36)
|
||
|
|
self.assertEqual(network["pair_count"], 12)
|
||
|
|
self.assertEqual(network["trial_count"], 36)
|
||
|
|
|
||
|
|
profiles = {
|
||
|
|
trial["factors"]["network_profile"]["profile_id"]
|
||
|
|
for trial in network["trials"]
|
||
|
|
}
|
||
|
|
self.assertEqual(
|
||
|
|
profiles,
|
||
|
|
{
|
||
|
|
"nominal",
|
||
|
|
"return_delay_80ms",
|
||
|
|
"forward_delay_40ms",
|
||
|
|
"asymmetric_delay",
|
||
|
|
"asymmetric_delay_plus_jitter",
|
||
|
|
"asymmetric_delay_plus_loss",
|
||
|
|
},
|
||
|
|
)
|
||
|
|
|
||
|
|
|
||
|
|
if __name__ == "__main__":
|
||
|
|
unittest.main()
|