Adding markers on specific points in bodeplot - matlab

I am currently designing a 5th order Butterworth filter and looking at its transfer function response in Matlab. I have successfully calculated it and have plotted its bode response like this:
% Butterworth Fifth Order Low Pass
figure(1)
h = bodeplot(FinalTF);
setoptions(h,'FreqUnits','Hz','PhaseVisible','off');
title('Butterworth LowPass Fifth Order');
grid on;
where FinalTF is the transfer function I'm talking about. What I want is to add markers on specific points in this plot (specifically I want to highlight the frequencies fp,fo,fs, you don't need to know what these are, they're just 3 different points on the x-axis, and the dB at each frequency) with code. I know how to do it by clicking on the graph, but that will be too time consuming, as I have many plots to go through. I am currently running into two basic problems:
1) I don't know how to get the specific dB at each frequency just by using the TF object. I tried using the function evalfr(), but tbh the values it returns seem a bit off.
2) Ignoring the previous point, even if I do the calculations by hand, I can't add them on the plot using this method, and I'm not sure what the problem is. Maybe because I'm using bodeplot instead of regular plot? I don't know how else to do it though.
I'm using Matlab 2015, if it makes any difference.
Any help would be appreciated. Thanks in advance.

I actually found a solution. Here is some sample code to illustrate the results. Before I was doing:
figure(3);
h = bodeplot(FinalTF);
setoptions(h,'FreqUnits','Hz','PhaseVisible','off');
grid on;
title('Chebyshev 2nd Order Band Pass');
It just printed the bodeplot of the transfer function. Now I managed to add markers to the specific frequencies I wanted like this:
figure(4);
myW = logspace(1,5,1000);
myW = 2*pi*myW;
[mag,~,wout] = bode(FinalTF,myW);
mag = squeeze(mag);
wout = squeeze(wout);
mag = 20*log10(mag);
wout = wout/2/pi;
semilogx(wout,mag,'-b');
axis([min(wout) max(wout) min(mag)-10 max(mag)+10]);
title('Chebyshev 2nd Order Band Pass');
xlabel('Frequency (Hz)');
ylabel('Magnitude (dB)');
grid on;
hold on;
freqMarkers = [w0 w1 w2 w3 w4];
[dbMarks,~,freqMarks] = bode(FinalTF,freqMarkers);
dbMarks = squeeze(dbMarks);
freqMarks = squeeze(freqMarks);
dbMarks = 20*log10(dbMarks);
freqMarks = freqMarks/2/pi;
semilogx(freqMarks,dbMarks,'r*');
And works great! Thanks to #Erik for the help.

You can use [mag,~,wout] = bode(sys) and then plot(wout,mag) to create the Bode plot. Then, using hold on and plot(...), you can add whatever points you need to the plot.
Note that wout is in radians per TimeUnit, which is a property of sys (source). To convert wout to a frequency axis in Hertz, you can set TimeUnit in sys using sys.TimeUnit = 'seconds' (which is the default, so probably unnecessary) and then f = wout/2/pi;. Plot it using plot(f,mag), then hold on and plot your markers.
To calculate the magnitude at certain frequencies, use mag = bode(sys,w); where w are the frequencies in radians per sys.TimeUnit. If sys.TimeUnit is 'seconds' and you frequencies are in Hertz, use w = 2*pi*f, where f are the frequencies you need.

Related

Lessening GPU processing power on MATLAB for plots

I have a graph with a lot of points and I want to be able to look at certain intervals using xlim. The issue is, when I increment the interval, I have to rerun my program. This is taking a lot of processing power.
So basically, I make graph using plot, then use xlim. I don't want to keep doing this. Is there a way to plot only certain intervals using plot? That way, MATLAB doesn't have to process the whole vector.
For example
A=[1,2,3,4]
and
B=[1,2,3,4]
If I do plot(A,B) then xlim(1,2) it would plot the graph first and then limit the interval. This takes a lot of processing power if you imagine a really massive complicated graph, thus I don't want to use plot using the normal method.
Is there a way to plot the graph on the interval x=[1,2] with only one function?
Update the XLimMode and NextPlot properties of your axes object before plotting. e.g.
x = randn(128,1);
y = randn(128,1);
hax = axes();
hax.XLimMode = 'manual';
hax.XLim = [1,2];
hax.NextPlot = 'add';
h = plot(x,y,'o','Parent',hax)
hax.NextPlot = 'replace'; % optional

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.

Issue when creating a code for a plot on Matlab

I am trying to create a plot using the below code, the plot it produces incorporates values of the x-axis from 0.5-1, however I need the plot to not incorporate this part on the x-axis, from values 0.5-1. I assumed that lines 9 & 10 of the code would exclude this part of the plot, however this is not the case.
Does anyone know what I would write for this part of the plot to be excluded. Thank you!
x = [0:0.01:1];
y = [0:0.01:1];
z = size(101,101);
for j = 1:101;
for k = 1:101;
z(j,k)=((x(j))./(0.5-y(k)));
if z(j,k)>1
z(j,k)=1;
elseif z(j,k)<0
z(j,k)=1;
end
end
end
surf(x,y,z)
xlim([0 .5]) sets the range to be displayed on the x axis. Use it after your plot command (surf).
x=[0:0.005:0.5];
This would exclude the data you do not want to see in the plot, but would give you better resolution for your answer.
MWc answer would work as well, but would just exclude the values from 0.5 on.
So it depends on exactly what you wanted to see given your overall problem.

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.

plotting pwelch with log axis

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?