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; obj.signal = obj.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,options) arguments obj options.fs options.logbook end if isa(obj,'Electricalsignal') %convert to information varargout{1} = obj.fs; i_sig = Informationsignal(obj.signal,"fs",options.fs,"logbook",options.logbook); 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) if isa(y,'Signal') Sum = X; Sum.signal = X.signal + y.signal; elseif isnumeric(y) Sum = X; Sum.signal = X.signal + y; end end function Product = times(X,y) if isa(y,'Signal') Product = X; Product.signal = X.signal .* y.signal; elseif isnumeric(y) Product = X; Product.signal = X.signal .* y; end 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 = num2str(obj.length, ['%' sprintf('.%df', 0)]);%[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); obj.fs = options.fs_out; 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_n] = delay(obj,options) arguments obj Signal options.delay_samples = 0 end obj.signal=delayseq(obj.signal,options.delay_samples); end %% function [obj,D,cuts] = tsynch(obj,options) % time sync and cut arguments obj Signal options.reference Signal options.fs_ref = 0; end %normalize the signal a = obj.normalize("mode","oneone").signal; %resample the reference q = obj.fs/options.fs_ref; b = options.reference.resample("fs_in",options.fs_ref,"fs_out",obj.fs).normalize("mode","oneone").signal; %estimate delay between signals [co,lags] = xcorr(a,b,100); [~,pos] = max(co); D = lags(pos); if D == 100 warning('Check Sync: Delay is found to be 100 which is the max. windowlength is xcorr function!') end % delay by lagging samples obj = obj.delay("delay_samples",-D); cuts = obj.length-(options.reference.length*q); if cuts > 10 warning('Check Sync: Signal difference larger than 10.') end if cuts < 0 % warning('Check Sync: Reference Signal shorter than signal to sync.') else % then cut out the length of the reference obj.signal = obj.signal(1:end-cuts); end end end end