MATLAB代码纠错与优化实践

table {
border-collapse: collapse;
width: 100%;
margin-bottom: 1rem;
}
th, td {
border: 1px solid #ddd;
padding: 8px;
text-align: left;
}
th {
background-color: #f2f2f2;
}
tr:nth-child(even) {
background-color: #f9f9f9;
}
pre {
background-color: #f8f8f8;
padding: 15px;
border-radius: 4px;
overflow-x: auto;
}

79、以下两段MATLAB代码段落中,每段至少有一个错误(a部分一个,b部分一个)。找出并纠正这两个错误。a. fftEEG = fft(csd(7,:,10),n_conv); fftWave = fft(wavelets(3,:),n_conv); as = ifft(mean(fftEEG.

fftWave),n_conv); b. sine_wave = exp(2

1i

pi

frequency(10).

time); gaus_win = exp(time.^2./(2

(6/(2

pi

frex(10)))^2)); wavelet = sine_wave .* gaus_win;

以下是将给定文本内容调整为

Markdown 格式

的结果:


a部分错误在于

mean(fftEEG.*fftWave)


fftEEG


fftWave

是向量,使用

mean

会将向量元素求平均,可能不是预期操作,应直接相乘后进行逆傅里叶变换。


修正后代码:


fftEEG = fft(csd(7,:,10),n_conv);
fftWave = fft(wavelets(3,:),n_conv);
as = ifft(fftEEG.*fftWave,n_conv);

b部分错误在于高斯窗函数

gaus_win

,指数部分应该是负的,以形成高斯形状。


修正后代码:


sine_wave = exp(2*1i*pi*frequency(10).*time);
gaus_win = exp(-time.^2./(2*(6/(2*pi*frex(10)))^2));
wavelet = sine_wave .* gaus_win;

80、在以下两组代码中,每组有一行代码正确,一行代码有错误。找出并修正错误。代码如下:hz = linspace(0,nyquist,floor(N/2)+1); hz = linspace(0,nyquist,floor(N/2)-1); n_conv = size(csd,3) + length(wavelet_time) – 1; n_conv = length(size(csd,3))+length(wavelet_time)–1;

第一组中,

hz = linspace(0,nyquist,floor(N/2)+1);

正确,

hz = linspace(0,nyquist,floor(N/2)-1);

错误,

应改为

hz = linspace(0,nyquist,floor(N/2)+1);

第二组中,

n_conv = size(csd,3) + length(wavelet_time) – 1;

正确,

n_conv = length(size(csd,3)) + length(wavelet_time) – 1;

错误,

应改为

n_conv = size(csd,3) + length(wavelet_time) - 1;

(注意原代码中减号为中文符号,应改为英文符号)。

81、下面的代码是正确的,但可能无法产生预期的结果。问题是什么,如何修复?代码为:x = 0:100; gaus = exp(-(x.^2)/100);

问题在于生成的高斯函数可能未按预期归一化,且绘图范围可能无法清晰展示高斯函数特征。可进行归一化处理,同时调整绘图范围。修复代码如下:


x = 0:100;
gaus = exp(-(x.^2)/100);
gaus = gaus / max(gaus);
plot(x, gaus);

归一化操作使高斯函数最大值为1,绘图能直观展示其特征。

82、在这个练习中,你将探究 Morlet 小波的周期数参数控制时间和频率精度权衡的原因。生成五个频率为 10 Hz 的小波,将周期数从 2 线性递增到 15。使用 5×2 的子图布局,在左图中展示对正弦波进行衰减的时域高斯函数,在右图中展示小波功率的频域表示。为每个子图添加标题以表明周期数。这个图能帮助你理解时频精度的权衡吗?(如果不能,请绘制一个更好的图!)

要完成此练习,可按以下步骤操作:

生成五个频率为 10 Hz 的小波,周期数从 2 线性递增到 15;

使用 5×2 的子图布局,左图展示时域高斯函数,右图展示小波功率的频域表示;

为每个子图添加标题表明周期数;

观察图形判断是否能理解时频精度的权衡,若不能则绘制更好的图。

由于没有具体代码实现,无法给出代码示例,但思路是明确的。

83、构建一系列有限脉冲响应(FIR)滤波器(带通:8 – 12 Hz),滤波器阶数从8 Hz的1个周期变化到15个周期,保持其他参数不变。展示滤波器内核在时域的图像(可以给每个内核的y轴添加一个小偏移以提高可见性),以及它们的功率谱在一个按频率 – 阶数排列的图像中(需要进行零填充以使功率谱具有可比性)。滤波器的频率特性如何随阶数变化?接下来,创建一个以10 Hz为中心的实值Morlet小波。将每个滤波器应用于该小波,并测量每个滤波结果的经验半高宽(FWHM)。(提示:在abs(hilbert(filtsig))的结果上测量FWHM)。绘制FWHM随滤波器阶数变化的图像。根据这些结果,在什么阶数点上你会基于不同阶数对结果得出不同的结论?

本题需按以下步骤完成:


构建滤波器

:构建一系列带通为8 – 12 Hz的FIR滤波器,阶数从8 Hz的1个周期到15个周期变化,保持其他参数不变。


绘制图像



– 绘制滤波器内核在时域的图像,可添加y轴小偏移;

– 绘制功率谱在频率 – 阶数图像中,进行零填充。

观察滤波器频率特性随阶数的变化规律。


创建小波

:创建以10 Hz为中心的实值Morlet小波。


应用滤波器并测量FWHM

:将每个滤波器应用于小波,在

abs(hilbert(filtsig))

结果上测量FWHM。


绘制FWHM图像

:绘制FWHM随滤波器阶数变化的图像。


得出结论

:根据上述结果,判断在什么阶数点会基于不同阶数对结果得出不同结论。但具体的频率特性变化规律、FWHM数值及不同结论的阶数点需通过实际编程和计算得出。

84、在时域中生成一个sinc函数。使用fft函数并绘制其功率谱。可能绘制结果为空。在命令窗口中检查傅里叶系数,分析出现这种情况的原因。查看sinc函数的公式,思考在x = 0时会发生什么。添加一些代码以确保整个信号包含有限值(可利用isfinite函数),然后检查频率分布。

可按以下步骤完成操作:

在时域生成sinc函数;

使用

fft

函数计算其傅里叶变换并绘制功率谱;

若绘制为空,在命令窗口检查傅里叶系数;

查看sinc函数公式,思考

x = 0

时情况;

使用

isfinite

函数添加代码确保信号含有限值;

检查频率分布。

85、创建一个线性啁啾信号并设计一个窄带通滤波器。从经过滤波的啁啾信号的希尔伯特变换中提取时变功率。同时提取滤波器核的功率谱。在滤波器阶数因子从 1 到 8 的范围内进行循环,重复上述过程。然后将所有功率时程曲线绘制在同一张图上,并在另一张单独的图上绘制所有滤波器核的功率谱。

可按照以下步骤实现该需求:

创建线性啁啾信号。

设计窄带通滤波器。

对啁啾信号进行滤波,并对滤波后的信号进行希尔伯特变换,提取时变功率。

提取滤波器核的功率谱。

设定循环,让滤波器阶数因子从 1 到 8 变化,重复步骤 1 – 4。

将所有功率时程曲线绘制在同一张图上。

在另一张单独的图上绘制所有滤波器核的功率谱。

86、已知线性调频功率时间序列呈高斯状。估算每个滤波器阶数因子对应的功率时间序列的半高宽(FWHM)。绘制半高宽随阶数变化的图。根据估算结果和所绘制的图,你对滤波器阶数参数有什么了解?你是否有办法来验证滤波器参数的合理性?

关于滤波器阶数参数,绘制

半高宽随阶数变化的图

后,可了解到滤波器阶数对滤波效果的影响,如:

不同阶数下滤波器

频率特性的变化

对信号处理后结果(如

半高宽

)的影响

验证滤波器参数合理性的方法有:


对比不同阶数下的滤波结果

,观察是否符合预期的频率特性


与理论计算或已知标准结果进行对比


检查滤波后的信号是否保留了期望的特征

且未引入不合理的噪声或失真

87、变量 step3 和 rmsx 之间有区别吗?(rms 是一个计算均方根的函数,所以这里用 rmsx 作为变量名)

有区别。二者虽都与均方根计算相关,但计算方式不同。step3 是分三步计算,rmsx 是一步计算。

88、变量EEG.data是一个三维矩阵(通道×时间×试验)。你的朋友弗朗西斯想通过对时间(即第二维)求平均来计算均方根(RMS)。以下代码行为什么是错误的,如何修正?你对弗朗西斯在类似情况下避免混淆有什么建议?代码为:rmsf = sqrt(mean(squeeze(EEG.data(30,:,:)).^2,2));

代码错误原因在于,弗朗西斯想对时间(第二维)求平均来计算RMS,但代码里

mean

函数的第二个参数设为

2

,这意味着是对第二个维度(时间)之外的维度求平均,与需求不符。

修正方法是把

mean

函数的第二个参数改为

1

,正确代码为:


rmsf = sqrt(mean(squeeze(EEG.data(30,:,:)).^2, 1));

建议弗朗西斯在处理多维矩阵时,仔细明确每个维度代表的含义,写代码前可以先在纸上列出操作步骤和对应的维度,避免维度使用错误。同时,编写代码后进行简单测试,验证结果是否符合预期。

89、Frances 回来了。她只测量一个电极和一次试验,让事情变简单了,但在 MATLAB 编程上仍有问题。她用代码“rmsf = sqrt(mean(data));”计算均方根(RMS),结果是复数。她的编程错误是什么,为什么会产生复数形式的 RMS?

编程错误在于代码未对数据先平方再求平均,而是直接求平均后开方。若数据中存在负数,直接求平均后的值可能为负,对负数开方就会产生复数形式的 RMS。

正确计算 RMS 应先对数据平方,再求平均,最后开方,即


rmsf = sqrt(mean(data.^2));

90、在双 sinc 函数中,找出所有局部最大值,然后从列表中移除振幅大于 1 或小于 0.1 的峰值。接着移除 x = 40 之后的峰值。绘制图形,以确认你的筛选器是否有效。

可按以下步骤操作:

先找出双

sinc

函数所有局部最大值,使用代码

matlab
peeks = find(diff(sign(diff(signal))) < 0) + 1

移除振幅大于 1 或小于 0.1 的峰值,可通过判断

signal(peeks)

的值进行筛选

移除

x = 40

之后的峰值,可根据

x(peeks)

的值筛选

最后绘制图形,以确认筛选器是否有效

91、变量hello是一个5×1的向量。以下代码行输出的大小分别是多少?先思考答案,然后在MATLAB中验证。mean(hello) mean(hello,1) mean(hello,2)

下面是给定的【文本内容】:

mean(hello)


mean(hello,1)

的输出大小为 1×1,因为它们计算的是向量的均值,结果是一个标量;

mean(hello,2)

的输出大小为 5×1,因为它按列计算均值,对于 5×1 的向量,每一行有一个均值,共 5 个,形成 5×1 的向量。

92、计算去趋势波动分析(DFA)或去趋势移动平均法(DMA)的初始步骤是对信号进行积分以创建无界形式。如何从无界形式回到原始的有界形式?(提示:积分的逆运算是什么,如何在MATLAB中实现?)

积分的逆运算是微分。在 MATLAB 中,可以使用

diff

函数进行数值微分。例如,若有一个向量

y

表示无界形式的信号,

dy = diff(y)

可得到其微分结果,以此尝试从无界形式回到有界形式。

但需注意

diff

函数会使向量长度减 1,可能需要根据具体情况处理边界问题。

93、以下两行代码有什么区别?是否存在区别?何时会有区别?dt = mean(diff(timevec)) / 1000; dt = mean(timevec(2)-timevec(1)) / 1000;


第一行代码中,`diff(timevec)` 计算 `timevec` 相邻元素的差值,`mean(diff(timevec))` 求这些差值的平均值,最终 `dt` 是这个平均值除以 1000。  

第二行代码中,`timevec(2)-timevec(1)` 只是 `timevec` 第二个元素与第一个元素的差值,`mean` 对这个单一差值求平均(结果还是该差值),最终 `dt` 是这个差值除以 1000。  

当 `timevec` 中相邻元素差值都相等时,两行代码结果相同;当 `timevec` 中相邻元素差值不相等时,两行代码结果不同。

94、这里有一种计算尖峰 – 场相干性的新方法:将局部场电位(LFP)相角时间序列离散成 N 个区间(例如 10 个区间),并计算每个区间的平均尖峰数。然后将结果绘制成以尖峰计数为 y 轴、LFP 相位为 x 轴的条形图。对几个频率进行此操作。请简要概括该方法的步骤。

该方法步骤为:

将 LFP 相角时间序列离散成若干区间;

计算每个区间的平均尖峰数;

绘制以尖峰计数为 y 轴、 LFP 相位为 x 轴的条形图;

对几个频率重复上述操作。

95、在计算尖峰节律性时,不使用代码行 spRhy = spRhy([end – win+1:end 1:win+1]),而是使用函数 fftshift 来获得相同的结果,应该怎么做?

可以使用如下代码替代原代码以获得相同结果:


spRhy = fftshift(spRhy);

fftshift

函数会将零频分量移到频谱中心,对于周期性数据,能实现与原代码类似的索引重排效果。

96、路易斯试图细致地检查叠加在同一图上的单试验数据,但MATLAB渲染图形花费了很长时间,部分原因是他使用的是一台旧笔记本电脑(2014年的)。他向你寻求帮助。根据他下面的代码,你至少可以给他哪两条不同的建议?(变量alldata包含60000次试验和1200个时间点)for i=1:size(alldata,1) figure(1), hold on plot(i+alldata(i,:)) end

建议一:不要逐行运行代码,可考虑批量处理数据后再绘图。

建议二:减少绘图次数,比如对数据进行抽样,减少参与绘图的试验数量。

97、有代码行 tempsps(tempsps < – win | tempsps>win) = []; ,不使用“或”运算符重写这一行。(提示:如何使负值和正值相等?)

可以将代码改写为


tempsps(abs(tempsps) > win) = [];

利用绝对值函数

abs()

去掉了“或”运算符。

98、以下代码行以错误的方式减去了尖峰时间序列的均值。你如何判断呢?(提示:合理性检查!)spikes = bsxfun(@minus,spikes,mean(spikes,1));

可以通过合理性检查判断。一般来说,减去均值是为了让数据中心化,即数据围绕零值分布。若减去均值的方式错误,可能导致数据没有正确中心化。

在代码中,

mean(spikes,1)

计算的是每列的均值。若尖峰时间序列应按行计算均值,这样就会出错。

可通过检查减去均值后的数据分布是否合理,比如数据是否大致围绕零值波动,来判断代码是否正确。

99、调整 k – 均值聚类以提取并绘制三个聚类。你是否认同这些结果?这对于 k – 均值聚类和预先知晓聚类数量有什么启示?

可以使用MATLAB的

kmeans

函数进行调整,示例代码如下:


[gidx, cents, sumdist, distances] = kmeans(d, 3);

其中

d

是 75 行 2 列的矩阵,包含 75 个数据点的 x 和 y 值,输入

3

指示提取三个聚类。

之后可通过绘图代码直观展示聚类结果。是否认同结果需结合具体数据情况判断。若结果符合数据的实际分布特征,则可认同。

这表明 k-均值聚类结果依赖于预先设定的聚类数量,若能事先知晓合适的聚类数量,聚类结果会更可靠;若缺乏先验知识,可能导致聚类结果不稳定或不合理。

100、现在你有两个尖峰簇,测试这些单元是否相互作用。识别簇2中在簇1中的尖峰前3毫秒或后3毫秒产生尖峰的动作电位。绘制它们的波形形状。为作比较,同时绘制随机选择的尖峰的平均波形形状。

要完成该任务,需按照以下步骤进行:


筛选符合条件的动作电位


从数据中找出

簇2

中在

簇1

尖峰前后

3毫秒

内产生尖峰的动作电位。


绘制波形


对筛选出的动作电位绘制其波形图。


随机选择与计算平均波形


随机选择部分尖峰,计算其平均波形,并进行绘制。

可使用的工具包括:



Python

:NumPy、Matplotlib 库



MATLAB

101、已知协方差矩阵(设为变量spikecov)是从数据矩阵spikes计算得到,计算方式为spikecov = spikes’ * spikes ,协方差矩阵spikecov的秩为11,其维度是12×12。那么spikes的秩是多少?基于这个结果,你能推测出关于矩阵A的秩和矩阵ATA的秩之间关系的线性代数法则吗?

由于协方差矩阵

spikecov

是由

spikes

矩阵通过

spikecov=spikes′⋅spikesspikecov=spikes′⋅spikes

计算得到,即 $ A^T A $ 的形式。

已知

spikecov

的秩为 11,维度为 $ 12 imes 12 $,根据线性代数中

rank(ATA)=rank(A)rank(ATA)=rank(A)

的法则,可推测

spikes

矩阵的秩为 11。


线性代数法则为



矩阵 $ A $ 的秩等于矩阵 $ A^T A $ 的秩,即

rank(ATA)=rank(A)rank(ATA)=rank(A)

102、编写额外的查看代码,以 3×4 的子图矩阵显示结构 MRI 扫描在第一个和最后一个切片之间的 12 个线性间隔切片。生成对应三个维度的三幅图。

以下是实现该功能的 MATLAB 代码示例:


% 读取结构 MRI 数据
strMRI = readnifti('MNI152_T1_1mm.nii');

% 获取每个维度的大小
[sizeX, sizeY, sizeZ] = size(strMRI);

% 生成 12 个线性间隔的切片索引
sliceIndices = linspace(1, sizeX, 12);

% 第一个维度的图
figure;
for i = 1:12
    sliceIndex = round(sliceIndices(i));
    subplot(3, 4, i);
    imagesc(squeeze(strMRI(sliceIndex, :, :))');
    axis image;
    axis xy;
    colormap gray;
end

% 生成 12 个线性间隔的切片索引
sliceIndices = linspace(1, sizeY, 12);

% 第二个维度的图
figure;
for i = 1:12
    sliceIndex = round(sliceIndices(i));
    subplot(3, 4, i);
    imagesc(squeeze(strMRI(:, sliceIndex, :))');
    axis image;
    axis xy;
    colormap gray;
end

% 生成 12 个线性间隔的切片索引
sliceIndices = linspace(1, sizeZ, 12);

% 第三个维度的图
figure;
for i = 1:12
    sliceIndex = round(sliceIndices(i));
    subplot(3, 4, i);
    imagesc(squeeze(strMRI(:, :, sliceIndex))');
    axis image;
    axis xy;
    colormap gray;
end

这段代码首先读取结构 MRI 数据,然后分别针对三个维度,生成 12 个线性间隔的切片索引,在每个维度上创建一个 3×4 的子图矩阵来显示这些切片。

103、结构扫描具有高分辨率。尝试通过创建包含跳过体素的新图像来对图像进行下采样(例如,每隔一个体素取一个,或每隔两个体素取一个,以此类推)。计算每个下采样版本的大小相对于原始版本大小的百分比。在不同下采样图像的z平面上绘制最接近50%的切片,并在图像标题中注明尺寸减小的比例。

本题是一个图像处理任务,可按以下步骤完成:

对图像进行下采样,创建包含跳过体素的新图像;

计算每个下采样版本的大小相对于原始版本大小的百分比;

在不同下采样图像的 z 平面上找到最接近 50% 的切片;

绘制这些切片,并在图像标题中注明尺寸减小的比例。

104、利用功能磁共振成像(fMRI)数据,计算每个体素随时间变化的信号强度值的均值和标准差。然后在一个图中展示这两个图的一些切片。若想获得额外加分,不使用均值(mean)和标准差(std)函数(或方差 var 函数,用它就太简单了)完成此练习。

可按以下步骤操作:

读取 fMRI 数据;

不使用

mean


std

函数计算每个体素信号强度值随时间的均值和标准差;

从均值和标准差图中选取一些切片;

将这些切片展示在一个图中。

105、已知阈值图颜色与代码所写相反(黑色为1,白色为0),通过修改代码行contourf(threshmap)重现此反转图(不要简单地重新定义颜色轴)。有一种添加一个字符的方法和一种添加两个字符的方法,请问分别是什么?

添加一个字符的方法可能是在

threshmap

前加一个波浪号

"~"

,即

contourf(~threshmap)

;添加两个字符的方法可能是在

threshmap

前加

"1 - "

,即

contourf(1 - threshmap)

106、下面这行代码不会产生 MATLAB 错误,但可能无法产生预期结果。请说明错误是什么、有什么影响以及如何修复。(dbmap 是一个二维矩阵,代表经过预刺激基线分贝标准化后的时频功率)imthresh = abs(dbmap>3);

错误:

dbmap>3

会生成一个逻辑矩阵,其中大于 3 的元素为

true

(即 1),小于等于 3 的元素为

false

(即 0),对逻辑矩阵取绝对值没有实际意义,无法得到预期结果。

影响:不能对

dbmap

中大于 3 的元素进行正确处理,只是简单得到一个逻辑矩阵的绝对值,值仍为 0 和 1。

修复方法:若要获取

dbmap

中大于 3 的元素的绝对值,可使用


imthresh = abs(dbmap) .* (dbmap>3);

107、创建一个正弦波,使用bwconncomp和bwlabel来确定正弦波中值大于0.5的位置。然后在正弦波中所有值大于0.5的时间点上绘制星号。最后,调整代码,使星号绘制在y = 0直线上。

代码实现正弦波处理

本题要求编写代码完成一系列操作。首先创建正弦波,然后用

bwconncomp


bwlabel

函数确定正弦波中值大于0.5的位置,接着在这些位置的正弦波上绘制星号,最后将星号绘制在y = 0直线上。可按以下步骤编写代码:

创建正弦波

找出正弦波中值大于0.5的位置

使用

bwconncomp


bwlabel

函数

在正弦波上绘制星号

调整代码将星号绘制在y = 0直线上

示例代码


% 创建正弦波
t = 0:0.01:10;
y = sin(t);

% 找出正弦波中值大于0.5的位置
idx = y > 0.5;

% 使用bwconncomp和bwlabel函数
CC = bwconncomp(idx);
labels = bwlabel(idx);

% 在正弦波上绘制星号
figure;
plot(t, y);
hold on;
plot(t(idx), y(idx), '*');
hold off;

% 调整代码将星号绘制在y = 0直线上
figure;
plot(t, y);
hold on;
plot(t(idx), zeros(size(t(idx))), '*');
hold off;

功能说明

上述代码首先创建了一个正弦波,然后找出正弦波中值大于0.5的位置,使用

bwconncomp


bwlabel

函数进行处理,接着在正弦波上绘制星号,最后将星号绘制在y = 0直线上。

© 版权声明

相关文章

暂无评论

none
暂无评论...