简体   繁体   English

MATLAB FFT xaxis限制了混乱和移位

[英]MATLAB FFT xaxis limits messing up and fftshift

This is the first time I'm using the fft function and I'm trying to plot the frequency spectrum of a simple cosine function: 这是我第一次使用fft函数,并且我试图绘制简单余弦函数的频谱:

f = cos(2*pi*300*t) f = cos(2 * pi * 300 * t)

The sampling rate is 220500. I'm plotting one second of the function f. 采样率是220500.我正在绘制函数f的一秒。

Here is my attempt: 这是我的尝试:

time = 1;
freq = 220500;
t = 0 : 1/freq : 1 - 1/freq;
N = length(t);
df = freq/(N*time);

F = fftshift(fft(cos(2*pi*300*t))/N);
faxis = -N/2 / time : df : (N/2-1) / time;

plot(faxis, real(F));
grid on;
xlim([-500, 500]);

Why do I get odd results when I increase the frequency to 900Hz? 当我将频率提高到900Hz时,为什么会得到奇怪的结果? These odd results can be fixed by increasing the x-axis limits from, say, 500Hz to 1000Hz. 可以通过将x轴限制从例如500Hz增加到1000Hz来修复这些奇怪的结果。 Also, is this the correct approach? 另外,这是正确的方法吗? I noticed many other people didn't use fftshift(X) (but I think they only did a single sided spectrum analysis). 我注意到很多其他人没有使用fftshift(X) (但我认为他们只进行了单侧光谱分析)。

Thank you. 谢谢。

Here is my response as promised. 这是我承诺的回应。

The first or your questions related to why you "get odd results when you increase the frequency to 900 Hz" is related to the Matlab's plot rescaling functionality as described by @Castilho. 第一个或者你的问题与你为什么“在将频率增加到900 Hz时得到奇怪的结果”有关,与@Castilho描述的Matlab的绘图重新缩放功能有关。 When you change the range of the x-axis, Matlab will try to be helpful and rescale the y-axis. 当您更改x轴的范围时,Matlab将尝试提供帮助并重新缩放y轴。 If the peaks lie outside of your specified range, matlab will zoom in on the small numerical errors generated in the process. 如果峰值位于指定范围之外,则matlab将放大过程中生成的小数值误差。 You can remedy this with the 'ylim' command if it bothers you. 如果它困扰你,您可以使用'ylim'命令来解决这个问题。

However, your second, more open question "is this the correct approach?" 但是,你的第二个更开放的问题是“这是正确的方法吗?” requires a deeper discussion. 需要更深入的讨论。 Allow me to tell you how I would go about making a more flexible solution to achieve your goal of plotting a cosine wave. 请允许我告诉您如何制定更灵活的解决方案,以实现绘制余弦波的目标。

You begin with the following: 您从以下开始:

time = 1;
freq = 220500;

This raises an alarm in my head immediately. 这立刻引起了我的警觉。 Looking at the rest of the post, you appear to be interested in frequencies in the sub-kHz range. 查看帖子的其余部分,您似乎对亚kHz范围内的频率感兴趣。 If that is the case, then this sampling rate is excessive as the Nyquist limit (sr/2) for this rate is above 100 kHz. 如果是这种情况,则该采样率过高,因为该速率的奈奎斯特极限(sr / 2)高于100 kHz。 I'm guessing you meant to use the common audio sampling rate of 22050 Hz (but I could be wrong here)? 我猜你的意思是使用22050赫兹的普通音频采样率(但我可能在这里错了)?

Either way, your analysis works out numerically OK in the end. 无论哪种方式,您的分析最终都会在数值上正常运行。 However, you are not helping yourself to understand how the FFT can be used most effectively for analysis in real-world situations. 但是,您并没有帮助自己了解如何在实际情况下最有效地使用FFT进行分析。

Allow me to post how I would do this. 请允许我发布我将如何做到这一点。 The following script does almost exactly what your script does, but opens some potential on which we can build . 以下脚本几乎完全符合您的脚本所做的,但是打开了我们可以构建的一些潜力。 .

%// These are the user parameters
durT = 1;
fs = 22050;
NFFT = durT*fs;
sigFreq = 300;

%//Calculate time axis
dt = 1/fs;
tAxis = 0:dt:(durT-dt);

%//Calculate frequency axis
df = fs/NFFT;
fAxis = 0:df:(fs-df);

%//Calculate time domain signal and convert to frequency domain
x = cos(  2*pi*sigFreq*tAxis  );
F = abs(  fft(x, NFFT)  /  NFFT  );

subplot(2,1,1);
plot(  fAxis, 2*F  )
xlim([0 2*sigFreq])
title('single sided spectrum')

subplot(2,1,2);
plot(  fAxis-fs/2, fftshift(F)  )
xlim([-2*sigFreq 2*sigFreq])
title('whole fft-shifted spectrum')

You calculate a time axis and calculate your number of FFT points from the length of the time axis. 您计算时间轴并根据时间轴的长度计算FFT点的数量。 This is very odd. 这很奇怪。 The problem with this approach, is that the frequency resolution of the fft changes as you change the duration of your input signal, because N is dependent on your "time" variable. 这种方法的问题在于,当你改变输入信号的持续时间时,fft的频率分辨率会发生变化,因为N取决于你的“时间”变量。 The matlab fft command will use an FFT size that matches the size of the input signal. matlab fft命令将使用与输入信号大小匹配的FFT大小。

In my example, I calculate the frequency axis directly from the NFFT. 在我的例子中,我直接从NFFT计算频率轴。 This is somewhat irrelevant in the context of the above example, as I set the NFFT to equal the number of samples in the signal. 这在上述示例的上下文中有些不相关,因为我将NFFT设置为等于信号中的样本数。 However, using this format helps to demystify your thinking and it becomes very important in my next example. 但是,使用这种格式有助于揭开思维的神秘面纱,在下一个例子中它变得非常重要。

** SIDE NOTE: You use real(F) in your example. **侧面注意:您在示例中使用了真实(F)。 Unless you have a very good reason to only be extracting the real part of the FFT result, then it is much more common to extract the magnitude of the FFT using abs(F). 除非您有充分的理由仅提取FFT结果的实部,否则使用abs(F)提取FFT的幅度更为常见。 This is the equivalent of sqrt(real(F).^2 + imag(F).^2).** 这相当于sqrt(real(F)。^ 2 + imag(F)。^ 2)。**

Most of the time you will want to use a shorter NFFT. 大多数时候你会想要使用更短的NFFT。 This might be because you are perhaps running the analysis in a real time system, or because you want to average the result of many FFTs together to get an idea of the average spectrum for a time varying signal, or because you want to compare spectra of signals that have different duration without wasting information. 这可能是因为您可能正在实时系统中运行分析,或者因为您想要将许多FFT的结果平均在一起以了解时变信号的平均频谱,或者因为您想比较频谱具有不同持续时间而不浪费信息的信号。 Just using the fft command with a value of NFFT < the number of elements in your signal will result in an fft calculated from the last NFFT points of the signal. 只需使用值为NFFT的fft命令<信号中元素的数量将导致从信号的最后NFFT点计算的fft。 This is a bit wasteful. 这有点浪费。

The following example is much more relevant to useful application. 以下示例与有用的应用程序更相关。 It shows how you would split a signal into blocks and then process each block and average the result: 它显示了如何将信号拆分为块然后处理每个块并平均结果:

%//These are the user parameters
durT = 1;
fs = 22050;
NFFT = 2048;
sigFreq = 300;

%//Calculate time axis
dt = 1/fs;
tAxis = dt:dt:(durT-dt);

%//Calculate frequency axis
df = fs/NFFT;
fAxis = 0:df:(fs-df);

%//Calculate time domain signal 
x = cos(  2*pi*sigFreq*tAxis  );

%//Buffer it and window
win = hamming(NFFT);%//chose window type based on your application
x = buffer(x, NFFT, NFFT/2); %// 50% overlap between frames in this instance
x = x(:, 2:end-1); %//optional step to remove zero padded frames
x = (  x' * diag(win)  )'; %//efficiently window each frame using matrix algebra

%// Calculate mean FFT
F = abs(  fft(x, NFFT)  /  sum(win)  );
F = mean(F,2);

subplot(2,1,1);
plot(  fAxis, 2*F  )
xlim([0 2*sigFreq])
title('single sided spectrum')

subplot(2,1,2);
plot(  fAxis-fs/2, fftshift(F)  )
xlim([-2*sigFreq 2*sigFreq])
title('whole fft-shifted spectrum')

I use a hamming window in the above example. 我在上面的例子中使用了汉明窗口。 The window that you choose should suit the application http://en.wikipedia.org/wiki/Window_function 您选择的窗口应该适合应用程序http://en.wikipedia.org/wiki/Window_function

The overlap amount that you choose will depend somewhat on the type of window you use. 您选择的重叠量在某种程度上取决于您使用的窗口类型。 In the above example, the Hamming window weights the samples in each buffer towards zero away from the centre of each frame. 在上面的示例中,汉明窗口将每个缓冲区中的样本加权到远离每个帧的中心的零。 In order to use all of the information in the input signal, it is important to use some overlap. 为了使用输入信号中的所有信息,重要的是使用一些重叠。 However, if you just use a plain rectangular window, the overlap becomes pointless as all samples are weighted equally. 但是,如果您只使用普通的矩形窗口,则重叠变得毫无意义,因为所有样本的权重相等。 The more overlap you use, the more processing is required to calculate the mean spectrum. 您使用的重叠越多,计算平均频谱所需的处理就越多。

Hope this helps your understanding. 希望这有助于您的理解。

Your result is perfectly right. 你的结果是完全正确的。 Your frequency axis calculation is also right. 您的频率轴计算也是正确的。 The problem lies on the y axis scale. 问题在于y轴刻度。 When you use the function xlims, matlab automatically recalculates the y scale so that you can see "meaningful" data. 当您使用xlims函数时,matlab会自动重新计算y比例,以便您可以看到“有意义”的数据。 When the cosine peaks lie outside the limit you chose (when f>500Hz), there are no peaks to show, so the scale is calculated based on some veeeery small noise (here at my computer, with matlab 2011a, the y scale was 10-16). 当余弦峰位于您选择的极限之外时(当f> 500Hz时),没有峰值显示,因此根据一些小的噪声计算比例(在我的计算机上,使用matlab 2011a,y标度为10) -16)。

Changing the limit is indeed the correct approach, because if you don't change it you can't see the peaks on the frequency spectrum. 更改限制确实是正确的方法,因为如果不更改它,则无法看到频谱上的峰值。

One thing I noticed, however. 然而,我注意到了一件事。 Is there a reason for you to plot the real part of the transform? 您是否有理由绘制变换的真实部分? Usually, it is abs(F) that gets plotted, and not the real part. 通常,绘制的是abs(F) ,而不是真实的部分。

edit: Actually, you're frequency axis is only right because df, in this case, is 1. The faxis line is right, but the df calculation isn't. 编辑:实际上,你的频率轴是正确的,因为在这种情况下,df是1. faxis线是正确的,但df计算不是。

The FFT calculates N points from -Fs/2 to Fs/2. FFT计算从-Fs / 2到Fs / 2的N个点。 So N points over a range of Fs yields a df of Fs/N. 因此,在一系列Fs上的N个点产生ff / N的df。 As N/time = Fs => time = N/Fs. 当N /时间= Fs =>时间= N / Fs。 Substituting that on the expression of df you used: your_df = Fs/N*(N/Fs) = (Fs/N)^2. 将其替换为您使用的df的表达式:your_df = Fs / N *(N / Fs)=(Fs / N)^ 2。 As Fs/N = 1, the final result was right :P 当Fs / N = 1时,最终结果是正确的:P

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM