corems.transient.calc.TransientCalc

  1import gc
  2import warnings
  3
  4from numpy import (
  5    arange,
  6    blackman,
  7    ceil,
  8    fft,
  9    hamming,
 10    hanning,
 11    kaiser,
 12    linspace,
 13    log2,
 14    pi,
 15    power,
 16    sin,
 17    sqrt,
 18    where,
 19    zeros,
 20)
 21
 22__author__ = "Yuri E. Corilo"
 23__date__ = "Jun 12, 2019"
 24
 25
 26class TransientCalculations(object):
 27    """Transient Calculations
 28
 29    Parameters
 30    ----------
 31    parameters : corems.transient.parameters.TransientParameters
 32        The transient parameters
 33    bandwidth : float
 34        The bandwidth of the transient (Hz)
 35    number_data_points : int
 36        The number of data points of the transient
 37    exc_low_freq : float
 38        The low frequency of the excitation (Hz)
 39    exc_high_freq : float
 40        The high frequency of the excitation (Hz)
 41
 42    Attributes
 43    ----------
 44    parameters : corems.transient.parameters.TransientParameters
 45        The transient parameters
 46    bandwidth : float
 47        The bandwidth of the transient (Hz)
 48    number_data_points : int
 49        The number of data points of the transient
 50    exc_low_freq : float
 51        The low frequency of the excitation (Hz)
 52    exc_high_freq : float
 53        The high frequency of the excitation (Hz)
 54
 55    Methods
 56    -------
 57    * cal_transient_time().
 58        Calculate the time domain length of the transient
 59    * zero_fill(transient).
 60        Zero fill the transient
 61    * truncation(transient).
 62        Truncate the transient
 63    * apodization(transient).
 64        Apodization of the transient
 65    * calculate_frequency_domain(number_data_points).
 66        Calculate the frequency domain (axis) of the transient
 67    * cut_freq_domain(freqdomain_X, freqdomain_Y).
 68        Cut the frequency domain of the transient
 69    * phase_and_absorption_mode_ft().
 70        [Not Functional] Produce a phased absorption mode FT spectrum
 71    * magnitude_mode_ft(transient).
 72        Perform magnitude mode FT of the transient
 73    * correct_dc_offset().
 74        [Not Yet Implemented] Correct the DC offset of the transient
 75
 76    """
 77
 78    def cal_transient_time(self):
 79        """Calculate the time domain length of the transient
 80
 81        Returns
 82        -------
 83        float
 84            The time domain length of the transient (s)
 85        """
 86        return (1 / self.bandwidth) * ((self.number_data_points) / 2)
 87
 88    def zero_fill(self, transient):
 89        """Zero fill the transient
 90
 91        Parameters
 92        ----------
 93        transient : numpy.ndarray
 94            The transient data points
 95
 96        Returns
 97        -------
 98        numpy.ndarray
 99            The transient data points zerofilled
100
101        Notes
102        -----
103        The number of zero fills is defined by the transient parameter number_of_zero_fills.
104        The function first calculate the next power of two of the transient length and zero fills to that length, to take advantage of FFT algorithm.
105            If the parameter next_power_of_two is set to False, the function will zero fill to the length of the original transient times the number of zero fills
106
107        """
108        if self.parameters.next_power_of_two:
109            exponent = int(
110                ceil(log2(len(transient) * (self.parameters.number_of_zero_fills + 1)))
111            )
112            zeros_filled_transient = zeros(2**exponent)
113        else:
114            zeros_filled_transient = zeros(
115                len(transient) * (self.parameters.number_of_zero_fills + 1)
116            )
117
118        zeros_filled_transient[0 : len(transient)] = transient
119
120        del transient
121
122        gc.collect()
123
124        return zeros_filled_transient
125
126    def truncation(self, transient):
127        """Truncate the transient
128
129        Parameters
130        ----------
131        transient : numpy.ndarray
132            The transient data points
133
134        Returns
135        -------
136        numpy.ndarray
137            The truncated transient data points
138
139        Notes
140        -----
141        The number of truncations is defined by the transient parameter number_of_truncations
142        """
143
144        data_count = len(transient)
145
146        for _ in range(self.parameters.number_of_truncations):
147            data_count = int(data_count / 2)
148
149        time_domain_truncated = transient[0:data_count]
150
151        del transient
152
153        gc.collect()
154
155        return time_domain_truncated
156
157    def apodization(self, transient):
158        """Apodization of the transient
159
160        Parameters
161        ----------
162        transient : numpy.ndarray
163            The transient data points
164
165        Returns
166        -------
167        numpy.ndarray
168            The apodized transient data points
169
170        Notes
171        -----
172        The apodization method is defined by the transient parameter apodization_method.
173        The following apodization methods are available:
174            Hamming,
175            Hanning,
176            Blackman,
177            Full-Sine,
178            Half-Sine,
179            Kaiser,
180            Half-Kaiser,
181            Rectangular/None
182
183        For Kaiser and Half-Kaiser, an additional parameter 'beta' is required, set by the transient parameter kaiser_beta.
184
185        """
186
187        apodi_method = self.parameters.apodization_method
188        beta = self.parameters.kaiser_beta
189
190        length = len(transient)
191
192        if apodi_method == "Hamming":
193            H_function = hamming(length)
194        elif apodi_method == "Hanning":
195            H_function = hanning(length)
196        elif apodi_method == "Blackman":
197            H_function = blackman(length)
198        elif apodi_method == "Full-Sine":
199            H_function = sin(linspace(0, pi, num=length))
200        elif apodi_method == "Half-Sine":
201            H_function = sin(linspace((pi / 2), 0, num=length))
202        elif apodi_method == "Kaiser":
203            H_function = kaiser(length, beta)
204        elif apodi_method == "Half-Kaiser":
205            H_function = kaiser(length * 2, beta)[length:]
206        elif apodi_method == 'Rectangular' or apodi_method is None:
207            H_function = 1
208
209        S_x = transient * H_function
210
211        del transient
212        gc.collect()
213
214        return S_x
215
216    def calculate_frequency_domain(self, number_data_points):
217        """Calculate the frequency domain (axis) of the transient
218
219        Parameters
220        ----------
221        number_data_points : int
222            The number of data points of the transient
223
224        Returns
225        -------
226        numpy.ndarray
227            The frequency domain of the transient (Hz)
228
229
230        """
231
232        qntpoints = arange(0, (number_data_points))
233
234        factor_distancy = (self.bandwidth) / (number_data_points)
235
236        frequency_domain = qntpoints * factor_distancy
237
238        del qntpoints
239        del factor_distancy
240        gc.collect()
241
242        return frequency_domain
243
244    def cut_freq_domain(self, freqdomain_X, freqdomain_Y):
245        """Cut the frequency domain of the transient
246
247        Parameters
248        ----------
249        freqdomain_X : numpy.ndarray
250            The frequency domain of the transient (Hz)
251        freqdomain_Y : numpy.ndarray
252            The frequency domain of the transient (Hz)
253
254        Returns
255        -------
256        numpy.ndarray
257            The frequency domain of the transient (Hz)
258        numpy.ndarray
259            The frequency domain of the transient (Hz)
260
261
262        """
263        # If the mw_low and mw_high are set, the frequency domain is cut to the mw range
264        # this accounts for the detection settings, not the excitation settings.
265        # TODO: Implement this - right now the f to mz function is in the ms class, not the transient class, so it doesnt work.
266        # if (self._mw_low != 0) & (self._mw_high != 0):
267        #    high_freq = self._f_to_mz(self._mw_high)
268        #    low_freq = self._f_to_mz(self._mw_low)
269        #
270        #    final =  where(freqdomain_X < high_freq)[-1][-1]
271        #      start =  where(freqdomain_X > low_freq)[0][0]
272        # else:
273        if self._qpd_enabled == 1:
274            low_freq = self._exc_low_freq * 2
275            high_freq = self._exc_high_freq * 2
276        else:
277            low_freq = self._exc_low_freq
278            high_freq = self._exc_high_freq
279
280        if self._exc_low_freq > self._exc_high_freq:
281            # TODO: This needs to be tested
282            # I'm not sure that this is relevant anyway - the excitation pulse is ramped in frequency but the detection is simulatenous
283            warnings.warn("This is not tested. Please check the results.")
284            final = where(freqdomain_X > low_freq)[0][0]
285            start = where(freqdomain_X > high_freq)[0][0]
286
287        else:
288            final = where(freqdomain_X < high_freq)[-1][-1]
289            start = where(freqdomain_X > low_freq)[0][0]
290
291        return freqdomain_X[start:final], freqdomain_Y[start:final]
292        # del freqdomain_X, freqdomain_Y
293        # gc.collect()
294
295    def phase_and_absorption_mode_ft(self):
296        """[Not Functional] Produce a phased absorption mode FT spectrum"""
297        # anyone wants to play with this part please make yourself comfortable. I will:
298        pass
299
300    def perform_magniture_mode_ft(self, transient):
301        """Perform magnitude mode FT of the transient
302
303        Parameters
304        ----------
305        transient : numpy.ndarray
306            The transient data points
307
308        Returns
309        -------
310        numpy.ndarray
311            The frequency domain of the transient (Hz)
312        numpy.ndarray
313            The magnitude of the transient (a.u.)
314
315
316        """
317
318        A = fft.rfft(transient)
319
320        # A = fft.fft(transient)
321        # A = A[0:int(len(A)/2)]
322
323        factor = int(self.parameters.number_of_zero_fills - 1)
324        if self.parameters.number_of_zero_fills:
325            if self.parameters.number_of_zero_fills == 1:
326                factor = 1 / 2
327
328            else:
329                factor = int(1 / self.parameters.number_of_zero_fills + 1)
330
331            Max_index = int(len(A) / factor)
332
333        else:
334            Max_index = int(len(A))
335
336        A = A[0:Max_index]
337
338        datapoints = len(A)
339
340        freqdomain_X = self.calculate_frequency_domain(datapoints)
341
342        magnitude_Y = sqrt((power(A.real, 2)) + (power(A.imag, 2)))
343
344        freqdomain_X_cut, magnitude_Y_cut = self.cut_freq_domain(
345            freqdomain_X, magnitude_Y
346        )
347
348        del transient
349        # del freqdomain_X
350        # del magnitude_Y
351        gc.collect()
352
353        return freqdomain_X_cut, magnitude_Y_cut
354
355    def correct_dc_offset(self):
356        """[Not Yet Implemented] Correct the DC offset of the transient
357
358        A simple baseline correction to compensate for a DC offset in the recorded transient.
359        Not implemented.
360
361        """
362        pass
class TransientCalculations:
 27class TransientCalculations(object):
 28    """Transient Calculations
 29
 30    Parameters
 31    ----------
 32    parameters : corems.transient.parameters.TransientParameters
 33        The transient parameters
 34    bandwidth : float
 35        The bandwidth of the transient (Hz)
 36    number_data_points : int
 37        The number of data points of the transient
 38    exc_low_freq : float
 39        The low frequency of the excitation (Hz)
 40    exc_high_freq : float
 41        The high frequency of the excitation (Hz)
 42
 43    Attributes
 44    ----------
 45    parameters : corems.transient.parameters.TransientParameters
 46        The transient parameters
 47    bandwidth : float
 48        The bandwidth of the transient (Hz)
 49    number_data_points : int
 50        The number of data points of the transient
 51    exc_low_freq : float
 52        The low frequency of the excitation (Hz)
 53    exc_high_freq : float
 54        The high frequency of the excitation (Hz)
 55
 56    Methods
 57    -------
 58    * cal_transient_time().
 59        Calculate the time domain length of the transient
 60    * zero_fill(transient).
 61        Zero fill the transient
 62    * truncation(transient).
 63        Truncate the transient
 64    * apodization(transient).
 65        Apodization of the transient
 66    * calculate_frequency_domain(number_data_points).
 67        Calculate the frequency domain (axis) of the transient
 68    * cut_freq_domain(freqdomain_X, freqdomain_Y).
 69        Cut the frequency domain of the transient
 70    * phase_and_absorption_mode_ft().
 71        [Not Functional] Produce a phased absorption mode FT spectrum
 72    * magnitude_mode_ft(transient).
 73        Perform magnitude mode FT of the transient
 74    * correct_dc_offset().
 75        [Not Yet Implemented] Correct the DC offset of the transient
 76
 77    """
 78
 79    def cal_transient_time(self):
 80        """Calculate the time domain length of the transient
 81
 82        Returns
 83        -------
 84        float
 85            The time domain length of the transient (s)
 86        """
 87        return (1 / self.bandwidth) * ((self.number_data_points) / 2)
 88
 89    def zero_fill(self, transient):
 90        """Zero fill the transient
 91
 92        Parameters
 93        ----------
 94        transient : numpy.ndarray
 95            The transient data points
 96
 97        Returns
 98        -------
 99        numpy.ndarray
100            The transient data points zerofilled
101
102        Notes
103        -----
104        The number of zero fills is defined by the transient parameter number_of_zero_fills.
105        The function first calculate the next power of two of the transient length and zero fills to that length, to take advantage of FFT algorithm.
106            If the parameter next_power_of_two is set to False, the function will zero fill to the length of the original transient times the number of zero fills
107
108        """
109        if self.parameters.next_power_of_two:
110            exponent = int(
111                ceil(log2(len(transient) * (self.parameters.number_of_zero_fills + 1)))
112            )
113            zeros_filled_transient = zeros(2**exponent)
114        else:
115            zeros_filled_transient = zeros(
116                len(transient) * (self.parameters.number_of_zero_fills + 1)
117            )
118
119        zeros_filled_transient[0 : len(transient)] = transient
120
121        del transient
122
123        gc.collect()
124
125        return zeros_filled_transient
126
127    def truncation(self, transient):
128        """Truncate the transient
129
130        Parameters
131        ----------
132        transient : numpy.ndarray
133            The transient data points
134
135        Returns
136        -------
137        numpy.ndarray
138            The truncated transient data points
139
140        Notes
141        -----
142        The number of truncations is defined by the transient parameter number_of_truncations
143        """
144
145        data_count = len(transient)
146
147        for _ in range(self.parameters.number_of_truncations):
148            data_count = int(data_count / 2)
149
150        time_domain_truncated = transient[0:data_count]
151
152        del transient
153
154        gc.collect()
155
156        return time_domain_truncated
157
158    def apodization(self, transient):
159        """Apodization of the transient
160
161        Parameters
162        ----------
163        transient : numpy.ndarray
164            The transient data points
165
166        Returns
167        -------
168        numpy.ndarray
169            The apodized transient data points
170
171        Notes
172        -----
173        The apodization method is defined by the transient parameter apodization_method.
174        The following apodization methods are available:
175            Hamming,
176            Hanning,
177            Blackman,
178            Full-Sine,
179            Half-Sine,
180            Kaiser,
181            Half-Kaiser,
182            Rectangular/None
183
184        For Kaiser and Half-Kaiser, an additional parameter 'beta' is required, set by the transient parameter kaiser_beta.
185
186        """
187
188        apodi_method = self.parameters.apodization_method
189        beta = self.parameters.kaiser_beta
190
191        length = len(transient)
192
193        if apodi_method == "Hamming":
194            H_function = hamming(length)
195        elif apodi_method == "Hanning":
196            H_function = hanning(length)
197        elif apodi_method == "Blackman":
198            H_function = blackman(length)
199        elif apodi_method == "Full-Sine":
200            H_function = sin(linspace(0, pi, num=length))
201        elif apodi_method == "Half-Sine":
202            H_function = sin(linspace((pi / 2), 0, num=length))
203        elif apodi_method == "Kaiser":
204            H_function = kaiser(length, beta)
205        elif apodi_method == "Half-Kaiser":
206            H_function = kaiser(length * 2, beta)[length:]
207        elif apodi_method == 'Rectangular' or apodi_method is None:
208            H_function = 1
209
210        S_x = transient * H_function
211
212        del transient
213        gc.collect()
214
215        return S_x
216
217    def calculate_frequency_domain(self, number_data_points):
218        """Calculate the frequency domain (axis) of the transient
219
220        Parameters
221        ----------
222        number_data_points : int
223            The number of data points of the transient
224
225        Returns
226        -------
227        numpy.ndarray
228            The frequency domain of the transient (Hz)
229
230
231        """
232
233        qntpoints = arange(0, (number_data_points))
234
235        factor_distancy = (self.bandwidth) / (number_data_points)
236
237        frequency_domain = qntpoints * factor_distancy
238
239        del qntpoints
240        del factor_distancy
241        gc.collect()
242
243        return frequency_domain
244
245    def cut_freq_domain(self, freqdomain_X, freqdomain_Y):
246        """Cut the frequency domain of the transient
247
248        Parameters
249        ----------
250        freqdomain_X : numpy.ndarray
251            The frequency domain of the transient (Hz)
252        freqdomain_Y : numpy.ndarray
253            The frequency domain of the transient (Hz)
254
255        Returns
256        -------
257        numpy.ndarray
258            The frequency domain of the transient (Hz)
259        numpy.ndarray
260            The frequency domain of the transient (Hz)
261
262
263        """
264        # If the mw_low and mw_high are set, the frequency domain is cut to the mw range
265        # this accounts for the detection settings, not the excitation settings.
266        # TODO: Implement this - right now the f to mz function is in the ms class, not the transient class, so it doesnt work.
267        # if (self._mw_low != 0) & (self._mw_high != 0):
268        #    high_freq = self._f_to_mz(self._mw_high)
269        #    low_freq = self._f_to_mz(self._mw_low)
270        #
271        #    final =  where(freqdomain_X < high_freq)[-1][-1]
272        #      start =  where(freqdomain_X > low_freq)[0][0]
273        # else:
274        if self._qpd_enabled == 1:
275            low_freq = self._exc_low_freq * 2
276            high_freq = self._exc_high_freq * 2
277        else:
278            low_freq = self._exc_low_freq
279            high_freq = self._exc_high_freq
280
281        if self._exc_low_freq > self._exc_high_freq:
282            # TODO: This needs to be tested
283            # I'm not sure that this is relevant anyway - the excitation pulse is ramped in frequency but the detection is simulatenous
284            warnings.warn("This is not tested. Please check the results.")
285            final = where(freqdomain_X > low_freq)[0][0]
286            start = where(freqdomain_X > high_freq)[0][0]
287
288        else:
289            final = where(freqdomain_X < high_freq)[-1][-1]
290            start = where(freqdomain_X > low_freq)[0][0]
291
292        return freqdomain_X[start:final], freqdomain_Y[start:final]
293        # del freqdomain_X, freqdomain_Y
294        # gc.collect()
295
296    def phase_and_absorption_mode_ft(self):
297        """[Not Functional] Produce a phased absorption mode FT spectrum"""
298        # anyone wants to play with this part please make yourself comfortable. I will:
299        pass
300
301    def perform_magniture_mode_ft(self, transient):
302        """Perform magnitude mode FT of the transient
303
304        Parameters
305        ----------
306        transient : numpy.ndarray
307            The transient data points
308
309        Returns
310        -------
311        numpy.ndarray
312            The frequency domain of the transient (Hz)
313        numpy.ndarray
314            The magnitude of the transient (a.u.)
315
316
317        """
318
319        A = fft.rfft(transient)
320
321        # A = fft.fft(transient)
322        # A = A[0:int(len(A)/2)]
323
324        factor = int(self.parameters.number_of_zero_fills - 1)
325        if self.parameters.number_of_zero_fills:
326            if self.parameters.number_of_zero_fills == 1:
327                factor = 1 / 2
328
329            else:
330                factor = int(1 / self.parameters.number_of_zero_fills + 1)
331
332            Max_index = int(len(A) / factor)
333
334        else:
335            Max_index = int(len(A))
336
337        A = A[0:Max_index]
338
339        datapoints = len(A)
340
341        freqdomain_X = self.calculate_frequency_domain(datapoints)
342
343        magnitude_Y = sqrt((power(A.real, 2)) + (power(A.imag, 2)))
344
345        freqdomain_X_cut, magnitude_Y_cut = self.cut_freq_domain(
346            freqdomain_X, magnitude_Y
347        )
348
349        del transient
350        # del freqdomain_X
351        # del magnitude_Y
352        gc.collect()
353
354        return freqdomain_X_cut, magnitude_Y_cut
355
356    def correct_dc_offset(self):
357        """[Not Yet Implemented] Correct the DC offset of the transient
358
359        A simple baseline correction to compensate for a DC offset in the recorded transient.
360        Not implemented.
361
362        """
363        pass

Transient Calculations

Parameters
  • parameters (corems.transient.parameters.TransientParameters): The transient parameters
  • bandwidth (float): The bandwidth of the transient (Hz)
  • number_data_points (int): The number of data points of the transient
  • exc_low_freq (float): The low frequency of the excitation (Hz)
  • exc_high_freq (float): The high frequency of the excitation (Hz)
Attributes
  • parameters (corems.transient.parameters.TransientParameters): The transient parameters
  • bandwidth (float): The bandwidth of the transient (Hz)
  • number_data_points (int): The number of data points of the transient
  • exc_low_freq (float): The low frequency of the excitation (Hz)
  • exc_high_freq (float): The high frequency of the excitation (Hz)
Methods
  • cal_transient_time(). Calculate the time domain length of the transient
  • zero_fill(transient). Zero fill the transient
  • truncation(transient). Truncate the transient
  • apodization(transient). Apodization of the transient
  • calculate_frequency_domain(number_data_points). Calculate the frequency domain (axis) of the transient
  • cut_freq_domain(freqdomain_X, freqdomain_Y). Cut the frequency domain of the transient
  • phase_and_absorption_mode_ft(). [Not Functional] Produce a phased absorption mode FT spectrum
  • magnitude_mode_ft(transient). Perform magnitude mode FT of the transient
  • correct_dc_offset(). [Not Yet Implemented] Correct the DC offset of the transient
def cal_transient_time(self):
79    def cal_transient_time(self):
80        """Calculate the time domain length of the transient
81
82        Returns
83        -------
84        float
85            The time domain length of the transient (s)
86        """
87        return (1 / self.bandwidth) * ((self.number_data_points) / 2)

Calculate the time domain length of the transient

Returns
  • float: The time domain length of the transient (s)
def zero_fill(self, transient):
 89    def zero_fill(self, transient):
 90        """Zero fill the transient
 91
 92        Parameters
 93        ----------
 94        transient : numpy.ndarray
 95            The transient data points
 96
 97        Returns
 98        -------
 99        numpy.ndarray
100            The transient data points zerofilled
101
102        Notes
103        -----
104        The number of zero fills is defined by the transient parameter number_of_zero_fills.
105        The function first calculate the next power of two of the transient length and zero fills to that length, to take advantage of FFT algorithm.
106            If the parameter next_power_of_two is set to False, the function will zero fill to the length of the original transient times the number of zero fills
107
108        """
109        if self.parameters.next_power_of_two:
110            exponent = int(
111                ceil(log2(len(transient) * (self.parameters.number_of_zero_fills + 1)))
112            )
113            zeros_filled_transient = zeros(2**exponent)
114        else:
115            zeros_filled_transient = zeros(
116                len(transient) * (self.parameters.number_of_zero_fills + 1)
117            )
118
119        zeros_filled_transient[0 : len(transient)] = transient
120
121        del transient
122
123        gc.collect()
124
125        return zeros_filled_transient

Zero fill the transient

Parameters
  • transient (numpy.ndarray): The transient data points
Returns
  • numpy.ndarray: The transient data points zerofilled
Notes

The number of zero fills is defined by the transient parameter number_of_zero_fills. The function first calculate the next power of two of the transient length and zero fills to that length, to take advantage of FFT algorithm. If the parameter next_power_of_two is set to False, the function will zero fill to the length of the original transient times the number of zero fills

def truncation(self, transient):
127    def truncation(self, transient):
128        """Truncate the transient
129
130        Parameters
131        ----------
132        transient : numpy.ndarray
133            The transient data points
134
135        Returns
136        -------
137        numpy.ndarray
138            The truncated transient data points
139
140        Notes
141        -----
142        The number of truncations is defined by the transient parameter number_of_truncations
143        """
144
145        data_count = len(transient)
146
147        for _ in range(self.parameters.number_of_truncations):
148            data_count = int(data_count / 2)
149
150        time_domain_truncated = transient[0:data_count]
151
152        del transient
153
154        gc.collect()
155
156        return time_domain_truncated

Truncate the transient

Parameters
  • transient (numpy.ndarray): The transient data points
Returns
  • numpy.ndarray: The truncated transient data points
Notes

The number of truncations is defined by the transient parameter number_of_truncations

def apodization(self, transient):
158    def apodization(self, transient):
159        """Apodization of the transient
160
161        Parameters
162        ----------
163        transient : numpy.ndarray
164            The transient data points
165
166        Returns
167        -------
168        numpy.ndarray
169            The apodized transient data points
170
171        Notes
172        -----
173        The apodization method is defined by the transient parameter apodization_method.
174        The following apodization methods are available:
175            Hamming,
176            Hanning,
177            Blackman,
178            Full-Sine,
179            Half-Sine,
180            Kaiser,
181            Half-Kaiser,
182            Rectangular/None
183
184        For Kaiser and Half-Kaiser, an additional parameter 'beta' is required, set by the transient parameter kaiser_beta.
185
186        """
187
188        apodi_method = self.parameters.apodization_method
189        beta = self.parameters.kaiser_beta
190
191        length = len(transient)
192
193        if apodi_method == "Hamming":
194            H_function = hamming(length)
195        elif apodi_method == "Hanning":
196            H_function = hanning(length)
197        elif apodi_method == "Blackman":
198            H_function = blackman(length)
199        elif apodi_method == "Full-Sine":
200            H_function = sin(linspace(0, pi, num=length))
201        elif apodi_method == "Half-Sine":
202            H_function = sin(linspace((pi / 2), 0, num=length))
203        elif apodi_method == "Kaiser":
204            H_function = kaiser(length, beta)
205        elif apodi_method == "Half-Kaiser":
206            H_function = kaiser(length * 2, beta)[length:]
207        elif apodi_method == 'Rectangular' or apodi_method is None:
208            H_function = 1
209
210        S_x = transient * H_function
211
212        del transient
213        gc.collect()
214
215        return S_x

Apodization of the transient

Parameters
  • transient (numpy.ndarray): The transient data points
Returns
  • numpy.ndarray: The apodized transient data points
Notes

The apodization method is defined by the transient parameter apodization_method. The following apodization methods are available: Hamming, Hanning, Blackman, Full-Sine, Half-Sine, Kaiser, Half-Kaiser, Rectangular/None

For Kaiser and Half-Kaiser, an additional parameter 'beta' is required, set by the transient parameter kaiser_beta.

def calculate_frequency_domain(self, number_data_points):
217    def calculate_frequency_domain(self, number_data_points):
218        """Calculate the frequency domain (axis) of the transient
219
220        Parameters
221        ----------
222        number_data_points : int
223            The number of data points of the transient
224
225        Returns
226        -------
227        numpy.ndarray
228            The frequency domain of the transient (Hz)
229
230
231        """
232
233        qntpoints = arange(0, (number_data_points))
234
235        factor_distancy = (self.bandwidth) / (number_data_points)
236
237        frequency_domain = qntpoints * factor_distancy
238
239        del qntpoints
240        del factor_distancy
241        gc.collect()
242
243        return frequency_domain

Calculate the frequency domain (axis) of the transient

Parameters
  • number_data_points (int): The number of data points of the transient
Returns
  • numpy.ndarray: The frequency domain of the transient (Hz)
def cut_freq_domain(self, freqdomain_X, freqdomain_Y):
245    def cut_freq_domain(self, freqdomain_X, freqdomain_Y):
246        """Cut the frequency domain of the transient
247
248        Parameters
249        ----------
250        freqdomain_X : numpy.ndarray
251            The frequency domain of the transient (Hz)
252        freqdomain_Y : numpy.ndarray
253            The frequency domain of the transient (Hz)
254
255        Returns
256        -------
257        numpy.ndarray
258            The frequency domain of the transient (Hz)
259        numpy.ndarray
260            The frequency domain of the transient (Hz)
261
262
263        """
264        # If the mw_low and mw_high are set, the frequency domain is cut to the mw range
265        # this accounts for the detection settings, not the excitation settings.
266        # TODO: Implement this - right now the f to mz function is in the ms class, not the transient class, so it doesnt work.
267        # if (self._mw_low != 0) & (self._mw_high != 0):
268        #    high_freq = self._f_to_mz(self._mw_high)
269        #    low_freq = self._f_to_mz(self._mw_low)
270        #
271        #    final =  where(freqdomain_X < high_freq)[-1][-1]
272        #      start =  where(freqdomain_X > low_freq)[0][0]
273        # else:
274        if self._qpd_enabled == 1:
275            low_freq = self._exc_low_freq * 2
276            high_freq = self._exc_high_freq * 2
277        else:
278            low_freq = self._exc_low_freq
279            high_freq = self._exc_high_freq
280
281        if self._exc_low_freq > self._exc_high_freq:
282            # TODO: This needs to be tested
283            # I'm not sure that this is relevant anyway - the excitation pulse is ramped in frequency but the detection is simulatenous
284            warnings.warn("This is not tested. Please check the results.")
285            final = where(freqdomain_X > low_freq)[0][0]
286            start = where(freqdomain_X > high_freq)[0][0]
287
288        else:
289            final = where(freqdomain_X < high_freq)[-1][-1]
290            start = where(freqdomain_X > low_freq)[0][0]
291
292        return freqdomain_X[start:final], freqdomain_Y[start:final]
293        # del freqdomain_X, freqdomain_Y
294        # gc.collect()

Cut the frequency domain of the transient

Parameters
  • freqdomain_X (numpy.ndarray): The frequency domain of the transient (Hz)
  • freqdomain_Y (numpy.ndarray): The frequency domain of the transient (Hz)
Returns
  • numpy.ndarray: The frequency domain of the transient (Hz)
  • numpy.ndarray: The frequency domain of the transient (Hz)
def phase_and_absorption_mode_ft(self):
296    def phase_and_absorption_mode_ft(self):
297        """[Not Functional] Produce a phased absorption mode FT spectrum"""
298        # anyone wants to play with this part please make yourself comfortable. I will:
299        pass

[Not Functional] Produce a phased absorption mode FT spectrum

def perform_magniture_mode_ft(self, transient):
301    def perform_magniture_mode_ft(self, transient):
302        """Perform magnitude mode FT of the transient
303
304        Parameters
305        ----------
306        transient : numpy.ndarray
307            The transient data points
308
309        Returns
310        -------
311        numpy.ndarray
312            The frequency domain of the transient (Hz)
313        numpy.ndarray
314            The magnitude of the transient (a.u.)
315
316
317        """
318
319        A = fft.rfft(transient)
320
321        # A = fft.fft(transient)
322        # A = A[0:int(len(A)/2)]
323
324        factor = int(self.parameters.number_of_zero_fills - 1)
325        if self.parameters.number_of_zero_fills:
326            if self.parameters.number_of_zero_fills == 1:
327                factor = 1 / 2
328
329            else:
330                factor = int(1 / self.parameters.number_of_zero_fills + 1)
331
332            Max_index = int(len(A) / factor)
333
334        else:
335            Max_index = int(len(A))
336
337        A = A[0:Max_index]
338
339        datapoints = len(A)
340
341        freqdomain_X = self.calculate_frequency_domain(datapoints)
342
343        magnitude_Y = sqrt((power(A.real, 2)) + (power(A.imag, 2)))
344
345        freqdomain_X_cut, magnitude_Y_cut = self.cut_freq_domain(
346            freqdomain_X, magnitude_Y
347        )
348
349        del transient
350        # del freqdomain_X
351        # del magnitude_Y
352        gc.collect()
353
354        return freqdomain_X_cut, magnitude_Y_cut

Perform magnitude mode FT of the transient

Parameters
  • transient (numpy.ndarray): The transient data points
Returns
  • numpy.ndarray: The frequency domain of the transient (Hz)
  • numpy.ndarray: The magnitude of the transient (a.u.)
def correct_dc_offset(self):
356    def correct_dc_offset(self):
357        """[Not Yet Implemented] Correct the DC offset of the transient
358
359        A simple baseline correction to compensate for a DC offset in the recorded transient.
360        Not implemented.
361
362        """
363        pass

[Not Yet Implemented] Correct the DC offset of the transient

A simple baseline correction to compensate for a DC offset in the recorded transient. Not implemented.