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
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
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)
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
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
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.
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)
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)
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
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.)
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.