classdef Scope %SCOPE Summary of this class goes here % Detailed explanation goes here properties fsimu fadc adcresolution quantbuffer rand_samplingdelay %on or off samplingdelay %specifiy a sampling delay freq_offset %offset of the sampler samp_jitter %include jitter fixed_delay %fix the delay of the filter or use minimal delay for kausal system delay %specify a fixed delay of the filter lpf_active filtertype lpf_bw H_lpf block_dc %during construction %during process Nout end methods function obj = Scope(options) %SCOPE Construct an instance of this class % Detailed explanation goes here arguments options.fsimu options.fadc options.adcresolution options.quantbuffer options.rand_samplingdelay = 0; options.samplingdelay = 0; options.freq_offset = 0; options.samp_jitter = 0; options.fixed_delay = 0; options.delay = 0; options.lpf_active = 0; options.filtertype = filtertypes.bessel_bilin; options.lpf_bw = 120e9; options.H_lpf; options.block_dc = 1; end fn = fieldnames(options); for n = 1:numel(fn) try obj.(fn{n}) = options.(fn{n}); end end end function signalclass_out = process(obj,signalclass_in) % actual processing of the signal signalclass_in.signal = obj.process_(signalclass_in.signal); signalclass_in.fs = obj.fadc; % apply LPF % 4. Apply LPF on the signal assert (signalclass_in.fs == obj.H_lpf.fs) if obj.lpf_active if isa(obj.H_lpf,'Filter') %4.A) user already specified a complete filter class when % initializing the AWG module signalclass_in = obj.H_lpf.process(signalclass_in); else %4.B) just use a standard filter obj.H_lpf = Filter('filtdegree',3,"f_cutoff",obj.lpf_bw,"fsamp",obj.fsimu,"filterType",obj.filtertype); signalclass_in = obj.H_lpf.process(signalclass_in); end end % cast the electrical signal to information signal signalclass_in = Informationsignal(signalclass_in,"fs",obj.fadc,"logbook",signalclass_in.logbook); % append to logbook lbdesc = ['Scope ']; signalclass_in = signalclass_in.logbookentry(lbdesc); % write to output signalclass_out = signalclass_in; end function yout = process_(obj,xin) %METHOD1 Summary of this method goes here % Detailed explanation goes here % sample signal % TODO: implement and test the delays. % resample yout = resample(xin,obj.fadc,obj.fsimu); % quantize signal yout = obj.quantize(yout); if obj.block_dc yout = yout-mean(yout,1); end end function jitvec = buildSamplingJitterVector(obj) % Generation of sampling jitter vector for real part of signal jitvec = obj.samp_jitter*randn(obj.Nout,1) ; % Avoid exceding the simulation block edges relentlessly! jitvec(1) = abs(jitvec(1)) ; jitvec(end) = -abs(jitvec(end)) ; end function sampout = sampleSignal(obj,xin) % Initialization sampler and output signal in case of 4real Tout = 1 / obj.fadc; % output signal sample period [sec] Tsig = length(xin) / obj.fsimu ; % simulation block period [sec] if obj.rand_samplingdelay == 1 obj.samplingdelay = Tout*rand ; end %get number of delayed samples Ndelay = floor(obj.samplingdelay*obj.fsimu) ; %get fractional sample delay fracdelay = obj.samplingdelay - Ndelay/obj.fsimu ; %calc number of samples after down-sampling no offset obj.Nout = ceil((Tsig - fracdelay)*obj.fadc) ; %build a jitter vector jitvec = obj.buildSamplingJitterVector(); % Create the index vector of the sampling instances for the real and imaginary part inx_re = ( (0: Tout : (obj.Nout-1) / obj.fadc)' + jitvec ) * obj.fsimu + 1 ; % Create the vector of the relative location of each sample between % to neighboring "Analog" samples for the real and imaginary part val_re = mod(inx_re,1) ; % Shift the signal xin = circshift(xin, [0 - Ndelay]) ; % Sample the signal using linear interpolation sampout = xin(floor(inx_re)) .* (1 - val_re) + xin(ceil(inx_re)) .* val_re ; sampout2 = resample(xin,obj.fadc,obj.fsimu); end function quantout = quantize(obj,xin) quant_steps = round(2^obj.adcresolution) + rem(round(2^obj.adcresolution),2); if quant_steps > 0 index = round(0.1*length(xin)); %sioe 2022: short blocksize resulted in error -> now 10%-90% of length are evaluated max_re = max(real(xin(index:end-index)))*(1+obj.quantbuffer/2); % adaptations in the indices min_re = min(real(xin(index:end-index)))*(1-obj.quantbuffer/2); %(1+para.max/2); range_re = max_re-min_re; max_im = max(imag(xin))*(1+obj.quantbuffer/2); min_im = min(imag(xin))*(1+obj.quantbuffer/2); range_im = max_im-min_im; if isreal(xin) % shift signal and clip to quantizer intervall xin = min(max(xin-min_re,0),range_re); % quantize signal xin = round((quant_steps-1)/range_re*xin); % scale and shift back quantout = xin*range_re/(quant_steps-1) +min_re; else % shift signal and clip to quantizer intervall xin_re = min(max(real(xin)-min_re,0),range_re); xin_im = min(max(imag(xin)-min_im,0),range_im); % quantize signal % quantize signal and shift back signal xin_re = round((quant_steps-1)/range_re*xin_re); xin_im = round((quant_steps-1)/range_im*xin_im); % scale and shift back quant_out_re = xin_re*range_re/(quant_steps-1) + min_re; quant_out_im = xin_im*range_im/(quant_steps-1) + min_im; quantout = quant_out_re + 1i * quant_out_im; end else quantout = xin; end end end end