How to stop Matlab quantising a graph? - matlab

So I have 2 sine waves, one is the input to a system, the other being the output of the anti-aliasing bessel filter on the output of the system. There is a slight phase difference, so I've been using Matlab to work out the difference between the two waves. I then plot them both to compare them - however I get this:
As you can see, the input wave is a sine wave, however the output wave appears to be being quantised. In comparison, here's the two waves before I take the phase difference out:
As you can see the Bessel output is also a smooth sine wave.
Here's the code I'm using to plot the first graph:
yyaxis left
plot(Time(1:length(s1a1)),CIN(1:length(s1a1)))
ylabel('CIN')
yyaxis right
plot(Time(1:length(s1a1)),Bessel(-lagDiff+1:end))
ylabel('Bessel Out')
xlabel('Time')
title('CIN vs Bessel')
And here's the code for the second:
yyaxis left
plot(Time,CIN)
ylabel('CIN')
yyaxis right
plot(Time,Bessel)
ylabel('Bessel Out')
xlabel('Time')
title('CIN vs Bessel')
I'm using the exact same variables, the only difference is instead of using the whole length of the data I'm using only a portion. The weird thing is that this works fine for CIN - it's perfectly normal, only when I do it for Bessel does it do this weird quantisation thing.
Would appreciate if I could get a solution - I've already tried interp1 function with spline as the method, and that doesn't change anything. As well as that, I need to use this data elsewhere outside of MATLAB so I can't really alter it.
Any help would be greatly appreciated.
Some edits for MCV Example.
I have reproduced my input wave and output wave roughly using these functions:
Time = 0:0.00002:4;
Bessel = 0.1+(sin(((2*pi*1).*Time)-1)).*0.05;
CIN = 4400+(sin((2*pi*1).*Time).*4000);
L = length(Bessel);
L = L/20;
L=round(L);
Value = Bessel(L);
Bessel(1:L) = linspace(0,Value,L);
Code being used to remove phase shift is:
Fs = 50000;
t1 = (0:length(Bessel)-1)/Fs;
t2 = (0:length(CIN)-1)/Fs;
[acor,lag] = xcorr(CIN,Bessel);
[~,I] = max(abs(acor));
lagDiff = lag(I);
timeDiff = lagDiff/Fs;
s1a1 = Bessel(-lagDiff+1:end);
t1a1 = (0:length(s1a1)-1)/Fs;
s2a2 = CIN(1:length(s1a1));
When I then run it through my code I get the following:
It works for these waves, using the exact same code. But the only change I have made is the input wave, which as established above in my 2nd figure, the input wave is not an issue, it's only when I shift it, as in my 1st figure.
I don't know what the issue is, but it's definitely not the input wave.

Related

how to calculate SNR in matlab from given two signals?

I am working on calculating the SNR of given signals.
length = linspace(-2*pi,2*pi);
signal_1 = sin(length);
plot(signal_1);
noise_1 = 0.5*rand(size(signal_1));
plot(noise_1);
snr_22 = snr(signal_1,noise_1);
But it shows only the noise figure (attached below) whenever I run this, nothing else. But it should also show signal figures and SNR in decibels. Can anyone help me out? I am using Matlab R2015b.
As the documentation on snr() shows:
snr(___) with no output arguments plots the spectrum of the signal in the current figure window and labels its main features. It uses different colors to draw the fundamental component, the DC value and the harmonics, and the noise. The SNR appears above the plot. This functionality works for all syntaxes listed above except snr(x,y).
emphasis mine.
In other words, call figure; snr(signal_1,noise_1, __);, i.e. with at least one other input argument and no output argument, at the end of your code to have the spectrum appear. Otherwise, take a look at the contents of snr_22 and plot it by hand.

Signal smoothing algorithm (Matlab's moving average)

I have written a simple code that performs a 3-point moving average smoothing algorithm. It is meant to follow the same basic algorithm as Matlab's smooth(...) function as described here.
However, the result of my code is very different from that of Matlab's. Matlab's 3-point filter appears to perform a much more aggressive smoothing.
Here is a comparison of a noisy data smoothed using my code (red) and Matlab's function (blue):
Here is my code written in the form of a function:
function [NewSignal] = smoothing(signal)
NewSignal = signal;
for i = 2 : length(signal)-1
NewSignal(i,:) = (NewSignal(i,:)+NewSignal(i-1,:)+NewSignal(i+1,:))./3;
end
end
Matlab's function is used as follows:
signal = smooth(time, signal, 3, 'moving');
As far as I understand Matlab's function works the same way; it averages 3 adjacent bins to a single bin. So I expected both algorithms to produce the same results.
So, what is the reason for the discrepancy? And how could I tweak my code to produce the same results?
Edit:
My sample data can be found here. It can be accessed using:
M = csvread('DS0009.csv');
time = M(:,1);
signal = M(:,2);
Here is the new result (red plot) using rinkert's correction:
One reason for the difference could be that you are partially using your smoothed signal during smoothing. In your loop, you store the smoothed value in NewSignal(i,:), and for the next sample to smooth this value will be called by NewSignal(i-1,:).
Let NewSignal be determined by the original signal only:
function [NewSignal] = smoothing(signal)
NewSignal = signal;
for i = 2 : length(signal)-1
NewSignal(i,:) = (signal(i,:)+signal(i-1,:)+signal(i+1,:))./3;
end
end
Update: To show that the function above in fact does the same as Matlab's smooth function, let's consider this MVCE:
t = (0:0.01:10).'; % time vector
y = sin(t) + 0.5*randn(size(t));
y_smooth1 = smooth(t,y,3,'moving');
y_smooth2 = smoothing(y);
difference_methods = abs(y_smooth1-y_smooth2);
So creating a sine wave, add some noise, and determine the absolute difference between the two methods. If you take the sum of all the differences you will see that this adds up to something like 7.5137e-14, which cannot explain the differences you see.
Plotting the smooth signal (blue original, red smoothed):
figure(1); clf; hold on
plot(t,y)
plot(t,y_smooth2)
And then plotting the difference between the two methods:
figure(2); clf; hold on;
plot(t,y_smooth1-y_smooth2)
As you can see, the difference is of the order 1e-16, so influenced by the Floating-point relative accuracy (see eps).
To answer your question in the comments: the Function filter and smooth perform arithmetically the same (in the case that they are applied for moving average). however, there are the special cases at the beginning and endpoints which are handled differently.
This is also stated in the documentation of smooth "Because of the way smooth handles endpoints, the result differs from the result returned by the filter function."
Here you see it in an example:
%generate randonm data
signal=rand(1,50);
%plot data
plot(signal,'LineWidth',2)
hold on
%plot filtered data
plot(filter(ones(3,1)/3,1,signal),'r-','LineWidth',2)
%plot smoothed data
plot( smooth(signal,3,'moving'),'m--','LineWidth',2)
%plot smoothed and delayed
plot([zeros(1,1); smooth(signal,3,'moving')],'k--','LineWidth',2)
hold off
legend({'Data','Filter','Smooth','Smooth-Delay'})
As you can see the filtered data (in red) is just a delayed version of the smoothed data (in magenta). Additionally, they differ in the beginning. Delaying the smoothed data results in an identical waveform as the filtered data (besides the beginning). As rinkert pointed out, your approach overwrites the data points which you are accessing in the next step. This is a different issue.
In the next example you will see that rinkerts implementation (smooth-rinkert) is identical to matlabs smooth, and that your approach differs from both due to overwriting the values:
So it is your function which low passes the input stronger. (as pointed out by Cris)

Adding markers on specific points in bodeplot

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.

Plotting my .wav file in the time domain instead of freq. domain in MATLAB?

I'm writing a Matlab program to perform a convoluted sum of two signals. I first started out creating a simple sinusoidal signal and a carrier signal. I convoluted the two and created the convoluted signal. You can see that my (x) axis is specified in the time domain. My code and a screen shot of my plot is shown below for clarity.
MY CODE:
note: This program doesn't use the .wav file and instead uses a simple sinusoidal signal.
mySignalFreq = 1E3;
%T = 1/f;
T = 1/mySignalFreq;
tmin = 0;
tmax = 5*T;%i want to graph 5 time periods
dt = T/60;%used 60 to specify spaceing of time domain
t = tmin:dt:tmax;
myCarrierFreq = 560E3;
Bandwidth = 10E3;
omega_mySignal = 2*pi*mySignalFreq;%determine angular frequency
omega_myCarrier = 2*pi*myCarrierFreq;%determine angular frequency
modIndex = 0.8;%modulation index
myCarrierAmp = 4.0;%amplitude of carrier signal
ys = sin(omega_mySignal*t);
yc = sin(omega_myCarrier*t);
convSum = myCarrierAmp*(1+modIndex.*ys).*yc;%Convolution Sum
%create txt file with Write permissions
convolutionData.txt = fopen('convolutionData.txt','w');
%7.5 specifies 7digits and 5digits to the right of decimal
%have to use \r\n for readability
%array of values need to be in [x;y1;y2;y3] format
%comma in the function denotes the seperator
fprintf(convolutionData.txt,'%7.5f,%7.5f,%7.5f,%7.5f\r\n',[t;ys;yc;convSum]);
%close out file
fclose(convolutionData.txt);
%creating a basic plot of all three signals
plot(t,ys,'r',t,yc,'g',t,convSum,'b');
title('Convoluted Signal');
xlabel('Time Periods');
ylabel('Amplitude (Volts)');
grid on;
This is the picture of the plot above. You can see that i'm using the variable 't' as my x axis data.
I have finally figured out some code that plots my .wav file i created with a recorder. However, it's plots it in the frequency domain. As you can see in the code i'm reading the data in the .wav file into what I'm understanding is an array. Not quite understanding this part so if someone could explain more on that as a side note that would be great.
My main question is how do I incorporate the data from my .wav file into my original code above so it can be plotted in the time domain like my plot above? Just can't figure that part out because the code below is just doing it in the frequency domain.
Here is the code and plot of the .wav file
[wave,fs]=audioread('myvoice1.wav');
t=0:1/fs:(length(wave)-1)/fs;
subplot(2,1,1);
plot(t,wave);
n=length(wave)-1;
f=0:fs/n:fs;
wavefft=abs(fft(wave));
subplot(2,1,2);
plot(f,wavefft);
The upper subfigure in your last plot already is the right signal, so the t and wave are the right variables.
Only the second subfigure in your last plot is the frequency domain (represented in the wavefft variable).
Just use the wave variable and you should have what you want.

MATLAB program about sine and cosine functions

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.