diff --git a/src/damaris/experiments/Experiment.py b/src/damaris/experiments/Experiment.py
index 9c0b954..70a25d8 100644
--- a/src/damaris/experiments/Experiment.py
+++ b/src/damaris/experiments/Experiment.py
@@ -402,10 +402,10 @@ class Experiment:
The state length is 2 µs. Stabilisation time depends on RF source.
:param float frequency: frequency to set in Hz
- :param float phase: phase to set
+ :param float phase: phase to set, normalized to the range [0, 360)
:param int ttls: default=0, additional ttl lines to set (integer)
"""
- s_content = '' % (frequency, phase)
+ s_content = '' % (frequency, phase % 360)
if ttls != 0:
s_content += '' % ttls
self.state_list.append(StateSimple(2e-6, s_content))
@@ -580,8 +580,9 @@ class Experiment:
- The state length for this command is 0.5 µs.
- The stabilization time for the phase change is RF source dependent. A typical value for PTS310 is 2 µs.
- The phase is relative to the initial phase set at start of the experiment.
+ - Negative phases are normalized to the range [0, 360) before writing the job file.
"""
- s_content = '' % (phase)
+ s_content = '' % (phase % 360)
if ttls!=0:
s_content += '' % ttls
self.state_list.append(StateSimple(0.5e-6, s_content))
diff --git a/tests/test_Experiment.py b/tests/test_Experiment.py
new file mode 100644
index 0000000..6479b63
--- /dev/null
+++ b/tests/test_Experiment.py
@@ -0,0 +1,47 @@
+import re
+import unittest
+
+from damaris.experiments.Experiment import Experiment
+
+
+def phase_of_state(state):
+ "extracts the phase value from a state's XML content"
+ match = re.search(r'phase="([-0-9.]+)"', state.content)
+ assert match, "no phase in state: %s" % state.content
+ return float(match.group(1))
+
+
+class TestExperimentPhase(unittest.TestCase):
+ def test_set_phase_negative_normalized(self):
+ """Test that set_phase() normalizes negative phases to [0, 360)."""
+ e = Experiment()
+ for degrees, expected in ((-90, 270.0), (-45.5, 314.5),
+ (-270, 90.0), (-360, 0.0)):
+ e.set_phase(degrees)
+ self.assertEqual(phase_of_state(e.state_list.list[-1]), expected)
+
+ def test_set_phase_positive_unchanged(self):
+ """Test that set_phase() passes positive phases through unchanged."""
+ e = Experiment()
+ for degrees, expected in ((0, 0.0), (90, 90.0), (270, 270.0),
+ (45.5, 45.5)):
+ e.set_phase(degrees)
+ self.assertEqual(phase_of_state(e.state_list.list[-1]), expected)
+
+ def test_set_frequency_negative_phase_normalized(self):
+ """Test that set_frequency() normalizes a negative phase."""
+ e = Experiment()
+ e.set_frequency(85e6, -90)
+ state = e.state_list.list[-1]
+ self.assertEqual(phase_of_state(state), 270.0)
+ self.assertIn('f="85000000.000000"', state.content)
+
+ def test_rf_pulse_negative_phase_normalized(self):
+ """Test that rf_pulse() normalizes a negative pulse phase."""
+ e = Experiment(gating=1e-6, rf_sources=[1], rf_gates=[2])
+ e.rf_pulse(length=1e-6, phase=-90, source=0)
+ self.assertEqual(phase_of_state(e.state_list.list[0]), 270.0)
+
+
+if __name__ == "__main__":
+ unittest.main()