I'm trying to display a spectrum of a sound sample with the correct frequency-axis, in Hertz, and a
log-amplitude y-axis. I thought I had the frequency display right, but the graphs that it produces look rather weird and I've found absolutely nothing regarding displaying the log amplitude on an axis.
The code that I'm using (heavily borrowed from mathsworks fft example) is:
y=x(100:200);
Fs = 10000; % Sampling frequency
numsamples = 20000; % Number of samples in the signal
NFFT = 2^nextpow2(numsamples); % Next power of 2 from length of y
Y = fft(y,NFFT)/numsamples;
f = Fs/2*linspace(0,1,NFFT/2+1);
plot(f,2*abs(Y(1:NFFT/2+1)))
And here's one of the graphs that it produced:
I don't know if that's right or not, but it doesn't look anything like the examples I've seen....
I'm aware this is probably a really stupid question and I'm missing something obvious, or maybe I've actually got it right and don't understand enough to realise it, but this stuff is really doing my head in and I'm not finding the documentation particularly illuminating.
I think the x-axis is correct.
To obtain a logarithmic y-axis replace the plot bysemilogy:
semilogy(f,2*abs(Y(1:NFFT/2+1)))
or equivalently use plot as it stands followed by
set(gca,'YScale','log')
Related
I have a signal 's' of voice of which you can see an extract here:
I would like to plot the zero crossing points in the same graph. I have tried with the following code:
zci = #(v) find(v(:).*circshift(v(:), [-1 0]) <= 0); % Returns Zero-Crossing Indices Of Argument Vector
zx = zci(s);
figure
set(gcf,'color','w')
plot(t,s)
hold on
plot(t(zx),s(zx),'o')
But it does not interpole the points in which the sign change, so the result is:
However, I'd like that the highlighted points were as near as possible to zero.
I hope someone can help me. Thanks you for your responses in advanced.
Try this?
w = 1;
crossPts=[];
for k=1:(length(s)-1)
if (s(k)*s(k+1)<0)
crossPts(w) = (t(k)+t(k+1))/2;
w = w + 1;
end
end
figure
set(gcf,'color','w')
plot(t,s)
hold on
plot(t, s)
plot(crossPts, zeros(length(crossPts)), 'o')
Important questions: what is the highest frequency conponent of the signal you are measuring? Can you remeasure this signal? What is your sampling rate? What is this analysis for? (Schoolwork or scholarly research). You may have quite a bit of trouble measuring the zeros of this function with any significance or accurracy because it looks like your waveform has a frequency greater than half of your sampling rate (greater than your Nyquist frequency). Upsampling/interpolating your entire waveform will allow you to find the zeros much more precisely (but with no greater degree of accurracy) but this is a huge no-no in the scientific community. While my method may not look super pretty, it's the most accurate method that doesn't make unsafe assumptions. If you just want it to look pretty, I would recommend interp1 and using the 'Spline' method. You can interpolate the whole waveform and then use the above answer to find more accurate zeros.
Also, you could calculate the zeros on the interpolated waveform and then display it on the raw data.
A remotely possible solution to improve your data;
If you're measuring a human voice, why not try filtering at the range of human speech? This should be fine mathematically and could possibly improve your waveform.
I am trying to plot the fft of a set of data I have. These data form a nearly perfect sinc function. Here is the data of which I am trying to plot the fft:
.
I know the fft of a sinc function should look like kind of a step function. However, the results I get are nowhere near that. Finding the fft in itself is super easy, but I think my mistake is when I try to compute the frequency axis. I have found several methods online, but so far I have not been able to make it work. Here is my code:
sampleRate = (max(xdata) - min(xdata))/length(xdata);
sampleN = length(xdata);
y = fft(ydata, sampleN);
Y = y.*conj(y)/sampleN;
freq = (0:1:length(Y)-1)*sampleRate/sampleNumber;
plot(freq, Y)
I have found pretty much all of that online and I understand pretty much none of it (which might be why it's not working...)
Zoom on what I get using that code:
It now seems to be working! This is what I get when I subtract the mean:
What you see here is the zero frequency being much, much larger than everything else. Plot with plot(freq,Y,'o-') to prove that the shape you see is just the linear interpolation between two samples.
The zero frequency is the sum of all samples. Because the mean of your signal is quite a bit larger than the amplitude, the zero frequency dwarfs everything else. And because you are plotting the power (absolute square of the DFT), this difference is enhanced even more.
There are two simple solutions:
Plot using logarithmic y-axis:
plot(freq, Y)
set(gca,'yscale','log')
Subtract the mean from your signal, remove the zero frequency, or scale the y-axis (these are all more or less equivalent):
y = fft(ydata-mean(ydata), sampleN);
or
y(1) = 0;
or
plot(freq, Y)
set(gca,'ylim',[0,max(Y(2:end))]);
I have measured signals (grid voltages and currents at 50Hz) of which I want to calculate the THD in MATLAB. However, using thd(signalVector, samplingFrequency, numberOfHarmonics) gives completely wrong results.
See the attached screenshot: The measured signal is on the left, the middle plot shows the FFT, on the right there is a closeup view of the FFT. As you can see, the THD is calculated to be too high at 86%:
Looking at the thd() itself, it obviously mismatches the FFT:
I used both fft() and thd() like in the MATLAB examples.
For FFT I use:
NFFT = 2^nextpow2(L);
Y = fft(signal_vector,NFFT)/(samples_vector);
f = sampling_frequency/2*linspace(0,1,NFFT/2+1);
y_fft = 2*abs(Y(1:NFFT/2+1));
plot(f,y_fft)
For THD up to the 40. harmonic I simply use:
thd(signal_vector,sampling_frequency,40)
where sampling frequency is 40kHz.
I guess I am doing something essentially wrong. Where is the flaw?
Do you need additional information? Any help is appreciated (I hope this is the right place for my question)
EDIT: Using a THD function from the Matlab File Exchange I get a THD of 1.78%, but I do not know if this is correct, but seems realistic.
It's my first time performing an FFT within MatLab by experimenting with some example code from the MathWorks website. I was wondering if it was possible to take the code I have and transform the x axis to a log-scale representation rather than linear. I understand most of the code, but it is the x axis line of code that I'm still not 100% sure exactly what it is doing apart from the +1 at the end of the line, which is that fact that MatLab's indexing structure doesn't start on 0.
My code so far is:
[y,fs] = wavread('Wav/800Hz_2sec.wav');
NFFT = 4096;
Y = fft(y,NFFT)/length(y);
f = fs/2*linspace(0,1,NFFT/2+1);
plot(f,2*abs(Y(1:NFFT/2+1))
frequency usually comes out in linear scale from Discrete Fourier Transform. if you want, you can make a new frequency vector in log scale and interpolate the results you already have
fnew=fs/2.*logspace(log10(fs/length(y)),0,npts);
Ynew= interp1(f,Y(1:NFFT/2+1),fnew);
where npts is the length of your new frequency vector. for just plotting
loglog(f,2*abs(Y(1:NFFT/2+1));
honestly IMO, the interpolation thing doesn't work very well because FFT of real signals produces strong peaks and troughs in spectra, so unless you smooth your spectrum first, the interpolated spectrum won't look as nice
So I plot sine(w*time) vs cosine(w*time)
w being angular frequency.
Hope I'm not wasting anyone's time if I ask:
Would this look like a circle?
I've researched a whole bunch but most websites only graph sine and cosine side-by-side and show comparisons.
I got it to look like a circle and I was just wondering if this is correct.
Also, What can I call this plot? I just gave it a title "plot of a circle". But I am wondering if that is professional enough since I am doing it for class.
Thanks for your time and answers. Greatly appreciated.
My MATLAB code for anyone interested:
clear all; clc; % clear the Workspace and the Command Window
f = 2; w = 2*pi*f; % specify a frequency in Hz and convert to rad/sec
T = 0.01; % specify a time increment
time = 0 : T : 0.5; % specify a vector of time points
x = sin(w*time); % evaluate the sine function for each element of the vector time
y = cos(w*time);
plot(x,y)
axis equal
grid on
xlabel('sin(w*time)');ylabel('cos(w*time)');title('Plot of a Circle');
axis([-1.1 1.1 -1.1 1.1]);
print
Here is a link to a Wolfram Alpha query I just did:
http://www.wolframalpha.com/input/?i=x%3Dsin%28t%29%2C+y%3Dcos%28t%29
I am not sure if it what you want to see, but that site (WolframAlpha.com) is a great place to explore and challenge mathematical concepts that are new to you.
Also, I would call it a plot of a circle since that is what the output looks like.
You are making a Lissajous curve. Keep in mind that a cosine is just a sine offset by pi/2 radians, and so plotting a sine against a cosine will indeed result in a circle. Changing the frequency and/or relative phase between x(t) and y(t) will result in many different interesting patterns.