Display Signal Noise Ratio SNR in MATLAB? - matlab

I have go a clean signal (manchester coding), and the same signal with an including noise - what formula I have to use to get the Signal to Noise Ratio?
%manchester code
T = length(bits)/bitrate; % full time of bit sequence
n = 200;
N = n*length(bits);
dt = T/N;
t = 0:dt:T;
x = zeros(1,length(t)); % output signal
for i = 0:length(bits)-1
if bits(i+1) == 1
x(i*n+1:(i+0.5)*n) = 1;
x((i+0.5)*n+1:(i+1)*n) = -1;
else
x(i*n+1:(i+0.5)*n) = -1;
x((i+0.5)*n+1:(i+1)*n) = 1;
end
end

It is relatively easy to do this in Matlab and there are several approaches. Good to mention is, that there is the snr-function in the Signal Processing Toolbox. If you don't have it, then use the RMS-values like described here.
An alternative for zero-mean signals is to use an approach with the standard deviation or the variance. Important: They do only work when the mean (expected value) is zero.
Here the code:
% random data
bits = randi(2,1,20)-1;
bitrate = 1;
% manchester code
T = length(bits)/bitrate; % full time of bit sequence
n = 200;
N = n*length(bits);
dt = T/N;
t = 0:dt:T;
x = zeros(1,length(t)); % output signal
for i = 0:length(bits)-1
if bits(i+1) == 1
x(i*n+1:(i+0.5)*n) = 1;
x((i+0.5)*n+1:(i+1)*n) = -1;
else
x(i*n+1:(i+0.5)*n) = -1;
x((i+0.5)*n+1:(i+1)*n) = 1;
end
end
% add offset to test (approach with standard deviation
% and variance are NOT going to produce the correct SNR then)
%x = x + 1;
% x is the clean signal
s = x + 0.1*randn(size(x)); % noisy signal
e = s - x; % noise
% Matlab function in the Signal Processing Toolbox
SNR = snr(x,e)
% with RMS values
rms_x = sqrt(mean(x.^2));
rms_e = sqrt(mean(e.^2));
SNR = 10*log10((rms_x/rms_e)^2) % SNR in dB
SNR = 20*log10(rms_x/rms_e) % SNR in dB
% with standard deviation (only for signals with zero-mean)
sigma_x = std(x);
sigma_e = std(e);
SNR = 20*log10(sigma_x/sigma_e) % SNR in dB
% with variance (only for signals with zero-mean)
var_x = var(x);
var_e = var(e);
SNR = 10*log10(var_x/var_e) % SNR in dB
This is the result:
SNR =
20.1780
SNR =
20.1780
SNR =
20.1780
SNR =
20.1781
SNR =
20.1781

Related

FFT Not Getting Expected Results And Too Much Noise

Here's my code:
close all;clc;clear all;
f=fopen ('sum_021223.txt');
Adata=cell2mat(textscan(f, '%f %f %f %f %f'));
time=Adata(:,5);
data = Adata;
data(:,5:end) = 0;
final=size(data,1);
data(1,1)=data(2,1);
testsum=sum(data,2);
Fs = .5; % Sampling frequency
T = 1/Fs; % Sampling period
L = final; % Length of signal
t = (0:L-1)*T;
t=t';
Y=fft(testsum)
P2 = abs(Y/L);
P1 = P2(1:L/2+1);
P1(2:end-1) = 2*P1(2:end-1);
f = Fs*(0:(L/2))/L;
% P1(1,1)=P1(2,1);
plot(f,P1)
title("Single-Sided Amplitude Spectrum of X(t)")
xlabel("f (Hz)")
ylabel("|P1(f)|")
I believe I setup my code correct. I am sampling data once per 2 seconds. I have 30530 rows of data (About 17 hours worth)
However my FFT just looks like a bunch of noise, and I would expect some spikes around the smaller frequencies that would represent changes in air temperature and such over the day I took the data.
The input data on Dropbox.
I tried to set P1(1,1) to be equal to P1(2,1). This somewhat helped, but not really.
Your FFT looks corect, you have a very noisy data. You can maybe plot a power spectrum of that signal. You can distinguish different parts in the signal, here is function:
close all;clc;clear all;
f=fopen ('sum_021223.txt');
Adata=cell2mat(textscan(f, '%f %f %f %f %f'));
time=Adata(:,5);
data = Adata;
data(:,5:end) = 0;
final=size(data,1);
data(1,1)=data(2,1);
testsum=sum(data,2);
Fs = .5; % Sampling frequency
T = 1/Fs; % Sampling period
L = numel(testsum); % Length of signal
t = (0:L-1)*T;
t=t';
[f,y]=MyPower(testsum,Fs);
plot(f,y)
title("Single-Sided Amplitude Spectrum of X(t)")
xlabel("f (Hz)")
ylabel("|P1(f)|")
ylim([0,6e-3]);
function [f,y]=MyPower(y,freq)
tuReal = "seconds";
samples=numel(y);
period=1/freq;
time=linspace(0,samples*period,samples)';
signal=y;
Fs=freq;
% Compute effective sampling rate.
tNumeric = time2num(time,tuReal);
[Fs,irregular] = effectivefs(tNumeric);
Ts = 1/Fs;
% Resample non-uniform signals.
x = signal;
if irregular
x = resample(x,tNumeric,Fs,'linear');
end
% Set Welch spectrum parameters.
L = fix(length(x)/4.5);
noverlap = fix(L*50/100);
win = window(#hamming,L);
% Compute the power spectrum.
[ps,f] = pwelch(x,win,noverlap,[],Fs);
w = 2*pi*f;
% Convert frequency unit.
factor = funitconv('rad/TimeUnit', 'Hz', 'seconds');
w = factor*w;
Fs = 2*pi*factor*Fs;
% Remove frequencies above Nyquist frequency.
I = w<=(Fs/2+1e4*eps);
w = w(I);
ps = ps(I);
% Configure the computed spectrum.
ps = table(w, ps, 'VariableNames', ["Frequency", "SpectrumData"]);
ps.Properties.VariableUnits = ["Hz", ""];
ps = addprop(ps, {'SampleFrequency'}, {'table'});
ps.Properties.CustomProperties.SampleFrequency = Fs;
f=ps.Frequency;
y=ps.SpectrumData;
end

Matlab FFT: Power Spectral Density or Amplitude Spectral Density?

The amplitude of a FFT should be depending on the length of the signal.
To display the result in a independent way the Power Spectral Density or the Amplitude Spectral Density should be used. There are calculated as follows:
Amplitude FFT = Y
Signal Length = L
Power Spectral Density PSD = Y^2/L
Amplitude Spectral Density ASD = Y/sqrt(L)
https://www.sjsu.edu/people/burford.furman/docs/me120/FFT_tutorial_NI.pdf
My problem is, that the result of the Matlab fft is already indipendent from the signal length and I do not understand if this is already a PSD or a ASD.
Let's take the Matlab example Noisy Signal: https://ch.mathworks.com/help/matlab/ref/fft.html
If we make the FFT on the same signal, but twice or ten times longer, the FFT amplitude does not change.
This because of the line:
P2 = abs(Y/L);
where the amplitude is divided through the signal length. But why is the formula different from the PSD or the ASD formula and we still obtain amplitudes indipendent from the signal length?
In this example it is shown, that the two signals, ones for 50s, ones for 500s, has almost the same amplitudes.
% Signal 1
sps = 1000; % Sampling frequency
T = 1/sps; % Sampling period
Frequency1 = 150; % frequency 1 [Hz]
SignalAmplitude1 = 1; % mm/s
Frequency2 = 45; % dominant frequency [Hz]
SignalAmplitude2 = 1.2; % mm/s
L = 50; % Length of signal, sek.
L = L*1000; % convert to ms
time = (0:L-1)*T; % Time vector
Signal = cos(2*pi*Frequency1*time)*SignalAmplitude1 + sin(2*pi*Frequency2*time)*SignalAmplitude2;
f = sps*(0:(L/2))/L;
FFTcomplex = fft(Signal);
P2 = abs(FFTcomplex)/L;
P1 = P2(:,round(1:L/2+1));
P1(:,2:end-1) = 2*P1(:,2:end-1);
Ampl_FFT_1 = P1;
% Signal 2
sps = 1000; % Sampling frequency
T = 1/sps; % Sampling period
Frequency1 = 150; % frequency 1 [Hz]
SignalAmplitude1 = 1; % mm/s
Frequency2 = 45; % dominant frequency [Hz]
SignalAmplitude2 = 1.2; % mm/s
L = 500; % Length of signal, sek.
L = L*1000; % convert to ms
time = (0:L-1)*T; % Time vector
Signal = cos(2*pi*Frequency1*time)*SignalAmplitude1 + sin(2*pi*Frequency2*time)*SignalAmplitude2;
f = sps*(0:(L/2))/L;
FFTcomplex = fft(Signal);
P2 = abs(FFTcomplex)/L;
P1 = P2(:,round(1:L/2+1));
P1(:,2:end-1) = 2*P1(:,2:end-1);
Ampl_FFT_2 = P1;
sum(Ampl_FFT_2)-sum(Ampl_FFT_1)

Calculate the phase of a signal based on the generated data

I have written a simple code to calculate the phase and magnitude of a signal, based on the sinusoidal input given in my problem. I have already determined the magnitude of the signal corresponding to different values of w. More specifically, the phase I want is a vector calculated for different values of w. Notice that the signal I'm talking about is the output signal of a linear process. As matter of fact, I want the phase difference between the input u and the output y, defined for all values of w for all time steps. I have created the time and w vector in my code. Here is the main code I have written in MATAB2021a:
clc;clear;close all;
%{
Problem 2 Simulation, By M.Sajjadi
%}
%% Predifined Parameters
tMin = 0;
tMax = 50;
Ts = 0.01; % Sample Time
n = tMax/Ts; % #Number of iterations
t = linspace(tMin,tMax,n);
% Hint: Frequency Domain
wMin = 10^-pi;
wMax = 10^pi;
Tw = 10;
w = wMin:Tw:wMax; % Vector of Frequency
Nw = length(w);
a1 = 1.8;
a2 = -0.95;
a3 = 0.13;
b1 = 1.3;
b2 = -0.5;
%% Input Generation
M = numel(w);
N = length(t);
U = zeros(M,N);
Y = U; % Response to the sinusoidal Input, Which means the initial conditions are set to ZERO.
U(1,:) = sin(w(1)*t);
U(2,:) = sin(w(2)*t);
U(3,:) = sin(w(3)*t);
Order = 3; % The Order of the Differential Equation, Delay.
%% Main Loop for Amplitude and Phase
Amplitude = zeros(Nw,1); % Amplitude Values
for i=1:numel(w)
U(i,:) = sin(w(i)*t);
for j=Order+1:numel(t)
Y(i,j) = a1*Y(i,j-1) + a2*Y(i,j-2) + a3*Y(i,j-3) + ...
b1*U(i,j-1) + b2*U(i,j-2);
end
Amplitude(i) = max(abs(Y(i,:)));
end
I know I should use fft or findpeaks function in MATLAB, but I do not know how I should do it.

How can I rotate a plot in MATLAB?

I want to rotate the plot scatterplot(rxSig) (shown below) 8 degrees, for example.
(the group of the red dots in the photo)
it's not looks like a regular plot and I didn't found a relevant information for that.
Expected Result: (with rotation)
Plot without rotation:
R = 1000.0;
freq = 28*1e9;
T = 20.0;
lwd = 0.5;
F = fogpl(R,freq,T,lwd);
P = 101300.0;
W = 7.5;
G = gaspl(R,freq,T,P,W);
RR=[0.75,1.75,2.5,3];
for irr=1:length(RR)
R = rainpl(10000,freq,RR(irr));
L=R+F+G;
end
M = 64; % Modulation order
k = log2(M); % Bits per symbol
EbNoVec = (0:25)'; % Eb/No values (dB)
numSymPerFrame = 1000;
for n = 1:length(EbNoVec)
% Convert Eb/No to SNR
snrdB = EbNoVec(n) + 10*log10(k)-L(1);
% Reset the error and bit counters
numErrs = 0;
numBits = 0;
while numErrs < 200 && numBits < 1e8
% Generate binary data and convert to symbols
dataIn = randi([0 1],numSymPerFrame,k);
dataSym = bi2de(dataIn);
% QAM modulate using 'Gray' symbol mapping
txSig = qammod(dataSym,M);
% Pass through AWGN channel
rxSig = awgn(txSig,snrdB,'measured');
% Demodulate the noisy signal
rxSym = qamdemod(rxSig,M);
% Convert received symbols to bits
dataOut = de2bi(rxSym,k);
% Calculate the number of bit errors
nErrors = biterr(dataIn,dataOut);
% Increment the error and bit counters
numErrs = numErrs + nErrors;
numBits = numBits + numSymPerFrame*k;
end
% Estimate the BER
berEst(n) = numErrs/numBits;
end
berTheory = berawgn(EbNoVec,'qam',M);
semilogy(EbNoVec,berEst,'*')
hold on
semilogy(EbNoVec,berTheory)
grid
legend('Estimated BER with our attenuation function','Theoretical Matlab BER')
xlabel('Eb/No (dB)')
ylabel('Bit Error Rate')
scatterplot(rxSig)
I combined both my suggestions to create the following code.
% Extract data points from current figure
h = findobj(gca,'Type','line');
x_org=get(h,'Xdata');
y_org=get(h,'Ydata');
points = [x_org; y_org]';
% to rotate 8 degree counterclockwise
theta = 8;
% Rotation matrix
R = [cosd(theta) -sind(theta); sind(theta) cosd(theta)];
% Rotate points
points_rot = R*points';
figure(3)
plot(points_rot(1,:), points_rot(2,:), '.');
Adding this to the end of your code results in the following figure:

Create a sinusoidal wave with increasing steps frequencies matlab

I'm novice in matlab programing and I thank you in advance for your help.
I would like to generate un sinus wave function starting to 0.25 Hz and increasing every 8 oscillations by 0.05 Hz until 0.7 Hz. The amplitude is constant.
I try this code:
cyc = 8; % number of cycles
for lF= 0.25:0.05:0.7 %% Frequency Increment
t=1/fE:1/fE:(cyc/lF); % time per freq step
wave = sin(2*pi*t)
end
plot(wave)
Thank you for your help.
1) Try this:
cyc = 8; % number of cycles
wave = [];
T = [];
for f = 0.25:0.05:0.7 %% Frequency Increment
t=0.01/f:0.01/f:(cyc/f); % time per freq step
wave = [wave,sin(2*pi*f*t)];
if isempty(T)
T = t;
else
T = [T,T(end)+t];
end
end
plot(T,wave)
2) Following to comment, the code with memory preallocation:
cyc = 8; % number of cycles
Npoints = 100; % number of points in one cycle
f = 0.25:0.05:0.7; %% Frequency Increment
Nf = length(f);
wave = zeros((cyc*Npoints-1)*Nf+1,1);
T = zeros((cyc*Npoints-1)*Nf+1,1);
t0 = 0;
t_f = linspace(0,cyc,cyc*Npoints); % time*frequency per freq step
for nf = 1:length(f)
ind = (nf-1)*(cyc*Npoints-1)+(1:cyc*Npoints);
wave(ind) = sin(2*pi*f(nf)*t_f);
T(ind) = t0 + t/f(nf);
t0 = t0+cyc/f(nf);
end
plot(T,wave)
3) Vectorized version:
t = cyc*linspace(0,1,cyc*Npoints)';
wave = sin(2*pi*t(:,ones(Nf,1)));
t = bsxfun(#plus,cumsum([0,cyc./f(1:end-1)]),bsxfun(#times,1./f,t))'; % for MATLAB version less than 2016b
[t,ind] = unique(t); wave = wave(ind); % remove duplicate values
plot(t,wave)