diff --git a/lisainstrument/instrument.py b/lisainstrument/instrument.py index 04489fa03382e15f260af48e47d1453c0cf7b043..890098179bb756c06a8cb086e192a9e11b3a5452 100755 --- a/lisainstrument/instrument.py +++ b/lisainstrument/instrument.py @@ -75,8 +75,8 @@ class Instrument: glitches=None, # Laser locking and frequency plan lock='N1-12', fplan='static', - # Laser sources laser_asds=28.2, central_freq=2.816E14, + offset_freqs='default', # Laser phase modulation modulation_asds='default', modulation_freqs='default', tdir_tone=None, # Clocks @@ -128,6 +128,10 @@ class Instrument: or 'static' for a default set of constant locking beatnote frequencies laser_asds: dictionary of amplitude spectral densities for laser noise [Hz/sqrt(Hz)] central_freq: laser central frequency from which all offsets are computed [Hz] + offset_freqs: dictionary of laser frequency offsets for unlocked lasers [Hz], + defined with respect to :attr:`lisainstrument.Instrument.central_freq`, + or 'default' for a default set of frequency offsets that yield valid beatnote + frequencies for 'six' lasers locked on cavity and default set of constant PPRs modulation_asds: dictionary of amplitude spectral densities for modulation noise on each MOSA [s/sqrt(Hz)], or 'default' for a default set of levels with a factor 10 higher on right-sided MOSAs to account for the frequency distribution system @@ -235,6 +239,15 @@ class Instrument: self.central_freq = float(central_freq) self.init_lock(lock) self.init_fplan(fplan) + if offset_freqs == 'default': + # Default set yields valid beatnote frequencies for all lasers ('six') + # with default 'static' set of MPRs + self.offset_freqs = ForEachMOSA({ + '12': 0.0, '23': 11E6, '31': 7.5E6, + '13': 16E6, '32': -12E6, '21': -6E6, + }) + else: + self.offset_freqs = ForEachMOSA(offset_freqs) # Laser and modulation noise self.laser_asds = ForEachMOSA(laser_asds) @@ -1463,7 +1476,7 @@ class Instrument: self.laser_noises[mosa] = noises.laser(self.physics_fs, self.physics_size, self.laser_asds[mosa]) logger.debug("Computing carrier offsets for primary local beam %s", mosa) - self.local_carrier_offsets[mosa] = 0.0 + self.local_carrier_offsets[mosa] = self.offset_freqs[mosa] logger.debug("Computing carrier fluctuations for primary local beam %s", mosa) self.local_carrier_fluctuations[mosa] = \ diff --git a/tests/test_fplan.py b/tests/test_fplan.py index 23d18f4cff1e1c94a29eb31c9402c4b5f2d76c58..43c1311aa18eb985a88f68092301c3b49e8be832 100755 --- a/tests/test_fplan.py +++ b/tests/test_fplan.py @@ -114,10 +114,10 @@ def test_static_fplan_valid_with_all_lock_configs(): instru.simulate() for mosa in instru.MOSAS: - assert np.all(5E6 < np.abs(instru.isi_carriers[mosa]) < 25E6) - assert np.all(5E6 < np.abs(instru.isi_usbs[mosa]) < 25E6) - assert np.all(5E6 < np.abs(instru.rfi_carriers[mosa]) < 25E6) - assert np.all(5E6 < np.abs(instru.rfi_usbs[mosa]) < 25E6) + assert np.all(5E6 <= np.abs(instru.isi_carriers[mosa]) <= 25E6) + assert np.all(5E6 <= np.abs(instru.isi_usbs[mosa]) <= 25E6) + assert np.all(5E6 <= np.abs(instru.rfi_carriers[mosa]) <= 25E6) + assert np.all(5E6 <= np.abs(instru.rfi_usbs[mosa]) <= 25E6) def test_constant_equal_fplan(): """Test a user-defined constant equal fplan.""" @@ -245,3 +245,36 @@ def test_esa_trailing_fplan_1_1(): instru = Instrument(size=100, lock='N4-12', fplan='tests/esa-trailing-fplan-1-1.h5') instru.simulate() assert _consistent_locking_beatnotes(instru) + +def test_offset_freqs(): + """Test that offset frequencies are correctly set for unlocked lasers.""" + + # Check that default set works for 'six' lock config + instru = Instrument(size=100, lock='six', offset_freqs='default') + instru.disable_all_noises() + instru.simulate() + for mosa in instru.MOSAS: + assert np.all(5E6 <= np.abs(instru.isi_carriers[mosa]) <= 25E6) + assert np.all(5E6 <= np.abs(instru.isi_usbs[mosa]) <= 25E6) + assert np.all(5E6 <= np.abs(instru.rfi_carriers[mosa]) <= 25E6) + assert np.all(5E6 <= np.abs(instru.rfi_usbs[mosa]) <= 25E6) + + # Check that unlocked laser frequency offsets are correctly set + offset_freqs = { + '12': 8.1E6, '23': 9.2E6, '31': 10.3E6, + '13': 1.4E6, '32': -11.6E6, '21': -9.5E6, + } + instru = Instrument(size=100, lock='six', offset_freqs=offset_freqs) + instru.simulate() + for mosa in instru.MOSAS: + assert instru.local_carrier_offsets[mosa] == offset_freqs[mosa] + + # Check that frequency offsets are only set on unlocked lasers + instru = Instrument(size=100, lock='N1-12', offset_freqs=offset_freqs) + instru.simulate() + instru.disable_all_noises() + assert instru.local_carrier_offsets['12'] == offset_freqs['12'] + instru = Instrument(size=100, lock='N1-23', offset_freqs=offset_freqs) + instru.simulate() + instru.disable_all_noises() + assert instru.local_carrier_offsets['23'] == offset_freqs['23']