Robochameleon  v1.0
signal_interface.m
Go to the documentation of this file.
1 classdef signal_interface
2  properties (SetAccess=protected) % Read-only (can be changed only by a method)
3  Fc = 0;
4  Fs;
5  Rs; % Symbol rate
6  P; % Power
7  PCol; % Power per column in signal field
8  end
9 
10  properties (SetAccess=protected,Hidden=true)
11  E;
12  end
13 
14  methods
15  function obj = signal_interface(signal,param)
16  if isfield(param,'Fc') && isscalar(param.Fc), obj.Fc = param.Fc; else obj.Fc = 1; end
17  if isfield(param,'Fs') && isscalar(param.Fs), obj.Fs = param.Fs; else robolog('Sampling frequency must be specified','ERR'); end
18  if isfield(param,'Rs') && isscalar(param.Rs), obj.Rs = param.Rs; else obj.Rs = 1; end
19  if isvector(signal)
20  signal = signal(:);
21  end
22  obj.E = signal;
23  if isfield(param, 'PCol')
24  if ~isa(param.PCol,'pwr')
25  robolog('Power needs to be specified as object of "pwr" class.','ERR');
26  else
27  if numel(param.PCol) ~= size(obj.E, 2)
28  robolog('The number of "pwr" objects in PCol must match the number of columns of the signal.', 'ERR');
29  end
30  obj.PCol = param.PCol;
31  obj.P = setPtot(obj);
32  end
33  elseif isfield(param,'P')
34  if ~isa(param.P,'pwr')
35  robolog('Power needs to be specified as object of "pwr" class.','ERR');
36  end
37  if length(param.P) > 1
38  robolog('Power cannot be an array of "pwr" object. Use PCol instead.','ERR');
39  end
40  obj.P = param.P;
41  avpow = pwr.meanpwr(signal);
42  pwrfraction = avpow/sum(avpow);
43  obj.PCol = repmat(obj.P, obj.N, 1).*pwrfraction;
44  else
45  robolog('Calculating power automatically - may be wrong', 'NFO0');
46  robolog(' Set power using pwr object constructor:', 'NFO0');
47  robolog(' signal = signal_interface(waveform, struct(''P'', pwr(SNR, Ptot), ...);', 'NFO0');
48  robolog(' where SNR is in dB and Ptot is in dBm', 'NFO0');
49  robolog(' See signal_interface and pwr documentation for more options', 'NFO0');
50  avpow = pwr.meanpwr(signal);
51  obj.PCol = pwr(inf, {avpow(1),'W'});
52  for jj=2:obj.N
53  obj.PCol(jj) = pwr(inf, {avpow(jj),'W'});
54  end
55  obj.P = setPtot(obj);
56  end
57  %Check that user is not specifying properties that do not exist
58  f = fieldnames(param);
59  props = {'Fc', 'Fs', 'Rs', 'PCol', 'P'};
60  [~,ai,~] = intersect(f,props);
61  ai2 = false(size(f)); ai2(ai)=true; ai2=~ai2;
62  if any(ai2), robolog('Following properties: %s are not used by signal_interface.', 'WRN', strjoin(strcat('''',f(ai2),''''),', ')); end
63 
64 
65  end
66 
67  function obj = fun1(obj,fun)
68  obj.enforceLhs(nargout);
69  s = cellfun(fun,mat2cell(get(obj),obj.L,ones(1,obj.N)),'UniformOutput',false);
70  if ~all(cellfun(@(c)isequal(size(c),size(s{1})),s))
71  robolog('Outputs after fun1 have different lengths. Cannot concatenate.','ERR');
72  end
73  obj.E = cell2mat(s);
74  % Compute new power.
75  % WARNING: SNR is not updated
76  Pout = pwr.meanpwr(obj.getRaw);
77  for i=1:length(obj.PCol)
78  PCol_new(i) = pwr(obj.PCol(i).SNR, {Pout(i), 'W'});
79  end
80  obj.PCol = PCol_new;
81  obj.P = setPtot(obj);
82  end
83 
84  function p = params(obj)
85  p = struct( ...
86  'Fs', obj.Fs, ...
87  'Rs', obj.Rs, ...
88  'Fc', obj.Fc, ...
89  'P', obj.P, ...
90  'PCol', obj.PCol ...
91  );
92  end
93 
94  function L = L(obj)
95  L = size(obj.E,1);
96  end
97 
98  function N = N(obj)
99  N = size(obj.E,2);
100  end
101 
102  function obj = mtimes(obj,M)
103  if isscalar(M)
104  M = M*eye(obj.N);
105  end
106  if ~isequal(size(M),([obj.N obj.N]))
107  robolog('Jones matrix must be a NxN square matrix.','ERR');
108  end
109 
110  Fnew=zeros(size(get(obj)));
111  Pscale=zeros(obj.N, 1);
112  for i=1:obj.N
113  Fnew(:,i) = get(obj)*M(i,:).';
114  Pscale(i) = norm(M(:,i), 2)^2;
115  end
116  obj.E = Fnew;
117  %power scaling
118  obj.PCol = obj.PCol.*Pscale;
119  obj.P = setPtot(obj);
120  end
121 
122  function Nss = Nss(obj)
123  % Oversampling rate of the signal
124  Nss = obj.Fs/obj.Rs;
125  end
126 
127  function Ts = Ts(obj)
128  % Sampling time of the signal
129  Ts = 1/obj.Fs;
130  end
131 
132  function Tb = Tb(obj)
133  % Symbol time of the signal
134  Tb = 1/obj.Rs;
135  robolog('Don''t use Tb for symbol time. Use 1/Rs. This function will be soon removed','WRN');
136  end
137 
138  function Pout = setPtot(obj)
139  Pout = obj.PCol(1);
140  for jj=2:numel(obj.PCol)
141  Pout = Pout + obj.PCol(jj);
142  end
143  end
144 
145  function ind = end(obj, k, n)
146  if n == 1
147  ind=obj.L*obj.N;
148  elseif n == 2
149  if k==1
150  ind=obj.L;
151  elseif k==2
152  ind=obj.N;
153  end
154  else
155  robolog('signal_interface has only two dimensions', 'ERR');
156  end
157  end
158 
159  function sref = subsref(obj,s)
160  switch s(1).type
161  case '.'
162  sref = builtin('subsref',obj,s);
163  case '()'
164  % If length(obj) > 1 obj is a vector fo signal_interface and the builtin method should be
165  % called
166  % length(s) <= 2 seems unuseful. Can be removed?
167  if length(s) <= 2 && length(obj) == 1
168  EScaled = obj.get;
169  sref = builtin('subsref',EScaled,s);
170  return
171  else
172  sref = builtin('subsref',obj,s);
173  end
174  case '{}'
175  error('MYDataClass:subsref',...
176  'Not a supported subscripted reference')
177  end
178  end
179 
180  function s = get(obj)
181  s = getScaled(obj);
182  end
183 
184  function s = getRaw(obj)
185  s = obj.E;
186  end
187 
188  function s = getScaled(obj)
189  % Modified by Robert to include power scaling (28.08.2014).
190  s = obj.E;
191  Pin = pwr.meanpwr(s);
192  for jj=1:obj.N
193  Pout(jj) = obj.PCol(jj).Ptot('W');
194  end
195  if Pin ~=0
196  s = bsxfun(@times, s, sqrt(Pout./Pin));
197  else
198  s = s;
199  if Pout>0;
200  robolog('Cannot scale waveform with 0 power to %.2e W','WRN', Pout)
201  end
202  end
203  end
204 
205  function s = getNormalized(obj)
206  snorm = obj.normalize();
207  s = snorm.E;
208  end
209 
210  function sigout=normalize(obj)
211  s = obj.E;
212  s = s/sqrt(mean(pwr.meanpwr(s)));
213  sigout = set(obj, s);
214  end
215 
216  function obj = plus(obj1,obj2)
217  %check inputs
218  param = struct('Fs',obj1.Fs);
219  N = obj1.N;
220  L = obj1.L;
221  if param.Fs~=obj2.Fs || N~=obj2.N || L~=obj2.L
222  robolog('Sampling rate, and signal sizes of both signals must be equal.','ERR');
223  end
224  param.Rs = obj1.Rs;
225  if param.Rs~=obj2.Rs
226  robolog('Assuming symbol rate of the first signal (%sBd).', 'WRN', formatPrefixSI(param.Rs,'%1.1f'));
227  end
228  param.PCol = obj1.PCol+obj2.PCol; %TEMPORARY - for SNR only; power should be calculated numerically b/c of coherence issues
229 
230  %frequency offset
231  Fc1 = obj1.Fc;
232  Fc2 = obj2.Fc;
233  param.Fc = (Fc1+Fc2)/2;
234  s1 = bsxfun(@times,getScaled(obj1),exp(2j*pi*(Fc1-param.Fc)/param.Fs*(0:L-1)'));
235  s2 = bsxfun(@times,getScaled(obj2),exp(2j*pi*(Fc2-param.Fc)/param.Fs*(0:L-1)'));
236 
237  % waveform addition
238  s = s1+s2;
239 
240  %power tracking
241  avpower = pwr.meanpwr(s);
242  for jj = 1:N
243  param.PCol(jj) = pwr(param.PCol(jj).SNR, {avpower(jj), 'W'});
244  end
245 
246  obj = signal_interface(s,param);
247  obj.P = setPtot(obj);
248  end
249 
250  function obj = truncate(obj, L)
251  obj.enforceLhs(nargout);
252  sig = get(obj);
253  obj = set(obj, sig(1:L, :));
254  end
255 
256  function obj = combine(varargin)
257  obj=Combiner_v1.combine(varargin);
258  end
259 
260  function disp(obj)
261  % Overload display function (for easy viewing in the console and
262  % debugger)
263  if isreal(get(obj))
264  txt_sig = 'Real';
265  else
266  txt_sig = 'Complex';
267  end
268  if obj.Fc == 1
269  strFc = 'Undefined ';
270  strWavelength = 'Undefined ';
271  else
272  strFc = formatPrefixSI(obj.Fc,'%1.3f');
273  strWavelength = formatPrefixSI(const.c/obj.Fc,'%1.5f');
274  end
275  if obj.Rs == 1
276  strRs = 'Undefined ';
277  strTs = 'Undefined ';
278  strNss = 'Undefined ';
279  else
280  strRs = formatPrefixSI(obj.Rs,'%1.1f');
281  strTs = formatPrefixSI(1/obj.Rs,'%1.1f');
282  strNss = formatPrefixSI(obj.Nss,'%1.2f');
283  end
284  fprintf(1,[
285  '%s signal\n' ...
286  ' Length: %sSa\n'...
287  'Number of components: %d\n'...
288  ' Sampling rate: %sHz (%ss)\n'...
289  ' Symbol rate: %sBd (%ss)\n'...
290  ' Oversampling ratio: %sSa/symbol\n'...
291  ' Carrier frequency: %sHz (%sm)\n'...
292  '\n' ],...
293  txt_sig,...
294  formatPrefixSI(obj.L,'%1.0f'),...
295  obj.N,...
296  formatPrefixSI(obj.Fs,'%1.2f'),formatPrefixSI(obj.Ts,'%1.2f'),...
297  strRs, strTs,...
298  strNss,...
299  strFc, strWavelength);
300 
301  disp(obj.P);
302  end
303 
304  function obj = set(obj,varargin)
305  rescaleP = 0;
306  rescalePCol = 0;
307  obj.enforceLhs(nargout);
308  if numel(varargin)==1
309  obj.E = varargin{1}; % TODO input checking --- can only be a matrix
310  if numel(obj.PCol)~=size(obj.E, 2)
311  robolog('The number of "pwr" objects in PCol must match the number of columns of the signal.', 'WRN');
312  robolog('Resetting quasi-arbitrarily. This warning will become an error in the future.', 'WRN');
313  if numel(obj.PCol)>size(obj.E, 2);
314  obj.PCol = obj.PCol(1:size(obj.E, 2));
315  else
316  obj.PCol = repmat(obj.P/obj.N, obj.N, 1);
317  end
318  obj.P = setPtot(obj);
319  end
320  elseif rem(nargin,2)
321  for i=1:(nargin-1)/2
322  obj.(varargin{2*i-1}) = varargin{2*i};
323  if strcmp(varargin{2*i-1}, 'P'), rescalePCol=1; end
324  if strcmp(varargin{2*i-1}, 'PCol')
325  if numel(varargin{2*i}) ~= size(obj.E, 2)
326  robolog('The number of "pwr" objects in PCol must match the number of columns of the signal.', 'ERR');
327  end
328  rescaleP=1;
329  end
330  end
331  else
332  robolog('Bad key-value pairs.','ERR');
333  end
334  if rescaleP, obj.P = setPtot(obj); end
335  if rescalePCol, obj.PCol = repmat(obj.P/obj.N, obj.N, 1); end
336  if rescalePCol && rescaleP
337  robolog('Both power per column and total power were specified. Power per column takes precedence')
338  end
339  end
340 
341  end
342 
343  methods (Access=private,Hidden,Static)
344 
345  function enforceLhs(n,minimum)
346  %ENFORCELHS Enforces assignment on the LHS to a certain
347  %number of arguments
348  if nargin<2
349  minimum = 1;
350  end
351  if n<minimum
352  robolog('When using this method, you must ensure that LHS exists. Due to memory considerations, overwriting the original object is recommended.','ERR');
353  end
354  end
355 
356  end
357 
358 end
Signal description class.
power description class
Definition: pwr.m:27
function P(in obj, in varargin)
Depreciated get for power.
function robolog(in msg, in varargin)
This function allows the user to print log messages in a standard way.
static function meanpwr(in x)
Mean signal power and energy.