如何将 2D FFT 图归一化为正确的频率 (Matlab)?
How to normalise a 2D FFT plot to the right frequency (Matlab)?
首先,请参阅 了解有关此问题的更多背景知识。
假设在这个样本信号的情况下:-
n = [0:1024];
signal = sin(2*pi*n/10) + sin(2*pi*n/20) + sin(2*pi*n/30);
N = 2048; %At least twice of the n value
X = abs(fft(signal,N));
X = fftshift(X); %normalise data
F = [-N/2:N/2-1]/N; %normalise data - shift it to the correct frequency
plot(F,X);
这里的变量F范围是从
中整理出x轴归一化的东西
以下
但是,我正在努力寻找一种方法来标准化 2D FFT 图的 x 和 y 轴值(图的图像可在上面给定的 link 中找到这句post.)
有人知道我应该怎么做吗?
我的代码的工作部分的片段是:-
clear;
deg_speed = 15.35; %degrees visual angle/sec
max_speed = deg_speed/5.15; %converting the required deg_speed in terms of frames
nr_of_dots = 10; %number of dots
sin_cycle_dur = 80; %number of frames (along Nt) required to complete a sin wave.
sineTOTAL = 0;
Nx = 160; % Frames along x-axis. 1 frame = 0.1 dva
Nt = 200; % Frames along y-asis. 1 frame = 10ms
start_dot_pos = round(rand(1,nr_of_dots) .* Nx); %spawn random starting positions of dots
dot_pos = zeros(Nt, nr_of_dots); %Initialise 2D stimulus array
dot_pos(1,:) = start_dot_pos; %Fill up first line of 2D array with the starting position of dots
dot_pos_sim = zeros(Nt, nr_of_dots); %Setup simulated array so the final dot_pos can be scaled to mean speed of outher condition
dot_pos_sim(1,:) = start_dot_pos; %Fill up first line of 2D array with the starting position of dots
for a = 2:Nt
sine_speed = max_speed .* sin((a-1) / sin_cycle_dur *2*pi); %Sine formula
sineTOTAL = sineTOTAL + abs(sine_speed); %Add all sine generated values from Sine formula to get an overall total for mean calculation
dot_pos_sim(a,:) = dot_pos_sim(a-1,:) + max_speed .* sin((a-1) / sin_cycle_dur *2*pi); %Sine simulated matrix (before scaling)
end
%Ignore this for loop for now. This is later required for normalising simulated
%array to the mean speed across other conditions.
for b = 1:Nt
dot_pos(b,:) = dot_pos_sim(b,:);
end
dot_pos = round(dot_pos); %Frames are in integers, therefore all float values needed to be rounded up.
dot_pos = mod(dot_pos,Nx)+1; %Wrap the dots the go beyond the edges to the other side of the plot
%For all of the slots filled with dots, set the value from 0 to 1.
for c = 1:Nt
stim(c,dot_pos(c,:)) = 1;
end
figure (1)
x=linspace(0,16,5);
y=linspace(0,2,10);
imagesc(x,y,stim);
xlabel('degrees');
ylabel('seconds');
colormap('gray');
X = abs(fft2(stim));
X = fftshift(X); %normalise data
X = log(1+X);
figure (2)
imagesc(X);
colormap('gray');
我一直在尝试在线查找指南和帮助,但到目前为止无济于事。任何帮助将不胜感激!
我认为这是一个非常简单的答案 - 您似乎在寻找的是沿 X 轴和 Y 轴表示归一化频率的刻度。当您使用 fftshift 时,DC 项将位于绘图的中间,因此您的比例应该 运行 从 -0.5 到 0.5。这可以使用 imagesc(x,y,C)
命令轻松完成,而不是像您当前所做的那样仅使用 imagesc(C)
。 (您使用 X,但 Matlab 帮助使用 C,因为它表示颜色图)。
将倒数第二行更改为:
imagesc([-0.5,0.5],[-0.5,0.5],X);
它能满足您的需求。
每当我不确定轴和比例时,我都会回到基础知识:复指数(复正弦曲线,实数 = cos 和虚数 = sin)。
我知道 exp(j * 2 * pi * f * t)
的一维 FFT,对于时间样本向量 t
(以秒为单位)和频率 f
(以赫兹为单位)将在f
,只要 fmin < f < fmax
,其中 fmax = 1 / diff(t(1:2)) / 2
和 fmin = -1.0 * fmax
,并且峰值将具有值 1.0.
完全相同的事情适用于 2D 情况。频率为 (fx, fy)
的二维复指数将在各自轴的 fx
和 fy
处具有峰值,峰值将为 1.0.
这是一个完整的 Matlab 示例,它通过详细信息和约定来获得这个已知结果。它在矩形二维网格上模拟二维复指数,x 频率为 2 Hz,y 频率为 -3 Hz。然后在补零后进行FFT。
clearvars
x = linspace(-2, 2, 100); % seconds
y = linspace(-3, 3, 200); % seconds
xFreq = 2; % Hz
yFreq = -3; % Hz
im = exp(2j * pi * y(:) * yFreq) * exp(2j * pi * x(:)' * xFreq);
figure;imagesc(x, y, real(im))
xlabel('x (seconds)'); ylabel('y (seconds)');
title('time-domain data (real)')
colorbar; colormap(flipud(gray))
Nfft = 4 * 2 .^ nextpow2(size(im));
imF = fftshift(fft2(im, Nfft(1), Nfft(2))) / numel(im);
fx = ([0 : Nfft(2) - 1] / Nfft(2) - 0.5) / diff(x(1:2));
fy = ([0 : Nfft(1) - 1] / Nfft(1) - 0.5) / diff(y(1:2));
figure; imagesc(fx, fy, abs(imF));
colorbar; colormap(flipud(gray))
xlabel('f_x (Hz)'); ylabel('f_y (Hz)')
title('Frequency-domain data (abs)')
grid; axis xy
这是输入时域数据:
确认您在 x 维度上看到 两个 个峰峰值循环,在 y 维度上看到 三个 个循环——它是如果您研究图的底部和左侧边缘,很容易看到这些。
这是 2D FFT,适当移动(使用 fftshift
),轴正确缩放(参见 fx
和 fy
),峰值正确缩放(参见我如何划分fft2
与 numel(im)
).
的输出
确认峰值在[fx, fy]
对应的(2, -3)Hz处,峰值的值几乎是1.0(由于量化网格的缘故小了一点)。
所以,我做了三件事来完成所有这些工作:
fftshift
fft2
, 的输出
- 正确生成
fx
和fy
以匹配fftshift
和
- 在零填充.
之前,根据它在 上操作的元素数量缩放 fft2
的输出
希望您能将这个完整的示例扩展到您自己的案例中。
首先,请参阅
假设在这个样本信号的情况下:-
n = [0:1024];
signal = sin(2*pi*n/10) + sin(2*pi*n/20) + sin(2*pi*n/30);
N = 2048; %At least twice of the n value
X = abs(fft(signal,N));
X = fftshift(X); %normalise data
F = [-N/2:N/2-1]/N; %normalise data - shift it to the correct frequency
plot(F,X);
这里的变量F范围是从
中整理出x轴归一化的东西以下
但是,我正在努力寻找一种方法来标准化 2D FFT 图的 x 和 y 轴值(图的图像可在上面给定的 link 中找到这句post.)
有人知道我应该怎么做吗?
我的代码的工作部分的片段是:-
clear;
deg_speed = 15.35; %degrees visual angle/sec
max_speed = deg_speed/5.15; %converting the required deg_speed in terms of frames
nr_of_dots = 10; %number of dots
sin_cycle_dur = 80; %number of frames (along Nt) required to complete a sin wave.
sineTOTAL = 0;
Nx = 160; % Frames along x-axis. 1 frame = 0.1 dva
Nt = 200; % Frames along y-asis. 1 frame = 10ms
start_dot_pos = round(rand(1,nr_of_dots) .* Nx); %spawn random starting positions of dots
dot_pos = zeros(Nt, nr_of_dots); %Initialise 2D stimulus array
dot_pos(1,:) = start_dot_pos; %Fill up first line of 2D array with the starting position of dots
dot_pos_sim = zeros(Nt, nr_of_dots); %Setup simulated array so the final dot_pos can be scaled to mean speed of outher condition
dot_pos_sim(1,:) = start_dot_pos; %Fill up first line of 2D array with the starting position of dots
for a = 2:Nt
sine_speed = max_speed .* sin((a-1) / sin_cycle_dur *2*pi); %Sine formula
sineTOTAL = sineTOTAL + abs(sine_speed); %Add all sine generated values from Sine formula to get an overall total for mean calculation
dot_pos_sim(a,:) = dot_pos_sim(a-1,:) + max_speed .* sin((a-1) / sin_cycle_dur *2*pi); %Sine simulated matrix (before scaling)
end
%Ignore this for loop for now. This is later required for normalising simulated
%array to the mean speed across other conditions.
for b = 1:Nt
dot_pos(b,:) = dot_pos_sim(b,:);
end
dot_pos = round(dot_pos); %Frames are in integers, therefore all float values needed to be rounded up.
dot_pos = mod(dot_pos,Nx)+1; %Wrap the dots the go beyond the edges to the other side of the plot
%For all of the slots filled with dots, set the value from 0 to 1.
for c = 1:Nt
stim(c,dot_pos(c,:)) = 1;
end
figure (1)
x=linspace(0,16,5);
y=linspace(0,2,10);
imagesc(x,y,stim);
xlabel('degrees');
ylabel('seconds');
colormap('gray');
X = abs(fft2(stim));
X = fftshift(X); %normalise data
X = log(1+X);
figure (2)
imagesc(X);
colormap('gray');
我一直在尝试在线查找指南和帮助,但到目前为止无济于事。任何帮助将不胜感激!
我认为这是一个非常简单的答案 - 您似乎在寻找的是沿 X 轴和 Y 轴表示归一化频率的刻度。当您使用 fftshift 时,DC 项将位于绘图的中间,因此您的比例应该 运行 从 -0.5 到 0.5。这可以使用 imagesc(x,y,C)
命令轻松完成,而不是像您当前所做的那样仅使用 imagesc(C)
。 (您使用 X,但 Matlab 帮助使用 C,因为它表示颜色图)。
将倒数第二行更改为:
imagesc([-0.5,0.5],[-0.5,0.5],X);
它能满足您的需求。
每当我不确定轴和比例时,我都会回到基础知识:复指数(复正弦曲线,实数 = cos 和虚数 = sin)。
我知道 exp(j * 2 * pi * f * t)
的一维 FFT,对于时间样本向量 t
(以秒为单位)和频率 f
(以赫兹为单位)将在f
,只要 fmin < f < fmax
,其中 fmax = 1 / diff(t(1:2)) / 2
和 fmin = -1.0 * fmax
,并且峰值将具有值 1.0.
完全相同的事情适用于 2D 情况。频率为 (fx, fy)
的二维复指数将在各自轴的 fx
和 fy
处具有峰值,峰值将为 1.0.
这是一个完整的 Matlab 示例,它通过详细信息和约定来获得这个已知结果。它在矩形二维网格上模拟二维复指数,x 频率为 2 Hz,y 频率为 -3 Hz。然后在补零后进行FFT。
clearvars
x = linspace(-2, 2, 100); % seconds
y = linspace(-3, 3, 200); % seconds
xFreq = 2; % Hz
yFreq = -3; % Hz
im = exp(2j * pi * y(:) * yFreq) * exp(2j * pi * x(:)' * xFreq);
figure;imagesc(x, y, real(im))
xlabel('x (seconds)'); ylabel('y (seconds)');
title('time-domain data (real)')
colorbar; colormap(flipud(gray))
Nfft = 4 * 2 .^ nextpow2(size(im));
imF = fftshift(fft2(im, Nfft(1), Nfft(2))) / numel(im);
fx = ([0 : Nfft(2) - 1] / Nfft(2) - 0.5) / diff(x(1:2));
fy = ([0 : Nfft(1) - 1] / Nfft(1) - 0.5) / diff(y(1:2));
figure; imagesc(fx, fy, abs(imF));
colorbar; colormap(flipud(gray))
xlabel('f_x (Hz)'); ylabel('f_y (Hz)')
title('Frequency-domain data (abs)')
grid; axis xy
这是输入时域数据:
确认您在 x 维度上看到 两个 个峰峰值循环,在 y 维度上看到 三个 个循环——它是如果您研究图的底部和左侧边缘,很容易看到这些。
这是 2D FFT,适当移动(使用 fftshift
),轴正确缩放(参见 fx
和 fy
),峰值正确缩放(参见我如何划分fft2
与 numel(im)
).
确认峰值在[fx, fy]
对应的(2, -3)Hz处,峰值的值几乎是1.0(由于量化网格的缘故小了一点)。
所以,我做了三件事来完成所有这些工作:
fftshift
fft2
, 的输出
- 正确生成
fx
和fy
以匹配fftshift
和 - 在零填充. 之前,根据它在 上操作的元素数量缩放
fft2
的输出
希望您能将这个完整的示例扩展到您自己的案例中。