diff --git a/lisainstrument/instrument.py b/lisainstrument/instrument.py index 0ed00d2cbd532b5aa5c7f0318878e822bdcb96a7..afaaa50c5edb9af7a4af5a61dfa0c4063d9fa05c 100644 --- a/lisainstrument/instrument.py +++ b/lisainstrument/instrument.py @@ -68,7 +68,7 @@ class Instrument: # Laser sources laser_asds=28.2, central_freq=2.816E14, # Laser phase modulation - modulation_asds='default', modulation_freqs='default', + modulation_asds='default', modulation_freqs='default', tdir_tone=None, # Clocks clock_asds=6.32E-14, clock_offsets=0, clock_freqoffsets='default', clock_freqlindrifts='default', clock_freqquaddrifts='default', @@ -112,6 +112,8 @@ class Instrument: 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 modulation_freqs: dictionary of modulation frequencies [Hz], or 'default' + tdir_tone: 3-tuple (amplitude [Hz], frequency [Hz], initial phase [rad]) of dictionaries + for parameters of TDIR assistance tone, or None clock_asds: dictionary of clock noise amplitude spectral densities clock_offsets: dictionary of clock offsets clock_freqoffsets: dictionary of clock frequency offsets [s^-1], or 'default' @@ -196,6 +198,17 @@ class Instrument: else: self.modulation_freqs = ForEachMOSA(modulation_freqs) + if tdir_tone is not None: + self.tdir_tone_amplitudes = ForEachMOSA(tdir_tone[0]) + self.tdir_tone_frequencies = ForEachMOSA(tdir_tone[1]) + self.tdir_tone_initial_phases = ForEachMOSA(tdir_tone[2]) + logger.debug("Using assistance tone for TDIR (amplitude=%s, frequency=%s, initial phase=%s)", + self.tdir_tone_amplitudes, self.tdir_tone_frequencies, self.tdir_tone_initial_phases) + else: + self.tdir_tone_amplitudes = ForEachMOSA(0) + self.tdir_tone_frequencies = ForEachMOSA(0) + self.tdir_tone_initial_phases = ForEachMOSA(0) + # Clocks self.clock_asds = ForEachSC(clock_asds) self.clock_offsets = ForEachSC(clock_offsets) @@ -579,10 +592,7 @@ class Instrument: self.simulate_noises() - ## Local beams - - logger.info("Simulating local beams") - self.simulate_locking() + ## TDIR tone logger.debug("Computing local timer deviations") self.local_timer_deviations = \ @@ -593,6 +603,20 @@ class Instrument: * self.physics_dt) ) + self.tdir_tones = ForEachMOSA(lambda mosa: + 0 if self.tdir_tone_amplitudes[mosa] == 0 \ + else self.tdir_tone_amplitudes[mosa] * numpy.sin( + 2 * numpy.pi * self.tdir_tone_frequencies[mosa] + * (self.physics_t + self.local_timer_deviations[mosa[0]]) + + self.tdir_tone_initial_phases[mosa] + ) + ) + + ## Local beams + + logger.info("Simulating local beams") + self.simulate_locking() + ## Propagation to distant MOSA logger.info("Propagating local beams to distant MOSAs") @@ -1204,7 +1228,7 @@ class Instrument: logger.debug("Computing carrier fluctuations for primary local beam %s", mosa) self.local_carrier_fluctuations[mosa] = \ - self.laser_noises[mosa] + self.glitch_lasers[mosa] + self.laser_noises[mosa] + self.glitch_lasers[mosa] + self.tdir_tones[mosa] logger.debug("Computing upper sideband offsets for primary local beam %s", mosa) self.local_usb_offsets[mosa] = self.offsets_freqs[mosa] \ @@ -1212,7 +1236,7 @@ class Instrument: logger.debug("Computing upper sideband fluctuations for primary local beam %s", mosa) self.local_usb_fluctuations[mosa] = \ - self.laser_noises[mosa] + self.glitch_lasers[mosa] \ + self.laser_noises[mosa] + self.glitch_lasers[mosa] + self.tdir_tones[mosa] \ + self.modulation_freqs[mosa] * (self.clock_noise_fluctuations[sc(mosa)] + self.modulation_noises[mosa]) def lock_on_adjacent(self, mosa): @@ -1236,7 +1260,8 @@ class Instrument: + self.central_freq * self.backlink_noises[mosa] self.local_carrier_fluctuations[mosa] = adjacent_carrier_fluctuations \ + self.offsets_freqs[mosa] * self.clock_noise_fluctuations[sc(mosa)] \ - + self.central_freq * self.oms_ref_carrier_noises[mosa] + + self.central_freq * self.oms_ref_carrier_noises[mosa] \ + + self.tdir_tones[mosa] logger.debug("Computing upper sideband offsets for local beam %s " "locked on adjacent beam %s", mosa, adjacent(mosa)) @@ -1250,7 +1275,8 @@ class Instrument: + self.central_freq * self.backlink_noises[mosa] self.local_usb_fluctuations[mosa] = adjacent_usb_fluctuations \ + self.offsets_freqs[mosa] * self.clock_noise_fluctuations[sc(mosa)] \ - + self.central_freq * self.oms_ref_usb_noises[mosa] + + self.central_freq * self.oms_ref_usb_noises[mosa] \ + + self.tdir_tones[mosa] def lock_on_distant(self, mosa): """Compute carrier and upper sideband offsets and fluctuations for locked laser to distant beam. @@ -1282,7 +1308,8 @@ class Instrument: - (self.central_freq + self.local_carrier_offsets[mosa]) * self.local_ttls[mosa] / c self.local_carrier_fluctuations[mosa] = distant_carrier_fluctuations \ + self.offsets_freqs[mosa] * self.clock_noise_fluctuations[sc(mosa)] \ - + self.central_freq * self.oms_isc_carrier_noises[mosa] + + self.central_freq * self.oms_isc_carrier_noises[mosa] \ + + self.tdir_tones[mosa] logger.debug("Computing upper sideband offsets for local beam %s " "locked on distant beam %s", mosa, distant(mosa)) @@ -1305,7 +1332,8 @@ class Instrument: - (self.central_freq + self.local_usb_offsets[mosa]) * self.local_ttls[mosa] / c self.local_usb_fluctuations[mosa] = distant_usb_fluctuations \ + self.offsets_freqs[mosa] * self.clock_noise_fluctuations[sc(mosa)] \ - + self.central_freq * self.oms_isc_usb_noises[mosa] + + self.central_freq * self.oms_isc_usb_noises[mosa] \ + + self.tdir_tones[mosa] def simulate_locking(self): """Simulate local beams from the locking configuration.""" @@ -1433,6 +1461,9 @@ class Instrument: self.glitch_tms.write(hdf5, 'glitch_tms') self.glitch_lasers.write(hdf5, 'glitch_lasers') + logger.debug("Writing TDIR assistance tone to %s", output) + self.tdir_tones.write(hdf5, 'tdir_tones') + logger.debug("Writing laser noise to '%s'", output) self.laser_noises.write(hdf5, 'laser_noises')