Theory stuff from sials work pc; minor stuff here and there

This commit is contained in:
Silas Oettinghaus
2026-02-19 15:11:32 +01:00
parent 1b8d83dec0
commit 2a724b833f
14 changed files with 810 additions and 39 deletions

View File

@@ -23,12 +23,16 @@ D_lin = S0 .* (lambda_nm - lambda0_nm);
% plot
figure('Color','w'); hold on;
cols = cbrewer2('paired',4);
plot(lambda_nm, D_lin(1,:), '-', 'LineWidth',2, 'DisplayName','Linearized model','Color',[cols(1,:)]);
plot(lambda_nm, D_exact(1,:), 'LineWidth',2, 'DisplayName',sprintf('Exact model'),'Color',[cols(2,:)]);
cols = [0.6510 0.8078 0.8902;...
0.1216 0.4706 0.7059;...
0.6980 0.8745 0.5412;...
0.2000 0.6275 0.1725];
plot(lambda_nm, D_lin(2,:), '-', 'LineWidth',2, 'HandleVisibility','off','Color',[cols(3,:)]);
plot(lambda_nm, D_exact(2,:), 'LineWidth',2, 'HandleVisibility','off','Color',[cols(4,:)]);
% plot(lambda_nm, D_lin(1,:), '-', 'LineWidth',2, 'DisplayName','Linearized model','Color',[cols(1,:)]);
plot(lambda_nm, D_exact(1,:), 'LineWidth',2, 'DisplayName',sprintf('S_0 = 0.07'),'Color',[cols(2,:)]);
% plot(lambda_nm, D_lin(2,:), '-', 'LineWidth',2, 'HandleVisibility','off','Color',[cols(3,:)]);
plot(lambda_nm, D_exact(2,:), 'LineWidth',2, 'HandleVisibility','on', 'DisplayName',sprintf('S_0 = 0.09'),'Color',[cols(4,:)]);
xlabel('Wavelength $\lambda$ [nm]','Interpreter','latex');
@@ -36,4 +40,7 @@ ylabel('D($\lambda$) [ps/(nm km)]','Interpreter','latex');
title('Chromatic Dispersion Around the ZDW');
legend('Location','best');
grid on; box on;
xlim([min(lambda_nm) max(lambda_nm)])
ylim([-5 5]);
% mat2tikz_improved('C:\Users\Silas\Documents\6971e0b65b380ca6d71c837f\02_IMDD_System\tikz\dispersion\dispersion')

View File

@@ -0,0 +1,124 @@
%% ============================================================
% SNR vs Optical Input Power (dBm) Shot vs Thermal vs Combined
% - Generate optical field as sine with target RMS power (verified)
% - Magnitude-square detection -> optical power
% - Photocurrent = Rd * P
% - Add shot noise + thermal noise (white, PSD-based)
% - Compute SNR for: shot-only, thermal-only, combined
% ============================================================
% Constants
k = Constant.Boltzmann;
q = Constant.ElementaryCharge;
% Receiver / PD parameters
T = 20 + 273.15; % K
R = 50; % Ohm (front-end/load)
Rd = 0.7; % A/W (responsivity)
Be = 100e9; % Hz (electrical noise bandwidth)
Id = 0; % A (dark current, optional)
% Sampling for time-domain demo (needs to be >> Be)
fs = 1e12; % Hz
N = 2^14; % samples
t = (0:N-1).'/fs;
% Choose an electrical tone within bandwidth (arbitrary for demo)
f0 = 10e9; % Hz
% Thermal current PSD (two-sided) and variance in Be
Si_th = 4*k*T/R; % A^2/Hz (two-sided)
sigma2_th = Si_th * Be; % A^2
sigma_th = sqrt(sigma2_th); % A_rms
% Optical input power sweep (in dBm)
P_dBm = linspace(-40, 10, 300);
P_W = 10.^((P_dBm - 30)/10); % W
% Pre-allocate results
SNR_shot_dB = zeros(size(P_dBm));
SNR_th_dB = zeros(size(P_dBm));
SNR_tot_dB = zeros(size(P_dBm));
% --- Main loop over optical input power
for ii = 1:numel(P_W)
Pavg = P_W(ii);
% Optical field with RMS power = Pavg:
% Let x(t) be the optical field amplitude such that |x|^2 has mean Pavg.
% Use a sinusoid: x(t) = A*sin(2*pi*f0*t), then mean(|x|^2)=A^2/2.
A = sqrt(2*Pavg); % -> mean(|x|^2) = Pavg
x = A * sin(2*pi*f0*t); % "optical field" (real for simplicity)
% Verify RMS/mean power numerically (optional)
P_meas = mean(abs(x).^2); % should be ~ Pavg
a = P_meas - Pavg;
assert(a<1);
% Magnitude-square detection -> optical power waveform
Popt = abs(x).^2; % W (instantaneous)
% Photocurrent waveform (includes DC + 2f0 component for this demo)
I_sig = Rd * Popt; % A
% Define "signal power" as the mean-squared photocurrent due to signal
% (for this sine-squared waveform, it's OK for a demo SNR definition)
P_sig = mean(I_sig.^2);
% -------- Shot noise (white) --------
% Two-sided PSD: Si_shot = 2*q*(I_photo + I_dark)
% For this demo, use average current to set the white-noise level:
Ibar = mean(I_sig) + Id;
Si_shot = 2*q*Ibar; % A^2/Hz
sigma2_sh = Si_shot * Be; % A^2
sigma_sh = sqrt(sigma2_sh); % A_rms
n_sh = sigma_sh * randn(N,1); % time-domain shot noise
% -------- Thermal noise (white Gaussian) --------
n_th = sigma_th * randn(N,1); % time-domain thermal noise
% Noise powers (mean-square) in time domain
Pn_sh = mean(n_sh.^2);
Pn_th = mean(n_th.^2);
Pn_tot = mean((n_sh + n_th).^2); % ~ Pn_sh + Pn_th (independent)
% SNRs
SNR_shot = P_sig / Pn_sh;
SNR_th = P_sig / Pn_th;
SNR_tot = P_sig / Pn_tot;
SNR_shot_dB(ii) = 10*log10(SNR_shot);
SNR_th_dB(ii) = 10*log10(SNR_th);
SNR_tot_dB(ii) = 10*log10(SNR_tot);
% Optional sanity check (can comment out)
% if ii == 1
% fprintf('Check Pavg target/meas: %.3g W / %.3g W\n', Pavg, P_meas);
% end
end
% Plot comparison
figure(1); clf; hold on;
plot(P_dBm, SNR_shot_dB, 'LineWidth', 1.5);
plot(P_dBm, SNR_th_dB, 'LineWidth', 1.5);
plot(P_dBm, SNR_tot_dB, 'LineWidth', 1.5);
grid on;
xlabel('Optical input power [dBm]');
ylabel('SNR [dB]');
title('SNR vs Optical Input Power: Shot vs Thermal vs Combined');
legend('Shot-noise only','Thermal-noise only','Shot + Thermal','Location','best');
% Print example at 0 dBm
[~,idx0] = min(abs(P_dBm - 0));
fprintf('At 0 dBm:\n');
fprintf(' SNR (shot only) = %.2f dB\n', SNR_shot_dB(idx0));
fprintf(' SNR (thermal only) = %.2f dB\n', SNR_th_dB(idx0));
fprintf(' SNR (combined) = %.2f dB\n', SNR_tot_dB(idx0));
% Also print NEP based on thermal PSD (constant NEP_th)
NEP_th = sqrt(Si_th)/Rd; % W/sqrt(Hz)
fprintf('Thermal NEP = %.3g W/sqrt(Hz)\n', NEP_th);

View File

@@ -0,0 +1,68 @@
%% ============================================================
% IM/DD Power Fading Evolution GIF (1 km -> 20 km)
% Uses the provided GifWriter (serial mode)
% ============================================================
clear; close all; clc;
%% Fiber and system parameters
lambda0 = 1310e-9; % zero-dispersion wavelength [m]
lambda = 1275e-9; % operating wavelength [m]
S0 = 0.09; % dispersion slope [ps/(nm^2·km)]
c = physconst('lightspeed');
%% Derived quantities (length-independent)
D_lambda = (S0/4) * (lambda*1e9 - (lambda0*1e9)^4/(lambda*1e9)^3); % ps/(nm·km)
D_si = D_lambda * 1e-6; % s/m^2
b2 = -D_si * lambda^2 / (2*pi*c); % s^2/m
%% Frequency grid
f_max = 150e9;
f = linspace(0, f_max, 4000); % [Hz]
%% Figure setup (keep it stable for nicer GIFs)
fig = figure('Color','w');
ax = axes(fig); %#ok<LAXES>
hold(ax,'on'); grid(ax,'on'); box(ax,'on');
xlabel(ax,'Frequency [GHz]');
ylabel(ax,'Magnitude [dB]');
ylim(ax,[-30 0]);
xlim(ax,[0 f_max/1e9]);
%% GIF writer (serial mode; simplest)
g = GifWriter('Name','power_fading_evolution', 'DelayTime',0.12, 'Parallel',false);
%% Loop: 1 km to 20 km
L = [1:20,19:-1:1];
for L_km = L
L_meter = L_km * 1e3; % [m]
% IM/DD transfer function (power fading)
phi = 2*pi^2 * b2 * f.^2 * L_meter;
H = abs(cos(phi));
HdB = 10*log10(max(H, 1e-12)); % avoid -Inf for deep notches
% Clear and redraw (stable axes)
cla(ax);
plot(ax, f/1e9, HdB, 'LineWidth', 1.8, 'Color','black');
% Analytic first-null frequency marker
f_null = sqrt(c*(0.5)/(abs(D_si)*lambda^2*L_meter));
xline(ax, f_null/1e9, 'r--', 'LineWidth', 1.2, ...
'Label', sprintf('f_{null}=%.1f GHz', f_null/1e9), ...
'LabelOrientation','horizontal', ...
'LabelVerticalAlignment','bottom');
title(ax, sprintf('Power Fading for: %.0f km @ 1275 nm', L_km));
drawnow;
% Add frame to GIF
g.addFrame(fig);
end
%% Done
g.compile(fig.Number);
disp(fullfile(g.OutputDir, sprintf('%s_fig_%d.gif', g.Name, fig.Number)));

View File

@@ -0,0 +1,69 @@
%% ============================================================
% IM/DD Power Fading Evolution vs Wavelength (L = 10 km)
% ============================================================
clear; close all; clc;
%% Fixed fiber parameters
lambda0 = 1310e-9; % zero-dispersion wavelength [m]
S0 = 0.09; % dispersion slope [ps/(nm^2·km)]
L = 10e3; % fiber length FIXED [m]
c = physconst('lightspeed');
%% Frequency grid
f_max = 150e9;
f = linspace(0, f_max, 4000); % [Hz]
%% Figure setup (stable axes for clean GIF)
fig = figure('Color','w');
ax = axes(fig);
hold(ax,'on'); grid(ax,'on'); box(ax,'on');
xlabel(ax,'Frequency [GHz]');
ylabel(ax,'Magnitude [dB]');
ylim(ax,[-30 0]);
xlim(ax,[0 f_max/1e9]);
%% GIF writer
g = GifWriter('Name','power_fading_vs_wavelength', ...
'DelayTime',0.12, ...
'Parallel',false);
%% Wavelength sweep (around ZDW)
lambda_vec = linspace(1260e-9, 1360e-9, 25); % 12601360 nm
for k = 1:length(lambda_vec)
lambda = lambda_vec(k);
%% Dispersion for current wavelength
D_lambda = (S0/4) * (lambda*1e9 - (lambda0*1e9)^4/(lambda*1e9)^3); % ps/(nm·km)
D_si = D_lambda * 1e-6; % s/m^2
b2 = -D_si * lambda^2 / (2*pi*c); % s^2/m
%% Power fading transfer function
phi = 2*pi^2 * b2 * f.^2 * L;
H = abs(cos(phi));
HdB = 10*log10(max(H, 1e-12));
cla(ax)
plot(ax, f/1e9, HdB, 'LineWidth',1.8,'Color','black');
%% First-null frequency
if abs(D_si) > 0
f_null = sqrt(c*(0.5)/(abs(D_si)*lambda^2*L));
xline(ax, f_null/1e9, 'r--', 'LineWidth',1.2, ...
'Label', sprintf('f_{null}=%.1f GHz', f_null/1e9), ...
'LabelOrientation','horizontal', ...
'LabelVerticalAlignment','bottom');
end
title(ax, sprintf('Power Fading for: 10 km @ %.0f nm', lambda*1e9));
drawnow;
g.addFrame(fig);
end
%% Compile GIF
g.compile(fig.Number);
disp(fullfile(g.OutputDir, sprintf('%s_fig_%d.gif', g.Name, fig.Number)));

View File

@@ -8,17 +8,16 @@ c = physconst('lightspeed');
S0_si = S0 * 1e3; % s/m³
Delta_lambda = linspace(5e-9, 80e-9, 300); % [m] detuning
f_null_2 = sqrt( c * 0.5 ./ (S0_si .* abs(Delta_lambda) .* lambda0.^2 .* L) );
L = 2e3; % m
f_null_10 = sqrt( c * 0.5 ./ (S0_si .* abs(Delta_lambda) .* lambda0.^2 .* L) );
cols = cbrewer2('Paired',10);
cols = [0.3467 0.5360 0.6907;...
0.9153 0.2816 0.2878;...
0.4416 0.7490 0.4322];
figure('Color','w');hold on
cnt = 2;
for L = 10%[2,5,10]
cnt = 1;
for L = [2,10,40]
f_null_10 = sqrt( c * 0.5 ./ (S0_si .* abs(Delta_lambda) .* lambda0.^2 .* L*1e3) );
plot(1310-Delta_lambda*1e9, f_null_10/1e9, 'LineWidth',2,'DisplayName',sprintf('%d km',L),'Color',cols(cnt,:));
cnt = cnt+2;
cnt = cnt+1;
end
% yticks([56,75,90,112])
% tickse = 1310-[7.5, 12, 17, 31.5];
@@ -29,4 +28,5 @@ ylabel('$F_{null}$ [GHz]');
grid on; box on;
lim=1310-[5,60];
xlim([lim(2) lim(1)]);
ylim([40,130])
ylim([10,130])
legend

View File

@@ -5,7 +5,7 @@
%% Fiber and system parameters
lambda0 = 1310e-9; % zero-dispersion wavelength [m]
lambda = 1275e-9; % operating wavelength [m]
lambda = 1290e-9; % operating wavelength [m]
S0 = 0.09; % dispersion slope [ps/(nm²·km)]
L = 10e3; % fiber length [m]
c = physconst('lightspeed');
@@ -30,7 +30,7 @@ plot(f/1e9, 10*log10(H), 'LineWidth', 1.8,'Color','black');
grid on; box on;
xlabel('Frequency [GHz]');
ylabel('Magnitude [dB]');
title(sprintf('IM/DD Power Fading: 10 km; 1275nm', lambda*1e9, L/1000),"Interpreter","latex");
% title(sprintf('IM/DD Power Fading: 10 km; 1275nm', lambda*1e9, L/1000),"Interpreter","latex");
ylim([-30 0]);
%% Mark analytic first-null frequency
@@ -38,3 +38,5 @@ f_null = sqrt(c*(0.5)/(abs(D_si)*lambda^2*L));
xline(f_null/1e9, 'r--', 'LineWidth', 1.2, ...
'Label', sprintf('f_{null}=%.1f GHz', f_null/1e9), ...
'LabelOrientation', 'horizontal', 'LabelVerticalAlignment', 'bottom');
mat2tikz_improved('C:\Users\Silas\Documents\6971e0b65b380ca6d71c837f\02_IMDD_System\tikz\dispersion\power_fading.tikz')

View File

@@ -0,0 +1,317 @@
%% Plot S-parameters from Touchstone S2P or S4P (schema-aware, no RF Toolbox)
clear; clc;
[file,path] = uigetfile({"*.s2p;*.S2P;*.s4p;*.S4P","Touchstone (*.s2p, *.s4p)"});
if isequal(file,0); return; end
filename = fullfile(path,file);
%%
% Decide port count by extension (minimal-invasive, robust)
[~,~,ext] = fileparts(file);
ext = upper(ext);
if strcmp(ext,'.S4P')
[matrix, meta] = loads4p_schema(filename);
N = 4;
elseif strcmp(ext,'.S2P')
[matrix, meta] = loads2p(filename); % your original loader kept (below)
N = 2;
else
error("Unsupported extension: %s", ext);
end
% Frequency in GHz
frex = matrix(:,1);
if isfield(meta,'freqScaleHz') && ~isempty(meta.freqScaleHz)
frex = frex * meta.freqScaleHz / 1e9; % convert to GHz
else
% fallback heuristic (your original)
for i = 1:numel(frex)
if frex(i) > 1e4
frex(i) = frex(i).*1e-9;
end
end
end
figure(101);
hold on;
% overlay indexing: count lines already there
if N == 2
lines = numel(findall(gcf, 'type','line'))/4 + 1;
else
lines = numel(findall(gcf, 'type','line'))/16 + 1;
end
% styles (kept)
[CC, LL, MM] = ndgrid({1,2,3,4}, {'-', ':', '-.', '--'}, {'none','+', 'o', '*', 'square', 'diamond'});
combinations = [CC(:), LL(:), MM(:)];
cols = [0.3467 0.5360 0.6907
0.9153 0.2816 0.2878
0.4416 0.7490 0.4322
1.0000 0.5984 0.2000];
% -------------------- Plotting --------------------
if N == 2
heads = ["S11","S12","S22","S21"];
% matrix layout from loads2p:
% col pairs:
% 2-3 S11, 4-5 S21, 6-7 S12, 8-9 S22
colPairs = [2 3; 6 7; 8 9; 4 5]; % order matches heads above
subplots = 1;
for k = 1:4
if subplots, subplot(2,2,k); else, figure('Color','w'); end
hold on; grid on;
reCol = colPairs(k,1);
imCol = colPairs(k,2);
% S-parameter magnitude in dB: 20*log10(|S|)
response = 20*log10(abs(matrix(:,reCol) + 1i.*matrix(:,imCol)));
response = movmean(response,1);
plot(frex, response, ...
"Color", cols(combinations{lines,1},:), ...
"DisplayName", file, ...
"LineStyle", combinations{lines,2}, ...
"Marker", combinations{lines,3}, ...
"MarkerSize", 3);
if k == 2 || k == 3
ylim([-6 2]);
else
ylim([-30 2]);
end
xlim([0 100]);
title(heads(k));
xlabel('Frequency in GHz');
ylabel('|S| (dB)');
legend('Location','best');
end
sgtitle(sprintf('S-Parameters (2-port) [%s]', meta.headerLine));
elseif N == 4
% For s4p schema we plot all Sij in a 4x4 grid
% matrix layout from loads4p_schema:
% columns: 1=f, then pairs in order:
% S11,S12,S13,S14, S21..S24, S31..S34, S41..S44
subplots = 1;
for i = 1:4
for j = 1:4
sp = (i-1)*4 + j;
if subplots, subplot(4,4,sp); else, figure('Color','w'); end
hold on; grid on;
idx = (i-1)*4 + j; % 1..16 for Sij in row-major
reCol = 1 + 2*(idx-1) + 1; % after freq col
imCol = 1 + 2*(idx-1) + 2;
response = 20*log10(abs(matrix(:,reCol) + 1i.*matrix(:,imCol)));
plot(frex, response, ...
"Color", cols(combinations{lines,1},:), ...
"DisplayName", file, ...
"LineStyle", combinations{lines,2}, ...
"Marker", combinations{lines,3}, ...
"MarkerSize", 2);
xlim([0 100]);
title(sprintf("S%d%d", i, j));
set(gca,'FontSize',8);
% reduce clutter
if j ~= 1, yticklabels([]); end
if i ~= 4, xticklabels([]); end
if j == 1, ylabel('|S| (dB)'); end
if i == 4, xlabel('GHz'); end
end
end
sgtitle(sprintf('S-Parameters (4-port) [%s]', meta.headerLine));
end
%% ========================================================================
% Loader for S4P with the EXACT provided schema (4 lines per frequency)
% ========================================================================
function [matrix, meta] = loads4p_schema(filepath)
meta = struct();
meta.headerLine = "";
meta.freqScaleHz = []; % Hz per file unit (e.g., GHz -> 1e9)
fid = fopen(filepath,'r');
if fid < 0, error("Cannot open file: %s", filepath); end
cleaner = onCleanup(@() fclose(fid));
% Parse header: find "#"
freUnit = "";
while true
t = fgetl(fid);
if ~ischar(t), break; end
ts = strtrim(t);
if startsWith(ts,'#')
meta.headerLine = ts;
parts = split(upper(string(ts)));
if numel(parts) >= 2, freUnit = parts(2); end
switch freUnit
case "HZ", meta.freqScaleHz = 1;
case "KHZ", meta.freqScaleHz = 1e3;
case "MHZ", meta.freqScaleHz = 1e6;
case "GHZ", meta.freqScaleHz = 1e9;
otherwise, meta.freqScaleHz = [];
end
break;
end
end
data = [];
while true
l1 = nextNumericLine(fid);
if strlength(l1) == 0
break;
end
% IMPORTANT: sscanf wants char for robust behavior
v1 = sscanf(char(l1), '%f').';
if numel(v1) < 9
error("S4P schema mismatch: expected 9 numbers on first line of a block, got %d.\nLine: %s", numel(v1), char(l1));
end
l2 = nextNumericLine(fid); if strlength(l2)==0, error("Unexpected EOF after first S4P line."); end
l3 = nextNumericLine(fid); if strlength(l3)==0, error("Unexpected EOF after second S4P line."); end
l4 = nextNumericLine(fid); if strlength(l4)==0, error("Unexpected EOF after third S4P line."); end
v2 = sscanf(char(l2), '%f').';
v3 = sscanf(char(l3), '%f').';
v4 = sscanf(char(l4), '%f').';
if numel(v2) < 8 || numel(v3) < 8 || numel(v4) < 8
error("S4P schema mismatch: expected 8 numbers on continuation lines.\nL2: %s\nL3: %s\nL4: %s", char(l2), char(l3), char(l4));
end
f = v1(1);
s1 = v1(2:9); % S11..S14 (re/im pairs)
s2 = v2(1:8); % S21..S24
s3 = v3(1:8); % S31..S34
s4 = v4(1:8); % S41..S44
row = [f, s1, s2, s3, s4]; % 1 + 32 = 33 columns
data = [data; row]; %#ok<AGROW>
end
matrix = data;
end
function ln = nextNumericLine(fid)
ln = "";
while true
t = fgetl(fid);
if ~ischar(t)
ln = "";
return;
end
ts = strtrim(t);
% Skip blanks and comments and header lines
if ts=="" || startsWith(ts,'!') || startsWith(ts,'#')
continue;
end
% Remove inline comment after '!' if present
excl = strfind(ts,'!');
if ~isempty(excl)
ts = strtrim(extractBefore(ts, excl(1)));
if ts==""; continue; end
end
% Keep only if there's at least one numeric token
if ~isempty(regexp(ts,'[-+]?\d*\.?\d+(?:[eEdD][-+]?\d+)?','once'))
ln = string(ts);
return;
end
end
end
%% ========================================================================
% Your original loads2p (kept as-is, but returns meta too)
% ========================================================================
function [matrix, meta] = loads2p(filepath)
meta = struct();
meta.headerLine = "";
meta.freqScaleHz = [];
% Try to read # line for unit scaling (minimal invasive)
fid = fopen(filepath,'r');
if fid >= 0
cleaner = onCleanup(@() fclose(fid));
while true
t = fgetl(fid);
if ~ischar(t), break; end
ts = strtrim(t);
if startsWith(ts,'#')
meta.headerLine = ts;
parts = split(upper(string(ts)));
if numel(parts) >= 2
switch parts(2)
case "HZ", meta.freqScaleHz = 1;
case "KHZ", meta.freqScaleHz = 1e3;
case "MHZ", meta.freqScaleHz = 1e6;
case "GHZ", meta.freqScaleHz = 1e9;
end
end
break;
end
end
end
startRow = 2;
formatSpec = '%20s%25s%23s%23s%23s%23s%23s%23s%23s%s%[^\n\r]';
fileID = fopen(filepath,'r');
dataArray = textscan(fileID, formatSpec, 'Delimiter', '', 'WhiteSpace', '', ...
'TextType', 'string', 'HeaderLines' ,startRow-1, 'ReturnOnError', false, 'EndOfLine', '\r\n');
fclose(fileID);
raw = repmat({''},length(dataArray{1}),length(dataArray)-1);
for col=1:length(dataArray)-1
raw(1:length(dataArray{col}),col) = mat2cell(dataArray{col}, ones(length(dataArray{col}), 1));
end
numericData = NaN(size(dataArray{1},1),size(dataArray,2));
for col=[1,2,3,4,5,6,7,8,9,10]
rawData = dataArray{col};
for row=1:size(rawData, 1)
regexstr = '(?<prefix>.*?)(?<numbers>([-]*(\d+[\,]*)+[\.]{0,1}\d*[eEdD]{0,1}[-+]*\d*[i]{0,1})|([-]*(\d+[\,]*)*[\.]{1,1}\d+[eEdD]{0,1}[-+]*\d*[i]{0,1}))(?<suffix>.*)';
try
result = regexp(rawData(row), regexstr, 'names');
numbers = result.numbers;
invalidThousandsSeparator = false;
if numbers.contains(',')
thousandsRegExp = '^[-/+]*\d+?(\,\d{3})*\.{0,1}\d*$';
if isempty(regexp(numbers, thousandsRegExp, 'once'))
numbers = NaN;
invalidThousandsSeparator = true;
end
end
if ~invalidThousandsSeparator
numbers = textscan(char(strrep(numbers, ',', '')), '%f');
numericData(row, col) = numbers{1};
raw{row, col} = numbers{1};
end
catch
raw{row, col} = rawData{row};
end
end
end
R = cellfun(@(x) ~isnumeric(x) && ~islogical(x),raw);
raw(R) = {NaN};
matrix = cell2mat(raw);
end