diff --git a/lisainstrument/instrument.py b/lisainstrument/instrument.py
index 2b6ee9e0972ae7ca12ecf6ba8c05ca8d42dc3361..745d37ef7c7a92633cf8c1009718b0caa74ad95b 100755
--- a/lisainstrument/instrument.py
+++ b/lisainstrument/instrument.py
@@ -78,7 +78,7 @@ class Instrument:
                  laser_asds=30, laser_shape='white+infrared',
                  central_freq=2.816E14, offset_freqs='default',
                  # Laser phase modulation
-                 modulation_asds='default', modulation_freqs='default', tdir_tone=None,
+                 modulation_asds='default', modulation_freqs='default', tdir_modulations=None,
                  # Clocks
                  clock_asds=6.32E-14, clock_offsets=0, clock_freqoffsets='default',
                  clock_freqlindrifts='default', clock_freqquaddrifts='default',
@@ -142,8 +142,7 @@ 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
+            tdir_modulations: dictionary of callables of TDIR assistance modulations, or None
             clock_asds: dictionary of clock noise amplitude spectral densities
             clock_offsets: dictionary of clock offsets from TPS [s]
             clock_freqoffsets: dictionary of clock frequency offsets [s^-1], or 'default'
@@ -293,16 +292,10 @@ 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)
+        if tdir_modulations is None:
+            self.tdir_modulations = {mosa: lambda times: 0 for mosa in ForEachMOSA.indices()}
         else:
-            self.tdir_tone_amplitudes = ForEachMOSA(0)
-            self.tdir_tone_frequencies = ForEachMOSA(0)
-            self.tdir_tone_initial_phases = ForEachMOSA(0)
+            self.tdir_modulations = tdir_modulations
 
         # Clocks
         self.clock_asds = ForEachSC(clock_asds)
@@ -978,16 +971,11 @@ class Instrument:
         self.moc_time_correlations = self.moc_time_correlation_noises \
             + self.the_wrt_tcb_withinitial.transformed(physics_to_telemetry)
 
-        ## TDIR tone
+        ## TDIR modulations
 
-        logger.debug("Forming TDIR assistance tones")
-        self.tdir_tones = ForEachMOSA(lambda mosa:
-            0 if self.tdir_tone_amplitudes[mosa] == 0 \
-            else self.tdir_tone_amplitudes[mosa] * np.sin(
-                2 * np.pi * self.tdir_tone_frequencies[mosa]
-                * (self.physics_et + self.the_wrt_tps_local[mosa[0]])
-                + self.tdir_tone_initial_phases[mosa]
-            )
+        logger.debug("Forming TDIR assistance modulations")
+        self.tdir_modulations = ForEachMOSA(lambda mosa:
+            self.tdir_modulations[mosa](self.physics_et + self.the_wrt_tps_local[mosa[0]])
         )
 
         ## Local beams
@@ -1734,7 +1722,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.tdir_tones[mosa]
+            self.laser_noises[mosa] + self.glitch_lasers[mosa] + self.tdir_modulations[mosa]
 
 
     def lock_on_adjacent(self, mosa):
@@ -1759,7 +1747,7 @@ class Instrument:
         self.local_carrier_fluctuations[mosa] = adjacent_carrier_fluctuations \
             - self.fplan[mosa] * self.clock_noise_fluctuations[sc(mosa)] \
             + self.central_freq * self.oms_rfi_carrier_noises[mosa] \
-            + self.tdir_tones[mosa]
+            + self.tdir_modulations[mosa]
 
 
     def lock_on_distant(self, mosa):
@@ -1793,7 +1781,7 @@ class Instrument:
         self.local_carrier_fluctuations[mosa] = distant_carrier_fluctuations \
             - self.fplan[mosa] * self.clock_noise_fluctuations[sc(mosa)] \
             + self.central_freq * self.oms_isi_carrier_noises[mosa] \
-            + self.tdir_tones[mosa]
+            + self.tdir_modulations[mosa]
 
 
     def simulate_locking(self):
@@ -1927,7 +1915,7 @@ class Instrument:
             'central_freq', 'lock_config', 'lock',
             'fplan_file', 'fplan',
             'laser_asds', 'modulation_asds', 'modulation_freqs',
-            'tdir_tone_amplitudes', 'tdir_tone_frequencies', 'tdir_tone_initial_phases',
+            'tdir_modulations',
             'clock_asds','clock_offsets', 'clock_freqoffsets', 'clock_freqlindrifts',
             'clock_freqquaddrifts', 'clockinv_tolerance', 'clockinv_maxiter',
             'ranging_biases', 'ranging_asds', 'prn_ambiguity',
@@ -1983,8 +1971,8 @@ 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 TDIR assistance modulations to %s", output)
+                self.tdir_modulations.write(hdf5, 'tdir_modulations')
 
                 logger.debug("Writing laser noise to '%s'", output)
                 self.laser_noises.write(hdf5, 'laser_noises')