summaryrefslogtreecommitdiff
path: root/pulse2snr.m
blob: 251bebf89dccc9066a4a06bc041e12c2239c38ce (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
function SNRdB = pulse2snr(P,N,M,ISILimit,NoiseRMS)
%SNR    signal to noise ratio of pulse response and RMS noise
%   Calculate SNR in dB from pulse response, considering UI centers
%   only. Assume bang-bang phase detection. Ignore ISI below limit.
%
%   The signal-to-noise ratio is calculated as follows
%   1. The sampling instants are determined by finding the bang-bang CDR lock
%      point for the input pulse response using the Hula-Hoop algorithm.
%   2. The cursor is the point equidistant to the two points identified in step
%      1; the cursor's amplitude is the signal power.
%   3. All of the other samples an integer of samples per symbol away from the cursor
%      that are greater than ISILimit in power are considered ISI noise.
%   4. ISI noise power is calculated as the root mean square (norm) of all ISI
%      points.
%   5. Cross talk noise is determined based on peak amplitude position in each
%      cross talk vector, if provided.
%   6. Total noise is the square-root of the squared sum of ISI noise power,
%      random noise power (NoiseRMS), and cross-talk power.
%   7. Signal and total noise are weighted depending on the modulation scheme,
%      used.  See formulas in code.
%
%   Inputs:
%     P - Pulse response
%     N - Samples per symbol
%     M - Modulation, number of levels
%     ISILimit - ISI limit, fraction of cursor. ISI values below this
%                threshold are considered not to contribute to total noise.
%     NoiseRMS - Noise RMS, V. Additional random noise power to be considered
%                towards SNR calculation.
%
%   Outputs:
%     SNRdB - Signal to Noise ratio (dB)

%   Copyright 2020 The MathWorks, Inc.

%Validate inputs
validateattributes(P,{'numeric'},{'2d','finite'},'SNR','P',1);
validateattributes(N,{'numeric'},...
    {'scalar','finite','integer','positive'},...
    'SNR','N',2);
validateattributes(M,{'numeric'},...
    {'scalar','finite','integer','positive'},...
    'SNR','M',3);
validateattributes(ISILimit,{'numeric'},...
    {'scalar','finite','positive','real'},...
    'SNR','ISILimit',4);
validateattributes(NoiseRMS,{'numeric'},...
    {'scalar','finite','positive','real'},...
    'SNR','NoiseRMS',5);

% Initialize ISI limit
if nargin < 4
    ISILimit = 0.0;
end

% Initialize noise RMS
if nargin < 5
    NoiseRMS = 0.0;
end

% Get number of points and number of aggressors
num_pts  = size(P, 1)    ;
num_aggr = size(P, 2) - 1;

% Look for Mueller-Muller lock point
i_curs = round(pulseRecoverClock(P(:,1), 2*N));
v_curs = P(i_curs, 1);

% Pre-/post-cursor positions, including cursor
i_isi_pre  = i_curs:-N:1      ;
i_isi_post = i_curs:+N:num_pts;

% ISI position & amplitude, excluding cursor
i_isi = [i_isi_pre(end:-1:2) i_isi_post(2:1:end)];
v_isi = P(i_isi, 1);

% Ignore ISI below threshold
i_isi = i_isi(abs(v_isi) >= v_curs * ISILimit);
v_isi = P(i_isi, 1);

% ISI RMS
isi_rms = norm(v_isi);

% Account for Xtalk if it's available
if num_aggr > 0
    
    % Find peak amplitude for all Xtalk pulses
    [~, i_peak] = max(abs(P(:, 2:end)), [], 1);
    
    % Shift Xtalk PRs to put peak to 1st position
    for i_aggr = 1:1:num_aggr
        P(:, i_aggr+1) = circshift(P(:, i_aggr+1), -(i_peak(i_aggr)-1));
    end % i_aggr
    
    % Sample Xtalk pulses, and calculate Xtalk RMS
    xt_rms = norm(P(1:N:end, 2:end));
else
    % Otherwise set Xtalk RMS to zero
    xt_rms = 0.0;
end

% Scale SNR components
if M == 4
    v_curs  = (   1     / 6) * v_curs ;
    isi_rms = ( sqrt(5) / 6) * isi_rms;
    xt_rms  = ( sqrt(5) / 6) * xt_rms ;
else
    v_curs  = (   1     / 2) * v_curs ;
    isi_rms = (   1     / 2) * isi_rms;
    xt_rms  = (   1     / 2) * xt_rms ;
end

% Combine all noise sources
n_total = norm([isi_rms xt_rms NoiseRMS]);

% SNR calculation
SNRdB = 10*log10((v_curs^2) / (n_total^2));
end