itla.pplaser

  1from enum import IntEnum
  2from time import sleep
  3
  4from . import logger
  5from .itla12 import ITLA12
  6from .itla_errors import (
  7    RVEError,
  8)
  9
 10
 11class Mode(IntEnum):
 12    normal = 0
 13    nodither = 1
 14    whisper = 2
 15
 16
 17class PPLaser(ITLA12):
 18    """
 19    The pure photonics laser class implements specific features or handles particular
 20    quirks of the pure photonics laser. The pure photonics laser has additional
 21    registers for a couple of applications.
 22
 23    * `set_frequency` and `set_fcf` had to be overridden
 24    * `get_frequency` is *not* overridden because these registers can still be read without issue
 25    """
 26
 27    def __init__(self, serial_port, baudrate=9600, sleep_time=0.1):
 28        """sets up the additional frequency max and min variables which will be set upon
 29        connecting to the laser. We have found that Pure Photonics lasers do not
 30        return the RVEError when setting the frequency out of spec.
 31
 32        This sets up the additional register yaml file for pure photonics specific functions.
 33        """
 34        register_files = ["registers_pp.yaml"]
 35
 36        self._frequency_max = None
 37        self._frequency_min = None
 38
 39        super().__init__(
 40            serial_port, baudrate, register_files=register_files, sleep_time=sleep_time
 41        )
 42
 43    def connect(self):
 44        """Overriden connect function with query for max and min frequency"""
 45        super().connect()
 46        self._frequency_max = self.get_frequency_max()
 47        self._frequency_min = self.get_frequency_min()
 48
 49    def set_fcf(self, freq):
 50        """
 51        This sets the first channel frequency.
 52        It does not reset the channel so this frequency will only be equal
 53        to the output frequency if channel=1.
 54
 55        Because the `set_frequency` function calls this function this will also
 56        correct the issue in setting the frequency generally.
 57
 58        verifies that fcf is set within the appropriate laser frequency range
 59        and raises RVE error if not
 60        """
 61        if freq < self._frequency_min or freq > self._frequency_max:
 62            raise RVEError(
 63                "The desired frequency is outside of the range for this laser."
 64            )
 65
 66        super().set_fcf(freq)
 67
 68    def get_mode(self):
 69        """get which low noise mode"""
 70
 71        response = self._mode()
 72        response = Mode(int.from_bytes(response, "big"))
 73
 74        return response
 75
 76    def set_mode(self, mode):
 77        self._mode(mode)
 78
 79    def normalmode(self):
 80        """set mode to standard dither mode"""
 81        self._mode(Mode.normal)
 82
 83    def nodithermode(self):
 84        """Set mode to nodither mode
 85
 86        It is unclear whether this just also activates whisper mode.
 87        The feature guide says "a value of 1 defaults to 2".
 88        """
 89        self._mode(Mode.nodither)
 90
 91    def whispermode(self):
 92        """Enables whisper mode where all control loops
 93        are disabled resulting in a lower noise mode."""
 94        self._mode(Mode.whisper)
 95
 96    def get_cleansweep_amplitude(self):
 97        """get the amplitude of the clean sweep.
 98
 99        The clean sweep will ramp to (+0.5 to -0.5) * amplitude.
100        (Basically it will be centered at the current frequency.)
101        """
102        response = self._csrange()
103        cs_amplitude = int.from_bytes(response, "big")
104
105        return cs_amplitude
106
107    def set_cleansweep_amplitude(self, range_GHz):
108        """Sets the amplitude of the clean sweep.
109
110        The clean sweep will ramp to (+0.5 to -0.5) * amplitude.
111        (Basically it will be centered at the current frequency.)
112        """
113        self._csrange(range_GHz)
114
115    def cleansweep_enable(self):
116        """Enables clean sweep mode.
117        The clean sweep will ramp to (+0.5 to -0.5) * amplitude.
118        (Basically it will be centered at the current frequency.)
119        """
120        response = self.get_mode()
121        if response == Mode.normal:
122            raise Exception(
123                "Laser currently in normal mode.",
124                "please set to nodither or whisper mode",
125            )
126
127        self._csstart(1)
128
129    def cleansweep_disable(self):
130        """Turn's off clean sweep mode."""
131
132        self._csstart(0)
133
134    def cleansweep_setup(self, freq_low, freq_high):
135        """
136        A wrapper function that takes the start and end frequencies
137        you would like to sweep over. It computes and sets the clean sweep
138        amplitude and the midpoint.
139
140        The clean sweep operation will begin in the center of the high and low.
141
142        """
143
144        if freq_low < self._frequency_min or freq_high > self._frequency_max:
145            raise ValueError(
146                "The range you would like to sweep over",
147                "is outside of the bounds for this laser",
148            )
149
150        # sets the clean sweep amplitude rounded to the nearest MHz.
151        cs_ampl = round(abs(freq_high - freq_low) * 1e3)
152        if cs_ampl > 50:
153            raise Exception(
154                "This is an error specific to SpectrumLab."
155                "Our laser has a 50GHz maximum cleansweep range."
156                "You should change the limit in source for your laser."
157                "If you know a way to query the laser for this value"
158                "then implementing that would be better."
159            )
160
161        self.set_cleansweep_amplitude(cs_ampl)
162
163        cs_center = round((freq_low + freq_high) * 1e4 / 2) * 1e-4
164        self.set_frequency(cs_center)
165
166    def get_cleansweep_rate(self):
167        """Gets the clean sweep rate. not sure about units."""
168        response = self._csrate()
169        cs_rate = int.from_bytes(response, "big")
170        return cs_rate
171
172    def set_cleansweep_rate(self, rate_MHz):
173        """sets the cleansweep rate in MHz/sec
174        idk if there is a way to check if its within some bounds.
175        There is conflicting info in the pure photonics docs."""
176        raise Warning("Dont use this. Need to confirm the units for the sweep rate.")
177        self._csrate(rate_MHz)
178
179    def get_cleansweep_offset(self):
180        raise Warning("This is not implemented yet.")
181
182    def set_cleansweep_offset(self, offset):
183        raise Warning("This is not implemented yet.")
184
185    def cleanjump(self):
186        """Tells the laser to perform the clean jump.
187        The clean jump must be precalibrated.
188        You should have the calibration points in your lab notebook
189        or written down somewhere.
190        If not you should perform the clean jump calibration."""
191        mode = self.get_mode()
192        if mode == Mode.normal:
193            raise Exception(
194                "Laser in normal mode. You must be in nodither"
195                "or whisper mode to use cleanjump."
196            )
197        self._cjstart(1)
198
199    def set_cleanjump(self, freq_jump):
200        """
201        Set the size of the jump in THz to the fourth decimal place.
202        XXX.XXXX
203        """
204        freq_jump = str(round(freq_jump * 1e4))
205        self._cjthz(int(freq_jump[0:3]))
206        self._cjghz(int(freq_jump[3:]))
207
208    def cleanjump_calibration(self, fcf, grid, pwr, n_jumppoints, confirmation=None):
209        """
210        This is a grid based calibration
211
212        **fcf**: the first channel frequency you would like to
213        begin calibration at. (THz)
214
215        **grid**: the grid spacing (GHz)
216
217        **pwr**: The power calibration will be at. (dBm)
218
219        **n_jumppoints**: The number of grid points to calibrate.
220
221        **confirmation**: If you would like to go ahead and confirm yes
222        and skip the user input you can set confirmation to 'y'
223        """
224
225        # calibration begins by writing the number of channels to 0xD2
226
227        calibration_points = [fcf + grid * n * 1e-3 for n in range(n_jumppoints)]
228
229        logger.info(
230            f"You are calibrating {n_jumppoints} clean jump setpoints",
231            f"at frequencies:\n{calibration_points}(THz).",
232            f"With power = {pwr}(dBm).",
233        )
234        logger.info(
235            "Write these down in your lab notebook because",
236            "you cannot query the device for these values later.",
237        )
238
239        if confirmation is None:
240            confirmation = input("Is the information above correct? (y/n): ")
241
242        if confirmation.lower() == "y":
243            # set up the first channel frequency, grid spacing, and power
244            self.set_frequency(fcf)
245            self.set_grid(grid)
246            self.set_power(pwr)
247            self._cleanjump_calibration(n_jumppoints)
248
249        elif confirmation.lower() == "n":
250            logger.info(
251                f"You answered {confirmation!r}.", "Calibration will not be performed."
252            )
253
254        else:
255            raise Exception("input not recognized")
256
257    def _cleanjump_calibration(self, n_jumppoints):
258        # does this return a response with bit 15 active?
259        self._cjcalibration(n_jumppoints)
260
261        is_calibrating = True
262
263        while is_calibrating:
264            response = self._cjcalibration()
265
266            response_bits = [bit for bit in f"{response:08}"].reverse()
267            is_calibrating = bool(response_bits[15])
268            sleep(1)
class Mode(enum.IntEnum):
12class Mode(IntEnum):
13    normal = 0
14    nodither = 1
15    whisper = 2
normal = <Mode.normal: 0>
nodither = <Mode.nodither: 1>
whisper = <Mode.whisper: 2>
class PPLaser(itla.itla12.ITLA12):
 18class PPLaser(ITLA12):
 19    """
 20    The pure photonics laser class implements specific features or handles particular
 21    quirks of the pure photonics laser. The pure photonics laser has additional
 22    registers for a couple of applications.
 23
 24    * `set_frequency` and `set_fcf` had to be overridden
 25    * `get_frequency` is *not* overridden because these registers can still be read without issue
 26    """
 27
 28    def __init__(self, serial_port, baudrate=9600, sleep_time=0.1):
 29        """sets up the additional frequency max and min variables which will be set upon
 30        connecting to the laser. We have found that Pure Photonics lasers do not
 31        return the RVEError when setting the frequency out of spec.
 32
 33        This sets up the additional register yaml file for pure photonics specific functions.
 34        """
 35        register_files = ["registers_pp.yaml"]
 36
 37        self._frequency_max = None
 38        self._frequency_min = None
 39
 40        super().__init__(
 41            serial_port, baudrate, register_files=register_files, sleep_time=sleep_time
 42        )
 43
 44    def connect(self):
 45        """Overriden connect function with query for max and min frequency"""
 46        super().connect()
 47        self._frequency_max = self.get_frequency_max()
 48        self._frequency_min = self.get_frequency_min()
 49
 50    def set_fcf(self, freq):
 51        """
 52        This sets the first channel frequency.
 53        It does not reset the channel so this frequency will only be equal
 54        to the output frequency if channel=1.
 55
 56        Because the `set_frequency` function calls this function this will also
 57        correct the issue in setting the frequency generally.
 58
 59        verifies that fcf is set within the appropriate laser frequency range
 60        and raises RVE error if not
 61        """
 62        if freq < self._frequency_min or freq > self._frequency_max:
 63            raise RVEError(
 64                "The desired frequency is outside of the range for this laser."
 65            )
 66
 67        super().set_fcf(freq)
 68
 69    def get_mode(self):
 70        """get which low noise mode"""
 71
 72        response = self._mode()
 73        response = Mode(int.from_bytes(response, "big"))
 74
 75        return response
 76
 77    def set_mode(self, mode):
 78        self._mode(mode)
 79
 80    def normalmode(self):
 81        """set mode to standard dither mode"""
 82        self._mode(Mode.normal)
 83
 84    def nodithermode(self):
 85        """Set mode to nodither mode
 86
 87        It is unclear whether this just also activates whisper mode.
 88        The feature guide says "a value of 1 defaults to 2".
 89        """
 90        self._mode(Mode.nodither)
 91
 92    def whispermode(self):
 93        """Enables whisper mode where all control loops
 94        are disabled resulting in a lower noise mode."""
 95        self._mode(Mode.whisper)
 96
 97    def get_cleansweep_amplitude(self):
 98        """get the amplitude of the clean sweep.
 99
100        The clean sweep will ramp to (+0.5 to -0.5) * amplitude.
101        (Basically it will be centered at the current frequency.)
102        """
103        response = self._csrange()
104        cs_amplitude = int.from_bytes(response, "big")
105
106        return cs_amplitude
107
108    def set_cleansweep_amplitude(self, range_GHz):
109        """Sets the amplitude of the clean sweep.
110
111        The clean sweep will ramp to (+0.5 to -0.5) * amplitude.
112        (Basically it will be centered at the current frequency.)
113        """
114        self._csrange(range_GHz)
115
116    def cleansweep_enable(self):
117        """Enables clean sweep mode.
118        The clean sweep will ramp to (+0.5 to -0.5) * amplitude.
119        (Basically it will be centered at the current frequency.)
120        """
121        response = self.get_mode()
122        if response == Mode.normal:
123            raise Exception(
124                "Laser currently in normal mode.",
125                "please set to nodither or whisper mode",
126            )
127
128        self._csstart(1)
129
130    def cleansweep_disable(self):
131        """Turn's off clean sweep mode."""
132
133        self._csstart(0)
134
135    def cleansweep_setup(self, freq_low, freq_high):
136        """
137        A wrapper function that takes the start and end frequencies
138        you would like to sweep over. It computes and sets the clean sweep
139        amplitude and the midpoint.
140
141        The clean sweep operation will begin in the center of the high and low.
142
143        """
144
145        if freq_low < self._frequency_min or freq_high > self._frequency_max:
146            raise ValueError(
147                "The range you would like to sweep over",
148                "is outside of the bounds for this laser",
149            )
150
151        # sets the clean sweep amplitude rounded to the nearest MHz.
152        cs_ampl = round(abs(freq_high - freq_low) * 1e3)
153        if cs_ampl > 50:
154            raise Exception(
155                "This is an error specific to SpectrumLab."
156                "Our laser has a 50GHz maximum cleansweep range."
157                "You should change the limit in source for your laser."
158                "If you know a way to query the laser for this value"
159                "then implementing that would be better."
160            )
161
162        self.set_cleansweep_amplitude(cs_ampl)
163
164        cs_center = round((freq_low + freq_high) * 1e4 / 2) * 1e-4
165        self.set_frequency(cs_center)
166
167    def get_cleansweep_rate(self):
168        """Gets the clean sweep rate. not sure about units."""
169        response = self._csrate()
170        cs_rate = int.from_bytes(response, "big")
171        return cs_rate
172
173    def set_cleansweep_rate(self, rate_MHz):
174        """sets the cleansweep rate in MHz/sec
175        idk if there is a way to check if its within some bounds.
176        There is conflicting info in the pure photonics docs."""
177        raise Warning("Dont use this. Need to confirm the units for the sweep rate.")
178        self._csrate(rate_MHz)
179
180    def get_cleansweep_offset(self):
181        raise Warning("This is not implemented yet.")
182
183    def set_cleansweep_offset(self, offset):
184        raise Warning("This is not implemented yet.")
185
186    def cleanjump(self):
187        """Tells the laser to perform the clean jump.
188        The clean jump must be precalibrated.
189        You should have the calibration points in your lab notebook
190        or written down somewhere.
191        If not you should perform the clean jump calibration."""
192        mode = self.get_mode()
193        if mode == Mode.normal:
194            raise Exception(
195                "Laser in normal mode. You must be in nodither"
196                "or whisper mode to use cleanjump."
197            )
198        self._cjstart(1)
199
200    def set_cleanjump(self, freq_jump):
201        """
202        Set the size of the jump in THz to the fourth decimal place.
203        XXX.XXXX
204        """
205        freq_jump = str(round(freq_jump * 1e4))
206        self._cjthz(int(freq_jump[0:3]))
207        self._cjghz(int(freq_jump[3:]))
208
209    def cleanjump_calibration(self, fcf, grid, pwr, n_jumppoints, confirmation=None):
210        """
211        This is a grid based calibration
212
213        **fcf**: the first channel frequency you would like to
214        begin calibration at. (THz)
215
216        **grid**: the grid spacing (GHz)
217
218        **pwr**: The power calibration will be at. (dBm)
219
220        **n_jumppoints**: The number of grid points to calibrate.
221
222        **confirmation**: If you would like to go ahead and confirm yes
223        and skip the user input you can set confirmation to 'y'
224        """
225
226        # calibration begins by writing the number of channels to 0xD2
227
228        calibration_points = [fcf + grid * n * 1e-3 for n in range(n_jumppoints)]
229
230        logger.info(
231            f"You are calibrating {n_jumppoints} clean jump setpoints",
232            f"at frequencies:\n{calibration_points}(THz).",
233            f"With power = {pwr}(dBm).",
234        )
235        logger.info(
236            "Write these down in your lab notebook because",
237            "you cannot query the device for these values later.",
238        )
239
240        if confirmation is None:
241            confirmation = input("Is the information above correct? (y/n): ")
242
243        if confirmation.lower() == "y":
244            # set up the first channel frequency, grid spacing, and power
245            self.set_frequency(fcf)
246            self.set_grid(grid)
247            self.set_power(pwr)
248            self._cleanjump_calibration(n_jumppoints)
249
250        elif confirmation.lower() == "n":
251            logger.info(
252                f"You answered {confirmation!r}.", "Calibration will not be performed."
253            )
254
255        else:
256            raise Exception("input not recognized")
257
258    def _cleanjump_calibration(self, n_jumppoints):
259        # does this return a response with bit 15 active?
260        self._cjcalibration(n_jumppoints)
261
262        is_calibrating = True
263
264        while is_calibrating:
265            response = self._cjcalibration()
266
267            response_bits = [bit for bit in f"{response:08}"].reverse()
268            is_calibrating = bool(response_bits[15])
269            sleep(1)

The pure photonics laser class implements specific features or handles particular quirks of the pure photonics laser. The pure photonics laser has additional registers for a couple of applications.

PPLaser(serial_port, baudrate=9600, sleep_time=0.1)
28    def __init__(self, serial_port, baudrate=9600, sleep_time=0.1):
29        """sets up the additional frequency max and min variables which will be set upon
30        connecting to the laser. We have found that Pure Photonics lasers do not
31        return the RVEError when setting the frequency out of spec.
32
33        This sets up the additional register yaml file for pure photonics specific functions.
34        """
35        register_files = ["registers_pp.yaml"]
36
37        self._frequency_max = None
38        self._frequency_min = None
39
40        super().__init__(
41            serial_port, baudrate, register_files=register_files, sleep_time=sleep_time
42        )

sets up the additional frequency max and min variables which will be set upon connecting to the laser. We have found that Pure Photonics lasers do not return the RVEError when setting the frequency out of spec.

This sets up the additional register yaml file for pure photonics specific functions.

def connect(self):
44    def connect(self):
45        """Overriden connect function with query for max and min frequency"""
46        super().connect()
47        self._frequency_max = self.get_frequency_max()
48        self._frequency_min = self.get_frequency_min()

Overriden connect function with query for max and min frequency

def set_fcf(self, freq):
50    def set_fcf(self, freq):
51        """
52        This sets the first channel frequency.
53        It does not reset the channel so this frequency will only be equal
54        to the output frequency if channel=1.
55
56        Because the `set_frequency` function calls this function this will also
57        correct the issue in setting the frequency generally.
58
59        verifies that fcf is set within the appropriate laser frequency range
60        and raises RVE error if not
61        """
62        if freq < self._frequency_min or freq > self._frequency_max:
63            raise RVEError(
64                "The desired frequency is outside of the range for this laser."
65            )
66
67        super().set_fcf(freq)

This sets the first channel frequency. It does not reset the channel so this frequency will only be equal to the output frequency if channel=1.

Because the set_frequency function calls this function this will also correct the issue in setting the frequency generally.

verifies that fcf is set within the appropriate laser frequency range and raises RVE error if not

def get_mode(self):
69    def get_mode(self):
70        """get which low noise mode"""
71
72        response = self._mode()
73        response = Mode(int.from_bytes(response, "big"))
74
75        return response

get which low noise mode

def set_mode(self, mode):
77    def set_mode(self, mode):
78        self._mode(mode)
def normalmode(self):
80    def normalmode(self):
81        """set mode to standard dither mode"""
82        self._mode(Mode.normal)

set mode to standard dither mode

def nodithermode(self):
84    def nodithermode(self):
85        """Set mode to nodither mode
86
87        It is unclear whether this just also activates whisper mode.
88        The feature guide says "a value of 1 defaults to 2".
89        """
90        self._mode(Mode.nodither)

Set mode to nodither mode

It is unclear whether this just also activates whisper mode. The feature guide says "a value of 1 defaults to 2".

def whispermode(self):
92    def whispermode(self):
93        """Enables whisper mode where all control loops
94        are disabled resulting in a lower noise mode."""
95        self._mode(Mode.whisper)

Enables whisper mode where all control loops are disabled resulting in a lower noise mode.

def get_cleansweep_amplitude(self):
 97    def get_cleansweep_amplitude(self):
 98        """get the amplitude of the clean sweep.
 99
100        The clean sweep will ramp to (+0.5 to -0.5) * amplitude.
101        (Basically it will be centered at the current frequency.)
102        """
103        response = self._csrange()
104        cs_amplitude = int.from_bytes(response, "big")
105
106        return cs_amplitude

get the amplitude of the clean sweep.

The clean sweep will ramp to (+0.5 to -0.5) * amplitude. (Basically it will be centered at the current frequency.)

def set_cleansweep_amplitude(self, range_GHz):
108    def set_cleansweep_amplitude(self, range_GHz):
109        """Sets the amplitude of the clean sweep.
110
111        The clean sweep will ramp to (+0.5 to -0.5) * amplitude.
112        (Basically it will be centered at the current frequency.)
113        """
114        self._csrange(range_GHz)

Sets the amplitude of the clean sweep.

The clean sweep will ramp to (+0.5 to -0.5) * amplitude. (Basically it will be centered at the current frequency.)

def cleansweep_enable(self):
116    def cleansweep_enable(self):
117        """Enables clean sweep mode.
118        The clean sweep will ramp to (+0.5 to -0.5) * amplitude.
119        (Basically it will be centered at the current frequency.)
120        """
121        response = self.get_mode()
122        if response == Mode.normal:
123            raise Exception(
124                "Laser currently in normal mode.",
125                "please set to nodither or whisper mode",
126            )
127
128        self._csstart(1)

Enables clean sweep mode. The clean sweep will ramp to (+0.5 to -0.5) * amplitude. (Basically it will be centered at the current frequency.)

def cleansweep_disable(self):
130    def cleansweep_disable(self):
131        """Turn's off clean sweep mode."""
132
133        self._csstart(0)

Turn's off clean sweep mode.

def cleansweep_setup(self, freq_low, freq_high):
135    def cleansweep_setup(self, freq_low, freq_high):
136        """
137        A wrapper function that takes the start and end frequencies
138        you would like to sweep over. It computes and sets the clean sweep
139        amplitude and the midpoint.
140
141        The clean sweep operation will begin in the center of the high and low.
142
143        """
144
145        if freq_low < self._frequency_min or freq_high > self._frequency_max:
146            raise ValueError(
147                "The range you would like to sweep over",
148                "is outside of the bounds for this laser",
149            )
150
151        # sets the clean sweep amplitude rounded to the nearest MHz.
152        cs_ampl = round(abs(freq_high - freq_low) * 1e3)
153        if cs_ampl > 50:
154            raise Exception(
155                "This is an error specific to SpectrumLab."
156                "Our laser has a 50GHz maximum cleansweep range."
157                "You should change the limit in source for your laser."
158                "If you know a way to query the laser for this value"
159                "then implementing that would be better."
160            )
161
162        self.set_cleansweep_amplitude(cs_ampl)
163
164        cs_center = round((freq_low + freq_high) * 1e4 / 2) * 1e-4
165        self.set_frequency(cs_center)

A wrapper function that takes the start and end frequencies you would like to sweep over. It computes and sets the clean sweep amplitude and the midpoint.

The clean sweep operation will begin in the center of the high and low.

def get_cleansweep_rate(self):
167    def get_cleansweep_rate(self):
168        """Gets the clean sweep rate. not sure about units."""
169        response = self._csrate()
170        cs_rate = int.from_bytes(response, "big")
171        return cs_rate

Gets the clean sweep rate. not sure about units.

def set_cleansweep_rate(self, rate_MHz):
173    def set_cleansweep_rate(self, rate_MHz):
174        """sets the cleansweep rate in MHz/sec
175        idk if there is a way to check if its within some bounds.
176        There is conflicting info in the pure photonics docs."""
177        raise Warning("Dont use this. Need to confirm the units for the sweep rate.")
178        self._csrate(rate_MHz)

sets the cleansweep rate in MHz/sec idk if there is a way to check if its within some bounds. There is conflicting info in the pure photonics docs.

def get_cleansweep_offset(self):
180    def get_cleansweep_offset(self):
181        raise Warning("This is not implemented yet.")
def set_cleansweep_offset(self, offset):
183    def set_cleansweep_offset(self, offset):
184        raise Warning("This is not implemented yet.")
def cleanjump(self):
186    def cleanjump(self):
187        """Tells the laser to perform the clean jump.
188        The clean jump must be precalibrated.
189        You should have the calibration points in your lab notebook
190        or written down somewhere.
191        If not you should perform the clean jump calibration."""
192        mode = self.get_mode()
193        if mode == Mode.normal:
194            raise Exception(
195                "Laser in normal mode. You must be in nodither"
196                "or whisper mode to use cleanjump."
197            )
198        self._cjstart(1)

Tells the laser to perform the clean jump. The clean jump must be precalibrated. You should have the calibration points in your lab notebook or written down somewhere. If not you should perform the clean jump calibration.

def set_cleanjump(self, freq_jump):
200    def set_cleanjump(self, freq_jump):
201        """
202        Set the size of the jump in THz to the fourth decimal place.
203        XXX.XXXX
204        """
205        freq_jump = str(round(freq_jump * 1e4))
206        self._cjthz(int(freq_jump[0:3]))
207        self._cjghz(int(freq_jump[3:]))

Set the size of the jump in THz to the fourth decimal place. XXX.XXXX

def cleanjump_calibration(self, fcf, grid, pwr, n_jumppoints, confirmation=None):
209    def cleanjump_calibration(self, fcf, grid, pwr, n_jumppoints, confirmation=None):
210        """
211        This is a grid based calibration
212
213        **fcf**: the first channel frequency you would like to
214        begin calibration at. (THz)
215
216        **grid**: the grid spacing (GHz)
217
218        **pwr**: The power calibration will be at. (dBm)
219
220        **n_jumppoints**: The number of grid points to calibrate.
221
222        **confirmation**: If you would like to go ahead and confirm yes
223        and skip the user input you can set confirmation to 'y'
224        """
225
226        # calibration begins by writing the number of channels to 0xD2
227
228        calibration_points = [fcf + grid * n * 1e-3 for n in range(n_jumppoints)]
229
230        logger.info(
231            f"You are calibrating {n_jumppoints} clean jump setpoints",
232            f"at frequencies:\n{calibration_points}(THz).",
233            f"With power = {pwr}(dBm).",
234        )
235        logger.info(
236            "Write these down in your lab notebook because",
237            "you cannot query the device for these values later.",
238        )
239
240        if confirmation is None:
241            confirmation = input("Is the information above correct? (y/n): ")
242
243        if confirmation.lower() == "y":
244            # set up the first channel frequency, grid spacing, and power
245            self.set_frequency(fcf)
246            self.set_grid(grid)
247            self.set_power(pwr)
248            self._cleanjump_calibration(n_jumppoints)
249
250        elif confirmation.lower() == "n":
251            logger.info(
252                f"You answered {confirmation!r}.", "Calibration will not be performed."
253            )
254
255        else:
256            raise Exception("input not recognized")

This is a grid based calibration

fcf: the first channel frequency you would like to begin calibration at. (THz)

grid: the grid spacing (GHz)

pwr: The power calibration will be at. (dBm)

n_jumppoints: The number of grid points to calibrate.

confirmation: If you would like to go ahead and confirm yes and skip the user input you can set confirmation to 'y'