-
Notifications
You must be signed in to change notification settings - Fork 19
/
RandMPChan.m
155 lines (130 loc) · 5.13 KB
/
RandMPChan.m
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
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
classdef RandMPChan < matlab.System
% RandMPChan: Random multi-path channel
%
% The channel impulse response is of the form:
%
% h(t) = \sum_k sqrt(g(k))*exp(1i*theta(k))*delta(t-dly(k))
%
% The path gains are generated by first computing un-normalized
% log normal values:
%
% g0(k) = d2bpow( v(k) ), v(k) ~N(0, gainStd^2)
%
% The values are then normalized to
%
% g(k) = d2pow( gainTot )*g0(k) / sum(g0(k))
%
% so that gainTot is the total wideband gain. The phases
% theta(k) ~ U[0,2*pi]. The delays are distributed as:
%
% dly(k) = dly0 + u(k),
%
% dly0 is U[dlyInitRange(1), dlyInitRange(2)] and u(k) is exponential
% with mean excessDlyMean.
properties
% Channel generation properties
npath; % number of paths
gainStd; % std dev of path gains in dB
gainTot; % total gain of paths in dB
dlyInitRange; % min and max delay in seconds of first path
excessDlyMean; % excess delay in seconds
wvar; % noise variance
fsamp; % sample rate in Hz
filLen; % fractional delay filter length
% Generated path parameters
dly; % path delays in seconds
phase; % phase in radians
gain; % channel gain in dB
% Number of output samples. Signal will be zero-padded
% if needed. A value of zero indicates not to fix the output
% size
nsampOut;
end
methods
function obj = RandMPChan(opt)
% Constructor
%
% Input parameters
% ----------------
% dlyInitRange: Range of delays for first path in seconds
% excessDlyMean: Mean delay of paths of initial paths
% npath: number of paths
% gainStd: std deviation of each path in dB
% gainTot: wideband gain in dB
% fsamp: Sampe frequency in Hz
% wvar: noise variance in linear scale
% filLen: Filter length in samples for fractional delays
arguments
opt.wvar (1,1) {mustBeNumeric} = 0;
opt.dlyInitRange (1,2) {mustBeNumeric} = [0,100e-6];
opt.excessDlyMean (1,1) {mustBeNumeric} = 50e-9;
opt.fsamp (1,1) {mustBeNumeric} = 40e6;
opt.gainStd (1,1) {mustBeNumeric} = 8;
opt.gainTot (1,1) {mustBeNumeric} = 0;
opt.npath (1,1) {mustBeInteger} = 20;
opt.nsampOut (1,1) {mustBeInteger} = 0;
opt.filLen (1,1) {mustBeInteger} = 32;
end
% Save the parameters
obj.wvar = opt.wvar;
obj.dlyInitRange = opt.dlyInitRange;
obj.fsamp = opt.fsamp;
obj.gainStd = opt.gainStd;
obj.gainTot = opt.gainTot;
obj.npath = opt.npath;
obj.nsampOut = opt.nsampOut;
obj.excessDlyMean = opt.excessDlyMean;
obj.filLen = opt.filLen;
end
function genPath(obj)
% Get random delay of first path
dly0 = unifrnd(obj.dlyInitRange(1), obj.dlyInitRange(2), 1);
% Generate random delays of other paths
obj.dly = dly0 + exprnd(obj.excessDlyMean, obj.npath,1);
% Generate random gains before normalization
obj.gain = obj.gainStd*randn(obj.npath,1);
% Normalize to unit gain
gainLin = db2pow(obj.gain);
gainLin = gainLin / sum(gainLin);
obj.gain = pow2db(gainLin) + obj.gainTot;
% Generate random phases
obj.phase = rand(obj.npath,1)*2*pi;
end
function r = dlySingPath(obj,x,gain,dly)
% dlySingPath: Simulates a single path channel with a delay in
% and gain.
% Find integer and fractional component of the delay
dly = dly*obj.fsamp;
dly1 = mod(dly,1);
dly0 = round(dly-dly1);
% Filter the fractional delay component
nfilt = obj.filLen;
tfilt = (-nfilt:nfilt)';
h = sinc(tfilt + dly1);
y = conv(h,x);
% Shift signal by fractional component
i0 = dly0-nfilt;
ny = length(y);
r = zeros(obj.nsampOut,1);
i1 = min(i0+ny-1, obj.nsampOut);
r(i0:i1) = db2mag(gain)*y(1:i1-i0+1);
end
end
methods (Access = protected)
function r = stepImpl(obj,x)
% Runs the time-domain x through the channel
% Compute the number of output samples
dlySamp = ceil(max(obj.dly)*obj.fsamp) + obj.filLen;
obj.nsampOut = dlySamp + length(x);
% Loop over paths
r = zeros(obj.nsampOut,1);
for ipath = 1:obj.npath
ri = obj.dlySingPath(x,obj.gain(ipath),obj.dly(ipath));
r = r + ri;
end
% Add noise
w = sqrt(obj.wvar/2)*(randn(obj.nsampOut,1) + 1i*randn(obj.nsampOut,1));
r = r + w;
end
end
end