Bohrium
robot
新建

空间站广场

论文
Notebooks
比赛
课程
Apps
我的主页
我的Notebooks
我的论文库
我的足迹

我的工作空间

任务
节点
文件
数据集
镜像
项目
数据库
公开
走进科学计算_11_核磁共振与NMRglue
中文
python
科学计算
中文python科学计算
ck
发布于 2023-08-23
推荐镜像 :Basic Image:bohrium-notebook:2023-04-07
推荐机型 :c2_m4_cpu
赞 2
3
11: 核磁共振与NMRglue
11.1 NMR 数据处理
11.2 使用 NMRglue 导入数据
11.3 傅里叶变换数据
11.4 相位校正数据
11.4.1 自动相位校正
11.4.2 手动相位校正
11.5 化学位移
11.5.1 生成 X 轴
11.5.2 参照数据
11.6 积分
11.7 峰值拾取
延伸阅读
参考
练习

11: 核磁共振与NMRglue

代码
文本

核磁共振(NMR)光谱学是现代化学中最常见和最强大的分析方法之一。到目前为止,我们主要处理的是基于文本的数据文件,也就是说,可以使用文本编辑器打开并仍包含人类可理解信息的文件。如果你用文本编辑器打开大多数来自 NMR 仪器的文件,它看起来更像是胡言乱语,而不是人类应该能够阅读的东西。这是因为它们是二进制文件;它们是用计算机语言而不是人类语言编写的。

我们需要一个专门的模块来导入和读取这些数据,幸运的是,一个名为 NMRglue 的 Python 模块正好可以做到这一点。该模块包含处理来自各种主要 NMR 光谱文件类型的数据的子模块,包括 Bruker、Pipe、Sparky 和 Varian。它不能读取 JOEL 文件,但现在JOEL光谱仪支持将数据导出为 NMRglue 支持的上述文件类型之一。

目前,Anaconda 不包含 NMRglue,因此您需要自行获取 NMRglue 并安装。以下网站包含安装说明,或者您可以使用 pip 来安装。如果 Jupyter 已经安装在您的计算机上,您应该可以通过终端使用 pip install nmrglue 进行安装,如果您在使用 Google Colab,您应该在笔记本的第一个代码单元格中包含 !pip install nmrglue(请参阅[第 0.2 节])。NMRglue 要求您已经安装了 NumPy 和 SciPy,还应该安装 matplotlib 以进行可视化。

https://nmrglue.readthedocs.io/en/latest/install.html

以下所有使用 NMRglue 的内容都假定使用了包含别名的导入。NMRglue 不是 SciPy 生态系统中的主要库,所以 ng 别名并非严格约定,但在此处使用它是为了方便,也是为了与在线文档保持一致。

代码
文本
[2]
import nmrglue as ng
import numpy as np
import matplotlib.pyplot as plt
代码
文本

11.1 NMR 数据处理

收集 NMR 数据的一般步骤是用射频脉冲激发给定类型的 NMR 活跃核,让它们放松。当它们旋转时,它们的旋转在仪器中引起特征频率的电压振荡,光谱仪记录这些振荡作为下面所示的自由感应衰减(fid)(图 1,左)。我们感兴趣的是这些振荡的频率,因为它们对于受过化学培训的人来说,可以了解核的化学环境。一个挑战是,来自每个核的所有不同信号都堆叠在一起,使得难以区分一个从另一个或确定波频。这类似于计算机在整个乐团同时演奏时辨别单个乐器的问题。幸运的是,有一个名为傅里叶变换的数学方程,它将上述 fid 转换为显示所有不同频率的图形(图 1,右)。这就是所谓的将时域转换为频域

图 1 原始 NMR 光谱数据通过傅里叶变换从时域(左)转换为频域(右)。

用 Python 处理 NMR 光谱数据的一般步骤如下。

  1. 使用 NMRglue 将 fid 数据加载到 NumPy 数组中

  2. 将数据傅里叶变换到频域

  3. 对光谱进行相位处理

  4. 对光谱进行校准

  5. 测量峰的化学位移和积分

代码
文本

11.2 使用 NMRglue 导入数据

使用 NMRglue 导入数据是通过表 1 中所示的子模块中的 read 函数完成的。可以在 NMRglue 文档 中找到其他模块。模块的选择取决于数据文件类型。

表 1 NMRglue 模块示例

模块 描述
bruker 作为单个文件的 Bruker 数据
pipe 作为具有 .fid 扩展名的单个文件的 Pipe 数据
sparky 带有 .ucsf 扩展名的 Sparky NMR 文件格式
varian 作为具有 .fid 扩展名的数据文件夹的 Varian/Agilent 数据
jcampdx 具有 .dx 或 .jdx 扩展名的 JCAMP-DX 文件

read() 函数加载 NMR 文件并返回一个包含元数据字典和 ndarray 中数据的元组。字典包括完成 NMR 日期处理所需的信息。查看下面的 NMR 数据,您可能注意到每个点都包括实部和虚部(即带有 j 的数学术语)。稍后在对光谱进行相位处理时,两者都是必需的,所以不要丢弃任何数据。

代码
文本
[ ]
!wget https://bohrium-example.oss-cn-zhangjiakou.aliyuncs.com/notebook/SciCompforChemists/notebooks/chapter_11/data/EtPh_1H_NMR_CDCl3.fid
代码
文本
[3]
dic, data = ng.pipe.read('EtPh_1H_NMR_CDCl3.fid')
data
array([-0.00194889-0.00471539j, -0.00192186-0.00472489j,
       -0.00191337-0.00473085j, ..., -0.00189737+0.00591656j,
       -0.00191882+0.005872j  , -0.00191135+0.00587132j], dtype=complex64)
代码
文本
本演示中使用的数据已经在光谱仪上进行了傅里叶变换,因此以下单元格为演示目的而反转此过程。有些光谱仪会自动进行傅里叶变换,而有些则不会。
代码
文本
[4]
# Reversed the Fourier transform for demo purposes being as this data
# was colleced on a spectrometer that already Fourier transformed the data.

from scipy.fft import ifft
data = ifft(data)[::-1]
代码
文本

上面的字典 dic 包含一个非常长的值列表,不同文件格式之间的字典键可能会有所不同。为了保持一个更短、更有用且更一致的元数据字典,NMRglue 提供了 guess_udic() 函数,用于在所有文件格式之间生成一个通用字典

代码
文本
[5]
udic = ng.pipe.guess_udic(dic, data)
udic
{'ndim': 1,
 0: {'sw': 5994.65478515625,
  'complex': True,
  'obs': 399.7821960449219,
  'car': 1998.9109802246094,
  'size': 13107,
  'label': 'Proton',
  'encoding': 'direct',
  'time': False,
  'freq': True}}
代码
文本

通用字典是一个嵌套字典。第一个键是 ndim,它提供了 NMR 光谱中的维度数量。大多数 NMR 光谱是一维的,但二维的也相当普遍。随后的键是 NMR 光谱中的每个维度,值为嵌套的元数据字典。因为上面的光谱数据是一维的,所以只有一个嵌套字典。下表 2 提供了通用字典中包含的每个元数据的描述。

表 2 单维度 udic 字典键*

描述 数据类型
car 载波频率 (Hz) 浮点数
complex 指示数据是否包含复数值 布尔值
encoding 编码格式 字符串
freq 指示数据是否在频率域中 布尔值
label 观察到的核 字符串
obs 观察频率 (MHz) 浮点数
size 光谱中的数据点数 整数
sw 频谱宽度 (Hz) 浮点数
time 指示数据是否在时域中** 布尔值

* 也就是说,我们假设我们正在查看来自 NMR 数据的单个维度,所以例如,我们正在查看 udic[0]

** 鉴于数据必须位于频率或时域中,freqtime 关键字实际上提供了相同的信息。

代码
文本

11.3 傅里叶变换数据

当数据首次导入时,它通常位于时域中。您可以通过检查 udic 中的 time 值是否设置为 True 来确认这一点,如下所示。

udic[0]['time']
代码
文本

我们还可以通过使用 matplotlib 绘制来查看数据。

代码
文本
[6]
fig0 = plt.figure(figsize=(16,6))
ax0 = fig0.add_subplot(1,1,1)
ax0.plot(data.real);
2023-06-10T08:59:50.958262 image/svg+xml Matplotlib v3.7.1, https://matplotlib.org/
代码
文本

要将数据转换为频率域,我们将使用来自 fft SciPy 模块的快速傅里叶变换函数(fft)。NMRglue 也包含傅里叶变换函数,但我们将在这里使用 SciPy。下面的图形通过以下方式反转 x 轴:

代码
文本
[7]
from scipy.fft import fft # imports only fft function
fdata = fft(data)
代码
文本
[8]
fig1 = plt.figure(figsize=(16,6))
ax1 = fig1.add_subplot(1,1,1)
ax1.plot(fdata.real)
plt.gca().invert_xaxis() # reverses direction of x-axis to conform to NMR plotting norms
2023-06-10T08:59:51.016906 image/svg+xml Matplotlib v3.7.1, https://matplotlib.org/
代码
文本

当你绘制傅里叶变换后的数据时,您可能会收到一个 ComplexWarning 错误消息,因为傅里叶变换将返回复数值(即具有实部和虚部的值)。要仅使用实部分量,请使用上面所做的 .real 方法。现在,图像看起来更像 NMR 光谱,但大部分共振是失去相位的。下一步是对光谱进行相位校正。

代码
文本

11.4 相位校正数据

相位校正是使所有峰值向上指向的后处理过程,如图 2 所示。这不仅仅是取绝对值,因为这样并不总是能产生单一峰值,所以 NMRglue 包含了一系列用于相位校正光谱的函数。

图 2 对 NMR 光谱进行相位校正会使所有信号指向正方向。

11.4.1 自动相位校正

相位校正 NMR 光谱的最简单方法是让自动相位校正函数为您处理。下面的函数接受数据和相位校正算法作为参数。

ng.process.proc_autophase.autops(data, algorithm)

允许的相位校正算法可以是 acmepeak_minima。向 autops() 函数提供带有实部分量和虚部分量的数据数组非常重要。

代码
文本
[9]
phased_data = ng.process.proc_autophase.autops(fdata,'acme')
Optimization terminated successfully.
         Current function value: 0.001729
         Iterations: 120
         Function evaluations: 238
代码
文本
[10]
fig2 = plt.figure(figsize=(16,6))
ax2 = fig2.add_subplot(1,1,1)
ax2.plot(phased_data.real)
plt.gca().invert_xaxis()
2023-06-10T08:59:51.136627 image/svg+xml Matplotlib v3.7.1, https://matplotlib.org/
代码
文本

你应该尝试这两种算法,看看哪种对你最有效。上面的光谱是使用 acme 自动相位校正算法得到的,结果接近但仍然有些偏差。如果这两种自动相位校正算法都不适用于你,那么你需要按照下面的讨论手动相位校正 NMR 光谱。

代码
文本

11.4.2 手动相位校正

手动相位校正 NMR 光谱分为两个步骤。首先,需要调用 manual_ps phasing() 函数并调整 p0p1 滑块,直到光谱看起来具有相位校正。

%matplotlib  # exists inline plotting
p0, p1 = ng.process.proc_autophase.manual_ps(fdata.real)

关闭窗口后,函数将返回 p0p1 的值,您发现这些值可以正确地相位校正光谱。第二步,将这些 p0p1 值输入到 ps() 相位校正函数中,以实际相位校正光谱。

phased_data = ng.proc_base.ps(fdata, p0=p0, p1=p1)

%matplotlib inline  # reinstates inline plotting

fig3 = plt.figure(figsize=(16,6))
ax3 = fig3.add_subplot(1,1,1)
ax3.plot(phased_data.real)
plt.gca().invert_xaxis()
代码
文本

然后,你可以绘制 phased_data 以获得具有所有峰值向上指向的 NMR 光谱。

代码
文本

11.5 化学位移

尽管 NMR 光谱现在已经相位校正,但它不太可能被正确地参照。也就是说,峰值目前并未位于正确的化学位移上。参照通常是通过了解溶剂共振或内部标准(如四甲基硅烷,TMS)的公认化学位移,并通过校正因子调整光谱来进行的。目前,我们是根据每个数据点的索引绘制数据,所以首先我们需要创建一个频率缩放的x轴数组,然后调整光谱的位置,使其正确参照。

11.5.1 生成 X 轴

x轴是频率刻度,因此这个轴有时以赫兹(Hz)表示。然而,由于 NMR 共振频率取决于仪器场强,因此相同的样品在不同的仪器中会产生不同的频率。为了使频率轴独立于谱仪场强,NMR 光谱通常以ppm 比例呈现,即观测到的化学位移(Hz)与观测到的特定核的谱仪频率(MHz)之间的比值。

这使得从谱仪到谱仪的峰值位置始终保持一致,无论磁场强度如何。这就是第 11.2 节中 udic 的重要性所在,因为我们可以获得光谱的观测频率宽度(Hz)和数据的分辨率。后者是光谱中有多少个数据点,这一点很重要,以便我们避免绘图错误(我们都知道这个错误:ValueError: x and y must have same first dimension, ...)。如果 udic 中的任何值为 999.99,这意味着谱仪没有记录这部分信息,您需要在其他地方找到它。

代码
文本
[11]
size = udic[0]['size'] # points in data
sw = udic[0]['sw'] # width in Hz
obs = udic[0]['obs'] # carrier frequency
代码
文本
[12]
from math import floor
hz = np.linspace(0, floor(sw), size) # x-axis in Hz
ppm = hz / obs # x-axis in ppm
代码
文本

现在,如果我们绘制光谱,我们会看到它是以ppm刻度显示的。

代码
文本
[13]
fig4 = plt.figure(figsize=(16,6))
ax4 = fig4.add_subplot(1,1,1)
ax4.plot(ppm, phased_data.real)
ax4.set_xlabel('Chemical Shift, ppm')
plt.gca().invert_xaxis()
2023-06-10T08:59:51.195391 image/svg+xml Matplotlib v3.7.1, https://matplotlib.org/
代码
文本

另外,NMRglue包含了一个称为单位转换对象的对象,可以用于在NMR光谱中的任何位置之间转换ppm、Hz和点索引值。要创建一个单位转换对象,请使用make_uc()函数,该函数需要两个参数 - 从第11.2节中读取的NMR文件生成的字典dic和原始数据数组data

如果您使用的是与pipe不同的NMR文件格式,请将`pipe`更改为表1中的适当格式。
unit_conv = ng.pipe.make_uc(dic, data)   

ppm = unit_conv.ppm_scale()

上述代码的最后一行生成了用于绘制 NMR 数据的 x 轴所需的 ppm 值数组。以下示例使用我们自己计算出的 ppm 刻度。

代码
文本

11.5.2 参照数据

在上面的光谱中,2.58 ppm 处的小共振是内部 TMS(四甲基硅烷)标准,应位于 0.00 ppm。诱惑是从 x 轴减去 2.58 ppm,但光谱不仅仅是移动,而是滚动。也就是说,当光谱移动时,其中一部分会从一端消失并在另一端重新出现(图 3)。

图 3 参照 NMR 光谱是通过滚动它,直到峰值位于正确的位移位置。当信号从光谱的一端掉落时,它会在另一端重新出现。

对我们来说方便的是,NumPy 有一个 np.roll() 函数,它可以将数据精确地滚动到数组数据中。

np.roll(array, shift)

np.roll() 函数需要两个参数。第一个是包含数据的数组,第二个是移动或滚动数据的量。位移不是以 ppm 为单位,而是以数据数组中的位置为单位。如果您知道以 ppm 为单位的参照校正(Δppm),请使用以下方程,该方程描述了 ppm 校正(Δppm)和数据点数量校正(Δpoints)之间的关系。size 是光谱中的点数,obs 是观测到的载波频率,sw 是扫描宽度(以 Hz 为单位)。这些值都可以从通用字典中获得。

下面的示例需要将光谱移动 -2.58 ppm。

代码
文本
[14]
point_shift = int((-2.5782 * size * obs) / sw)
data_ref = np.roll(phased_data, point_shift)
代码
文本
[15]
fig5 = plt.figure(figsize=(16,6))
ax6 = fig5.add_subplot(1,1,1)
ax6.plot(ppm, data_ref.real)
ax6.set_xlabel('Chemical Shift, ppm')
plt.xlim(8,0)
plt.xticks(np.arange(0,8,0.2))
plt.show()
2023-06-10T08:59:51.273610 image/svg+xml Matplotlib v3.7.1, https://matplotlib.org/
代码
文本

如果您想将绘图范围缩小到共振所在的位置,可以使用 plt.xlim(8,0) 函数。注意,首先是8,表示绘图范围从 8 ppm 0 ppm。使用 plt.xlim(8,0) 可以避免使用 plt.gca().invert_xaxis() 来翻转 x 轴。

代码
文本

11.6 积分

可以使用 scipy.integrate 模块中的积分函数或 NMRglue 的积分函数来对峰下面积进行积分。由于 NMRglue 中的积分函数支持 ppm 比例中的极限值,所以它可能是最方便的,如下所示。

使用下面的 integrate() 函数执行积分,其中 data 是作为 NumPy 数组的 NMR 数据,conv_obj 是 NMRglue 单位转换对象(参见第 11.5.1 节),而 limits 是积分极限的列表或数组。

ng.analysis.integration.integrate(data, conv_obj, limits)
代码
文本
[16]
uc = ng.pipe.make_uc(dic, data)
代码
文本
[17]
limits = np.array([[7.07,7.37], [1.10, 1.35], [2.50,2.75]])
代码
文本
[18]
fig6 = plt.figure(figsize=(16,6))
ax6 = fig6.add_subplot(1,1,1)
ax6.plot(ppm, data_ref.real)
ax6.set_xlabel('Chemical Shift, ppm')
plt.xlim(8,0)
plt.xticks(np.arange(0,8,0.2))
for lim in limits.flatten():
plt.axvline(lim, c='r')
2023-06-10T08:59:51.380614 image/svg+xml Matplotlib v3.7.1, https://matplotlib.org/
代码
文本

极限值以 ppm 为单位,因此观察上面的光谱并决定您想要放置积分极限的位置。上面的 NMR 光谱显示了选定的积分极限,这些极限以红色垂直线表示。

现在开始对我们的 NMR 光谱进行积分。

代码
文本
[19]
area = ng.analysis.integration.integrate(data_ref.real, uc, limits)
area
array([-0.00061348, -0.00035478, -0.00034138], dtype=float32)
代码
文本

这些值可能不是你预期的,但是如果我们将所有值除以最小值,我们就会得到峰下相对面积,就像你从大多数 NMR 处理软件中获得的那样。

代码
文本
[20]
area / np.min(area)
array([1.        , 0.5783051 , 0.55646706], dtype=float32)
代码
文本

上图是在中的乙基苯的 NMR光谱,其中有五个芳香质子,另外两个共振应该有三个和两个质子。如果我们进行一些数学计算,使积分总和为十个质子,并四舍五入到最接近的整数,我们得到 5:3:2。可能由于溶剂共振(,7.27 ppm)被包含在芳香质子的积分中,误差较小。

代码
文本

11.7 峰值拾取

从 NMR 光谱中提取的另一条常见信息是共振的化学位移。与积分类似,SciPy 包含了诸如 scipy.signal.argrelmax() 之类的函数,可以在光谱中找到峰值,但同样,NMRglue 包含了一个专门用于在 NMR 光谱中定位峰值的函数,如下所示。

ng.analysis.peakpick.pick(data, pthres=)

峰值拾取函数有许多可选参数,但是必须提供两个必要的信息:data 数组和一个正阈值(pthres),超过该阈值的任何峰值都将被识别。观察下面的光谱,所有峰值都在0.1(绿色虚线)以上,基线在0.1以下,因此这看起来是一个合理的阈值。

代码
文本
[21]
fig7 = plt.figure(figsize=(16,6))
ax7 = fig7.add_subplot(1,1,1)
ax7.plot(ppm, data_ref.real)
ax7.set_xlabel('Chemical Shift, ppm')
plt.xlim(8,0)
plt.xticks(np.arange(0,8,0.2))
plt.axhline(0.1, c='C2', ls='--');
2023-06-10T08:59:51.513602 image/svg+xml Matplotlib v3.7.1, https://matplotlib.org/
代码
文本
`ng.analysis.peakpick.pick()` 目前无法与 NumPy 1.24 及更高版本一起使用。如果您需要使用此功能,请将 NumPy 降级到 1.23 或更早版本。
代码
文本
[22]
peaks = ng.analysis.peakpick.pick(data_ref.real, pthres=0.1)
peaks
rec.array([(1077., 1, 34.1857841 , 27.63016701),
           (2299., 2, 31.36229494, 16.87085152),
           (2332., 3,  5.        ,  0.88378525),
           (6275., 4, 35.96975553, 25.60304451),
           (6355., 5, 32.1389443 , 17.82140732)],
          dtype=[('X_AXIS', '<f8'), ('cID', '<i8'), ('X_LW', '<f8'), ('VOL', '<f8')])
代码
文本

此函数的输出是一个元组数组,每个元组包含有关识别的峰值的信息。从这里我们已经可以看出有四个峰值被识别。每个元组包含峰值的索引、峰值编号、峰值的线宽以及每个峰值面积的估计。我们可以使用索引值来索引 ppm 数组以获取化学位移。

代码
文本
[23]
peak_loc = []
for x in peaks:
peak_loc.append(ppm[int(x[0])])
print(peak_loc)
[1.2320797763091693, 2.6300384454361936, 2.6677901934568085, 7.178552085738197, 7.2700714748790825]
代码
文本
[24]
fig8 = plt.figure(figsize=(16,6))
ax8 = fig8.add_subplot(1,1,1)
ax8.plot(ppm, data_ref.real)
ax8.set_xlabel('Chemical Shift, ppm')
plt.xlim(8,0)
plt.xticks(np.arange(0,8,0.2))
for p in peak_loc:
plt.axvline(p, c='C1', ls='--', alpha=1)
2023-06-10T08:59:51.626846 image/svg+xml Matplotlib v3.7.1, https://matplotlib.org/
代码
文本

我们可以绘制带有这些化学位移的 NMR 光谱,这些化学位移用下面的垂直虚线标记。看起来它在定位共振方面做得相当好!如果 NMRglue 未能正确识别峰值,可以调整 NMRglue文档 中描述的许多参数。

代码
文本

延伸阅读

  1. NMRglue 官网:https://www.nmrglue.com/(免费资源)

  2. NMRglue 文档页面:http://nmrglue.readthedocs.io/en/latest/tutorial.html(免费资源)

  3. J.J. Helmus, C.P. Jaroniec, Nmrglue: An open source Python package for the analysis of multidimensional NMR data, J. Biomol. NMR, 2013, 55, 355-367, http://dx.doi.org/10.1007/s10858-013-9718-x.(关于 nmrglue 的论文)

代码
文本

练习

代码
文本
  1. 使用 NMRglue 打开在 中使用 TMS 测量的乙醇(EtOH_1H_NMR.fid)的 1H NMR 光谱。使用 pipe 模块。

    a) 绘制结果光谱,并确保正确引用(如果尚未完成)。

    b) 积分甲基()与亚甲基(--)共振,并计算比值。

代码
文本
  1. 打开 2-乙基-1-己醇的 NMR 光谱,2-ethyl-1-hexanol_1H_NMR_CDCl3.fid2-ethyl-1-hexanol_13C_NMR_CDCl3.fid,它们是在 中使用 TMS 测量的。在 ppm 刻度上绘制它们。如果尚未完成,请确保正确调整相位并引用光谱。使用 pipe 模块。
代码
文本
中文
python
科学计算
中文python科学计算
已赞2
本文被以下合集收录
走进科学计算
ck
更新于 2024-07-22
14 篇17 人关注
推荐阅读
公开
走进科学计算_09_模拟
中文python科学计算
中文python科学计算
ck
发布于 2023-08-21
4 转存文件
公开
NRI:基于图神经网络的相互作用推断
Deep LearningTutorialnotebookMachine LearningNBHubNeural NetworksPyTorch
Deep LearningTutorialnotebookMachine LearningNBHubNeural NetworksPyTorch
yefengcan@dp.tech
发布于 2023-07-11
2 赞3 转存文件9 评论