I am designing composite sin wave such as
input=sin(2*pi*Fm_1*t) + sin(2*pi*Fm_2*t);
where Fm_1, and Fm_2 are given by the user and
t=0:Ts:2*Tm;
where
Ts=1/Fs;
Tm=1/(maxof(Fm_1,Fm_2) (NOT A FUNCTION, just to explain)
and Fm_1 = 5and Fm_2 = 10 and Fs = 30
and plot using plot(t,input);
Now for some reason, the output is correct but instead of being a sine wave, it's a triangular wave (straight lines). Other than that, the output is correct.
EDIT:
I just found out that because I plotted two graphs on the same scale, an error in the second graph screwed up the first.
Now the problem is filtering the input using this :
output = filtfilt(B,A,input);
Why does this give me nothing when I plot it (I also tried using filter)?
As mentioned in the comments above, the problem is that you're using a way too low sampling frequency to plot a detailed graph. You can see this using the function below:
function myplot(Fm_1, Fm_2, Fs)
Ts = 1/Fs;
Tm = 1/max(Fm_1,Fm_2);
t = 0:Ts:2*Tm;
input = sin(2*pi*Fm_1*t) + sin(2*pi*Fm_2*t);
plot(t, input);
end
As you noticed, for Fs = 30 you get a plot like this:
Increasing to Fs = 100, the situation improves:
And for Fs = 1000 the plot is what you'd probably expect in the first place:
Note that for all the above I've used the values Fm_1 = 5 and Fm_2 = 10 that you provided.
Related
I'm trying to get a frequency response curve from a microphone that I have connected to my pc, using matlab.
I think I'm pretty close of getting the final code, but i think I'm missing something.
This is what I have right now:
close all, clear all, clc
x = 5; % seconds recording
Fs = 44100; % Sampling frequency
T = 1/Fs; % Sample time
L= x*1000; % Length of signal
t = (0:L-1)*T; % Time vector
% Record your voice for 'x' seconds.
recObj = audiorecorder(Fs, 24, 1);
disp('Start of Recording.');
recordblocking(recObj, x);
disp('End of Recording.');
% Store data in double-precision array.
myRecording = getaudiodata(recObj);
NFFT = 2^nextpow2(L); % Next power of 2 from length of y
fourier = fft(myRecording);
Y = fft(myRecording,NFFT)/L;
f = Fs/2*linspace(0,1,NFFT/2+1);
X = 2*abs(Y(1:NFFT/2+1));
samples = get(recObj,'TotalSamples');
plot(f,X)
title('Single-Sided Amplitude Spectrum)
xlabel('Frequency (Hz)')
ylabel('|Y(f)|')
This part of the code is correct I think.
For example, when I play a tone of 5kHz I get this plot:
Now I play pink noise, and add this small part of code to convert it to dB, so I can get the frequency response curve:
dbX = db(X);
plot(f,dbX)
I expect (or my goal is..) a frequency response curve (as you can find on google images for example, I don't have enough reputation for more than 2 links, so sorry I didn't use a picture link here) , but I got this instead:
Clearly I'm doing something wrong, but I don't know what ..
You are closer than you think. Here are three tips to get a little closer.
Firstly, you need a logarithmic plot of your frequency domain data. Use semilogx() instead of plot.
Secondly, you're going to need to smooth the data. The simplest function for this in Matlab is smooth() but there are more advanced options that may better suit your needs.
Finally, in order to get a relative response, subtract the mean from your data. dbx_relative = dbx-mean(dbx)
Putting it all together:
dbX = db(X);
relative_dbx = dbx-mean(dbx);
smoothed_dbx = smooth(relative_dbx);
semilogx(f,smoothed_dbx);
Use pwelch to compute the transfer function between the stimulus signal (i.e. the reference audio waveform ) and the response (what you measure with your microphone).
I'm using scatter function to plot data containing only 25000 rows, however when I use saveas function to save the image as png, it takes 2+ minutes to do so.
For example:
scatter(x,y,'filled');
pic_name = ['scatterplot.png'];
tic
saveas(gcf,pic_name,'png');
toc
Elapsed time is 152.681511 seconds.
Is there a quicker way to save a scatter plot?
scatter is known to be slow for high number of datapoints; that might include saving them (each point has a difference color, thus needs separate handling).
You might want to try plotting the data differently, like described here: matlab: scatter plots with high number of datapoints
This way, you get the same behaviour as with regular plots.
Instead of calling saveas(), you could try calling getframe() and then calling imwrite(), like this:
npoints = 25000;
x = linspace(0,3*pi, npoints);
y = cos(x) + rand(1, npoints);
scatter_series_handle = scatter(x,y,'filled');
pic_name = ['scatterplot.png'];
axes_handle = get(scatter_series_handle, 'Parent');
figure_handle = get(axes_handle, 'Parent');
img = getframe(figure_handle);
imwrite(img.cdata, pic_name, 'png');
I created the following code in order to find the natural frequencies of a test sample which is excited by use of an impact hammer and has an accelerometer attached to it. However, I got stuck at interp_accelerance_dB_first. This interpolation creates a set of NaN values and I don't know why. I find it strange since interp_accelerance worked fine. I hope someone can help me!
N = 125000;
fs = 1/(x(2)-x(1));
ts = 1/fs;
f = -fs/2:fs/(N-1):fs/2;
% Set x-axis of graph
x_max = (N-1)*ts;
x_axis=0:ts:x_max;
% find the first natural frequency between these boundaries
First_lower_boundary = 15;
First_upper_boundary = 30;
Input = abs(fft(y)); %FFT input force
Output = abs(fft(o)); %FFT output acceleration
Accelerance = Output./Input;
bin_vals = [0 : N-1];
fax_Hz = bin_vals*fs/N;
N_2 = ceil(N/2);
% Interpolate accelerance function in order to be able to average all accelerance functions
Interp_accelerance = interp1(fax_Hz(1:N_2),Accelerance(1:N_2),x_axis);
% --- Find damping ratio of first natural frequency
% Determine the x-axis (from the boundries at the beginning of this script)
x_axis_first_peak = First_lower_boundary:ts:First_upper_boundary;
% Accelerance function with a logarithmic scale [dB]
Accelerance_dB_first = 20*log10(Accelerance(First_lower_boundary:First_upper_boundary));
% Interpolate the accelerance function [dB]
Interp_accelerance_dB_first = interp1(fax_Hz(First_lower_boundary:First_upper_boundary),Accelerance_dB_first,x_axis_first_peak);
Hard to say for sure without knowing what x,y,o are, but generally interp1 returns NaN when you try to interpolate outside of the bounds of the data's x-axis. Append the following at the end of your code:
[min(fax_Hz(First_lower_boundary:First_upper_boundary)),max(fax_Hz(First_lower_boundary:First_upper_boundary))]
[min(x_axis_first_peak),max(x_axis_first_peak)]
If the second segment doesn't fall inside of the first segment, then you've found your problem.
Incidentally, I think that interp_accelerance may be susceptible to the same error, again depending on the input parameters' exact nature.
I want to create a 2d plot of hilbert spectrum. What i want is a time vs frequency plot, where the amplitude of the signal is represented by color changes in the plot.
What i have done is this, but I need it to look like this.
Thank you in advance
EDIT:
I have the values of amplitude and instantaneous frequency over time, that i have produced using Hilbert Huang Transform.
Let's say we only use the first IMF, and we have 100 samples. Then what we have is:
instantaneous_frequency = [f1 f2 f3 ... f100]
instantaneous_amplitude = [a1 a2 a3 ... a100]
time = [t1 t2 t3 ... t100]
What i need is a way to plot them like the second image, without using the spectrogram function, since it uses STFT and I have already applied HHT.
The code for producing the first plot is:
Time_Window = 1:101;
signal= rand(1,101);
hilb = hilbert(signal);
inst_amp = abs(hilb);
inst_th = angle(hilb);
inst_freq = diff(a_inst_th)/(1/256)/(2*pi); %instantaneous frequency
%inst_freq = remove_outliers(inst_freq,Time_Window(1:end-1));
inst_freq(end+1) = inst_freq(end); % This is done due to diff()
plot(Time_Window*4,inst_freq,'k.','MarkerSize',5)
There is already a MATLAB function to produce a spectrogram, which looks a lot like what you want. See if that solves your problem.
After reading a lot of research and works on subject I still have got problems applying FFT to my accelerometer data. Most of my code is taken from official MATLAB example: FFT for one dimension. After more reading I've found this question: FFT and accelerometer data: why am I getting this output? where there was suggestion to use windowing. So after some more reading I've added hamming window to my code.
My data looks like that on plot:
And this is the code that I am using for FFT:
fs = 1/0.02; %0.02 comes from picking sample each 20ms
m = size(data,1);
w = hanning(m);
yw = w.*data;
n = pow2(nextpow2(yw));
y = fft(yw,size(n,1));
f = (0:size(n,1)-1)*(fs/size(n,1));
power = y.*conj(y)/size(n,1);
figure
plot(f,power)
The problem is that my plot from this code looks like that:
Can someone tell me what is wrong with my code? To be honest I'd excepted it would look better (something like this:http://imgur.com/wGs43) so that's why I am asking this question.
EDIT:
My data can be found here: https://dl.dropboxusercontent.com/u/58774274/exp.txt
Your Fs is 50 so the highest frequency in your data can be Fs/2 = 25Hz.
See if this code helps.
fid = fopen('1.txt','r');
C = textscan(fid, '%f');
fclose(fid);
data = C{1};
fs = 50;
m = length(data);
nfft = 2^nextpow2(m);
y = fft(data,nfft)/m;
f = fs/2 * linspace(0,1,nfft/2+1);
power = abs(y);
subplot(211)
plot(f,power(1:nfft/2+1))
t = (0 : m-1)/fs;
s0 = .8*fs : 3.2*fs; % .8 sec to 3.2 sec
p(s0) = .5*cos(2*pi*3.3*t(s0)+.25*pi);
p = p + mean(data);
subplot(212)
plot(t,data);hold on
plot(t,p,'r')
This is your data in frequency domain.
There is a peak at 3.3 Hz.
As a proof I plotted a sinusoidal with frequency of 3.3 Hz along with your data,
As you can see, it totally matches your data.
Your plots will look better if you first remove the DC offset (subtract the average of all samples from each point before computing the FFT), and then plot only half the FFT result data points (N/2) or less (since the upper half of an FFT result is just a conjugate mirror of the first half for real data input).
What your reference plot shows is just the magnitude on a logarithmic scale (in dB). Also it seems that the DC offset is removed. So you end up with something like this if you adapt it in your code.
data = data-mean(data); % DC removal
fs = 50;
m = length(data);
nfft = 2^nextpow2(m);
y = fft(data,nfft)/m;
f = fs/2 * linspace(0,1,nfft/2+1);
power = abs(y);
plot(f,10*log10(power(1:nfft/2+1))); % plot log magnitude
ylim([-30 0]) %limit axis
Looks at least similar to me.
If you additionally take the absolute square you are basically estimating the power spectral density of your signal. So meaning you have to change power = abs(y); to power = abs(y.^2); and then obviously have to adapt your ylim([-30 0]) to something lower like -50.