how to calculate SNR in matlab from given two signals? - matlab

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.

Related

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)

How to Calculate the transfer function and plot it after making fourier transform in frequency domain in terms of magnitude and phase?

I have a trouble of plotting the transfer function in terms of magnitude and phase after making the Fourier transform of two signals.
First, I have used excel xlxs to read the column to plot in time domain and frequency domain, then I calculate the transfer function and this goes fine.
But for magnitude and phase, I have trouble for plotting them. I tired to plot them, but this is totally incorrect. Would someone help me with this?
Here is the code and excel file also.
solarcell1 = xlsread('solarcell.xlsx','A2:C100005');
t=solarcell1(:,1);
N=length(t);
Channel1V = solarcell1(:,2);
Channel2V = solarcell1(:,3);
sig1=Channel1V;
sig2=Channel2V;
fs=1/((solarcell1(3)-solarcell1(2))*1e-3);
FA1=fs/length(sig1);
FA2=fs/length(sig2);
frange1=-fs/2:FA1:fs/2-FA1;
frange2=-fs/2:FA2:fs/2-FA2;
subplot(3,2,1);
plot(t,sig1);
hold on
plot(t,sig2);
title('Input and Output of Solar cell');
xlabel('Time');ylabel('Amplitude');
subplot(3,2,2);
plot(t,sig2);
title('Output');
xlabel('Time');ylabel('Amplitude');
z1=fftshift(fft(sig1))/length(t);
subplot(3,2,3);
plot(frange1,abs(z1));
title('Input');
xlabel('Freq.');ylabel('Amplitude');
z2=fftshift(fft(sig2))/length(t);
subplot(3,2,4);
plot(frange2,abs(z2));
title('Output');
xlabel('Freq.');ylabel('Amplitude');
TFC=z2./z1;
magnitude=20*log(abs(TFC));
phase=atan2(imag(TFC),real(TFC));
subplot(3,2,5);
bode(frange1(1002:N),magnitude(1002:N));
title('Magnitude');
xlabel('Freq.');ylabel('Magnitude');
subplot(3,2,6);
semilogx(frange1(1002:N),phase(1002:N));
title('Phase');
xlabel('Freq.');ylabel('Phase');
I can see three issues in the code you provided.
First, your usage of bode is incorrect. This function takes a dynamic model system as argument, and you gave two vectors frange1(1002:N)and magnitude(1002:N). For now, I suggest you simply use plot instead.
subplot(3,2,5);
plot(frange1(1002:N),magnitude(1002:N));
title('Magnitude');
xlabel('Freq.');ylabel('Magnitude');
Then, your usage of semilogx is also risky when you have negative values for the x-axis. With frange1=-fs/2:FA1:fs/2-FA1; you shouldn't ask for semilogx of it. For now, I suggest plot.
Finally, I suggest you use unwrap to plot the phase.
subplot(3,2,6);
plot(frange1(1002:N),unwrap(phase(1002:N)));
title('Phase');
xlabel('Freq.');ylabel('Phase');
It plots:

Wrong results from THD calculation in MATLAB

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.

MATLAB Adding Gaussian fit to histogram

I am trying to add Gaussian fit to the histogram in MATLAB, but I do not know how to apply the fit to one particular peak only.
http://postimg.org/image/phms61rdh/ first plot
http://postimg.org/image/sindrn8er/ second plot
I am also posting part of the code I have been using:
data_Rb = (importdata('path\name.txt'));
counts_Rb = data_Rb.data(:,3);
figure
hist(counts_Rb, nbins);
xlim([0 120]);
title('Rubidium');
histfit(counts_Rb,1000);
pd=fitdist(counts_Rb(:),'normal')
x=0:0.001:120;
PDF=pdf(pd,x); %PDF is a vector of y values: it's our fit
PDF=PDF/max(PDF); %nor
y=ylim;
PDF=PDF*y(2);
hold on
plot(x,PDF,'r-','LineWidth',2);
hold off
These two blocks give me two different Gaussians as shown in the first picture. I do not understand why they fit data so badly: is it because of the tail on the RHS?
In the second plot I need to apply Gaussian fit to the last peak only. How should I do it?
And finally, after applying the fit, fit results are outputed onto the screen. Is there a function to save them into an array or so for later use?
Thanks in advance!
Regarding your last question, see How can I access the fitted distribution parameters from the HISTFIT function in Statistiics Toolbox ?
There is a workaround for this isssue by making a copy of the HISTFIT
function and modifying the code to pass out the "pd" variable. One way
to do this is to change the "h" output on the first line of the code
to "varargout" and add the following to the end of the file:
h = [hh; hh1];
argout={h,pd};
if nargout > length(argout)
error('Too many output arguments.');
end
[varargout{1:nargout}]=argout{1:nargout};

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?