diff --git a/Classes/00_signals/Signal.m b/Classes/00_signals/Signal.m index 95cd78b..80ed39f 100644 --- a/Classes/00_signals/Signal.m +++ b/Classes/00_signals/Signal.m @@ -192,6 +192,19 @@ classdef Signal end + %% Add signals from one signal to another, the first object will sustain + function Diff = minus(X,y) + + if isa(y,'Signal') + Diff = X; + Diff.signal = X.signal - y.signal; + elseif isnumeric(y) + Diff = X; + Diff.signal = X.signal - y; + end + + end + function Product = times(X,y) if isa(y,'Signal') @@ -282,9 +295,11 @@ classdef Signal xlim([-obj.fs/2 obj.fs/2].*1e-9) edgetick = 2^(nextpow2(obj.fs*1e-9)); % xticks([-edgetick:16:edgetick]); - xlim([-244, 244]) - ylim([-120,10]); + xlim([100*round( min(w.*1e-9)/100,1)-10,100*round( max(w.*1e-9)/100,1)+10]) + ylim([100*round( min(p_dbm)/100,1)-3,100*round( max(p_dbm)/100,1)+3]); yticks([-200:10:10]); + grid on + grid minor legend end @@ -437,10 +452,13 @@ classdef Signal end %plot all synced signals and the ref signal - figure;hold on; - for i = 1:size(S,1) - plot(S{i}.normalize('mode','oneone').signal(1000:1100),'LineWidth',0.1,'Color',[0.2157 0.4941 0.7216]); - plot(b(1000:1100),'LineWidth',1); + debug = 0; + if debug + figure;hold on; + for i = 1:size(S,1) + plot(S{i}.normalize('mode','oneone').signal(1000:1100),'LineWidth',0.1,'Color',[0.2157 0.4941 0.7216]); + plot(b(1000:1100),'LineWidth',1); + end end %return the sinal with the highest correlation... @@ -602,7 +620,6 @@ classdef Signal % beautify colormap(cbrewer2("Blues",4096)); - if isa(obj,'Opticalsignal') title("Optical Eye") ylabel("Power in mW"); @@ -652,41 +669,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 hist_interest = plot_data(:,posxall); hist_interest_smoth = smooth(hist_interest,20); 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); + yline(loc,'Color','red','LineWidth',1,'LineStyle',':'); for i = 1:numel(loc) @@ -717,6 +708,37 @@ classdef Signal thirdboxstring = ['OMA outer:',num2str(er),' V']; 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, ... @@ -728,6 +750,8 @@ classdef Signal 'HorizontalAlignment', 'center'); end + end + yticks(linspace(0,histpoints,16)); y_tickstring = sprintfc('%.2f', y_tickstring); yticklabels(y_tickstring); diff --git a/Classes/01_transmit/ChannelFreqResp.m b/Classes/01_transmit/ChannelFreqResp.m index 5095539..ebe3a93 100644 --- a/Classes/01_transmit/ChannelFreqResp.m +++ b/Classes/01_transmit/ChannelFreqResp.m @@ -132,7 +132,7 @@ classdef ChannelFreqResp < handle 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 = fnew(2:end-1); @@ -154,7 +154,7 @@ classdef ChannelFreqResp < handle %smoothing takes time and sometimes the result looks odd, %however the performance is most of the time better - smoothing = 1; + smoothing = 0; if smoothing iH = smooth(fnew,iH,0.1,'loess')'; end @@ -163,16 +163,10 @@ classdef ChannelFreqResp < handle % 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?) - % 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 % 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 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. 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))]; 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 function plot(obj) - figure(55551); + figure(55); clf; Havg = obj.H; @@ -290,6 +285,7 @@ classdef ChannelFreqResp < handle end function data = load(obj, options) + % Function to load data from a specified file and path. arguments obj @@ -334,12 +330,20 @@ classdef ChannelFreqResp < handle % Load the data from the specified file loadedData = load(fullFileName); - % Replace whole obj here.. is this save or unsave?! - fn = fieldnames(loadedData.obj); - for n = 1:numel(fn) - try - obj.(fn{n}) = loadedData.obj.(fn{n}); + 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?! + fn = fieldnames(loadedData.obj); + for n = 1:numel(fn) + try + obj.(fn{n}) = loadedData.obj.(fn{n}); + end end + end fprintf('Frequency response information successfully loaded from %s\n', fullFileName); @@ -373,26 +377,29 @@ classdef ChannelFreqResp < handle 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 - 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 [~, peak] = max(corr) ; peak=max(1,peak-1); - data_in = circshift(data_in,-peak) ; - %Y = data_in(peak:peak+(Nfft+obj.Ncp)*obj.Navg-1) ; + %! Dont (circ)shift the signal here (if signals are equally long) 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 + + % data_in = circshift(data_in,-peak) ; + data_in = data_in(peak:peak+(Nfft+obj.Ncp)*obj.Navg-1) ; end % 1. Reshape signal to a matrix to support noise averaging - Nfft = 2*obj.Nacq + 1 ; - + Y = reshape(data_in, Nfft+obj.Ncp, obj.Navg).' ; X = reshape(ref_in, Nfft + obj.Ncp, obj.Navg).' ; diff --git a/Classes/04_DSP/Equalizer/EQ.m b/Classes/04_DSP/Equalizer/EQ.m index b999c69..888f85a 100644 --- a/Classes/04_DSP/Equalizer/EQ.m +++ b/Classes/04_DSP/Equalizer/EQ.m @@ -110,6 +110,9 @@ classdef EQ [signalclass_in.signal,error_log] = obj.process_(signalclass_in.signal', reference_signalclass_in.signal'); signalclass_in.signal = signalclass_in.signal'; + + signalclass_in.fs = reference_signalclass_in.fs; + % append to logbook lbdesc = ['EQ ']; signalclass_in = signalclass_in.logbookentry(lbdesc); diff --git a/Classes/04_DSP/Equalizer/FFE_adaptive_decision.m b/Classes/04_DSP/Equalizer/FFE_adaptive_decision.m index 892305a..f1f9c9d 100644 --- a/Classes/04_DSP/Equalizer/FFE_adaptive_decision.m +++ b/Classes/04_DSP/Equalizer/FFE_adaptive_decision.m @@ -124,6 +124,7 @@ classdef FFE_adaptive_decision < handle d_hat(symbol,1) = obj.constellation(symbol_idx); end + y_buffer(symbol_idx,1) = y(symbol); y_buffer(symbol_idx,:) = circshift(y_buffer(symbol_idx,:),1); diff --git a/Classes/04_DSP/Equalizer/VNLE.m b/Classes/04_DSP/Equalizer/VNLE.m index 0901fa5..397d58e 100644 --- a/Classes/04_DSP/Equalizer/VNLE.m +++ b/Classes/04_DSP/Equalizer/VNLE.m @@ -148,18 +148,19 @@ classdef VNLE < handle y(symbol,1) = obj.e.' * x_in; % Calculating output of LMS __ * | if training - err(symbol) = y(symbol) - d(symbol); % Instantaneous error + err = y(symbol) - d(symbol); % Instantaneous error else [~,symbol_idx] = min(abs(y(symbol) - obj.constellation)); % decision for closest constellation point 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 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 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 if mod(sample,100) == 1 && showviz @@ -173,7 +174,7 @@ classdef VNLE < handle drawnow; end - obj.error(epoch,symbol) = err(symbol) * err(symbol)'; % Instantaneous square error + obj.error(epoch,symbol) = err * err'; % Instantaneous square error end end diff --git a/Classes/05_Lab/AwgKeysight.m b/Classes/05_Lab/AwgKeysight.m index c37c37f..f02a7c5 100644 --- a/Classes/05_Lab/AwgKeysight.m +++ b/Classes/05_Lab/AwgKeysight.m @@ -203,6 +203,8 @@ classdef AwgKeysight 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); diff --git a/Classes/05_Lab/DC_supply.m b/Classes/05_Lab/DC_supply.m index a5a5288..5d79681 100644 --- a/Classes/05_Lab/DC_supply.m +++ b/Classes/05_Lab/DC_supply.m @@ -47,8 +47,7 @@ classdef DC_supply %connect to device v = visadev("GPIB1::19::INSTR"); - writeline(v, '*IDN?;'); - disp(['DC Source: ' readline(v)]); + disp(['Connected to Instrument: ',char(v.Vendor),' ',char(v.Model),' SerNo:',char(v.SerialNumber)]); cmd = 'INST:SEL?'; writeline(v, cmd); @@ -109,13 +108,14 @@ classdef DC_supply end % choose channel - cmd = ['INST:SEL ',prev_selected_channel]; + cmd = ['INST:SEL ',char(strtrim(prev_selected_channel))]; writeline(v, cmd); %disconnect delete(v); catch + end end end diff --git a/Classes/05_Lab/OptAtten.m b/Classes/05_Lab/OptAtten.m index 0356084..5e0e320 100644 --- a/Classes/05_Lab/OptAtten.m +++ b/Classes/05_Lab/OptAtten.m @@ -1,4 +1,4 @@ -classdef OptAtten +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 @@ -10,6 +10,14 @@ classdef OptAtten 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) @@ -34,6 +42,7 @@ classdef OptAtten end + function success = set(obj,options) arguments @@ -46,47 +55,47 @@ classdef OptAtten %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 + 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(obj.active) + 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 ~obj.active(i) %atten slot 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 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']); + 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 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']); + 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(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']); + 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 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']); + 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(obj.value(i))]); + writeline(v, [':OUTP' num2str(slot) ':POW ' num2str(options.value(i))]); end %set value for speed @@ -160,8 +169,8 @@ classdef OptAtten pause(2); %read output power from attenuator and save to state.ouputpower - for i = 1:length(obj.active) - if obj.active(i) + for i = 1:length(options.active) + if options.active(i) %convert index number i into slot number slot = 2*i - 1; @@ -174,11 +183,11 @@ classdef OptAtten %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 + for i = 1:length(options.active) + if options.active(i) == 2 %determine absolute difference - differ = abs(state.outputpower(i)-obj.value(i)); + 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!']); @@ -188,22 +197,27 @@ classdef OptAtten 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); + 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 @@ -216,57 +230,51 @@ classdef OptAtten end - function readvals(obj) + function readvals(obj,options) + + arguments + obj + options.print2console = 0; + 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 - - power=[]; - + cnt = 1; 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']); + obj.value_state(cnt) = answer; - writeline(v, [':OUTP' num2str(s) ':POW:CONTR?']); + writeline(v, [':READ' num2str(s) ':POW?']); line = readline(v); answer = sscanf(line,'%f'); - disp(['Power control for Slot ' num2str(s) ': ' num2str(answer)]); + obj.power_state(cnt) = 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, [':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'); - disp(['Wavelength for Slot ' num2str(s) ': ' num2str(answer) ' nm']); + obj.wavelength_state(cnt) = answer; - writeline(v, [':OUTP' num2str(s) ':ATIM?']); + writeline(v, [':INP' num2str(s) ':WAV?']); line = readline(v); answer = sscanf(line,'%f'); - disp(['Averaging time for Slot ' num2str(s) ': ' num2str(answer) ' s']); - - fprintf('\n') + obj.speed_state(cnt) = answer; + + cnt = cnt+1; end delete(v); @@ -281,7 +289,7 @@ classdef OptAtten end end - + end end diff --git a/Classes/05_Lab/ScopeKeysight.m b/Classes/05_Lab/ScopeKeysight.m index 31053b9..9b33923 100644 --- a/Classes/05_Lab/ScopeKeysight.m +++ b/Classes/05_Lab/ScopeKeysight.m @@ -8,6 +8,7 @@ classdef ScopeKeysight channel autoScale extRef + removeDC interpolate recordLen IPaddress @@ -25,6 +26,7 @@ classdef ScopeKeysight 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 @@ -169,11 +171,21 @@ classdef ScopeKeysight 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 @@ -181,6 +193,16 @@ classdef ScopeKeysight 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 diff --git a/projects/Lab_2024/imdd_standard.m b/projects/Lab_2024/imdd_standard.m deleted file mode 100644 index 8b13789..0000000 --- a/projects/Lab_2024/imdd_standard.m +++ /dev/null @@ -1 +0,0 @@ - diff --git a/projects/Lab_2024/lab_minimal.m b/projects/Lab_2024/lab_minimal.m new file mode 100644 index 0000000..dbb690f --- /dev/null +++ b/projects/Lab_2024/lab_minimal.m @@ -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 + diff --git a/projects/Lab_2024/runEQ.m b/projects/Lab_2024/runEQ.m new file mode 100644 index 0000000..1fe66a8 --- /dev/null +++ b/projects/Lab_2024/runEQ.m @@ -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 \ No newline at end of file diff --git a/projects/standard_system/400G_simulative_setup.mat b/projects/standard_system/400G_simulative_setup.mat index c8259fb..0202264 100644 Binary files a/projects/standard_system/400G_simulative_setup.mat and b/projects/standard_system/400G_simulative_setup.mat differ diff --git a/projects/standard_system/imdd_minimal_2.m b/projects/standard_system/imdd_minimal_2.m index ef56fb2..b20ab78 100644 --- a/projects/standard_system/imdd_minimal_2.m +++ b/projects/standard_system/imdd_minimal_2.m @@ -4,9 +4,9 @@ params = struct; params.M = [4]; params.datarate = [224]; -params.rop = [-5]; +params.rop = [-12:-7]; -precomp_mode = 2; %0=do nothing ; 1= measure; 2=precomp active +precomp_mode = 0; %0=do nothing ; 1= measure; 2=precomp active if ismac precomp_path = "/Users/silasoettinghaus/Documents/MATLAB/imdd_simulation/projects/standard_system"; @@ -165,7 +165,7 @@ for M = wh.parameter.M.values for i = 1: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 @@ -182,7 +182,6 @@ cols = linspecer(8); %cnt = cnt+1; ber_ffe = wh.getStoValue('ber_ffe',M,datarate,wh.parameter.rop.values); - % Create the initial plot figure(44); @@ -190,8 +189,6 @@ a = gca; 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"); - - yline(3.8e-3,'DisplayName','HD-FEC','LineStyle','--','HandleVisibility','off'); xlabel('Received Optical Power (dBm)'); ylabel('Bit Error Rate (BER)'); diff --git a/projects/standard_system/lab_mpi_setup.mat b/projects/standard_system/lab_mpi_setup.mat new file mode 100644 index 0000000..36decc1 Binary files /dev/null and b/projects/standard_system/lab_mpi_setup.mat differ diff --git a/projects/standard_system/lab_mpi_setup_2.mat b/projects/standard_system/lab_mpi_setup_2.mat new file mode 100644 index 0000000..d91e330 Binary files /dev/null and b/projects/standard_system/lab_mpi_setup_2.mat differ