classdef Signal %SIGNAL Summary of this class goes here % Detailed explanation goes here properties signal logbook end methods function obj = Signal(signal) %SIGNAL Construct an instance of this class % Detailed explanation goes here obj.signal = signal; SignalType = []; TimeStamp = []; Length = []; SignalPower = []; Nase = []; Description = []; obj.logbook = table(SignalType,TimeStamp,Length,SignalPower,Nase,Description); end %% CONVERT TO INFORMATIONSIGNAL function [i_sig, varargout] = Informationsignal(obj) if isa(obj,'Electricalsignal') %convert to optical varargout{1} = obj.fs; i_sig = Informationsignal(obj.signal); elseif isa(obj,'Opticalsignal') error("Cannot convert from optical- to informationsignal. Use O/E conversion first."); end end %% CONVERT TO Electricalsignal function [e_sig, varargout] = Electricalsignal(obj,options) arguments obj options.fs options.logbook end obj.logbook = options.logbook; if isa(obj,'Opticalsignal') %convert to electrical varargout{1} = obj.nase; varargout{2} = obj.lambda; e_sig = Electricalsignal(obj.signal,"fs",obj.fs,"logbook",obj.logbook); elseif isa(obj,'Informationsignal') try % specify fs at varargin{1} e_sig = Electricalsignal(obj.signal,"fs",options.fs,"logbook",options.logbook); catch error("Signal Conversion failed [I -> E] "); end end end %% CONVERT TO Opticalsignal function o_sig = Opticalsignal(obj, options) arguments obj options.fs options.logbook options.nase options.lambda end fn = fieldnames(options); for l = 1:numel(fn) try obj.(fn{l}) = options.(fn{l}); end end if isa(obj,'Electricalsignal') %convert to optical o_sig = Opticalsignal(obj.signal,"fs",obj.fs,"lambda",options.lambda,"logbook",obj.logbook,"nase",options.nase); elseif isa(obj,'Informationsignal') error("Cannot convert from information- to opticalsignal. Use E/O conversion first."); end end %% Add signals from one signal to another, the first object will sustain function Sum = plus(X,Y) Sum = X; %first input object will sustain Sum.signal = X.signal + Y.signal; end %% Display length function return_length = length(obj) %METHOD1 Summary of this method goes here % Detailed explanation goes here return_length = length(obj.signal); end %% Write Logbook Entry function obj = logbookentry(obj,varargin) if nargin > 1 Description = varargin{1}; else Description = ""; end SignalType = [string(class(obj))]; TimeStamp = [(datetime('now','TimeZone','local','Format','HH:mm:ss'))]; Length = [obj.length]; SignalPower = [obj.power]; Nase = [0]; cell = {SignalType , TimeStamp , Length , SignalPower , Nase, Description}; obj.logbook = [obj.logbook;cell]; end %% Resample Signal function obj = resample(obj,options) arguments obj Signal options.fs_in double options.fs_out double end obj.signal = resample(obj.signal,options.fs_out,options.fs_in); desc = ['resample signal from ', num2str(options.fs_in*1e-9), ' GHz to ', num2str(options.fs_out*1e-9), ' GHz' ]; obj = obj.logbookentry(desc); end %% function spectrum(obj,fsamp,options) arguments obj fsamp options.figurename = []; options.displayname = []; end %Get figure if there is already a spectrum plot -> I want to add the new %spectum "onto" the existing plot to have a better comparison if isempty(options.figurename) fig = findall(groot, 'Type', 'figure', 'Name', 'power density'); if isvalid(fig) fig = get(fig); ax = gca; hold on else figure('name','power density'); ax = gca; end else fig = findall(groot, 'Type', 'figure', 'Name', options.figurename); if isvalid(fig) ax = fig.CurrentAxes; hold on else figure('name',options.figurename); ax = gca; hold on end end %compute FFT of input Fsignal = fft(obj.signal); %POWER spectral density (todo: toggle?) psd = Fsignal.*conj(Fsignal); %Use only magnitude of FFT (which was complex) psd = abs(psd); %Shift the spectrum to yield psd = fftshift(psd); %divide by N psd = psd/length(Fsignal); %smoothing psd = smooth(psd,1000); psd_plot = 20*log10(psd); psd_plot(psd_plot<-120) = -120; testParseval = 1; if testParseval == 1 E_FreqDomain = sum(psd); %test parseval E_TimeDomain = sum(abs(Fsignal.^2)); if isequal(round(E_FreqDomain,1),round(E_TimeDomain,1)) %disp('Parseval is right!'); else disp('Parseval theorem is not right...'); end end if fsamp <= 1e+100 %Frequency Axis freq_vec = linspace(-fsamp/2,fsamp/2,length(psd)); freq_vec = reshape(freq_vec,size(psd_plot)); if ~isempty(options.displayname) plot(freq_vec*1e-9,psd_plot,'Linewidth',0.5,'DisplayName',options.displayname,'Parent',ax); else plot(freq_vec*1e-9,psd_plot,'Linewidth',0.5,'Parent',ax); end xlabel('Frequency [GHz]') else %Wavelength Axis freq_vec = physconst('LightSpeed')*linspace(-fsamp/2,fsamp/2,length(psd))./((physconst('LightSpeed')/1550e-9)^2); if ~isempty(options.displayname) plot(freq_vec*1e9,psd_plot,'Linewidth',0.5,'DisplayName',options.displayname,'Parent',ax); else plot(freq_vec*1e9,psd_plot,'Linewidth',0.5,'Parent',ax); end xlabel('Wavelength [nm]') end ylabel('Magnitude [dB]') legend grid minor; end %% function obj = normalize(obj,options) arguments obj Signal options.mode normalization_mode = normalization_mode.rms end switch options.mode case normalization_mode.rms obj.signal = obj.signal/sqrt(mean(abs(obj.signal).^2,"all")); case normalization_mode.oneone obj.signal = obj.signal/max(abs(obj.signal)); end end %% function obj = delay(obj,options) arguments obj Opticalsignal options.delay_meter double = 0 end delay_t = options.delay_meter /(physconst("LightSpeed")/1.4677); delay_n = round(delay_t .* obj.fs); % build "long" hann window to fade the signal in and out % -> prevent hard step in the signal! hann_wind = hann(200); ones_wind = ones(size(obj.signal)); ones_wind(1:100) = hann_wind(1:100); ones_wind(end-100:end) = hann_wind(end-100:end); % subtract average mu = mean(obj.signal,"all"); obj.signal = obj.signal - mu; %apply hann obj.signal = obj.signal .* ones_wind; %add average again obj.signal = obj.signal + mu; % finally circshift the signal obj.signal=circshift(obj.signal,delay_n); end end end