Lab Connections are here!

This commit is contained in:
Silas Labor Zizour
2024-09-26 14:50:25 +02:00
parent 9571f73b24
commit 8577f5f6f4
13 changed files with 1078 additions and 40 deletions

View File

@@ -192,7 +192,7 @@ classdef ChannelFreqResp < handle
% iH(1) is DC ---> iH(end) is High Freq. % iH(1) is DC ---> iH(end) is High Freq.
H_inv = [iH(1) iH fliplr(conj(iH)) conj(iH(1))]; H_inv = [iH(1) iH fliplr(conj(iH)) conj(iH(1))];
H_inv = [iH(1) iH iH(end) fliplr(conj(iH)) conj(iH(1))]; % H_inv = [iH(1) iH iH(end) fliplr(conj(iH)) conj(iH(1))];
obj.H_apply = H_inv; obj.H_apply = H_inv;

View File

@@ -57,7 +57,7 @@ classdef PAMsource
end end
end end
if boolean(obj.applypulseform) && isempty(obj.pulseformer) if obj.applypulseform && isempty(obj.pulseformer)
warning('No Pulseformer given. Proceeding with RRC and alpha 0.05'); warning('No Pulseformer given. Proceeding with RRC and alpha 0.05');
options.pulseformer = Pulseformer("fsym",obj.fsym,"fdac",obj.fs_out,"pulse","rrc","pulselength",16,"rrcalpha",0.05); options.pulseformer = Pulseformer("fsym",obj.fsym,"fdac",obj.fs_out,"pulse","rrc","pulselength",16,"rrcalpha",0.05);
end end

View File

@@ -0,0 +1,417 @@
classdef AwgKeysight
% AWG implementation only for Keysight devices:
% a) M8196A (92 GSa/s 4Ch)
% b) M8199A (128 GSa/s 4Ch) % TODO
% c) M8199A_ILV (256 GSa/s 2Ch) % TODO
% d) M8199B (256 GSa/s 2Ch) % Commands worked in 2023
% Summary of SCPI Commands:
% *IDN? Identify the instrument.
% *RST Reset the instrument.
% :SOUR:FREQ:RAST <frequency> Set the DAC sample frequency.
% :OUTP<channel>:STAT ON Enable output for a channel.
% :VOLT<channel>:LEVel[:IMMediate][:AMPLitude] Set output voltage.
% :TRAC<channel>:DATA <data> Load waveform data.
% :INIT:IMM Start waveform generation.
% Construct Class:
% AWG = AwgKeysight("model","M8196A","fdac",92e9,"scaletodac",[1,1,1,1],"skews",[0,0,0,0],"voltages",[0,0,0,0.6]);
% Upload new Signal (use either normal array of doubles or Silas Informationsignal class)
% AWG.upload("Signal4",Signal);
properties(Access=protected)
model awg_model
fdac double
skews double
voltages double
scaletodac logical
numChannels double
waveformGranularity double
sampleMemorySize double
numProvidedSignals double
end
methods (Access=public)
function obj = AwgKeysight(options)
arguments
options.model awg_model
options.fdac double
options.skews double
options.voltages double
options.scaletodac logical
end
%
fn = fieldnames(options);
for n = 1:numel(fn)
try
obj.(fn{n}) = options.(fn{n});
end
end
switch obj.model
case awg_model.M8196A
obj.numChannels = 4;
obj.waveformGranularity = 128;
obj.sampleMemorySize = 512000;
case awg_model.M8199A
obj.numChannels = 4;
obj.waveformGranularity = 512;
obj.sampleMemorySize = 1024000; %to check
case awg_model.M8199A_ILV
obj.numChannels = 2;
obj.waveformGranularity = 512;
obj.sampleMemorySize = 1024000; %to check
case awg_model.M8199B
obj.numChannels = 2;
obj.waveformGranularity = 512;
obj.sampleMemorySize = 1024000; %to check
end
end
function upload(obj,channels,options)
arguments
obj
% leave this as it is! Important for further handling/ parsing
channels.signal1 Informationsignal = Informationsignal([])
channels.signal2 Informationsignal = Informationsignal([])
channels.signal3 Informationsignal = Informationsignal([])
channels.signal4 Informationsignal = Informationsignal([])
% add new optional arguments here
options.bla = 1;
end
% Every signal at this point is an Informationsignal!
% Argument block above casts everything to Informaionsignal...
% Count the number of nonempty Informationsignal
obj.numProvidedSignals = sum(structfun(@(x) ~isempty(x.signal), channels));
assert(obj.numProvidedSignals<=obj.numChannels,['Only ',num2str(obj.numChannels),' AWG Channels. User provided ',num2str(obj.numProvidedSignals),' waveforms!'])
% Additional check for invalid signals beyond available channels
if obj.numChannels == 2
% Check if Signal3 or Signal4 is nonempty
if ~isempty(channels.signal3.signal) || ~isempty(channels.signal4.signal)
error('Only 2 channels are available. Signals for Channel 3 and 4 should not be defined.');
end
end
% Extract the actual signals to cell array
unpackedSignals = {};
fn = fieldnames(channels);
for s = 1:obj.numChannels
unpackedSignals{s} = channels.(fn{s}).signal;
end
success = obj.upload_(unpackedSignals);
end
end
methods(Access=private)
function success = upload_(obj,signal)
%%%%%%%%%%%%%%%%%%%%%%
%%% PREPARE SIGNALS %%
%%%%%%%%%%%%%%%%%%%%%%
for s = 1:obj.numChannels
% assure laying row vector
signal{s} = reshape(signal{s},[1, length(signal{s})]);
% set to zeros if voltage == 0
if obj.voltages(s) == 0
signal{s} = signal{s} .* 0;
end
%scale to max DAC resolution
if obj.scaletodac(s)
factor = max(abs(signal{s}));
if factor~=0
signal{s} = signal{s}./factor;
end
end
% clip warning (if autoscale is off)
if ~isempty(signal{s})
clip(s) = sum(signal{s}>1);
if clip(s)
warning(['Clipwarning CH ',num2str(s),'. Clipped Samples', num2str(clip(s))]);
end
end
% The waveform granularity is e.g. 128. This means that the waveform length must be a multiple of this granularity. The minimum waveform length is 128 samples.
if rem(length(signal{s}),obj.waveformGranularity) ~= 0
signal{s} = [signal{s} signal{s}(:,1:(obj.waveformGranularity-rem(length(signal{s}),obj.waveformGranularity)))];
warning(['data should have a length multiple of ',num2str(obj.waveformGranularity),'!']);
end
% Digitally apply skews to the signals
if obj.skews(s) > 0
delay_sec = obj.skews(s)*1e-12;
signal{s} = delayseq(signal{s},delay_sec,obj.fdac);
end
% Scale to DAC values
signal{s} = int8(round(127 * signal{s}));
% Check signal length, truncate if too long for AWG
siglen = min(length(signal{s}),obj.sampleMemorySize);
signal{s} = signal{s}(1:siglen);
if siglen==obj.sampleMemorySize
warning(['Signal ',num2str(s),' was truncated to ',num2str(obj.sampleMemorySize),' to fit into AWG sample memory'])
end
end
%%%%%%%%%%%%%%%%%%%%%%
%%% CONNECT TO AWG %%%
%%%%%%%%%%%%%%%%%%%%%%
% read/write lock file to our ntserver/scratch
try
obj.check_lock(char(obj.model),1);
obj.lock_device(char(obj.model));
catch
warning('Could not reach ntserver to write lock!')
end
% Open Visa
switch obj.model
case awg_model.M8196A
v = visadev('TCPIP0::zizou.tf.uni-kiel.de::hislip0::INSTR');
case awg_model.M8196A
v = visadev('TCPIP0::localhost::hislip0::INSTR');
end
%check if channel config matches
writeline(v,'*opt?');
aw=readline(v);
assert(obj.numChannels==sscanf(aw, '%f'),['Wrong Channel config. AWG response: ',num2str(sscanf(aw, '%f')), ' Channels']);
switch obj.model
case awg_model.M8196A
obj.writeNcheck(v,':INST:DACM FOUR');
obj.writeNcheck(v,':ABORt');
obj.writeNcheck(v,sprintf(':FREQuency:RASTer %.15g;', obj.fdac));
case awg_model.M8199B
obj.writeNcheck(v,':ABORt ''M2'''); %war auf M2, das wird wohl der CH sein oder?
obj.writeNcheck(v,sprintf(':FREQ ''M1.ClkGen'', %.15g;', obj.fdac));
end
%%%%%%%%%%%%%%%%%%%%%%
%%% UPLOAD SIGNALS %%%
%%%%%%%%%%%%%%%%%%%%%%
for chan = 1:obj.numChannels
segm_num = 1; %we usually have one segment
segm_len = length(signal{chan});%there are max signl lengths
if segm_len > 0
switch obj.model
case awg_model.M8196A
% 1) TRAC DEl - delete the previous waveform
obj.writeNcheck(v,sprintf(':TRACe%d:DELete %d', chan, segm_num));
% 2) TRAC DEF - define properties of waveform
obj.writeNcheck(v,sprintf(':TRACe%d:DEFine %d,%d', chan, segm_num, segm_len));
% 3) TRAC DATA - load the new waveform
offset = 0;
cmd = sprintf(':TRACe%d:DATA %d,%d,', chan, segm_num, offset);
binblockwrite(v, signal{chan}, 'int8', cmd);
aw = obj.writeReceiveCheck(v,'*opc?');
% 4) SET VOLTAGE (not possible to set 0v)
obj.writeNcheck(v, sprintf(':VOLTage%d:AMPLitude %g', chan, obj.voltages(chan)));
% 5) SET OUTPUTS ON/ OFF (generation not started at this point)
obj.writeNcheck(v, sprintf(':OUTPut%d ON', chan));
case awg_model.M8199B
% 1) TRAC DEl - delete the previous waveform
xfprintf(f, sprintf(':TRAC:DEL ''M2.DataOut1'', %d', segm_num), 1);
xfprintf(f, sprintf(':TRAC:DEL ''M2.DataOut2'', %d', segm_num), 1);
% 2) TRAC DEF - define properties of waveform
xfprintf(f, sprintf(':TRAC:DEF ''M2.DataOut1'', %d,%d', segm_num, len));
xfprintf(f, sprintf(':TRAC:DEF ''M2.DataOut2'', %d,%d', segm_num, len));
% 3) TRAC DATA - load the new waveform
% Example command: :TRAC:DATA 'M1.DataOut1', 1, 0 , -127,-126,,-1,0,1,,127,-127,,-1,0,1,,127
% means : :TRAC:DATA 'identifier' , <segment_id>, <offset>, <block>|<numeric_values>
cmd = sprintf(':TRAC:DATA ''M2.DataOut1'', %d,%d,', segm_num, offset);
binblockwrite(f, data(1+offset:offset+len), dataFormat, cmd);
cmd = sprintf(':TRAC:DATA ''M2.DataOut2'', %d,%d,', segm_num, offset);
binblockwrite(f, data(1+offset:offset+len), dataFormat, cmd);
% 4) SET VOLTAGE (not possible to set 0v)
xfprintf(f, sprintf(':VOLT:AMPL ''M2.DataOut1'', %gv', awg_volt(1)));
xfprintf(f, sprintf(':VOLT:AMPL ''M2.DataOut2'', %gv', awg_volt(2)));
% xfprintf(f, ':VOLT:AMPL ''M2.DataOut2'', 0.1v');
% 5) SET OUTPUTS ON/ OFF
xfprintf(f, ':OUTP ''M2.DataOut1'', ON'); %sioe 11.23: Hier habe ich absichtlich auf OFF gestellt, wenn Kanal nicht bentigt!
xfprintf(f, ':OUTP ''M2.DataOut2'', ON');
end
end
end
% Set global output on/ off to start generation
switch obj.model
case awg_model.M8196A
obj.writeNcheck(v,':INIT:IMMediate');
case awg_model.M8199B
% :OUTP:GLOB 'M1.System', OFF
obj.writeNcheck(v, ':OUTP:GLOB ''M1.System'', ON');
obj.writeNcheck(v, ':OUTP:GLOB ''M2.System'', ON');
obj.writeNcheck(v,':INIT:IMMediate ''M2''');
end
% operation ceomplete (opc)
obj.writeNcheck(v,'*OPC');
aw = obj.writeReceiveCheck(v,'*opc?');
% close visa connection
delete(v);
% delete lock file to our ntserver/scratch
try
obj.release_lock(char(obj.model));
catch
warning('Could not reach ntserver to write lock!')
end
% at this point the signal upload should be successful :-)
success = 1;
end
function writeNcheck(~,visaobj,command)
% 1) send command to intstument
% 2) check if everything is okay
writeline(visaobj,char(command));
writeline(visaobj,':syst:err?');
err_aw=readline(visaobj);
assert(strfind(err_aw,"No error"),['AWG System Error? after command: ', char(command)])
end
function [aw]=writeReceiveCheck(~,visaobj,command)
% 1) send command to intstument
% 2) receive answer from instrument
% 3) check if everything is okay
writeline(visaobj,char(command));
aw = readline(visaobj);
writeline(visaobj,':syst:err?');
err_aw=readline(visaobj);
assert(strfind(err_aw,"No error"),['AWG System Error? after command: ', char(command)])
end
function check_lock(~,aDeviceName,lock_timeout)
pause(0.2);
rdy = 0;
for n = 1:(lock_timeout*100)
pause(0.1);
if rem(n,100) == 0
display(['waiting for device lock! (' num2str(n/10) 's)']);
button = questdlg(['Lab Measurement is LOCKED! ',...
'be careful'],...
'LOCKED','Wait','Unlock','Abort Meas','Wait') ;
switch button
case {'Abort Meas' ,''}
delete(findobj('name','Simulation Status Window'));
error('Measurement aborted by the user') ;
case 'Unlock'
rdy = 1;
break;
case 'Wait'
%wait another ten secs
end
end
% file_handle = fopen(['\\ntserver\scratch\labor\lock\' aDeviceName '.lock'],'r');
file_handle = fopen([filesep, filesep, 'ntserver.tf.uni-kiel.de', filesep, 'scratch', filesep 'Labor', filesep, 'lock', filesep, aDeviceName, '.lock'],'r');
if file_handle == -1
rdy = 1;
break;
end
time_flag=datenum(clock);
dev_flag = fread(file_handle,time_flag,'double');
fclose(file_handle);
if time_flag > dev_flag+60/(24*60)
rdy = 1;
break;
end
end
if ~rdy
errordlg([aDeviceName ' is locked by someone else!!!']);
errormsg('AWG2SCOPE',[aDeviceName ' is locked by someone else!!!']);
else
end
end
function lock_device(~,aDeviceName)
file_handle = fopen([filesep, filesep, 'ntserver.tf.uni-kiel.de', filesep, 'scratch', filesep 'Labor', filesep, 'lock', filesep, aDeviceName, '.lock'],'wb');
if ~isempty(file_handle)
time_flag=datenum(clock);
fwrite(file_handle,time_flag,'double');
fclose(file_handle);
end
end
function release_lock(~,aDeviceName)
pause(0.5);
delete([filesep, filesep, 'ntserver.tf.uni-kiel.de', filesep, 'scratch', filesep 'Labor', filesep, 'lock', filesep, aDeviceName '.lock']);
end
end
end

View File

@@ -1,6 +1,9 @@
classdef DC_supply classdef DC_supply
% Simple control of DC supply via fixed GBIB address. % Simple control of DC supply via fixed GBIB address.
% Agilent E3646A % Agilent E3646A
% No OVP or OCP implementation
% Not tested what happens if this script asks for Voltage in higher V
% Range (8V vs. 22V)
properties(Access=public) properties(Access=public)
active active
@@ -10,10 +13,10 @@ classdef DC_supply
methods (Access=public) methods (Access=public)
function obj = DC_supply(options) function obj = DC_supply(options)
arguments arguments
options.active bool = true options.active logical = true
options.voltage double = [0,0]; options.voltage double = [0,0];
end end
@@ -30,35 +33,40 @@ classdef DC_supply
end end
function success = set(obj) function success = set(obj,options)
success = false;
arguments
obj
options.voltage double = obj.voltage;
end
success = [0,0];
try try
%connect to device %connect to device
v = visadev("GPIB0::19::INSTR"); v = visadev("GPIB1::19::INSTR");
% fopen(v);
writeline(v, '*IDN?;'); writeline(v, '*IDN?;');
disp(['DC Source: ' readline(v)]); disp(['DC Source: ' readline(v)]);
cmd = 'INST:SEL?'; cmd = 'INST:SEL?';
fprintf(v, cmd); writeline(v, cmd);
selected_channel = fscanf(v); prev_selected_channel = readline(v);
for ch = 1:2 for ch = 1:2
% choose channel % choose channel
cmd = ['INST:SEL OUT',num2str(ch)]; cmd = ['INST:SEL OUT',num2str(ch)];
fprintf(v, cmd); writeline(v, cmd);
% get current voltage level % get current voltage level
cmd = ['VOLT?']; cmd = 'VOLT?';
fprintf(v, cmd); writeline(v, cmd);
act_volt = str2num(fscanf(v)); act_volt = str2num(readline(v));
% desired voltage (round to two digits after comma) % desired voltage (round to two digits after comma)
des_volt = round(obj.voltage(ch),2); des_volt = round(options.voltage(ch),2);
cnt = 0; cnt = 0;
while abs(act_volt-des_volt) > 0 while abs(act_volt-des_volt) > 0
@@ -66,9 +74,9 @@ classdef DC_supply
selected_channel = ['OUT',num2str(ch)]; selected_channel = ['OUT',num2str(ch)];
% get current voltage level % get current voltage level
cmd = ['VOLT?']; cmd = 'VOLT?';
fprintf(v, cmd); writeline(v, cmd);
act_volt = str2num(fscanf(v)); act_volt = str2num(readline(v));
% difference % difference
diff_volt = act_volt-des_volt; diff_volt = act_volt-des_volt;
@@ -76,7 +84,7 @@ classdef DC_supply
% set new voltage % set new voltage
increment_voltage = -0.01* sign(diff_volt) ; increment_voltage = -0.01* sign(diff_volt) ;
cmd = ['VOLT ',num2str(act_volt+increment_voltage)]; cmd = ['VOLT ',num2str(act_volt+increment_voltage)];
fprintf(v, cmd); writeline(v, cmd);
cnt = cnt+1; cnt = cnt+1;
if mod(cnt,100) == 0 if mod(cnt,100) == 0
@@ -84,9 +92,9 @@ classdef DC_supply
end end
% get current voltage level % get current voltage level
cmd = ['VOLT?']; cmd = 'VOLT?';
fprintf(v, cmd); writeline(v, cmd);
act_volt = str2num(fscanf(v)); act_volt = str2num(readline(v));
end end
@@ -94,31 +102,21 @@ classdef DC_supply
if act_volt ~= des_volt if act_volt ~= des_volt
hMsgBox = msgbox('An error occurred in dc supply module. Check if voltage is set correctly.'); hMsgBox = msgbox('An error occurred in dc supply module. Check if voltage is set correctly.');
uiwait(hMsgBox); uiwait(hMsgBox);
else
success(ch) = 1;
end end
end end
% choose channel % choose channel
cmd = ['INST:SEL ',selected_channel]; cmd = ['INST:SEL ',prev_selected_channel];
fprintf(v, cmd); writeline(v, cmd);
%disconnect %disconnect
fclose(v);
delete(v); delete(v);
catch catch
end end
end end
end
methods (Access=private)
end end
end end

287
Classes/05_Lab/OptAtten.m Normal file
View File

@@ -0,0 +1,287 @@
classdef OptAtten
% control optical attenuator Keysight N7764a via LAN
% set parameters of optical attenuator, e.g. attenuation, wavelength, etc. and read out output power from attenuator
properties(Access=public)
active %'Enable/Disable attenuator slots. Array position indexes detemines attenuator slot: [1->2 3->4 5->6 7->8]. Value determines mode: 0: off; 1: constant attenuation value; 2: constant output power';
value %'Set attenuation [dB] or constant output power [dBm]. Range attenuation [0, 45], range constant output power [-50, 20]';
speed %'Enter a desired speed for attenuation changes [dB/s]. Range: [0.1, 1000]';
wavelength %'Enter the wavelength of the applied light [nm]. Range: [1260, 1640]';
avgTime %'Enter a desired averaging time [ms]. Higher averaging times will increase stability of the readings but will slow down measurement speed. Range: [2, 1000]';
dbOffset %'A non-zero attenuation offset shifts the logarithmic attenuation scale. Then, the set attenuation value differs from the internally calibrated attenuation. Range [-200, 200]';
psetOffset %'A non-zero power offset shifts the logarithnic power scale. Then, the power reading and the set power (Pset) values differ from the internal power calibration. Range [-60, 60]';
end
methods (Access=public)
function obj = OptAtten(options)
arguments
options.active double = [0,0,0,0];
options.value double = [0,0,0,0];
options.speed double = [1000 1000 1000 1000];
options.wavelength double = [1550 1550 1550 1550];
options.avgTime double = [2 2 2 2];
options.dbOffset double = [0 0 0 0];
options.psetOffset double = [0 0 0 0];
end
fn = fieldnames(options);
for n = 1:numel(fn)
try
obj.(fn{n}) = options.(fn{n});
end
end
end
function success = set(obj,options)
arguments
obj
options.active = obj.active; %if not used as arg of .set('active',[0,0,0,0]) method the class values are used...
options.value = obj.value;
end
try
%connect to device
v = visadev('TCPIP::134.245.243.248::INSTR');
writeline(v, '*IDN?;');
disp(['Active atten: ' readline(v)]); %Keysight Technologies, N7764A, MY49A00696, 1.13.1
slot = 0; %init slot number
%loop to set values for every attenuator slot
for i = 1:length(obj.active)
%convert index number i into slot number
slot = 2*i - 1;
%check whether attenuator is used or unused
if ~obj.active(i) %atten slot unused
writeline(v, [':OUTP' num2str(slot) ':STAT OFF']);
else %atten slot used (attenuation/const output power)
%set attenuation or output power
if obj.active(i) == 1 %attenuation
if obj.value(i) < 0
obj.value(i) = 0;
hMsgBox = msgbox(['Value for attenuation out of range. Please consider minimum value. Attenuation set to ' num2str(obj.value(i)) 'dB']);
uiwait(hMsgBox);
elseif obj.value(i) > 45
obj.value(i) = 45;
hMsgBox = msgbox(['Value for attenuation out of range. Please consider maximum value. Attenuation set to ' num2str(obj.value(i)) 'dB']);
uiwait(hMsgBox);
end
writeline(v, [':OUTP' num2str(slot) ':POW:CONTR OFF']);
writeline(v, [':INP' num2str(slot) ':ATT ' num2str(obj.value(i)) 'dB']);
elseif obj.active(i) == 2 %constant output power
if obj.value(i) < -50
obj.value(i) = -50;
hMsgBox = msgbox(['Value for output power out of range. Please consider minimum value. Output power set to ' num2str(obj.value(i)) 'dBm']);
uiwait(hMsgBox);
elseif obj.value(i) > 20
obj.value(i) = 20;
hMsgBox = msgbox(['Value for output power out of range. Please consider maximum value. Output set to ' num2str(obj.value(i)) 'dBm']);
uiwait(hMsgBox);
end
writeline(v, [':OUTP' num2str(slot) ':POW:CONTR ON']);
writeline(v, [':OUTP' num2str(slot) ':POW ' num2str(obj.value(i))]);
end
%set value for speed
if obj.speed(i) < 0.1
obj.speed(i) = 0.1;
hMsgBox = msgbox(['Value for speed out of range. Please consider minimum value. Speed set to ' num2str(obj.speed(i)) 'dB/s']);
uiwait(hMsgBox);
elseif obj.speed(i) > 1000
obj.speed(i) = 1000;
hMsgBox = msgbox(['Value for speed out of range. Please consider maximum value. Speed set to ' num2str(obj.speed(i)) 'dB/s']);
uiwait(hMsgBox);
end
writeline(v, [':INP' num2str(slot) ':ATT:SPE ' num2str(obj.speed(i))]);
%set value for wavelength
if obj.wavelength(i) < 1260
obj.wavelength(i) = 1260;
hMsgBox = msgbox(['Value for wavelength out of range. Please consider minimum value. Wavelength set to ' num2str(obj.wavelength(i)) 'nm']);
uiwait(hMsgBox);
elseif obj.wavelength(i) > 1640
obj.wavelength(i) = 1640;
hMsgBox = msgbox(['Value for wavelength out of range. Please consider maximum value. Wavelength set to ' num2str(obj.wavelength(i)) 'nm']);
uiwait(hMsgBox);
end
wavelength_nm = obj.wavelength(i) * 1e-9;
writeline(v, [':INP' num2str(slot) ':WAV ' num2str(wavelength_nm)]);
%set value for averaging times
if obj.avgTime(i) < 2
obj.avgTime(i) = 2;
hMsgBox = msgbox(['Value for average time out of range. Please consider minimum value. Average time set to ' num2str(obj.avgTime(i)) 'ms']);
uiwait(hMsgBox);
elseif obj.avgTime(i) > 1000
obj.avgTime(i) = 1000;
hMsgBox = msgbox(['Value for average time out of range. Please consider maximum value. Average time set to ' num2str(obj.avgTime(i)) 'ms']);
uiwait(hMsgBox);
end
avgTime_sec = obj.avgTime(i) / 1000;
writeline(v, [':OUTP' num2str(slot) ':ATIM ' num2str(avgTime_sec)]);
%set value for attenuation offset and output power offset
if obj.dbOffset(i) < -200
obj.dbOffset(i) = -200;
hMsgBox = msgbox(['Value for attenuation offset out of range. Please consider minimum value. Attenuation offset set to ' num2str(obj.dbOffset(i)) 'dB']);
uiwait(hMsgBox);
elseif obj.dbOffset(i) > 200
obj.dbOffset(i) = 200;
hMsgBox = msgbox(['Value for attenuation out of range. Please consider maximum value. Attenuation offset set to ' num2str(obj.dbOffset(i)) 'dB']);
uiwait(hMsgBox);
end
writeline(v, [':INP' num2str(slot) ':OFFS ' num2str(obj.dbOffset(i)) 'dB']);
if obj.psetOffset < -60
obj.psetOffset = -60;
hMsgBox = msgbox(['Value for output power offset out of range. Please consider minimum value. Output power offset set to ' num2str(obj.psetOffset(i)) 'dBm']);
uiwait(hMsgBox);
elseif obj.psetOffset > 60
obj.psetOffset = 60;
hMsgBox = msgbox(['Value for output power offset out of range. Please consider maximum value. Output power offset set to ' num2str(obj.psetOffset(i)) 'dBm']);
uiwait(hMsgBox);
end
writeline(v, [':OUTP' num2str(slot) ':POW:OFFS ' num2str(obj.psetOffset(i))]);
%turn on attenuator slot
writeline(v, [':OUTP' num2str(slot) ':STAT ON']);
end
end
%pause 2 seconds before measuring output power
pause(2);
%read output power from attenuator and save to state.ouputpower
for i = 1:length(obj.active)
if obj.active(i)
%convert index number i into slot number
slot = 2*i - 1;
%read and save
writeline(v, [':READ' num2str(slot) ':POW?']);
state.outputpower(i) = sscanf(readline(v),'%f');
end
end
%create warning message when measured output power differs from
%set output power by 2dB.
for i = 1:length(obj.active)
if obj.active(i) == 2
%determine absolute difference
differ = abs(state.outputpower(i)-obj.value(i));
%create msgbox when necessary
if differ >= 2
hMsgBox = msgbox(['Output Power at attenuator slot ' num2str(2) ' differs by 2dB or more!']);
uiwait(hMsgBox);
end
end
end
%create output
for i = 1:length(obj.active)
if obj.active(i) == 2
% Output power mode:
%differ = abs(state.outputpower(i)-obj.value(i));
ch_info_txt = ['OptAtten: ',num2str(i),' -> Desired: ',num2str(obj.value(i)),' dBm; Cur Output: ',num2str(state.outputpower(i)),'dBm'];
disp(ch_info_txt);
else
ch_info_txt = ['OptAtten: ',num2str(i),' -> Attenuated by: ',num2str(obj.value(i)),' dB; Cur Output: ',num2str(state.outputpower(i)),'dBm'];
disp(ch_info_txt);
end
end
%disconnect
delete(v);
catch error
%disconnect if error occurrs
delete(v);
hMsgBox = msgbox('An error occurred while connecting or writing to the attenuator. Please try again. Otherwise, please restart MATLAB. For more information see error message in command window.');
uiwait(hMsgBox);
rethrow(error);
end
end
function readvals(obj)
try
%connect to device
v = visadev('TCPIP::134.245.243.248::INSTR');
writeline(v, '*IDN?;');
disp(['Active atten: ' readline(v)]); %Keysight Technologies, N7764A, MY49A00696, 1.13.1
power=[];
for s = 1:2:7
writeline(v, [':OUTP' num2str(s) ':STAT?']);
line = readline(v);
answer = sscanf(line,'%f');
disp(['Slot ' num2str(s) ' enabled state: ' num2str(answer)]);
writeline(v, [':OUTP' num2str(s) ':POW?']);
line = readline(v);
answer = sscanf(line,'%f');
disp(['P_set (output power) for Slot ' num2str(s) ': ' num2str(answer) ' dBm']);
writeline(v, [':OUTP' num2str(s) ':POW:CONTR?']);
line = readline(v);
answer = sscanf(line,'%f');
disp(['Power control for Slot ' num2str(s) ': ' num2str(answer)]);
if answer == 1
writeline(v, [':READ' num2str(s) ':POW?']);
line = readline(v);
answer = sscanf(line,'%f');
disp([' -> Slot ' num2str(s) ' desired outut power: ' num2str(answer) ' dBm']);
else
writeline(v, [':INP' num2str(s) ':ATT?']);
line = readline(v);
answer = sscanf(line,'%f');
disp([' -> Alpha (fix attenuation) for slot ' num2str(s) ': ' num2str(answer) ' dB']);
end
writeline(v, [':INP' num2str(s) ':WAV?']);
line = readline(v);
answer = sscanf(line,'%f');
disp(['Wavelength for Slot ' num2str(s) ': ' num2str(answer) ' nm']);
writeline(v, [':OUTP' num2str(s) ':ATIM?']);
line = readline(v);
answer = sscanf(line,'%f');
disp(['Averaging time for Slot ' num2str(s) ': ' num2str(answer) ' s']);
fprintf('\n')
end
delete(v);
catch error
%disconnect if error occurrs
delete(v);
hMsgBox = msgbox('An error occurred while connecting or writing to the attenuator. Please try again. Otherwise, please restart MATLAB. For more information see error message in command window.');
uiwait(hMsgBox);
rethrow(error);
end
end
end
end

View File

@@ -0,0 +1,279 @@
classdef ScopeKeysight
%NAME Summary of this class goes here
% Detailed explanation goes here
properties(Access=public)
model scope_model
fadc scope_fadc
channel
autoScale
extRef
interpolate
recordLen
IPaddress
end
methods (Access=public)
function obj = ScopeKeysight(options)
%NAME Construct an instance of this class
% Detailed explanation goes here
arguments
options.model scope_model = scope_model.DSAZ634A;
options.fadc scope_fadc = scope_fadc.GSa_160;
options.channel logical = [0,0,0,0];
options.autoScale logical = 0;
options.extRef logical = 1;
options.interpolate logical = 0;
options.recordLen double = 1000000;
options.IPaddress
end
%
fn = fieldnames(options);
for n = 1:numel(fn)
try
obj.(fn{n}) = options.(fn{n});
end
end
switch obj.model
case scope_model.DSAZ634A
case scope_model.UXR1102A
end
end
function recordedSignals = read(obj,options)
arguments
obj
options.channel logical = obj.channel
end
%%%%%%%%%%%%%%%%%%%%%%%%
%%% CONNECT TO SCOPE %%%
%%%%%%%%%%%%%%%%%%%%%%%%
if isempty(obj.IPaddress)
switch obj.model
case scope_model.DSAZ634A
v=visadev('TCPIP0::keysight.tf.uni-kiel.de::inst0::INSTR');% TCPIP0::127.0.0.1::inst0::INSTR
case scope_model.UXR1102A
v=visadev('TCPIP0::testscope.tf.uni-kiel.de::inst0::INSTR');% TCPIP0::127.0.0.1::inst0::INSTR
case scope_model.UXR1104A
v=visadev('TCPIP0::134.245.243.223::inst0::INSTR');
end
else
try
ressourceName=['TCPIP0::',char(obj.IPaddress),'::inst0::INSTR'];
v=visadev(ressourceName);
catch
error(['Could not connect to instrument using VISA. Check VISA ressourcename -> ', ressourceName]);
end
end
disp(['Connected to Instrument: ',char(v.Vendor),' ',char(v.Model),' SerNo:',char(v.SerialNumber)]);
% Check if Scope is ready to go
opdone = 0;
acqdone = 0;
procdone = 0;
while ~opdone || ~acqdone || ~procdone
opdone = sscanf(obj.writeReceiveCheck(v,'*opc?'), '%f');
acqdone = sscanf(obj.writeReceiveCheck(v,'ader?'), '%f');
procdone = sscanf(obj.writeReceiveCheck(v,'pder?'), '%f');
pause(0.005);
end
armed = sscanf(obj.writeReceiveCheck(v,'aer?'), '%f');
scope_state = strtrim(obj.writeReceiveCheck(v,'RSTate?'));
% Set sample rate / activate real edge
if obj.fadc == scope_fadc.GSa_160
obj.writeNcheck(v,':ACQuire:REDGe 1');
if length(obj.channel)>1
if obj.channel(2) == 1
error("CH 2 is invalid for Real Edge configuration. ONLY use channel 1 and 3 as shown on scope! Simply use [1,0,1,0] as channel config to record 1 and 3.")
end
elseif length(obj.channel)>3
if obj.channel(2) == 1 || obj.channel(4) == 1
error("CH 2 is invalid for Real Edge configuration. ONLY use channel 1 and 3 as shown on scope! Simply use [1,0,1,0] as channel config to record 1 and 3.")
end
end
else
obj.writeNcheck(v,':ACQuire:REDGe 0');
obj.writeNcheck(v,':ACQuire:SRATe %u',double(obj.fadc).*1e9);
end
%
for n = find(obj.channel == 1)
obj.writeNcheck(v,sprintf(':CHANnel%u:DISPlay ON',n));% display captured data trace
end
if obj.autoScale
obj.writeNcheck(v,':AUTOscale');
for n = 1:4
range = str2double(obj.writeReceiveCheck(v,sprintf(':CHANnel%u:RANGe?',n)));
obj.writeNcheck(v,sprintf(':CHANnel%u:RANGe %.3f',n,range/1.2));
end
else
obj.writeNcheck(v,':SINGLE');
end
if obj.extRef
switch obj.model
case scope_model.DSAZ634A
obj.writeNcheck(v,':TIMebase:REFClock HFR');
case scope_model.UXR1102A || scope_model.UXR1104A
obj.writeNcheck(v,':TIMebase:REFClock 1');
end
REFclock = strtrim(obj.writeReceiveCheck(v,':TIMebase:REFClock?'));
if ~strcmp(REFclock,'HFR')
obj.writeNcheck(v,':TIMebase:REFClock ON');
REFclock = strtrim(obj.writeReceiveCheck(v,':TIMebase:REFClock?'));
assert(~(strcmp(REFclock,'OFF') || strcmp(REFclock,'0')),'No Refclock found: Using internal')
end
else
obj.writeNcheck(v,':TIMebase:REFClock 0');
end
if obj.interpolate
obj.writeNcheck(v,'ACQ:INTerpolate INT16');
obj.writeNcheck(v,sprintf(':ACQuire:POINts %u',obj.recordLen+100));
else
obj.writeNcheck(v,sprintf(':ACQuire:POINts %u',obj.recordLen+100));
obj.writeNcheck(v,'ACQ:INTerpolate OFF');
end
obj.writeNcheck(v,':SYSTem:HEADer OFF'); % turn off system headers
obj.writeNcheck(v,':WAVEFORM:FORMAT WORD');% set the data format type to WORD
obj.writeNcheck(v,':WAVEFORM:BYTeorder LSBFirst');% Setup transfer of LSB first
obj.writeNcheck(v,':WAVEFORM:STReaming off');% Turn off waveform streaming
for n = find(obj.channel == 1)
obj.writeNcheck(v,sprintf(':CHANnel%u:DISPlay ON',n));% display captured data trace
end
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%%% Acquire Data from Scope %%%
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
obj.writeNcheck(v,':DIGitize');
recordedSignals = cell(size(obj.channel));
for n = find(obj.channel == 1)
recordedSignals{n} = obj.readChannel(v,n);
recordedSignals{n} = recordedSignals{n}(1:obj.recordLen);
obj.writeNcheck(v,sprintf(':CHANnel%u:DISPlay ON',n));
end
for n = find(obj.channel == 0)
recordedSignals{n} = [];
end
obj.writeNcheck(v,sprintf(':%s',scope_state));
obj.writeNcheck(v,'*OPC?');
end
end
methods (Access=private)
function captured_signal = readChannel(obj, v, aCH)
Format = 'word';
if strcmpi(Format,'word')
nBytes = 2;
blockReadType = 'int16';
elseif strcmpi(Format,'byte')
nBytes = 1;
blockReadType = 'int8';
else
error('Param.Format not recognized');
end
maxBlockSize = pow2(20);
obj.writeNcheck(v,sprintf(':WAVeform:SOURce CHANnel%u',aCH)); % read x origin:WAVeform:SOURce
xOrg = str2double(obj.writeReceiveCheck(v,':wav:xor?'));% read x origin
xInc = str2double(obj.writeReceiveCheck(v,':wav:xinc?'));% read x increment => 1/fadc
xRef = str2double(obj.writeReceiveCheck(v,':wav:xref?'));
yOrg = str2double(obj.writeReceiveCheck(v,':wav:yor?'));% read y origin
yInc = str2double(obj.writeReceiveCheck(v,':wav:yInc?'));% read y increment
yRef = str2double(obj.writeReceiveCheck(v,':wav:yref?'));
points = str2double(obj.writeReceiveCheck(v,':wav:points?'));
% timerperiod = max(10,1e-6*points*nBytes);
% set(v,'TimerPeriod',timerperiod);
timeout = min([max(10,1e-6*points*nBytes) 1000]);
set(v,'Timeout',timeout);
blockSize = min(pow2(ceil(log2(points))),maxBlockSize);
set(v,'InputBufferSize',nBytes*blockSize);
blockCount = int8(ceil(max(1,points/blockSize)));
for block = 0:blockCount - 1
startPoint = double(block) * blockSize + 1;
endPoint = min((double(block + 1)) * blockSize,points);
pointsRead = endPoint - startPoint + 1;
obj.writeNcheck(v, sprintf(':wav:data? %d,%d', startPoint, pointsRead));
%Wfm.data(startPoint:endPoint,1) = binblockread(v,blockReadType); %old Matlab
data(startPoint:endPoint,1) = readbinblock(v,blockReadType);
Junk = fread(v,1,'schar'); %#ok Read out end of file character.
end
%scale the signal back to volt
captured_signal = data*yInc+yOrg;
end
function writeNcheck(~,visaobj,command)
% 1) send command to intstument
% 2) check if everything is okay
writeline(visaobj,char(command));
% writeline(visaobj,':syst:err?');
% err_aw=readline(visaobj);
% assert(strfind(err_aw,"No error"),['AWG System Error? after command: ', char(command)])
end
function [aw]=writeReceiveCheck(~,visaobj,command)
% 1) send command to intstument
% 2) receive answer from instrument
% 3) check i f everything is okay
writeline(visaobj,char(command));
aw = readline(visaobj);
% writeline(visaobj,':syst:err?');
% err_aw=readline(visaobj);
% assert(strfind(err_aw,"No error"),['AWG System Error? after command: ', char(command)])
end
end
end

10
Datatypes/awg_model.m Normal file
View File

@@ -0,0 +1,10 @@
classdef awg_model < int32
enumeration
M8196A (1)
M8199A (2)
M8199A_ILV (3)
M8199B (4)
end
end

22
Datatypes/scope_fadc.m Normal file
View File

@@ -0,0 +1,22 @@
classdef scope_fadc < int32
enumeration
GSa_2_5 (2.5) %Gigasamples
GSa_4 (4) %Gigasamples
GSa_5 (5) %Gigasamples
GSa_10 (10) %Gigasamples
GSa_20 (20)
GSa_40 (40)
GSa_80 (80)
GSa_160 (160)
GSa_256 (256)
end
methods
function val = getValue(obj)
val = double(obj); % Convert int32 to double to get the numeric value
end
end
end

9
Datatypes/scope_model.m Normal file
View File

@@ -0,0 +1,9 @@
classdef scope_model < int32
enumeration
DSAZ634A (1)
UXR1102A (2)
UXR1104A (3)
end
end

View File

@@ -0,0 +1 @@

View File

@@ -3,15 +3,15 @@
params = struct; params = struct;
params.M = [4]; params.M = [4];
params.datarate = [300]; params.datarate = [224];
params.rop = [0]; params.rop = [-5];
precomp_mode = 0; %0=do nothing ; 1= measure; 2=precomp active precomp_mode = 2; %0=do nothing ; 1= measure; 2=precomp active
if ismac if ismac
precomp_path = "/Users/silasoettinghaus/Documents/MATLAB/imdd_simulation/projects/standard_system"; precomp_path = "/Users/silasoettinghaus/Documents/MATLAB/imdd_simulation/projects/standard_system";
else else
precomp_path = "C:\Users\Silas\Documents\MATLAB\imdd_simulation\projects\standard_system\"; precomp_path = "C:\Users\sioe\Documents\MATLAB\imdd_simulation\projects\standard_system\";
end end
precomp_fn = "400G_simulative_setup"; precomp_fn = "400G_simulative_setup";

15
test/awg_test.m Normal file
View File

@@ -0,0 +1,15 @@
if 0
AWG = AwgKeysight("model","M8196A","fdac",92e9,"scaletodac",[1,1,1,1],"skews",[0,0,0,0],"voltages",[0,0,0,0.6]);
tx_sig = Electricalsignal(clip_out,"fs",92e9);
tic
AWG.upload("signal4",clip_out);
toc
end
SCP = ScopeKeysight("model","DSAZ634A",'autoscale',1,"fadc",'GSa_160',"channel",[1],"recordLen",2000000);
signals = SCP.read();