fMRI学习笔记


fMRI学习资料来源链接


T1、T2、T2*

受人为强磁场干预的氢原子中的唯一质子的自旋方向发生改变,并且自旋方向一样,其产生的净磁化强度与人为强磁场方向一致,且每个原子核旋转频率一致(拉莫频率?)。

在强磁场(假设纵向)中加入一个射频脉冲(假设横向),产生一个横向磁场,原子核被迫移到同一个相位,磁化强度矢量方向朝横向平面倾斜。脉冲消失的间隔中原子核逐渐恢复,该过程被称为‘弛豫’。分纵向(强磁场方向)、横向(射频脉冲方向)两种弛豫。

  • T1时间常数为纵向弛豫中,原子核纵向磁化强度增长到原来(无脉冲时)63%所需的时间
  • T2时间常数指横向弛豫中,原子核横向磁化强度从100%衰减到37%所需的时间
  • T2*衰减的比T2快,所以如果不加其他处理,我们得到的数据是T2*时间

SNR、CNR

SNR:信号的平均值与噪音方差的比值

CNR:两个信号差的平均值与噪音方差的比值

  • 空间上看:SNR应该是信噪比的结果;CNR是分辨两个不同区域是否是相似组织的依据
  • 时间上看:目标都是一块体素,SNR还是信噪比;CNR代表的是体素对相应的实验操作或者心理状态的响应程度

血液动力响应函数(HRF,Hemodynamic Response Function)

  • 启动下降:神经元兴奋消耗氧气,脱氧血红蛋白短时间内增加,磁场趋于不均匀,信号减弱

  • 顶峰:人体负反馈机制输送来大量富氧血红蛋白,信号增强,甚至调节过度持续走高,在神经元兴奋后大约4到6秒达到顶峰。

  • 最后下降:在到达顶峰后,BOLD信号会大幅度的下降,甚至下降到基线以下(Baseline)。过度下降的原因是血流流出量逐渐减少,血流含量升高(这里不太明白)

HRF曲线

MRI信号如何得到

二维傅里叶原理


疑惑

  • MR扫描仪器测量的信号是氢原子的含量,和血红蛋白是什么样的联系?

依据:MR测量信号即BOLD信号,对应HRF函数

  • 如果就说MR扫描仪器测量的信号是血红蛋白的含量,会由于脱氧、富氧血红蛋白的顺磁性和反磁性使得T2信号有差别而两种血红蛋白的相对含量能分别测出么?
  • 如果不是,那BOLD相对比值是如何求得的?

依据:MR测量一中间步骤即,不断采集获取K-space图,再作IFT得到大脑亮度图像,那么可思考K-space中的每一个点的信号是怎样采集的,是什么形式的(其实是二维傅里叶公式的表示形式)。现知利用磁矩变化推导而来,没时间仔细研究推导过程。

  • 如果MRI的待处理信号表示为一个图像离散数据的二维傅里叶,那么其中的kx、ky的值具体是如何得到的?作为分析数据,我们需要从哪一步开始?直接可以得到T1、T2*之类的图像么?

标定记录 2nd

2020.4.27


陀螺仪问题解决


先做线(杜邦线),用2s锂电池单独给陀螺仪供电后问题解决

  • 每次转一圈的数据比较稳定,每转1080°陀螺仪若干数据之间的差不超过20

再次标定


  • 由于陀螺仪数据稳定,需要再次标定,标定后角度经验证比较准确:

    • 每转三圈读取的角度值在1080°±3°之间浮动
  • 角度标准不同后,还需要整体重新标定,结果图示如下:

    • 验证正y轴

      • y方向行进约 1300 mm,x方向偏移量约为 0.7 mm

    • 验证假x轴

      • x方向行进约 1400 mm,y方向偏移量约为 10 mm

    • 验证正y轴转为假x轴后沿正y轴走

      • 这里最终x方向偏移量约 4 mm

  • 根据上图走假x轴的x、y位移数据 acrtan(10.04 / 1373)= 0.4189653°

​ 又推车转角为 89.5257507°

89.5257507° + 0.4189653° = 89.944716° ≈ 90°

​ 在这里再次验证了之前的结论

重复性误差


  • 在这里我推车测试了8条不同的路径(左下角到右上角),并且把每条路径最终的x、y坐标都列了出来,横线代表8个值的平均值,由于条件有限无法知道精确的实际值,所以把平均值当作实际值。

  • 结果发现,在推车直线距离大概 1.5 m的情况下,小车在x、y方向都可能存在5mm内的偏移

旋转误差


  • 这里每次旋转 3 - 4 圈后回到起始点,来观察小车的定位误差情况

  • 顺逆时针都测试了,发现顺时针坐标整体偏移了 5 mm,然而逆时针坐标整体偏移了约 20 mm

为何会有偏移?


  1. 由上图可以发现转三圈的角度值都是1080°左右,说明陀螺仪提供的角度数据没有问题

  2. 旋转算法matlab程序实现是否有问题?

    • 我把程序中 alpha 和 L 的值都设为 0,再次转3圈看结果:

      结论是与旋转算法无关测试结果照样有十几到二十多毫米的偏移

(这里发现路径图中由于是随动中心,会绕中心转圈,是对的,之前是车的中心,所以路径图比较奇怪)

  1. 直行算法matlab程序实现是否有问题?**(由于在家标定时旋转角度方向变了,我改了一部分matlab代码,所以怀疑是不是这个有问题)

    • 我把之前 Adams 的仿真理想数据带入现在的matlab程序,并且在程序里再次分别验证走正y轴,假x轴:正y轴的x方向偏移 0 mm;正x轴的y方向偏移 1.2 mm 比较理想,证明程序无误
  2. 综上,那就意味之标定的系数(8个)还是不准,那就再小心的标定一次

再再次标定


  • 这次标定不一样,电脑不用放在车上了,标定也用蓝牙传数据(这周第一次整体标定电脑还是放在车上的);并且,走一个方向多次重复取平均值。

  • 这一次标定效果如下:

    • 验证正y轴

      • y方向行进约 1400 mm,x方向偏移量约为 0.25 mm

    • 验证假x轴:(这次两边测得正好是90°,没办法每次都测的不一样,这个车有一边有问题)

      • x方向行进约 1400 mm,y方向偏移量约为 1.293 mm

    • 验证正y轴转为假x轴后沿正y轴走

      • 这里最终x方向偏移量约 4 mm,和这周第一次标定的效果

再次看看旋转的误差大小

  • 旋转三圈回到起始点,依然会有 10 - 20 mm的坐标偏移

结论


  考虑到标定时的车身的振动,旋转时车身的振动,自身操作使随动轮前后小幅度摇摆造成回程差等等的条件受到限制。

  这一套系统的精度目前看来就是上述的研究结果。

基于matlab的蓝牙串口通信

一、前言

  用蓝牙做主控串口和电脑通信的想法呢,是因为实践标定的时候需要持续的很稳的推动小车,而且要把jlink将电脑和主控连起来debug看数据又得给主控供5V电(当时忘记充电宝可以供5v电了,一时英明被摧毁),所以无线就没多想了。想过做很长的线、把电脑放在电竞椅上跟着小推车推着走,都不太靠谱,所以在标定的时候还是把电脑架在了小推车上

  标定进度完成了大半,现在得点空,还是想把这个蓝牙无线通信做起来,因为我在想这个方法是不是可以把WLan的网卡看参数替换掉,个人感觉那种Labview结合Matlab🐂是🐂,但是有点太麻烦了,路由器架在车上得自带一个充电宝,主控上的网线插槽老是松,还要先生成调试组文件带入主控更新…我电脑现在也是再也连不上了,所以这个我觉得某种程度上有一些必要


二、尝试pybluez模块

  之前竞培营的时候买过蓝牙,所以家里留了一个(也是为什么想蓝牙通信)。主控串口连接蓝牙再和电脑通信,问题不在串口,而在电脑是如何接收到的数据?什么形式的数据?怎么处理这类数据成为我想要看到的数据甚至生成动态曲线?由于觉得python无所不能,第一时间想到的就是它,结果在下载pybluez模块时出现问题,电脑提示我没有Microsoft Visual C++ 2014的组件工具,这个我百度了也是很多py模块下载时出现的问题

  有一个解决方法就是在一个国外大学提供实时更新的模块下载网站上先把需要的模块的类似安装包(whl类型文件)下载到本地,之后pip install 安装包绝对地址最后pip install 模块名称,不过这个方法我在尝试的时候仍然出现错误,个人认为是这个pybluez模块版本较老,有一些bug也比较正常

  这条路走不通,以后必须用到的时候再试试把。之后在想wifi也能无线传输数据,而且速率更高,pywifi模块的安装没有问题。不过我手上只有蓝牙模块啊,当务之急是选择什么方法在电脑上得到蓝牙传输的数据


三、Matlab成为选择

  此时,在寻找与蓝牙通信相关的过程中,看到了Matlab的字眼,对啊,之前怎么没想到它呢。说干就干,百度关键词Matlab蓝牙通信,果然就有,不过不多,好在matlab的使用者多,而且内置的help搜索向导非常方便,即使不太了解有的也有官方示例。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
%Examples
%Find available Bluetooth devices.

instrhwinfo('Bluetooth');
instrhwinfo('Bluetooth', RemoteName);
%Construct a Bluetooth object called b using channel 3 of a Lego Mindstorm robot with RemoteName of NXT.

b = Bluetooth('NXT', 3);
%Connect to the remote device.

fopen(b)
%Send a message to the remote device using the fwrite function.

fwrite(b, uint8([2,0,1,155]));
%Read data from the remote device using the fread function.

name = fread(b,35);
%Disconnect the Bluetooth device.

fclose(b);
%Clean up by deleting and clearing the object.

fclose(b);
clear('b');
  • 结合官方提供的例子,快速入手蓝牙通信,关键在于定义蓝牙的特定变量b = Bluetooth('NXT', 3);,以及fopen(b)来开启蓝牙通信。重点就在于数据的规范、格式。手册上介绍的函数如下:
Matlab蓝牙相关函数

You can read and write both text data (ASCII based) and binary data. For text data, use the fscanf and fprintf functions. For binary data, use the fread and fwrite functions.
你可以借助ASCII码或者二进制数据进行读写操作。对于txt数据使用fscanffprintf函数,对于二进制数据使用freadfwrite函数

  • 以下是目前我脚本中的蓝牙初始化操作
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
%% 配置蓝牙操作

instrhwinfo('Bluetooth');
instrhwinfo('Bluetooth','col_test');
col_test = Bluetooth('col_test',1);

% col_test.TimerPeriod = 0.1;
% col_test.TimerFcn = {@plotcallback,p};
col_test.Timeout = 10;


%% 开启蓝牙数据监控,同时开启定时器
% fopen(col_test);
try
fopen(col_test);
catch err
disp('col_test蓝牙通道打开失败');
flag = 0;
end

if err_flag
disp('col_test蓝牙通道成功打开');
fwrite(col_test,Command_data);
start(t);
end

通信接口的回调函数

  • 在搜索帮助中有对串口接收数据的中断回调函数,终端的类型我所了解的有
    • 设定接受字节数触发
    • 设定截至字符触发
    • 定时间间隔触发
  • 不过目前没尝试出来,而且我觉得也没有那个必要所以暂时搁置了研究

四、如何有效的接受主控数据

  如果需要监控主控数据,那么每一次就要同时接收数十个浮点数类型的数据。

  1. 接受的方式不可能是直接不停循环接收数据,那么对于高速率传输数据的串口,错误必然存在而且经验证发现错误率不低,所以需要加密再解码确保数据准确。
  2. 其次,由于测试发现fread函数接受蓝牙数据是以字节(8bit)为单位,多个字节数据如何正确转换为float类型我之前没接触过。
  3. 最后蓝牙的速率不出众,那么我也需要测试一下他的速度究竟能有多快?

4.1 报文形式发送与接收

  • 主控上的串口dma接收发送不必多说,使用串口六,定义两个结构体Bluez_TXBluez_RX包含同样的两帧头两帧尾,那么在Matlab脚本中就需要相似的对于报文的解包,这一部分不难,那么我认为matlab接收数据的优点在于in/outputbuf数据一边进另一边出,在读取过程中的操作十分方便。
  • 还有一点就是我的脚本中做到,matlab向主控发送一帧数据,命令主控开始发送数据给蓝牙从而开始数据监控。也有停止命令,非常方便。操作就是在主控中的dma发送函数判断一个标志位(发送函数写在一个任务中)

4.2 多个单字节与浮点数的转换

  • 已知,主控中的dma发送是将发送结构体变量bluez_tx的头指针作为地址,那么这种方式下浮点数就是按一般的占据4字节进行发送。在Matlab中可以接收到4个字节与该浮点数对应。
1
2
3
raw_data1 = [byte1 byte2 byte3 byte4];
temp = uint8(raw_data1);
stRobot_x(count) = typecast(temp,'single');
  • 通过上述方法进行通信之后的变量类型转换成功

4.3 速率监测

  • 一开始我都是用串口调试助手来研究的,没有用上主控,中间尝试过一次发现主控确实在发送数据,但是Matlab端就是感觉没接收到,很是奇怪。那么我用调试助手时发现,一个包里有单个数据或是多个数据并不影响接收帧率增大串口波特率略微提高解包帧率,但是在发送帧率到达1000fps时,数据的接收帧率只能到650fps左右。
  • 我发现,并不是Matlab没接收到主控的数据,而是没有成功解包,这个问题也一直困扰我,发送结构体变量中的总字节数理论上和实际发的不一样,在帧头和数据之间有两位0x00并不知道从何而来,这样总字节数多了2,dma发送字节数加了2,且在解包过程中多两个字节消耗掉就行了
  • 结果在测试主控与Matlab通信时又发现问题,由于设置的波特率为921600,虽然配置没错但是串口发送的数完全不对,向下减小一些至460800就正常了,看来这种情况波特率有了限制。并且波特率460800时帧数据肉眼可见的概率会发生传输数据错误,说明串口确实不太稳定
  • 最后我一共让主控一帧传输20个数据,能够正常接收,100fps的发送帧率对应100fps的解包帧率。再次说明数据量不影响接受帧率,并且最大帧率在600fps(发送帧率1000fps),不过这种情况在接受10s时间左右程序不再接受蓝牙数据,未找到原因。
  • 另外,如果要在接收过程中画出实时曲线,势必影响接收帧率,我尝试在发送帧率100fps的情况下,每解完一次包绘制两个变量的曲线,结果接受帧率掉到70fps。因此,不画实时图像或者仅绘制1-2张是允许的,不然影响过大。

4.3.1 帧率计算timer

  • Matlab中也有定时器,我通过定时器1s定时来计算每秒钟的接收帧率,特别提醒往往回调函数的函数名的定义变量规范很重要。具体可以查阅帮助,下面是代码部分:
1
2
3
4
5
6
7
t = timer('StartDelay',1,'TimerFcn',@t_TimerFcn,'Period',1,'ExecutionMode','fixedRate');
%StartDelay:开始计时后的延时;TimerFcn:定时中断函数;Period:定时时间周期;ExecutionMode:优先级

start(t)

stop(t)
Delete(t)

4.3.2 打印变量disp()

1
2
string = sprintf('Have received stRobot_x:%d',stRobot_x(count));
disp(string)
  • 类似于format格式化输出,打印在命令行区
Your browser is out-of-date!

Update your browser to view this website correctly. Update my browser now

×