MPI Simulations and stuff
This commit is contained in:
@@ -46,7 +46,7 @@ classdef AWG < handle
|
||||
options.lpf_type = 0;
|
||||
options.f_cutoff = 32e9;
|
||||
options.H_lpf Filter
|
||||
|
||||
|
||||
end
|
||||
|
||||
fn = fieldnames(options);
|
||||
@@ -60,26 +60,33 @@ classdef AWG < handle
|
||||
|
||||
function signalclass_out = process(obj,signalclass_in)
|
||||
|
||||
|
||||
% 0) START AWG SIMULATION
|
||||
|
||||
len_in = length(signalclass_in.signal);
|
||||
|
||||
% disp(['Power Raw Input: ', num2str(mean(abs(real(signalclass_in.signal).^2)))]);
|
||||
|
||||
% 1) RESAMPLE IF NESSECARY
|
||||
if signalclass_in.fs ~= obj.fdac
|
||||
k = obj.kover*obj.fdac / signalclass_in.fs;
|
||||
signalclass_in = signalclass_in.resample("fs_in",signalclass_in.fs,"fs_out",obj.fdac);
|
||||
% min_ = min(signalclass_in.signal);
|
||||
% max_ = max(signalclass_in.signal);
|
||||
signalclass_in = signalclass_in.resample("fs_in",signalclass_in.fs,"fs_out",obj.fdac,"n",10,"beta",5);
|
||||
% signalclass_in.signal = clip(signalclass_in.signal,-1.3414,1.3414);
|
||||
% signalclass_in.signal = softclip(signalclass_in.signal,7,1.3414);
|
||||
% signalclass_in.plot("displayname",'resampled and clipped','fignum',1);
|
||||
end
|
||||
|
||||
% 1-3. actual processing of the signal (normalize->quantize->sample hold)
|
||||
|
||||
% disp(['Power after resamp: ', num2str(mean(abs(real(signalclass_in.signal).^2)))]);
|
||||
|
||||
% 4) PROCESSING of the signal (normalize->quantize->sample hold)
|
||||
signalclass_in.signal = obj.process_(signalclass_in.signal);
|
||||
|
||||
|
||||
% cast the inform. signal to electrical signal
|
||||
if ~isa(signalclass_in,'Electricalsignal')
|
||||
signalclass_in = Electricalsignal(signalclass_in,"fs",obj.fdac*obj.kover,"logbook",signalclass_in.logbook);
|
||||
end
|
||||
|
||||
% normalize to 0dBm before applying the lowpass
|
||||
%signalclass_in = signalclass_in.normalize("mode","milliwatt");
|
||||
signalclass_in = signalclass_in.setPower(13,"dBm");
|
||||
|
||||
|
||||
% 4. Apply LPF on the signal
|
||||
if obj.lpf_active
|
||||
if isa(obj.H_lpf,'Filter')
|
||||
@@ -92,9 +99,9 @@ classdef AWG < handle
|
||||
signalclass_in = lpf.process(signalclass_in);
|
||||
end
|
||||
end
|
||||
|
||||
disp(['AWG output power: ',num2str(signalclass_in.power),' dBm']);
|
||||
|
||||
|
||||
% disp(['AWG output power: ',num2str(signalclass_in.power),' dBm']);
|
||||
|
||||
% append to logbook
|
||||
current_class = class(obj);
|
||||
lbdesc = ['AWG ', current_class , '// k_over:',num2str(obj.kover),'. f_dac:',num2str(obj.fdac*1e-9),'GHz. Resolution:',num2str(obj.bit_resolution),' bits.'];
|
||||
@@ -125,9 +132,57 @@ classdef AWG < handle
|
||||
|
||||
obj.signal_length = length(data_in);
|
||||
|
||||
%%%%%%%%% PRECOMP SINC ROLLOFF %%%%%%%%%
|
||||
if 1
|
||||
% X: design FIR filter for sinc precomp
|
||||
ntaps = 13;
|
||||
npts = 32;
|
||||
% least-squares FIR design
|
||||
fmax = obj.fdac*0.5;
|
||||
ff = linspace(0,fmax,npts);
|
||||
hsinc = sin(pi*ff/obj.fdac)./(pi*ff/obj.fdac + eps); % transfer function of sample and hold DAC
|
||||
hsinc(1) = 1;
|
||||
h_goal= 1./hsinc; % goal function
|
||||
f = 2.*ff./obj.fdac; %vector between 0 and 1, where 1 is nyquist is fsamp/2
|
||||
b = firls(ntaps-1,f,h_goal);
|
||||
data_in = conv(data_in,b,"same");
|
||||
end
|
||||
|
||||
if 0
|
||||
%compare different fir construction methods in matlab
|
||||
b_fir = fir2(ntaps-1,f,h_goal);
|
||||
b_pm = firpm(ntaps-1,f,h_goal);
|
||||
b = firls(ntaps-1,f,h_goal);
|
||||
|
||||
figure(111)
|
||||
freqz(b,1,[],obj.fdac);
|
||||
hold on
|
||||
freqz(b_fir,1,[],obj.fdac);
|
||||
hold on
|
||||
freqz(b_pm,1,[],obj.fdac);
|
||||
plot(f.*obj.fdac./2.*1e-9,20*log10(h_goal),'Marker','o');
|
||||
legend('firls','fir2','firpm','target')
|
||||
end
|
||||
|
||||
if 0
|
||||
% design filter as inverse of the goal transfer function
|
||||
freq_vec = linspace(-obj.fdac/2,obj.fdac/2,length(data_in));
|
||||
h = sin(pi*freq_vec/obj.fdac)./(pi*freq_vec/obj.fdac + eps);
|
||||
max_amp_db = 45;
|
||||
max_amp_lin = 10^(-max_amp_db/20);
|
||||
p = find(h<max_amp_lin);
|
||||
% h(p)=10^(-max_amp_db/20);
|
||||
h_sinc = 1./h;
|
||||
|
||||
convol = fftshift(h_sinc).'.*fft(data_in);
|
||||
data_in = ifft(convol);
|
||||
data_in = real(data_in);
|
||||
end
|
||||
|
||||
%%%%%%%%% Normalize to DAC range %%%%%%%%%
|
||||
% X:
|
||||
if obj.normalize2dac
|
||||
% 0a Normalize the signal to full scale DAC range
|
||||
|
||||
data_in = data_in - min(data_in); %set "foot" to zero
|
||||
data_in = data_in / (max(data_in)-min(data_in)); %scale between 0 and 1
|
||||
data_in = data_in * (obj.dac_max-obj.dac_min); %scale to desired total range of DAC
|
||||
@@ -136,7 +191,10 @@ classdef AWG < handle
|
||||
|
||||
data_in = data_in - mean(data_in);
|
||||
|
||||
% 1. Quantize the signal - Full Scale is between obj.dac_min
|
||||
% disp(['Power after scaling to DAC: ', num2str(mean(abs(real(data_in).^2)))]);
|
||||
|
||||
%%%%%%%%% Quantize %%%%%%%%%
|
||||
% X. Quantize the signal - Full Scale is between obj.dac_min
|
||||
% and dac_max. If signal is smaller in between, you won't use
|
||||
% the full bit-resolution.
|
||||
if obj.bit_resolution>0
|
||||
@@ -144,9 +202,9 @@ classdef AWG < handle
|
||||
else
|
||||
elec_out = data_in;
|
||||
end
|
||||
|
||||
|
||||
% 2. Sample and hold + repeat (data_out: 1xsignal length)
|
||||
%%%%%%%%% Sample and hold %%%%%%%%%
|
||||
% X. Sample and hold + repeat (data_out: 1xsignal length)
|
||||
if obj.upsampling_method == 1
|
||||
% just use matlab function
|
||||
elec_out = resample(elec_out,obj.kover,1);
|
||||
@@ -157,8 +215,8 @@ classdef AWG < handle
|
||||
else
|
||||
error('chosen upsampling method not implemented?');
|
||||
end
|
||||
|
||||
|
||||
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
||||
% 3. Add skew (not implemented so far)
|
||||
if obj.skew_active
|
||||
elec_out = obj.skew(elec_out);
|
||||
|
||||
@@ -5,26 +5,22 @@ classdef M8196A < AWG
|
||||
|
||||
methods
|
||||
|
||||
function obj = M8196A()
|
||||
function obj = M8196A(options)
|
||||
%This is a ready to use AWG simulation that resembles the
|
||||
%properties of the Keysighe M8196A % M8196A (92GBd) https://www.keysight.com/us/en/product/M8196A/92-gsa-s-arbitrary-waveform-generators.html
|
||||
arguments
|
||||
%options.bla = 1;
|
||||
options.kover = 8;
|
||||
end
|
||||
|
||||
obj = obj@AWG();
|
||||
obj.dac_max = 0.5;
|
||||
obj.dac_min = -.5;
|
||||
obj.bit_resolution = 5.5;
|
||||
dac_max = 0.4;
|
||||
dac_min = -0.4;
|
||||
|
||||
obj.fdac = 92e9;
|
||||
|
||||
obj.lpf_active = 1;
|
||||
|
||||
obj.f_cutoff = 32e9;
|
||||
obj.lpf_type = filtertypes.gaussian;
|
||||
obj.H_lpf = Filter('filtdegree',5,"f_cutoff",obj.f_cutoff,"fsamp",obj.kover*obj.fdac,"filterType",obj.lpf_type);
|
||||
fdac = 92e9;
|
||||
|
||||
Lp_awg = Filter('filtdegree',4,"f_cutoff",32e9,"fs",fdac*options.kover,"filterType",filtertypes.butterworth,"active",true);
|
||||
|
||||
obj = obj@AWG("fdac",fdac,"dac_min",dac_min,"dac_max",dac_max,"lpf_active",1,"H_lpf",Lp_awg,"kover",options.kover,...
|
||||
"bit_resolution",5.5,"normalize2dac",1,"upsampling_method","samplehold");
|
||||
|
||||
end
|
||||
|
||||
|
||||
32
Classes/01_transmit/M8199A.m
Normal file
32
Classes/01_transmit/M8199A.m
Normal file
@@ -0,0 +1,32 @@
|
||||
classdef M8199A < AWG
|
||||
properties
|
||||
|
||||
end
|
||||
|
||||
methods
|
||||
|
||||
function obj = M8199A(options)
|
||||
%This is a ready to use AWG simulation that resembles the
|
||||
%properties of the Keysight M8199A
|
||||
|
||||
arguments
|
||||
options.kover = 8;
|
||||
end
|
||||
|
||||
dac_max = 0.3;
|
||||
dac_min = -0.3;
|
||||
|
||||
fdac = 256e9;
|
||||
|
||||
Lp_awg = Filter('filtdegree',4,"f_cutoff",65e9,"fs",fdac*options.kover,"filterType",filtertypes.butterworth,"active",true);
|
||||
|
||||
obj = obj@AWG("fdac",fdac,"dac_min",dac_min,"dac_max",dac_max,"lpf_active",1,"H_lpf",Lp_awg,"kover",options.kover,...
|
||||
"bit_resolution",5.5,"normalize2dac",1,"upsampling_method","samplehold");
|
||||
|
||||
end
|
||||
|
||||
|
||||
end
|
||||
|
||||
|
||||
end
|
||||
@@ -5,25 +5,22 @@ classdef M8199B < AWG
|
||||
|
||||
methods
|
||||
|
||||
function obj = M8199B()
|
||||
function obj = M8199B(options)
|
||||
%This is a ready to use AWG simulation that resembles the
|
||||
%properties of the Keysighe M8199B https://www.keysight.com/us/en/assets/3120-1465/data-sheets/M8199A-128-256-GSa-s-Arbitrary-Waveform-Generator.pdf
|
||||
arguments
|
||||
%options.bla = 1;
|
||||
options.kover = 8;
|
||||
end
|
||||
|
||||
obj = obj@AWG();
|
||||
obj.dac_max = 0.5;
|
||||
obj.dac_min = -.5;
|
||||
obj.bit_resolution = 5.5;
|
||||
dac_max = 0.6;
|
||||
dac_min = -0.6;
|
||||
|
||||
obj.fdac = 256e9;
|
||||
fdac = 256e9;
|
||||
|
||||
Lp_awg = Filter('filtdegree',4,"f_cutoff",75e9,"fs",fdac*options.kover,"filterType",filtertypes.butterworth,"active",true);
|
||||
|
||||
obj.lpf_active = 1;
|
||||
|
||||
obj.f_cutoff = 80e9;
|
||||
obj.lpf_type = filtertypes.gaussian;
|
||||
obj.H_lpf = Filter('filtdegree',5,"f_cutoff",obj.f_cutoff,"fsamp",obj.kover*obj.fdac,"filterType",obj.lpf_type);
|
||||
obj = obj@AWG("fdac",fdac,"dac_min",dac_min,"dac_max",dac_max,"lpf_active",1,"H_lpf",Lp_awg,"kover",options.kover,...
|
||||
"bit_resolution",5.5,"normalize2dac",1,"upsampling_method","samplehold");
|
||||
|
||||
end
|
||||
|
||||
|
||||
117
Classes/01_transmit/PAMsource.m
Normal file
117
Classes/01_transmit/PAMsource.m
Normal file
@@ -0,0 +1,117 @@
|
||||
classdef PAMsource
|
||||
%NAME Summary of this class goes here
|
||||
% Detailed explanation goes here
|
||||
|
||||
properties(Access=public)
|
||||
order
|
||||
useprbs
|
||||
M
|
||||
fsym
|
||||
randkey
|
||||
|
||||
applypulseform
|
||||
pulseformer
|
||||
|
||||
fs_out
|
||||
|
||||
applyclipping
|
||||
clipfactor
|
||||
end
|
||||
|
||||
methods (Access=public)
|
||||
function obj = PAMsource(options)
|
||||
%NAME Construct an instance of this class
|
||||
% Detailed explanation goes here
|
||||
|
||||
arguments
|
||||
options.order = 16;
|
||||
options.useprbs = true;
|
||||
options.M = true
|
||||
options.fsym = 112e9;
|
||||
options.randkey = 0;
|
||||
|
||||
options.applypulseform = 1;
|
||||
options.pulseformer Pulseformer;
|
||||
|
||||
options.fs_out ;
|
||||
|
||||
options.applyclipping = 0;
|
||||
options.clipfactor = 10;
|
||||
end
|
||||
|
||||
|
||||
fn = fieldnames(options);
|
||||
for n = 1:numel(fn)
|
||||
try
|
||||
obj.(fn{n}) = options.(fn{n});
|
||||
end
|
||||
end
|
||||
|
||||
if boolean(obj.applypulseform) && isempty(obj.pulseformer)
|
||||
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);
|
||||
end
|
||||
|
||||
|
||||
|
||||
end
|
||||
|
||||
function [digi_sig,symbols,bits] = process(obj)
|
||||
|
||||
%%%%% PRBS Generation in correct shape for Modulation Format %%%%%%
|
||||
O = obj.order; %order of prbs
|
||||
N = 2^(O-1); %length of prbs
|
||||
[~,seed] = prbs(O,1); %initialize first seed of prbs
|
||||
bitpattern=[];
|
||||
|
||||
if obj.useprbs
|
||||
for i = 1:log2(obj.M)
|
||||
[bitpattern(:,i),seed] = prbs(O,N,seed);
|
||||
end
|
||||
else
|
||||
s = RandStream('twister','Seed',obj.randkey);
|
||||
for i = 1:log2(obj.M)
|
||||
bitpattern(:,i) = randi(s,[0 1], N, 1);
|
||||
end
|
||||
end
|
||||
|
||||
if obj.M == 6
|
||||
bitpattern = reshape(bitpattern,[],1);
|
||||
bitpattern = bitpattern(1:end-mod(length(bitpattern),5));
|
||||
end
|
||||
|
||||
bits = Informationsignal(bitpattern);
|
||||
|
||||
symbols = PAMmapper(obj.M,0).map(bits);
|
||||
symbols.fs = obj.fsym;
|
||||
|
||||
if obj.applyclipping
|
||||
sym_min = min(symbols.signal);
|
||||
sym_max = max(symbols.signal);
|
||||
end
|
||||
|
||||
%%%%% Pulseforming %%%%%%
|
||||
if obj.applypulseform
|
||||
digi_sig = obj.pulseformer.process(symbols);
|
||||
else
|
||||
digi_sig = symbols;
|
||||
end
|
||||
|
||||
%%%%% Resample to f DAC %%%%%%
|
||||
digi_sig = digi_sig.resample("fs_in",digi_sig.fs,"fs_out",obj.fs_out,"n",10,"beta",5);
|
||||
|
||||
%%%%% Hard clip digital signal to PAM range before DAC %%%%%%
|
||||
if obj.applyclipping
|
||||
digi_sig.signal = clip(digi_sig.signal , sym_min * obj.clipfactor , sym_max * obj.clipfactor);
|
||||
end
|
||||
|
||||
% append to logbook
|
||||
lbdesc = ['Generated PAM Signal'];
|
||||
digi_sig = digi_sig.logbookentry(lbdesc);
|
||||
|
||||
end
|
||||
|
||||
|
||||
end
|
||||
|
||||
end
|
||||
@@ -123,9 +123,9 @@ classdef Pulseformer
|
||||
%data_out_ = upfirdn(data_in,h,up,dn);
|
||||
%
|
||||
% %cut signal, which is longer due to fir filter
|
||||
st = round(up/dn*racos_len/2); %we need to cut y_out
|
||||
% en = round(st + (length(data_in)*up/dn) -1);
|
||||
% data_out = data_out(st:en);
|
||||
% st = round(up/dn*racos_len/2); %we need to cut y_out
|
||||
% en = round(st + (length(data_in)*up/dn) -1);
|
||||
% data_out = data_out(st:en);
|
||||
|
||||
%scaling?! see pulsef module line 696
|
||||
% scale = max(max([abs(real(data_out)) abs(imag(data_out))])); %find max value from real and imag part
|
||||
@@ -134,8 +134,8 @@ classdef Pulseformer
|
||||
data_out = data_out';
|
||||
|
||||
%Check output integrity
|
||||
if round(up/dn * length(data_in)) ~= length(data_out)
|
||||
%warning('Check signal length after pulse shaping');
|
||||
if abs(round(up/dn * length(data_in)) - length(data_out)) > 4
|
||||
warning('Check signal length after pulse shaping');
|
||||
%disp('Check signal length after pulse shaping');
|
||||
end
|
||||
|
||||
|
||||
87
Classes/01_transmit/Signalgenerator.m
Normal file
87
Classes/01_transmit/Signalgenerator.m
Normal file
@@ -0,0 +1,87 @@
|
||||
classdef Signalgenerator
|
||||
%NAME Summary of this class goes here
|
||||
% Detailed explanation goes here
|
||||
|
||||
properties(Access=public)
|
||||
form
|
||||
length
|
||||
fs
|
||||
fsig
|
||||
|
||||
end
|
||||
|
||||
methods (Access=public)
|
||||
function obj = Signalgenerator(options)
|
||||
%NAME Construct an instance of this class
|
||||
% Detailed explanation goes here
|
||||
|
||||
arguments
|
||||
options.form signalform = signalform.sine
|
||||
options.length double = 1024
|
||||
options.fs double = 1000 %Hz sampling
|
||||
options.fsig double = 50 % Hz fundamental frex e.g. of the sine or sawtooth
|
||||
end
|
||||
|
||||
%
|
||||
fn = fieldnames(options);
|
||||
for n = 1:numel(fn)
|
||||
try
|
||||
obj.(fn{n}) = options.(fn{n});
|
||||
end
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
function signalclass_out = process(obj)
|
||||
|
||||
% actual processing of the signal (steps 1. - 3.)
|
||||
signal = obj.build_signal();
|
||||
signalclass_out = Informationsignal(signal,"fs",obj.fs);
|
||||
|
||||
% append to logbook
|
||||
lbdesc = ['Signalgenerator: ',char(obj.form), ''];
|
||||
signalclass_out = signalclass_out.logbookentry(lbdesc);
|
||||
|
||||
end
|
||||
|
||||
function signal = build_signal(obj)
|
||||
%METHOD1 Summary of this method goes here
|
||||
% Detailed explanation goes here
|
||||
arguments(Input)
|
||||
obj
|
||||
end
|
||||
|
||||
arguments(Output)
|
||||
signal double
|
||||
end
|
||||
|
||||
switch obj.form
|
||||
case signalform.sine
|
||||
% Parameters
|
||||
T = 1/obj.fs; % Sampling period (seconds per sample)
|
||||
L = obj.length; % Length of signal (number of samples)
|
||||
t = (0:L-1)*T; % Time vector
|
||||
|
||||
% Sine wave parameters
|
||||
f = obj.fsig; % Frequency of the sine wave (Hz)
|
||||
A = 1; % Amplitude of the sine wave
|
||||
|
||||
% Generate sine wave
|
||||
signal = A * sin(2*pi*f*t);
|
||||
case signalform.noise
|
||||
|
||||
end
|
||||
|
||||
|
||||
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
methods (Access=private)
|
||||
% Cant be seen from outside! So put all your functions here that can/
|
||||
% shall not be called from outside
|
||||
|
||||
|
||||
end
|
||||
end
|
||||
Reference in New Issue
Block a user