Merge remote-tracking branch 'origin/main'
This commit is contained in:
@@ -193,14 +193,14 @@ classdef Signal
|
|||||||
end
|
end
|
||||||
|
|
||||||
%% Add signals from one signal to another, the first object will sustain
|
%% Add signals from one signal to another, the first object will sustain
|
||||||
function Difference = minus(X,y)
|
function Diff = minus(X,y)
|
||||||
|
|
||||||
if isa(y,'Signal')
|
if isa(y,'Signal')
|
||||||
Difference = X;
|
Diff = X;
|
||||||
Difference.signal = X.signal - y.signal;
|
Diff.signal = X.signal - y.signal;
|
||||||
elseif isnumeric(y)
|
elseif isnumeric(y)
|
||||||
Difference = X;
|
Diff = X;
|
||||||
Difference.signal = X.signal - y;
|
Diff.signal = X.signal - y;
|
||||||
end
|
end
|
||||||
|
|
||||||
end
|
end
|
||||||
@@ -303,9 +303,11 @@ classdef Signal
|
|||||||
xlim([-obj.fs/2 obj.fs/2].*1e-9)
|
xlim([-obj.fs/2 obj.fs/2].*1e-9)
|
||||||
edgetick = 2^(nextpow2(obj.fs*1e-9));
|
edgetick = 2^(nextpow2(obj.fs*1e-9));
|
||||||
% xticks([-edgetick:16:edgetick]);
|
% xticks([-edgetick:16:edgetick]);
|
||||||
xlim([-244, 244])
|
xlim([100*round( min(w.*1e-9)/100,1)-10,100*round( max(w.*1e-9)/100,1)+10])
|
||||||
ylim([-120,10]);
|
ylim([100*round( min(p_dbm)/100,1)-3,100*round( max(p_dbm)/100,1)+3]);
|
||||||
yticks([-200:10:10]);
|
yticks([-200:10:10]);
|
||||||
|
grid on
|
||||||
|
grid minor
|
||||||
legend
|
legend
|
||||||
|
|
||||||
end
|
end
|
||||||
@@ -423,8 +425,8 @@ classdef Signal
|
|||||||
|
|
||||||
end
|
end
|
||||||
|
|
||||||
%% Synchronize with reference
|
%%
|
||||||
function [obj,D,cuts] = tsynch(obj,options)
|
function [obj,S] = tsynch(obj,options)
|
||||||
% time sync and cut
|
% time sync and cut
|
||||||
arguments
|
arguments
|
||||||
obj Signal
|
obj Signal
|
||||||
@@ -440,29 +442,36 @@ classdef Signal
|
|||||||
b = options.reference.resample("fs_in",options.fs_ref,"fs_out",obj.fs).normalize("mode","oneone").signal;
|
b = options.reference.resample("fs_in",options.fs_ref,"fs_out",obj.fs).normalize("mode","oneone").signal;
|
||||||
|
|
||||||
%estimate delay between signals
|
%estimate delay between signals
|
||||||
[co,lags] = xcorr(a,b,100);
|
[co,lags] = xcorr(a,b);
|
||||||
[~,pos] = max(co);
|
[~,pos] = max(co);
|
||||||
D = lags(pos);
|
D = lags(pos);
|
||||||
|
|
||||||
if D == 100
|
%estimate start pos of signal
|
||||||
warning('Check Sync: Delay is found to be 100 which is the max. windowlength is xcorr function!')
|
maxpeaknum = floor(length(a)/length(b));
|
||||||
|
[pks,pkpos] = findpeaks(co./max(co),'MinPeakDistance',length(b)/2,'MinPeakHeight',0.2,'NPeaks',maxpeaknum);
|
||||||
|
shifts = lags(pkpos);
|
||||||
|
|
||||||
|
%Cut occurences of ref signal from signal
|
||||||
|
S = {};
|
||||||
|
for c = shifts
|
||||||
|
sig = obj.delay(-c,'mode','samples');
|
||||||
|
sig.signal = sig.signal(1:length(b));
|
||||||
|
S{end+1,1} = sig;
|
||||||
end
|
end
|
||||||
|
|
||||||
% delay by lagging samples
|
%plot all synced signals and the ref signal
|
||||||
obj = obj.delay(-D,'mode','samples');
|
debug = 0;
|
||||||
|
if debug
|
||||||
cuts = obj.length-(options.reference.length*q);
|
figure;hold on;
|
||||||
|
for i = 1:size(S,1)
|
||||||
if cuts > 10
|
plot(S{i}.normalize('mode','oneone').signal(1000:1100),'LineWidth',0.1,'Color',[0.2157 0.4941 0.7216]);
|
||||||
warning('Check Sync: Signal difference larger than 10.')
|
plot(b(1000:1100),'LineWidth',1);
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
if cuts < 0
|
%return the sinal with the highest correlation...
|
||||||
% warning('Check Sync: Reference Signal shorter than signal to sync.')
|
[~,idx]=max(pks);
|
||||||
else
|
obj.signal = S{idx}.signal;
|
||||||
% then cut out the length of the reference
|
|
||||||
obj.signal = obj.signal(1:end-cuts);
|
|
||||||
end
|
|
||||||
|
|
||||||
|
|
||||||
end
|
end
|
||||||
@@ -623,7 +632,6 @@ classdef Signal
|
|||||||
% beautify
|
% beautify
|
||||||
colormap(cbrewer2("Blues",4096));
|
colormap(cbrewer2("Blues",4096));
|
||||||
|
|
||||||
|
|
||||||
if isa(obj,'Opticalsignal')
|
if isa(obj,'Opticalsignal')
|
||||||
title("Optical Eye")
|
title("Optical Eye")
|
||||||
ylabel("Power in mW");
|
ylabel("Power in mW");
|
||||||
@@ -673,41 +681,15 @@ classdef Signal
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
% Define properties
|
|
||||||
boxPosition = [0.15 0.86 0.2 0.05]; % Position for the first box [x y width height]
|
|
||||||
boxColor = [0.9 0.9 0.9]; % Light grey background color
|
|
||||||
boxEdgeColor = 'k'; % Black edge color
|
|
||||||
boxLineStyle = '--'; % Dashed line style
|
|
||||||
boxFontWeight = 'bold'; % Bold font
|
|
||||||
|
|
||||||
% Create first annotation box for Power
|
|
||||||
annotation('textbox', boxPosition, ...
|
|
||||||
'String', ['Power: ',num2str(pwr_dbm),' dBm'], ...
|
|
||||||
'BackgroundColor', boxColor, ...
|
|
||||||
'EdgeColor', boxEdgeColor, ...
|
|
||||||
'LineStyle', boxLineStyle, ...
|
|
||||||
'FontWeight', boxFontWeight, ...
|
|
||||||
'HorizontalAlignment', 'center');
|
|
||||||
|
|
||||||
% Adjust position for the second box (slightly to the right)
|
|
||||||
boxPosition = [0.37 0.86 0.2 0.05]; % Adjusted position
|
|
||||||
|
|
||||||
% Create second annotation box for PAPR
|
|
||||||
annotation('textbox', boxPosition, ...
|
|
||||||
'String', ['PAPR(lin):',num2str(papr_),''], ...
|
|
||||||
'BackgroundColor', boxColor, ...
|
|
||||||
'EdgeColor', boxEdgeColor, ...
|
|
||||||
'LineStyle', boxLineStyle, ...
|
|
||||||
'FontWeight', boxFontWeight, ...
|
|
||||||
'HorizontalAlignment', 'center');
|
|
||||||
|
|
||||||
try
|
try
|
||||||
hist_interest = plot_data(:,posxall);
|
hist_interest = plot_data(:,posxall);
|
||||||
hist_interest_smoth = smooth(hist_interest,20);
|
hist_interest_smoth = smooth(hist_interest,20);
|
||||||
a = scatter(hist_interest_smoth+posxall,1:length(hist_interest_smoth),4,'.','MarkerEdgeColor','red');
|
a = scatter(hist_interest_smoth+posxall,1:length(hist_interest_smoth),4,'.','MarkerEdgeColor','red');
|
||||||
|
|
||||||
[pk,loc] = findpeaks(hist_interest_smoth,"MinPeakDistance",40,"NPeaks",M,"MinPeakHeight",30);
|
[pk,loc] = findpeaks(hist_interest_smoth,"MinPeakDistance",10,"NPeaks",M,"MinPeakHeight",30,"MinPeakProminence",10);
|
||||||
|
|
||||||
scatter(posxall,loc,'red','Marker','x','LineWidth',2);
|
scatter(posxall,loc,'red','Marker','x','LineWidth',2);
|
||||||
|
|
||||||
yline(loc,'Color','red','LineWidth',1,'LineStyle',':');
|
yline(loc,'Color','red','LineWidth',1,'LineStyle',':');
|
||||||
|
|
||||||
for i = 1:numel(loc)
|
for i = 1:numel(loc)
|
||||||
@@ -738,6 +720,37 @@ classdef Signal
|
|||||||
thirdboxstring = ['OMA outer:',num2str(er),' V'];
|
thirdboxstring = ['OMA outer:',num2str(er),' V'];
|
||||||
end
|
end
|
||||||
|
|
||||||
|
plot_infos = 0;
|
||||||
|
if plot_infos
|
||||||
|
|
||||||
|
% Define properties
|
||||||
|
boxPosition = [0.15 0.86 0.2 0.05]; % Position for the first box [x y width height]
|
||||||
|
boxColor = [0.9 0.9 0.9]; % Light grey background color
|
||||||
|
boxEdgeColor = 'k'; % Black edge color
|
||||||
|
boxLineStyle = '--'; % Dashed line style
|
||||||
|
boxFontWeight = 'bold'; % Bold font
|
||||||
|
|
||||||
|
% Create first annotation box for Power
|
||||||
|
annotation('textbox', boxPosition, ...
|
||||||
|
'String', ['Power: ',num2str(pwr_dbm),' dBm'], ...
|
||||||
|
'BackgroundColor', boxColor, ...
|
||||||
|
'EdgeColor', boxEdgeColor, ...
|
||||||
|
'LineStyle', boxLineStyle, ...
|
||||||
|
'FontWeight', boxFontWeight, ...
|
||||||
|
'HorizontalAlignment', 'center');
|
||||||
|
|
||||||
|
% Adjust position for the second box (slightly to the right)
|
||||||
|
boxPosition = [0.37 0.86 0.2 0.05]; % Adjusted position
|
||||||
|
|
||||||
|
% Create second annotation box for PAPR
|
||||||
|
annotation('textbox', boxPosition, ...
|
||||||
|
'String', ['PAPR(lin):',num2str(papr_),''], ...
|
||||||
|
'BackgroundColor', boxColor, ...
|
||||||
|
'EdgeColor', boxEdgeColor, ...
|
||||||
|
'LineStyle', boxLineStyle, ...
|
||||||
|
'FontWeight', boxFontWeight, ...
|
||||||
|
'HorizontalAlignment', 'center');
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
annotation('textbox', boxPosition, ...
|
annotation('textbox', boxPosition, ...
|
||||||
@@ -749,6 +762,8 @@ classdef Signal
|
|||||||
'HorizontalAlignment', 'center');
|
'HorizontalAlignment', 'center');
|
||||||
end
|
end
|
||||||
|
|
||||||
|
end
|
||||||
|
|
||||||
yticks(linspace(0,histpoints,16));
|
yticks(linspace(0,histpoints,16));
|
||||||
y_tickstring = sprintfc('%.2f', y_tickstring);
|
y_tickstring = sprintfc('%.2f', y_tickstring);
|
||||||
yticklabels(y_tickstring);
|
yticklabels(y_tickstring);
|
||||||
|
|||||||
@@ -132,7 +132,7 @@ classdef ChannelFreqResp < handle
|
|||||||
|
|
||||||
fstarget = Target.fs;
|
fstarget = Target.fs;
|
||||||
|
|
||||||
% Build new frequencie axis (with current fs)
|
% Build new frequency axis (with current fs)
|
||||||
fnew = linspace(0,fstarget/2,length(Target)/2+1);
|
fnew = linspace(0,fstarget/2,length(Target)/2+1);
|
||||||
fnew = fnew(2:end-1);
|
fnew = fnew(2:end-1);
|
||||||
|
|
||||||
@@ -154,7 +154,7 @@ classdef ChannelFreqResp < handle
|
|||||||
|
|
||||||
%smoothing takes time and sometimes the result looks odd,
|
%smoothing takes time and sometimes the result looks odd,
|
||||||
%however the performance is most of the time better
|
%however the performance is most of the time better
|
||||||
smoothing = 1;
|
smoothing = 0;
|
||||||
if smoothing
|
if smoothing
|
||||||
iH = smooth(fnew,iH,0.1,'loess')';
|
iH = smooth(fnew,iH,0.1,'loess')';
|
||||||
end
|
end
|
||||||
@@ -163,16 +163,10 @@ classdef ChannelFreqResp < handle
|
|||||||
% angle (-pi,pi) at lowest frequency
|
% angle (-pi,pi) at lowest frequency
|
||||||
iH = iH.*exp(-1j*angle(iH(1))); % to be checked (<- not from silas, so what needs to be checked?)
|
iH = iH.*exp(-1j*angle(iH(1))); % to be checked (<- not from silas, so what needs to be checked?)
|
||||||
|
|
||||||
% Phase difference between lowest and hiughest frequency
|
|
||||||
% component -> but what is this for? dPhase is not used...
|
|
||||||
noncausal = 0;
|
|
||||||
if noncausal
|
|
||||||
dPhase = angle(iH(end))-angle(iH(1));
|
|
||||||
end
|
|
||||||
|
|
||||||
% normalize complex freq. resp. by magnitude at the first
|
% normalize complex freq. resp. by magnitude at the first
|
||||||
% five frequencies -> should be the vaue at f=0=DC component?
|
% five frequencies -> should be the vaue at f=0=DC component?
|
||||||
iH = iH./mean(abs(iH(1:100))); %why 1:5??
|
iH = iH./mean(abs(iH)); %why 1:5??
|
||||||
|
|
||||||
% set maximum amplification
|
% set maximum amplification
|
||||||
% set als values higher than hmax to hmax and keep the
|
% set als values higher than hmax to hmax and keep the
|
||||||
@@ -191,19 +185,20 @@ 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 0 fliplr(conj(iH))];
|
||||||
|
|
||||||
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;
|
||||||
|
|
||||||
Target.signal = real((ifft( ( fft(real( Target.signal )) .* H_inv' ) )));
|
Target.signal = real((ifft( ( fft(real( Target.signal' )) .* H_inv ) )));
|
||||||
|
Target.signal = Target.signal';
|
||||||
|
|
||||||
end
|
end
|
||||||
|
|
||||||
function plot(obj)
|
function plot(obj)
|
||||||
|
|
||||||
figure(55551);
|
figure(55);
|
||||||
clf;
|
clf;
|
||||||
|
|
||||||
Havg = obj.H;
|
Havg = obj.H;
|
||||||
@@ -290,6 +285,7 @@ classdef ChannelFreqResp < handle
|
|||||||
end
|
end
|
||||||
|
|
||||||
function data = load(obj, options)
|
function data = load(obj, options)
|
||||||
|
|
||||||
% Function to load data from a specified file and path.
|
% Function to load data from a specified file and path.
|
||||||
arguments
|
arguments
|
||||||
obj
|
obj
|
||||||
@@ -334,6 +330,12 @@ classdef ChannelFreqResp < handle
|
|||||||
% Load the data from the specified file
|
% Load the data from the specified file
|
||||||
loadedData = load(fullFileName);
|
loadedData = load(fullFileName);
|
||||||
|
|
||||||
|
if ~strcmp(fieldnames(loadedData),'obj')
|
||||||
|
% user want to load a moveit precomp file
|
||||||
|
obj.H = 1./loadedData.uFF;
|
||||||
|
obj.faxis = loadedData.f;
|
||||||
|
else
|
||||||
|
|
||||||
% Replace whole obj here.. is this save or unsave?!
|
% Replace whole obj here.. is this save or unsave?!
|
||||||
fn = fieldnames(loadedData.obj);
|
fn = fieldnames(loadedData.obj);
|
||||||
for n = 1:numel(fn)
|
for n = 1:numel(fn)
|
||||||
@@ -342,6 +344,8 @@ classdef ChannelFreqResp < handle
|
|||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
end
|
||||||
|
|
||||||
fprintf('Frequency response information successfully loaded from %s\n', fullFileName);
|
fprintf('Frequency response information successfully loaded from %s\n', fullFileName);
|
||||||
end
|
end
|
||||||
|
|
||||||
@@ -373,25 +377,28 @@ classdef ChannelFreqResp < handle
|
|||||||
|
|
||||||
function [rH] = estHfromDMT(obj, data_in, ref_in)
|
function [rH] = estHfromDMT(obj, data_in, ref_in)
|
||||||
|
|
||||||
%! Dont (circ)shift the signal here as this would remove the phase information!
|
|
||||||
%tested with a butterworth filter this exactly reconstructs the
|
|
||||||
%phase and the magnitude. However, the option is here
|
|
||||||
estimatephase = 1;
|
|
||||||
|
|
||||||
if ~estimatephase
|
Nfft = 2*obj.Nacq + 1 ;
|
||||||
|
data_in = reshape(data_in,1,length(data_in));
|
||||||
|
ref_in = reshape(ref_in,1,length(ref_in));
|
||||||
|
|
||||||
|
if length(data_in) ~= length(ref_in)
|
||||||
% 0. cross-correlate the received signal with its reference to extract the periods
|
% 0. cross-correlate the received signal with its reference to extract the periods
|
||||||
corr = abs(ifft( fft(data_in(1:length(ref_in))).* conj(fft(ref_in)) )) ;
|
corr = abs(ifft( fft(data_in(1:length(ref_in))) .* conj(fft(ref_in)) )) ;
|
||||||
|
|
||||||
% find max
|
% find max
|
||||||
[~, peak] = max(corr) ;
|
[~, peak] = max(corr) ;
|
||||||
peak=max(1,peak-1);
|
peak=max(1,peak-1);
|
||||||
|
|
||||||
data_in = circshift(data_in,-peak) ;
|
%! Dont (circ)shift the signal here (if signals are equally long) as this would remove the phase information!
|
||||||
%Y = data_in(peak:peak+(Nfft+obj.Ncp)*obj.Navg-1) ;
|
%tested with a butterworth filter this exactly reconstructs the
|
||||||
|
%phase and the magnitude. However, the option is here
|
||||||
|
|
||||||
|
% data_in = circshift(data_in,-peak) ;
|
||||||
|
data_in = data_in(peak:peak+(Nfft+obj.Ncp)*obj.Navg-1) ;
|
||||||
end
|
end
|
||||||
|
|
||||||
% 1. Reshape signal to a matrix to support noise averaging
|
% 1. Reshape signal to a matrix to support noise averaging
|
||||||
Nfft = 2*obj.Nacq + 1 ;
|
|
||||||
|
|
||||||
Y = reshape(data_in, Nfft+obj.Ncp, obj.Navg).' ;
|
Y = reshape(data_in, Nfft+obj.Ncp, obj.Navg).' ;
|
||||||
|
|
||||||
|
|||||||
@@ -59,7 +59,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
|
||||||
|
|||||||
@@ -110,6 +110,9 @@ classdef EQ
|
|||||||
[signalclass_in.signal,error_log] = obj.process_(signalclass_in.signal', reference_signalclass_in.signal');
|
[signalclass_in.signal,error_log] = obj.process_(signalclass_in.signal', reference_signalclass_in.signal');
|
||||||
|
|
||||||
signalclass_in.signal = signalclass_in.signal';
|
signalclass_in.signal = signalclass_in.signal';
|
||||||
|
|
||||||
|
signalclass_in.fs = reference_signalclass_in.fs;
|
||||||
|
|
||||||
% append to logbook
|
% append to logbook
|
||||||
lbdesc = ['EQ '];
|
lbdesc = ['EQ '];
|
||||||
signalclass_in = signalclass_in.logbookentry(lbdesc);
|
signalclass_in = signalclass_in.logbookentry(lbdesc);
|
||||||
|
|||||||
@@ -124,6 +124,7 @@ classdef FFE_adaptive_decision < handle
|
|||||||
d_hat(symbol,1) = obj.constellation(symbol_idx);
|
d_hat(symbol,1) = obj.constellation(symbol_idx);
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
||||||
y_buffer(symbol_idx,1) = y(symbol);
|
y_buffer(symbol_idx,1) = y(symbol);
|
||||||
y_buffer(symbol_idx,:) = circshift(y_buffer(symbol_idx,:),1);
|
y_buffer(symbol_idx,:) = circshift(y_buffer(symbol_idx,:),1);
|
||||||
|
|
||||||
|
|||||||
@@ -148,18 +148,19 @@ classdef VNLE < handle
|
|||||||
y(symbol,1) = obj.e.' * x_in; % Calculating output of LMS __ * |
|
y(symbol,1) = obj.e.' * x_in; % Calculating output of LMS __ * |
|
||||||
|
|
||||||
if training
|
if training
|
||||||
err(symbol) = y(symbol) - d(symbol); % Instantaneous error
|
err = y(symbol) - d(symbol); % Instantaneous error
|
||||||
else
|
else
|
||||||
[~,symbol_idx] = min(abs(y(symbol) - obj.constellation)); % decision for closest constellation point
|
[~,symbol_idx] = min(abs(y(symbol) - obj.constellation)); % decision for closest constellation point
|
||||||
d_hat(symbol,1) = obj.constellation(symbol_idx);
|
d_hat(symbol,1) = obj.constellation(symbol_idx);
|
||||||
err(symbol) = y(symbol) - d_hat(symbol); % Instantaneous error
|
err = y(symbol) - d_hat(symbol); % Instantaneous error
|
||||||
end
|
end
|
||||||
|
|
||||||
if ~all(mu==0,'all') %mu has not only zeros
|
if ~all(mu==0,'all') %mu has not only zeros
|
||||||
obj.e = obj.e - (mu * err(symbol) * x_in) ; % Weight update rule of LMS
|
% obj.e = obj.e - (mu * err * x_in) ; % Weight update rule of LMS
|
||||||
|
obj.e = obj.e - ( (mu * x_in) * err ) ; % Weight update rule of LMS
|
||||||
else
|
else
|
||||||
normalizationfactor = (x_in.' * x_in);
|
normalizationfactor = (x_in.' * x_in);
|
||||||
obj.e = obj.e - err(symbol) * x_in / normalizationfactor; % Weight update rule of NLMS
|
obj.e = obj.e - err * x_in / normalizationfactor; % Weight update rule of NLMS
|
||||||
end
|
end
|
||||||
|
|
||||||
if mod(sample,100) == 1 && showviz
|
if mod(sample,100) == 1 && showviz
|
||||||
@@ -173,7 +174,7 @@ classdef VNLE < handle
|
|||||||
drawnow;
|
drawnow;
|
||||||
end
|
end
|
||||||
|
|
||||||
obj.error(epoch,symbol) = err(symbol) * err(symbol)'; % Instantaneous square error
|
obj.error(epoch,symbol) = err * err'; % Instantaneous square error
|
||||||
|
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|||||||
419
Classes/05_Lab/AwgKeysight.m
Normal file
419
Classes/05_Lab/AwgKeysight.m
Normal file
@@ -0,0 +1,419 @@
|
|||||||
|
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
|
||||||
|
|
||||||
|
disp(['Connected to Instrument: ',char(v.Vendor),' ',char(v.Model),' SerNo:',char(v.SerialNumber)]);
|
||||||
|
|
||||||
|
%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
|
||||||
122
Classes/05_Lab/DC_supply.m
Normal file
122
Classes/05_Lab/DC_supply.m
Normal file
@@ -0,0 +1,122 @@
|
|||||||
|
classdef DC_supply
|
||||||
|
% Simple control of DC supply via fixed GBIB address.
|
||||||
|
% 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)
|
||||||
|
active
|
||||||
|
voltage
|
||||||
|
end
|
||||||
|
|
||||||
|
methods (Access=public)
|
||||||
|
|
||||||
|
function obj = DC_supply(options)
|
||||||
|
|
||||||
|
|
||||||
|
arguments
|
||||||
|
options.active logical = true
|
||||||
|
options.voltage double = [0,0];
|
||||||
|
end
|
||||||
|
|
||||||
|
%
|
||||||
|
fn = fieldnames(options);
|
||||||
|
for n = 1:numel(fn)
|
||||||
|
try
|
||||||
|
obj.(fn{n}) = options.(fn{n});
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
assert(size(obj.voltage,1)==1,'Set Voltage for CH1 and CH2 must be given as vector [V1, V2]');
|
||||||
|
assert(size(obj.voltage,2)==2,'Set Voltage for CH1 and CH2 must be given as vector [V1, V2]');
|
||||||
|
|
||||||
|
end
|
||||||
|
|
||||||
|
function success = set(obj,options)
|
||||||
|
|
||||||
|
|
||||||
|
arguments
|
||||||
|
obj
|
||||||
|
options.voltage double = obj.voltage;
|
||||||
|
end
|
||||||
|
|
||||||
|
success = [0,0];
|
||||||
|
|
||||||
|
try
|
||||||
|
%connect to device
|
||||||
|
v = visadev("GPIB1::19::INSTR");
|
||||||
|
|
||||||
|
disp(['Connected to Instrument: ',char(v.Vendor),' ',char(v.Model),' SerNo:',char(v.SerialNumber)]);
|
||||||
|
|
||||||
|
cmd = 'INST:SEL?';
|
||||||
|
writeline(v, cmd);
|
||||||
|
prev_selected_channel = readline(v);
|
||||||
|
|
||||||
|
for ch = 1:2
|
||||||
|
|
||||||
|
% choose channel
|
||||||
|
cmd = ['INST:SEL OUT',num2str(ch)];
|
||||||
|
writeline(v, cmd);
|
||||||
|
|
||||||
|
% get current voltage level
|
||||||
|
cmd = 'VOLT?';
|
||||||
|
writeline(v, cmd);
|
||||||
|
act_volt = str2num(readline(v));
|
||||||
|
|
||||||
|
% desired voltage (round to two digits after comma)
|
||||||
|
des_volt = round(options.voltage(ch),2);
|
||||||
|
|
||||||
|
cnt = 0;
|
||||||
|
while abs(act_volt-des_volt) > 0
|
||||||
|
|
||||||
|
selected_channel = ['OUT',num2str(ch)];
|
||||||
|
|
||||||
|
% get current voltage level
|
||||||
|
cmd = 'VOLT?';
|
||||||
|
writeline(v, cmd);
|
||||||
|
act_volt = str2num(readline(v));
|
||||||
|
|
||||||
|
% difference
|
||||||
|
diff_volt = act_volt-des_volt;
|
||||||
|
|
||||||
|
% set new voltage
|
||||||
|
increment_voltage = -0.01* sign(diff_volt) ;
|
||||||
|
cmd = ['VOLT ',num2str(act_volt+increment_voltage)];
|
||||||
|
writeline(v, cmd);
|
||||||
|
|
||||||
|
cnt = cnt+1;
|
||||||
|
if mod(cnt,100) == 0
|
||||||
|
wait(1);
|
||||||
|
end
|
||||||
|
|
||||||
|
% get current voltage level
|
||||||
|
cmd = 'VOLT?';
|
||||||
|
writeline(v, cmd);
|
||||||
|
act_volt = str2num(readline(v));
|
||||||
|
|
||||||
|
end
|
||||||
|
|
||||||
|
% check if voltage is set
|
||||||
|
if act_volt ~= des_volt
|
||||||
|
hMsgBox = msgbox('An error occurred in dc supply module. Check if voltage is set correctly.');
|
||||||
|
uiwait(hMsgBox);
|
||||||
|
else
|
||||||
|
success(ch) = 1;
|
||||||
|
end
|
||||||
|
|
||||||
|
end
|
||||||
|
|
||||||
|
% choose channel
|
||||||
|
cmd = ['INST:SEL ',char(strtrim(prev_selected_channel))];
|
||||||
|
writeline(v, cmd);
|
||||||
|
|
||||||
|
%disconnect
|
||||||
|
delete(v);
|
||||||
|
|
||||||
|
catch
|
||||||
|
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
295
Classes/05_Lab/OptAtten.m
Normal file
295
Classes/05_Lab/OptAtten.m
Normal file
@@ -0,0 +1,295 @@
|
|||||||
|
classdef OptAtten < handle
|
||||||
|
% 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]';
|
||||||
|
|
||||||
|
atten_state
|
||||||
|
value_state
|
||||||
|
power_state
|
||||||
|
speed_state
|
||||||
|
wavelength_state
|
||||||
|
|
||||||
|
|
||||||
|
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');
|
||||||
|
|
||||||
|
disp(['Connected to Instrument: ',char(v.Vendor),' ',char(v.Model),' SerNo:',char(v.SerialNumber)]);
|
||||||
|
%Keysight Technologies, N7764A, MY49A00696, 1.13.1
|
||||||
|
|
||||||
|
|
||||||
|
slot = 0; %init slot number
|
||||||
|
%loop to set values for every attenuator slot
|
||||||
|
for i = 1:length(options.active)
|
||||||
|
%convert index number i into slot number
|
||||||
|
slot = 2*i - 1;
|
||||||
|
|
||||||
|
%check whether attenuator is used or unused
|
||||||
|
if ~options.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 options.active(i) == 1 %attenuation
|
||||||
|
if options.value(i) < 0
|
||||||
|
options.value(i) = 0;
|
||||||
|
hMsgBox = msgbox(['Value for attenuation out of range. Please consider minimum value. Attenuation set to ' num2str(options.value(i)) 'dB']);
|
||||||
|
uiwait(hMsgBox);
|
||||||
|
elseif options.value(i) > 45
|
||||||
|
options.value(i) = 45;
|
||||||
|
hMsgBox = msgbox(['Value for attenuation out of range. Please consider maximum value. Attenuation set to ' num2str(options.value(i)) 'dB']);
|
||||||
|
uiwait(hMsgBox);
|
||||||
|
end
|
||||||
|
writeline(v, [':OUTP' num2str(slot) ':POW:CONTR OFF']);
|
||||||
|
writeline(v, [':INP' num2str(slot) ':ATT ' num2str(options.value(i)) 'dB']);
|
||||||
|
elseif options.active(i) == 2 %constant output power
|
||||||
|
if options.value(i) < -50
|
||||||
|
options.value(i) = -50;
|
||||||
|
hMsgBox = msgbox(['Value for output power out of range. Please consider minimum value. Output power set to ' num2str(options.value(i)) 'dBm']);
|
||||||
|
uiwait(hMsgBox);
|
||||||
|
elseif options.value(i) > 20
|
||||||
|
options.value(i) = 20;
|
||||||
|
hMsgBox = msgbox(['Value for output power out of range. Please consider maximum value. Output set to ' num2str(options.value(i)) 'dBm']);
|
||||||
|
uiwait(hMsgBox);
|
||||||
|
end
|
||||||
|
writeline(v, [':OUTP' num2str(slot) ':POW:CONTR ON']);
|
||||||
|
writeline(v, [':OUTP' num2str(slot) ':POW ' num2str(options.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(options.active)
|
||||||
|
if options.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(options.active)
|
||||||
|
if options.active(i) == 2
|
||||||
|
|
||||||
|
%determine absolute difference
|
||||||
|
differ = abs(state.outputpower(i)-options.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
|
||||||
|
silent = 0;
|
||||||
|
if silent
|
||||||
|
for i = 1:length(options.active)
|
||||||
|
if options.active(i) == 2
|
||||||
|
% Output power mode:
|
||||||
|
%differ = abs(state.outputpower(i)-options.value(i));
|
||||||
|
ch_info_txt = ['OptAtten: ',num2str(i),' -> Desired: ',num2str(options.value(i)),' dBm; Cur Output: ',num2str(state.outputpower(i)),'dBm'];
|
||||||
|
disp(ch_info_txt);
|
||||||
|
else
|
||||||
|
ch_info_txt = ['OptAtten: ',num2str(i),' -> Attenuated by: ',num2str(options.value(i)),' dB; Cur Output: ',num2str(state.outputpower(i)),'dBm'];
|
||||||
|
disp(ch_info_txt);
|
||||||
|
end
|
||||||
|
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
%disconnect
|
||||||
|
delete(v);
|
||||||
|
|
||||||
|
obj.readvals();
|
||||||
|
|
||||||
|
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,options)
|
||||||
|
|
||||||
|
arguments
|
||||||
|
obj
|
||||||
|
options.print2console = 0;
|
||||||
|
end
|
||||||
|
|
||||||
|
try
|
||||||
|
%connect to device
|
||||||
|
v = visadev('TCPIP::134.245.243.248::INSTR');
|
||||||
|
|
||||||
|
cnt = 1;
|
||||||
|
for s = 1:2:7
|
||||||
|
|
||||||
|
writeline(v, [':OUTP' num2str(s) ':POW?']);
|
||||||
|
line = readline(v);
|
||||||
|
answer = sscanf(line,'%f');
|
||||||
|
obj.value_state(cnt) = answer;
|
||||||
|
|
||||||
|
writeline(v, [':READ' num2str(s) ':POW?']);
|
||||||
|
line = readline(v);
|
||||||
|
answer = sscanf(line,'%f');
|
||||||
|
obj.power_state(cnt) = answer;
|
||||||
|
|
||||||
|
writeline(v, [':READ' num2str(s) ':POW?']);
|
||||||
|
line = readline(v);
|
||||||
|
answer = sscanf(line,'%f');
|
||||||
|
obj.power_state(cnt) = answer;
|
||||||
|
|
||||||
|
writeline(v, [':INP' num2str(s) ':ATT?']);
|
||||||
|
line = readline(v);
|
||||||
|
answer = sscanf(line,'%f');
|
||||||
|
obj.atten_state(cnt) = answer;
|
||||||
|
|
||||||
|
writeline(v, [':INP' num2str(s) ':WAV?']);
|
||||||
|
line = readline(v);
|
||||||
|
answer = sscanf(line,'%f');
|
||||||
|
obj.wavelength_state(cnt) = answer;
|
||||||
|
|
||||||
|
writeline(v, [':INP' num2str(s) ':WAV?']);
|
||||||
|
line = readline(v);
|
||||||
|
answer = sscanf(line,'%f');
|
||||||
|
obj.speed_state(cnt) = answer;
|
||||||
|
|
||||||
|
cnt = cnt+1;
|
||||||
|
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
|
||||||
301
Classes/05_Lab/ScopeKeysight.m
Normal file
301
Classes/05_Lab/ScopeKeysight.m
Normal file
@@ -0,0 +1,301 @@
|
|||||||
|
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
|
||||||
|
removeDC
|
||||||
|
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.removeDC 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)
|
||||||
|
|
||||||
|
% record
|
||||||
|
recordedSignals{n} = obj.readChannel(v,n);
|
||||||
|
|
||||||
|
% cut "safety samples" that were added at the end
|
||||||
|
recordedSignals{n} = recordedSignals{n}(1:obj.recordLen);
|
||||||
|
|
||||||
|
if obj.removeDC
|
||||||
|
recordedSignals{n} = recordedSignals{n}-mean(recordedSignals{n});
|
||||||
|
end
|
||||||
|
|
||||||
|
obj.writeNcheck(v,sprintf(':CHANnel%u:DISPlay ON',n));
|
||||||
|
end
|
||||||
|
|
||||||
|
% fill all other channels with nothing
|
||||||
|
for n = find(obj.channel == 0)
|
||||||
|
recordedSignals{n} = [];
|
||||||
|
end
|
||||||
|
|
||||||
|
obj.writeNcheck(v,sprintf(':%s',scope_state));
|
||||||
|
obj.writeNcheck(v,'*OPC?');
|
||||||
|
|
||||||
|
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
|
||||||
|
|
||||||
|
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
10
Datatypes/awg_model.m
Normal 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
22
Datatypes/scope_fadc.m
Normal 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
9
Datatypes/scope_model.m
Normal file
@@ -0,0 +1,9 @@
|
|||||||
|
classdef scope_model < int32
|
||||||
|
|
||||||
|
enumeration
|
||||||
|
DSAZ634A (1)
|
||||||
|
UXR1102A (2)
|
||||||
|
UXR1104A (3)
|
||||||
|
end
|
||||||
|
|
||||||
|
end
|
||||||
16
Tests/05_Lab/DC_Supply_test.m
Normal file
16
Tests/05_Lab/DC_Supply_test.m
Normal file
@@ -0,0 +1,16 @@
|
|||||||
|
classdef DC_Supply_test < matlab.unittest.TestCase
|
||||||
|
% Test class for DC_Supply
|
||||||
|
|
||||||
|
methods (Test)
|
||||||
|
function testExample(testCase)
|
||||||
|
% Example test case for DC_Supply
|
||||||
|
% Add your test code here
|
||||||
|
|
||||||
|
dc_supply = DC_supply("voltage",[0,9],"active",1);
|
||||||
|
|
||||||
|
dc_supply.set();
|
||||||
|
|
||||||
|
testCase.verifyTrue(true);
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
@@ -5,6 +5,7 @@ function generateTests()
|
|||||||
else
|
else
|
||||||
|
|
||||||
end
|
end
|
||||||
|
|
||||||
% Define the root folders for classes and tests
|
% Define the root folders for classes and tests
|
||||||
classesFolder = 'Classes'; % Folder containing the class files
|
classesFolder = 'Classes'; % Folder containing the class files
|
||||||
testsFolder = 'Tests'; % Folder where test files should be created
|
testsFolder = 'Tests'; % Folder where test files should be created
|
||||||
|
|||||||
146
projects/Lab_2024/lab_minimal.m
Normal file
146
projects/Lab_2024/lab_minimal.m
Normal file
@@ -0,0 +1,146 @@
|
|||||||
|
%%% SIR Sweep for MPI Experiment %%%
|
||||||
|
params = struct;
|
||||||
|
params.i_atten = 10;
|
||||||
|
|
||||||
|
wh = DataStorage(params);
|
||||||
|
|
||||||
|
wh.addStorage("ber");
|
||||||
|
wh.addStorage("sir");
|
||||||
|
wh.addStorage("pd_in");
|
||||||
|
|
||||||
|
playandrecord = 0;
|
||||||
|
|
||||||
|
precomp_mode = 2; %0=do nothing ; 1= measure; 2=precomp active
|
||||||
|
M = 4;
|
||||||
|
pn_key = 2;
|
||||||
|
usemrds = 0;
|
||||||
|
fdac = 92e9;
|
||||||
|
fsym = 92e9;
|
||||||
|
fadc = 160e9;
|
||||||
|
rrcalpha = 0.05;
|
||||||
|
v_bias = 2.27;
|
||||||
|
i_atten = 40;
|
||||||
|
pd_in_desired = 7;
|
||||||
|
|
||||||
|
disp(['Start Measurement of ',num2str(prod(wh.dim)),' loops...'])
|
||||||
|
|
||||||
|
%%%%% SET Volatges %%%%%%
|
||||||
|
dcs = DC_supply("active",[1,1],"voltage",[v_bias, 9]);
|
||||||
|
dcs.set("voltage",[v_bias, 9]);
|
||||||
|
|
||||||
|
voa = OptAtten("active",[0,2,1,1],"value",[0,pd_in_desired,0,i_atten],"wavelength",[1310,1310,1310,1310]);
|
||||||
|
voa.set('active',[0,2,1,1],'value',[0,pd_in_desired,0,i_atten]);
|
||||||
|
voa.readvals();
|
||||||
|
%%%%% SET Volatges %%%%%%
|
||||||
|
|
||||||
|
|
||||||
|
if 1
|
||||||
|
precomp_path = "C:\Users\sioe\Documents\MATLAB\imdd_simulation\projects\standard_system\";
|
||||||
|
precomp_fn = "lab_mpi_setup_2";
|
||||||
|
else
|
||||||
|
precomp_path = "C:\Users\sioe\Documents\MATLAB\model-collection\sioe_models\Labor_2024\Lab_PAM4\";
|
||||||
|
precomp_fn = "precomp_bla__loop1_1";
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
|
%%%%% Symbol Generation %%%%%%
|
||||||
|
Pform = Pulseformer("fsym",fsym,"fdac",4*fsym,"pulse","rrc","pulselength",16,"rrcalpha",rrcalpha);
|
||||||
|
[Digi_sig,Symbols,Bits] = PAMsource("fsym",fsym,"M",M,"order",18,"useprbs",1,...
|
||||||
|
"fs_out",fdac,"applyclipping",0,"clipfactor",1.7,...
|
||||||
|
"applypulseform",0,"pulseformer",Pform,"randkey",pn_key,...
|
||||||
|
"db_precode",0,...
|
||||||
|
"mrds_code",usemrds,"mrds_blocklength",512).process();
|
||||||
|
|
||||||
|
if precomp_mode == 1 % measure channel
|
||||||
|
freqresp = ChannelFreqResp("Nacq",1024,"Navg",64,"Ncp",63,'f_ref',Digi_sig.fs);
|
||||||
|
Digi_sig = freqresp.buildOFDM();
|
||||||
|
elseif precomp_mode == 2 % apply precomp
|
||||||
|
freqresp = ChannelFreqResp("Nacq",1024,"Navg",64,"Ncp",63,'f_ref',Digi_sig.fs);
|
||||||
|
Digi_sig = freqresp.precomp(Digi_sig,'maxampdb',3,'loadPath',precomp_path,'fileName',precomp_fn);
|
||||||
|
end
|
||||||
|
|
||||||
|
%%%%% AWG %%%%%%
|
||||||
|
AWG = AwgKeysight("model","M8196A","fdac",fdac,"scaletodac",[1,1,1,1],"skews",[0,0,0,0],"voltages",[0,0,0,0.62]);
|
||||||
|
AWG.upload("signal4",Digi_sig);
|
||||||
|
|
||||||
|
for i_atten = wh.parameter.i_atten.values
|
||||||
|
|
||||||
|
%%%%% SET ATTENUATOR %%%%%%
|
||||||
|
voa.set('active',[0,2,1,1],'value',[0,7,0,i_atten]);
|
||||||
|
|
||||||
|
%%%%% Scope %%%%%%
|
||||||
|
SCP = ScopeKeysight("model","DSAZ634A",'autoscale',1,"fadc",'GSa_160',"channel",[1],"recordLen",2000000,"removeDC",1);
|
||||||
|
Scpe_sig = SCP.read();
|
||||||
|
Scpe_sig = Electricalsignal(Scpe_sig{1},"fs",fadc);
|
||||||
|
|
||||||
|
% Scpe_sig.spectrum("displayname",'Rx Signal','fignum',10);
|
||||||
|
|
||||||
|
%%%%%% Sample to 2x fsym %%%%%%
|
||||||
|
Scpe_sig = Scpe_sig.resample("fs_in",160e9,"fs_out",2*92e9);
|
||||||
|
|
||||||
|
if precomp_mode == 1
|
||||||
|
freqresp.estimate(Scpe_sig,"save",true,"savePath",precomp_path,"fileName",precomp_fn);
|
||||||
|
freqresp.plot();
|
||||||
|
end
|
||||||
|
|
||||||
|
%%%%%% Sync Rx signal with reference %%%%%%
|
||||||
|
[Scpe_sig,S] = Scpe_sig.tsynch("reference",Symbols,"fs_ref",fsym);
|
||||||
|
|
||||||
|
Scpe_sig.eye(fsym,M);
|
||||||
|
|
||||||
|
%%%%% EQUALIZE %%%%%%
|
||||||
|
|
||||||
|
Eq_ffe_only = FFE("epochs_tr",5,"epochs_dd",5,"len_tr",4096*2,"mu_dd",1e-4,"mu_tr",0,"order",25,"sps",2,"decide",0);
|
||||||
|
ber_ffe_only = runEQ(Eq_ffe_only,Scpe_sig,Symbols,Bits,M);
|
||||||
|
|
||||||
|
Eq_move_it = EQ("Ne",[50,7,7],"Nb",[0,0,0],"training_length",4096*2,"training_loops",5,"dd_loops",5,"K",2,"DCmu",0.05,"DDmu",[0.0004 0.0004 0.0004 0.0004 ],"DFEmu",0.005,"FFEmu",0,"plotfinal",0,"ideal_dfe",1);
|
||||||
|
ber_move_it = runEQ(Eq_move_it,Scpe_sig,Symbols,Bits,M);
|
||||||
|
|
||||||
|
Eq_nonlin = EQ("Ne",[50,7,7],"Nb",[0,0,0],"training_length",4096*2,"training_loops",5,"dd_loops",5,"K",2,"DCmu",0.0,"DDmu",[0.0004 0.0004 0.0004 0.0004 ],"DFEmu",0.005,"FFEmu",0,"plotfinal",0,"ideal_dfe",1);
|
||||||
|
%VNLE("epochs_tr",5,"epochs_dd",5,"len_tr",4096*2,"mu_dd",[0.0004 0.0005 0.0006],"mu_tr",0,"order",[50,7,7],"sps",2,"decide",0);
|
||||||
|
ber_nonlin = runEQ(Eq_nonlin,Scpe_sig,Symbols,Bits,M);
|
||||||
|
|
||||||
|
Eq_adaptive_decision = FFE_adaptive_decision("epochs_tr",5,"epochs_dd",5,"len_tr",4096*2,"mu_dd",1e-4,"mu_tr",0,"order",25,"sps",2,"decide",0,"buffer_length",80);
|
||||||
|
ber_adaptive_decision = runEQ(Eq_adaptive_decision,Scpe_sig,Symbols,Bits,M);
|
||||||
|
|
||||||
|
FFE_FFDCAVG("epochs_tr",5,"epochs_dd",5,"len_tr",4096*2,"mu_dd",1e-4,"mu_tr",0,"order",25,"sps",2,"decide",0,"mu_buff",128);
|
||||||
|
ber_ff_dcavg = runEQ(FFE_FFDCAVG,Scpe_sig,Symbols,Bits,M);
|
||||||
|
|
||||||
|
Eq_feedback_removal = FFE_DCremoval("epochs_tr",5,"epochs_dd",5,"len_tr",4096*2,"mu_dd",1e-4,"mu_tr",0,"order",25,"sps",2,"decide",0,"mu_dc",0.05,"dc_buffer_len",1);
|
||||||
|
ber_feedback_removal = runEQ(Eq_feedback_removal,Scpe_sig,Symbols,Bits,M);
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
sir = voa.power_state(3)-voa.power_state(4);
|
||||||
|
pd_in = voa.power_state(2);
|
||||||
|
|
||||||
|
disp(['BER: ',sprintf('%.1E',ber_eq),' | SIR: ',num2str(sir),' dB | PD_in: ',num2str(pd_in),' dBm']);
|
||||||
|
|
||||||
|
wh.addValueToStorage(ber_eq,'ber',i_atten);
|
||||||
|
wh.addValueToStorage(sir,'sir',i_atten);
|
||||||
|
wh.addValueToStorage(pd_in,'pd_in',i_atten);
|
||||||
|
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
cols = linspecer(8);
|
||||||
|
|
||||||
|
sir_vals = wh.parameter.i_atten.values;
|
||||||
|
bers = wh.getStoValue('ber',sir_vals);
|
||||||
|
|
||||||
|
figure(44);
|
||||||
|
a = gca;
|
||||||
|
hold on; % Retain the plot so new points can be added without complete redraw
|
||||||
|
|
||||||
|
plot(sir_vals,bers,"LineWidth",0.5,"LineStyle","-","Marker",".","MarkerSize",15,"DisplayName","FFE only");
|
||||||
|
yline(3.8e-3,'DisplayName','HD-FEC','LineStyle','--','HandleVisibility','off');
|
||||||
|
xlabel('Received Optical Power (dBm)');
|
||||||
|
ylabel('Bit Error Rate (BER)');
|
||||||
|
title('Bit Error Rate vs. ROP');
|
||||||
|
set(gca,'yscale','log');
|
||||||
|
set(gca,'Box','on');
|
||||||
|
grid on;
|
||||||
|
grid minor
|
||||||
|
legend
|
||||||
|
|
||||||
13
projects/Lab_2024/runEQ.m
Normal file
13
projects/Lab_2024/runEQ.m
Normal file
@@ -0,0 +1,13 @@
|
|||||||
|
|
||||||
|
function BER = runEQ(Eq_class,Scpe_sig,Symbols,Bits,M)
|
||||||
|
|
||||||
|
[EQ_sig] = Eq_class.process(Scpe_sig,Symbols);
|
||||||
|
|
||||||
|
error = EQ_sig-Symbols;
|
||||||
|
error.spectrum("displayname",['Error PSD after: ',inputname(1),' '],'fignum',564);
|
||||||
|
|
||||||
|
Rx_bits = PAMmapper(M,0).demap(EQ_sig);
|
||||||
|
|
||||||
|
[~,errors_bm,BER,errors] = calc_ber(Rx_bits.signal,Bits.signal,"skip_front",100,"skip_end",150,"returnErrorLocation",1);
|
||||||
|
|
||||||
|
end
|
||||||
59
projects/Lab_analysis/eq_lab.m
Normal file
59
projects/Lab_analysis/eq_lab.m
Normal file
@@ -0,0 +1,59 @@
|
|||||||
|
|
||||||
|
%% Parameter to simulate and save
|
||||||
|
params = struct;
|
||||||
|
|
||||||
|
params.M = [4];
|
||||||
|
params.datarate = [300];
|
||||||
|
params.rop = [0];
|
||||||
|
|
||||||
|
precomp_mode = 2; %0=do nothing ; 1= measure; 2=precomp active
|
||||||
|
|
||||||
|
if ismac
|
||||||
|
precomp_path = "/Users/silasoettinghaus/Documents/MATLAB/imdd_simulation/projects/standard_system";
|
||||||
|
else
|
||||||
|
precomp_path = "C:\Users\Silas\Documents\MATLAB\imdd_simulation\projects\standard_system\";
|
||||||
|
end
|
||||||
|
|
||||||
|
precomp_fn = "400G_simulative_setup";
|
||||||
|
usemrds = 0;
|
||||||
|
|
||||||
|
name = ['wh_',strrep(num2str(now),'.','')];
|
||||||
|
|
||||||
|
wh = DataStorage(params);
|
||||||
|
|
||||||
|
wh.addStorage("ber_ffe");
|
||||||
|
|
||||||
|
%% Init Params
|
||||||
|
link_length = 0; %meter
|
||||||
|
pn_key = 2;
|
||||||
|
laser_linewidth = 0;
|
||||||
|
|
||||||
|
endcnt = prod(wh.dim);
|
||||||
|
cnt=0;
|
||||||
|
|
||||||
|
disp(['Start Simulation of ',num2str(endcnt),' loops...'])
|
||||||
|
tic
|
||||||
|
|
||||||
|
|
||||||
|
% SETUP HERE: %%
|
||||||
|
fsym = 92e9;
|
||||||
|
|
||||||
|
Symbols = Informationsignal(digi_mod_out',"fs",92e9);
|
||||||
|
|
||||||
|
Scpe_sig = Electricalsignal(awg2scope_keysight_out.no1',"fs",160e9);
|
||||||
|
Scpe_sig = Scpe_sig.resample("fs_in",160e9,"fs_out",2*92e9);
|
||||||
|
|
||||||
|
Bits = Informationsignal(prms_out',"fs",92e9);
|
||||||
|
|
||||||
|
%%%%%% Sync Rx signal with reference %%%%%%
|
||||||
|
[Scpe_sig,S] = Scpe_sig.tsynch("reference",Symbols,"fs_ref",fsym);
|
||||||
|
|
||||||
|
%%%%% EQUALIZE %%%%%%
|
||||||
|
% Eq = FFE("epochs_tr",5,"epochs_dd",5,"len_tr",4096*2,"mu_dd",1e-4,"mu_tr",0,"order",25,"sps",2,"decide",1);
|
||||||
|
Eq = VNLE("epochs_tr",5,"epochs_dd",5,"len_tr",4096*2,"mu_dd",[0.0004 0.0005 0.0006],"mu_tr",0,"order",[50,7,7],"sps",2,"decide",1);
|
||||||
|
[EQ_sig] = Eq.process(Scpe_sig,Symbols);
|
||||||
|
Rx_bits = PAMmapper(M,0).demap(EQ_sig);
|
||||||
|
[~,errors_bm,ber_ffe,errors] = calc_ber(Rx_bits.signal,Bits.signal,"skip_front",100,"skip_end",150,"returnErrorLocation",1);
|
||||||
|
disp(['BER: ',sprintf('%.1E',ber_ffe),' - - - ',num2str(fsym*1e-9),' GBd']);
|
||||||
|
|
||||||
|
|
||||||
Binary file not shown.
@@ -17,7 +17,7 @@ db_channelapproach = 0;
|
|||||||
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";
|
||||||
@@ -157,7 +157,7 @@ for M = wh.parameter.M.values
|
|||||||
Scpe_sig = Scpe_sig.resample("fs_in",fadc,"fs_out",2*fsym);
|
Scpe_sig = Scpe_sig.resample("fs_in",fadc,"fs_out",2*fsym);
|
||||||
|
|
||||||
%%%%%% Sync Rx signal with reference %%%%%%
|
%%%%%% Sync Rx signal with reference %%%%%%
|
||||||
[Scpe_sig,D,cuts] = Scpe_sig.tsynch("reference",Symbols,"fs_ref",fsym);
|
[Scpe_sig,S] = Scpe_sig.tsynch("reference",Symbols,"fs_ref",fsym);
|
||||||
|
|
||||||
%%%%% EQUALIZE %%%%%%
|
%%%%% EQUALIZE %%%%%%
|
||||||
Eq = FFE("epochs_tr",5,"epochs_dd",5,"len_tr",4096*2,"mu_dd",1e-4,"mu_tr",0,"order",25,"sps",2,"decide",0);
|
Eq = FFE("epochs_tr",5,"epochs_dd",5,"len_tr",4096*2,"mu_dd",1e-4,"mu_tr",0,"order",25,"sps",2,"decide",0);
|
||||||
@@ -208,7 +208,7 @@ for M = wh.parameter.M.values
|
|||||||
for i = 1:i_
|
for i = 1:i_
|
||||||
rop=wh.parameter.rop.values(i);
|
rop=wh.parameter.rop.values(i);
|
||||||
|
|
||||||
wh.addValueToStorage(ber_ffe(i) ,'ber_ffe',M,datarate,rop);
|
wh.addValueToStorage(ber_ffe(i),'ber_ffe',M,datarate,rop);
|
||||||
|
|
||||||
end
|
end
|
||||||
|
|
||||||
@@ -235,8 +235,6 @@ a = gca;
|
|||||||
hold on; % Retain the plot so new points can be added without complete redraw
|
hold on; % Retain the plot so new points can be added without complete redraw
|
||||||
|
|
||||||
plot(wh.parameter.rop.values,ber_ffe,"LineWidth",0.5,"LineStyle","-","Marker",".","MarkerSize",15,"DisplayName","FFE only");
|
plot(wh.parameter.rop.values,ber_ffe,"LineWidth",0.5,"LineStyle","-","Marker",".","MarkerSize",15,"DisplayName","FFE only");
|
||||||
|
|
||||||
|
|
||||||
yline(3.8e-3,'DisplayName','HD-FEC','LineStyle','--','HandleVisibility','off');
|
yline(3.8e-3,'DisplayName','HD-FEC','LineStyle','--','HandleVisibility','off');
|
||||||
xlabel('Received Optical Power (dBm)');
|
xlabel('Received Optical Power (dBm)');
|
||||||
ylabel('Bit Error Rate (BER)');
|
ylabel('Bit Error Rate (BER)');
|
||||||
|
|||||||
BIN
projects/standard_system/lab_mpi_setup.mat
Normal file
BIN
projects/standard_system/lab_mpi_setup.mat
Normal file
Binary file not shown.
BIN
projects/standard_system/lab_mpi_setup_2.mat
Normal file
BIN
projects/standard_system/lab_mpi_setup_2.mat
Normal file
Binary file not shown.
15
test/awg_test.m
Normal file
15
test/awg_test.m
Normal 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();
|
||||||
Reference in New Issue
Block a user