classdef AWG %AWG Summary of this class goes here % Detailed explanation goes here properties(Access=public) kover %oversampling factor e.g. 16 repetitions %repeat the signal to generate a longer sequence? fdac %needed normalize %want to normalize at first? either 0 or 1 bit_resolution %bit res. of quantizer (e.g. 5 bit) dac_min dac_max skew_active = 0; awg_skew ; %skew vector for each output channel lpf_active = 0; lpf_type ; f_cutoff ; signal_length; H_lpf; end methods (Access=public) function obj = AWG(options) %AWG Construct an instance of this class % Detailed explanation goes here arguments options.preset = [] ; options.kover = 16; options.repetitions = 1; options.normalize = 1; options.fdac = 92e9; options.bit_resolution = 5.5 options.dac_min = -0.5; options.dac_max = 0.5; options.skew_active = 0; options.awg_skew = 0; options.lpf_active = 0; options.lpf_type = 0; options.f_cutoff = 32e9; end fn = fieldnames(options); for n = 1:numel(fn) try obj.(fn{n}) = options.(fn{n}); end end if options.preset == "M8196A" % M8196A (92GBd) https://www.keysight.com/us/en/product/M8196A/92-gsa-s-arbitrary-waveform-generators.html obj.dac_max = 0.5; obj.dac_min = -.5; obj.f_cutoff = 50e9; elseif options.preset == "M8199B" %https://www.keysight.com/us/en/assets/3120-1465/data-sheets/M8199A-128-256-GSa-s-Arbitrary-Waveform-Generator.pdf % obj.fdac = 256e9; obj.dac_max = 0.5; obj.dac_min = -.5; obj.f_cutoff = 80e9; end end function signalclass_out = process(obj,signalclass_in) % actual processing of the signal (steps 1. - 3.) signalclass_in.signal = obj.process_(signalclass_in.signal); % 4. Apply LPF on the signal if obj.lpf_active lpf = Filter('filtdegree',5,"f_cutoff",obj.f_cutoff,"fsamp",obj.kover*obj.fdac,"filterType",obj.lpf_type); signalclass_in = lpf.process(signalclass_in); end % cast the inform. signal to electrical signal signalclass_in = Electricalsignal(signalclass_in,"fs",obj.fdac*obj.kover,"logbook",signalclass_in.logbook); % append to logbook signalclass_in = signalclass_in.logbookentry(); % write to output signalclass_out = signalclass_in; end function elec_out = process_(obj,data_in) %METHOD1 Summary of this method goes here % Detailed explanation goes here arguments(Input) obj data_in end arguments(Output) elec_out end obj.signal_length = length(data_in); if obj.normalize % 0a Normalize the signal to 1 Vpp and set the amplitude of the signal data_in = data_in/(max(data_in)-min(data_in)); else % 0b Cut the Signal at -1 and 1 and scale to amplitude data_in(data_in > 1) = 1; data_in(data_in < -1) = -1; end % 1. Quantize the signal if obj.bit_resolution>0 elec_out = obj.quantization(data_in) ; else elec_out = data_in; end % 2. Sample and hold + repeat (data_out: 1xsignal length) elec_out = repmat(elec_out,obj.repetitions,obj.kover); elec_out = reshape(elec_out',[],1); % 3. Add skew if obj.skew_active elec_out = obj.skew(elec_out); end end end methods (Access=private) function quant_out = quantization(obj,x_in) steps = round(2^obj.bit_resolution) + rem(round(2^obj.bit_resolution),2) ; if isreal(x_in) % shift signal and clip to quantizer intervall x_in = min(max(x_in-obj.dac_min,0),obj.dac_max-obj.dac_min); % quantize signal x_in = round((steps-1)/(obj.dac_max-obj.dac_min)*x_in); % scale and shift back quant_out = x_in*(obj.dac_max-obj.dac_min)/(steps-1) +obj.dac_min; else % shift signal and clip to quantizer intervall x_in = min(max(real(x_in)-obj.dac_min,0),obj.dac_max-obj.dac_min) + ... 1i*min(max(imag(x_in)-obj.dac_min,0),obj.dac_max-obj.dac_min); % quantize signal and shift back signal x_in = round((steps-1)/(obj.max-obj.dac_min)*x_in); % scale and shift back quant_out = x_in*(obj.dac_max-obj.dac_min)/(steps-1) +(1+1i)*obj.dac_min; end end function skew_out = skew(obj,x_in) % Exact delay calculation % Calculate transfer function fsimu = obj.kover*obj.fdac; faxis = linspace(fsimu/2, fsimu/2, length(x_in)+1); faxis = fftshift(faxis(1:end-1)); skew_out = ifft(fft(x_in) .* exp(-1i*2*pi*obj.awg_skew*faxis)' ); skew_out = real(skew_out) ; % get rid of negligible imaginary part end end end