plotting pwelch with log axis - matlab

I'm using pwelch to plot a power spectral density. I want to use the format
pwelch=(x,window,noverlap,nfft,fs,'onesided')
but with a log scale on the x axis.
I've also tried
[P,F]=(x,window,noverlap,nfft,fs);
plot(F,P)
but it doesn't give the same resulting plot as above. Therefore,
semilogx(F,P)
isn't a good solution.

OK, so to start, I've never heard of this function or this method. However, I was able to generate the same plot that the function produced using output arguments instead. I ran the example from the help text.
EXAMPLE:
Fs = 1000; t = 0:1/Fs:.296;
x = cos(2*pi*t*200)+randn(size(t)); % A cosine of 200Hz plus noise
pwelch(x,[],[],[],Fs,'twosided'); % Uses default window, overlap & NFFT.
That produces this plot:
I then did: plot(bar,10*log10(foo)); grid on; to produce the linear version (same exact plot, minus labels):
or
semilogx(bar,10*log10(foo)); grid on; for the log scale on the x-axis.
I don't like that the x-scale is sampled linearly but displayed logarithmically (that's a word right?), but it seems to look ok.
Good enough?

Related

Calclulating a set of lines slopes after using Xlim in Matlab

I'm plotting a series of lines in MATLAB and the figure is like this:
As you can see the X-axis is Frequency, I want to limit the frequency spectrum so I use Xlim function in my code to select my desired bandwidth while plotting.
Now I want to calculate the slope of those lines in the chosen frequency bandwidth (what's in the plot window), not the entire band but if I choose the basic fitting option, it's clearly giving me a linear fit for the line over the entire frequency band.
Any advice?
Thanks.
You can do this in the matlab script:
% your data
f = linspace(2e7,11e7,100);
x = linspace(-0.5,-2.5,100)+0.1*rand(1,100);
% Linear fit in a specific range:
[~,i] = find( f>3e7 & f<9e7 ); % <= set your range here
p = polyfit(f(i),x(i),1); % <= note the (i) for both variables
figure;
hold all
plot(f,x,'r.-')
plot(f(i),polyval(p,f(i)),'k-','LineWidth',2) % <= polyval takes the 'p' from polyfit + the data on the x-axis
% the fit is y = p(1)*x+p(2)
You won't be able to use the basic fitting GUI for what you want to do. You will probably need to write a custom function that will "crop" the data in question to the x-limits of your current view. Then use polyfit or similar on those data segments to create the fit.

ksdensity of frequency histogram

I would like to plot multiple frequency histograms on one graph, however, my frequency plot is jagged and not pretty. As shown below with this code:
mmin = min([Data]);
mmax = max([Data]);
figure(1);n = hist(Data, x);
f = n/sum(n);
plot(x,f,'r','LineWidth',3)
To make it smooth, I looked into ksdensity and created the graph below based on this code:
[f,xi] = ksdensity(data);
figure(1)
plot(xi,f);
However, I noticed that my graph is no longer plotting frequency on the y-axis. Is there anyway to correct for this change using ksdensity? I really like how the graph looks as opposed to my frequency histogram and would like to keep using ksdensity, unless there is a better suggestion.
Thank you!
Data Sample:
https://www.dropbox.com/s/4ax2cuvugvqxjh6/splicing_attempt2_normalized_combined.txt?dl=0
The trick is here that I don't think you are calculating the frequency correctly in your histogram. You are neglecting the bin width. Your frequency should be the number of SNPs per position, which requires dividing by the number of (possibly fractional) positions per bin.
Try this:
Data = rand(1, 1e4);
figure(1);
[n, c] = hist(Data, 20);
dc = abs(c(2) - c(1));
f = n./(dc * sum(n));
plot(c,f,'r','LineWidth',3)
[~,f_kde,xi] = kde(Data);
line(xi,f_kde);
I don't have the Statistics Toolbox, so I'm using the File Exchange kde function instead, but both work the same way.
If the first graph is indeed what you are after, then do a little algebra-fu, and instead of dividing the histogram values by the bin width, multiply the kdensity values by the same bin width.
As I mention in my other histogram answer, there are numerous methods for choosing optimal bin widths for a histogram. I chose 20 here for expediency.

STFT computation without using spectrogram function!

I was trying to plot STFT using plot3 in MATLAB but failed. Can somebody guide me how to do that? My MWE is given below:
%% STFT Computataion
clear; clc; clf;
%% Get input and calculate frame size and overlap/shift
[Y,Fs]=wavread('D_NEHU_F0001_MN_10001');
frame_size=round(20*Fs/1000); % calculate frame size for 20ms
frame_shift=round(10*Fs/1000); % calculate frame shift for 10ms
%% Plot the input signal in time domain
t=1/Fs:1/Fs:(length(Y)/Fs);
subplot(2,1,1)
plot(t,Y);
title('Speech signal in time domain');
ylabel('Magnitude of samples');
xlabel('time in seconds');
%% Calculation of STFT
%NoOfFrames=floor((length(Y)/frame_shift)-1);
NoOfFrames=length(Y)-frame_size;
j=1;
%for i=1:frame_shift:(length(Y)-frame_size)
for i=1:frame_shift:((length(Y)-frame_size))%+frame_shift)
sp_frame=Y(i:(i+frame_size)).*hamming(frame_size+1);
sp_frame_dft=abs(fft(sp_frame)); % Compute STFT
sp_frame_array(:,j)=sp_frame_dft;
j=j+1;
end
%% Plot the STFT in 3D
[rows,cols]=size(sp_frame_array);
F=linspace(1/Fs,Fs/2000,cols);
T=1/Fs:(frame_shift*Fs/1000):(cols*(frame_shift*Fs/1000));
Z=1:frame_size+1;
subplot(2,1,2)
%mesh(sp_frame_array);
%surf(sp_frame_array,'EdgeColor','none');
plot3(T,F,sp_frame_array);
I am not sure what your question exactly is about, but I guess the problem is, with the provided code, that you do not get a plot similar to the one you'd get, say, with surf.
Furthermore, I am also not quite sure why you would want to use plot3, maybe to get the labels on the time and frequency right ? you could do that all the same with surf:
surf(T, F, sp_frame_array,'EdgeColor','none');
As a matter of fact, the reason why your plot3 does not give the same figure is because the arguments of plot3 must be three matrices of the same size (check it on help plot3). Your code should actually be broken on Matlab, which it's not, according to my test. Well, once again Matlab allowing people to mess around without warnings (go Python! :D)... Anyway, try to set the matrices more like the following:
F=linspace(1/Fs,Fs/2000, rows); % note: has to be rows, not cols here!
Fmat = F(:) * ones(1,cols); % or use repmat
T=1/Fs:(frame_shift*Fs/1000):(cols*(frame_shift*Fs/1000));
Tmat = ones(rows,1) * T(:)';
plot3(Tmat,Fmat,sp_frame_array);
While this will normally produce something more in line with what I would expect in drawing a spectrogram, I'd still make some remarks:
your F vector should go up to Fs, because of the way you filled sp_frame_dft in. More specifically, it should go from 0Hz to Fs - Fs/rows:
F = linspace(0,Fs*(1-1/rows)/1000,rows); % in kHz
you would probably like to draw the amplitudes in dBs:
plot3(Tmat,Fmat,db(sp_frame_array));
plot3 draws one line per column of the provided matrices. That means potentially lots of lines to draw! As #atul-ingle asked, are you sure this is what you want? Maybe waterfall would provide a better rendering at a lower cost?
waterfall(T,F,db(sp_frame_array));
Well, you'll get the lines for the rows, instead of the columns, so you might need to transpose if the latter is what you want.
You might also prefer to visualise only the first half of the matrix (because the frequencies higher than Fs/2 are only mirrors of the other half of the matrix).
Hope that helps!

Detect and mark maximum peak on power spectral analysis plot using Matlab?

I'm trying to find the maximum peak on a power spectral density plot created in Matlab. I can create the plot just fine but am having difficulty correctly marking it. I use the find peaks and max function to find it but Matlab cannot correctly mark it. It finds the correct height but marks it a little to the left or right. Here is the code:
data = load ('EEGData(test1).txt', '-ascii');
figure(1)
plot(data)
Y =fft(data,251);
Pyy = Y.*conj(Y)/251;
f = 1000/251*(0:127);
figure(2)
plot(f,Pyy(1:128))
title('Power spectral density')
xlabel('Frequency (Hz)')
[a,b] = findpeaks(Pyy(1:128));
MAX = max(a);
hold on
plot(f(b), MAX,'or')
any help would be greatly appreciated.
When I tested your code as is by replacing data with
data=randn(251,1);
...I found that the local peak locations indicated by the red o markers were in the correct locations. It was just that all peaks were marked at the height of the maximum peak.
I'm not 100% sure what you are trying to do, but it looks as if you are trying to just find the maximum peak. If this is the case then you do not need the findpeaks function. Just replace the last few lines of your code with the following ...
[MAX, MAXidx] = max(Pyy(1:128));
hold on
plot(f(MAXidx), MAX,'or')

Matlab cdfplot: how to control the spacing of the marker spacing

I have a Matlab figure I want to use in a paper. This figure contains multiple cdfplots.
Now the problem is that I cannot use the markers because the become very dense in the plot.
If i want to make the samples sparse I have to drop some samples from the cdfplot which will result in a different cdfplot line.
How can I add enough markers while maintaining the actual line?
One method is to get XData/YData properties from your curves follow solution (1) from #ephsmith and set it back. Here is an example for one curve.
y = evrnd(0,3,100,1); %# random data
%# original data
subplot(1,2,1)
h = cdfplot(y);
set(h,'Marker','*','MarkerSize',8,'MarkerEdgeColor','r','LineStyle','none')
%# reduced data
subplot(1,2,2)
h = cdfplot(y);
set(h,'Marker','*','MarkerSize',8,'MarkerEdgeColor','r','LineStyle','none')
xdata = get(h,'XData');
ydata = get(h,'YData');
set(h,'XData',xdata(1:5:end));
set(h,'YData',ydata(1:5:end));
Another method is to calculate empirical CDF separately using ECDF function, then reduce the results before plotting with PLOT.
y = evrnd(0,3,100,1); %# random data
[f, x] = ecdf(y);
%# original data
subplot(1,2,1)
plot(x,f,'*')
%# reduced data
subplot(1,2,2)
plot(x(1:5:end),f(1:5:end),'r*')
Result
I know this is potentially unnecessary given MATLAB's built-in functions (in the Statistics Toolbox anyway) but it may be of use to other viewers who do not have access to the toolbox.
The empirical CMF (CDF) is essentially the cumulative sum of the empirical PMF. The latter is attainable in MATLAB via the hist function. In order to get a nice approximation to the empirical PMF, the number of bins must be selected appropriately. In the following example, I assume that 64 bins is good enough for your data.
%# compute a histogram with 64 bins for the data points stored in y
[f,x]=hist(y,64);
%# convert the frequency points in f to proportions
f = f./sum(f);
%# compute the cumulative sum of the empirical PMF
cmf = cumsum(f);
Now you can choose how many points you'd like to plot by using the reduced data example given by yuk.
n=20 ; % number of total data markers in the curve graph
M_n = round(linspace(1,numel(y),n)) ; % indices of markers
% plot the whole line, and markers for selected data points
plot(x,y,'b-',y(M_n),y(M_n),'rs')
verry simple.....
try reducing the marker size.
x = rand(10000,1);
y = x + rand(10000,1);
plot(x,y,'b.','markersize',1);
For publishing purposes I tend to use the plot tools on the figure window. This allow you to tweak all of the plot parameters and immediately see the result.
If the problem is that you have too many data points, you can:
1). Plot using every nth sample of the data. Experiment to find an n that results in the look you want.
2). I typically fit curves to my data and add a few sparsely placed markers to plots of the fits to differentiate the curves.
Honestly, for publishing purposes I have always found that choosing different 'LineStyle' or 'LineWidth' properties for the lines gives much cleaner results than using different markers. This would also be a lot easier than trying to downsample your data, and for plots made with CDFPLOT I find that markers simply occlude the stairstep nature of the lines.