more and more

This commit is contained in:
Silas Oettinghaus
2026-07-08 21:36:08 +02:00
parent 699d146fb5
commit 1879441999
22 changed files with 2197 additions and 174 deletions

View File

@@ -33,7 +33,7 @@ switch preprocessMode
error('preprocessSignal:InvalidMode', 'Unsupported preprocessing mode "%s".', preprocessMode);
end
[Scpe_sig, Scpe_cell] = Scpe_sig.tsynch("reference", Symbols, "fs_ref", fsym, "debug_plots", options.debug_plots);
[Scpe_sig, Scpe_cell, inverted] = Scpe_sig.tsynch("reference", Symbols, "fs_ref", fsym, "debug_plots", options.debug_plots);
% Scpe_sig = Scpe_cell{1};
% Apply Gaussian filter

View File

@@ -21,18 +21,14 @@ function output = mpi_recipe_dev(Scpe_sig_raw, Symbols, Tx_bits, options)
"debug_plots", options.debug_plots);
mu_dc = 0; % 1e-5
dc_buffer_len = 0;
ffe_buffer_len = 0;
smoothing_buffer_length = options.userParameters.smoothing_length;
smoothing_buffer_update = 1;
mu_dc = 0.005;%1e-5;
eq_settings = { ...
"epochs_tr", 5, ...
"epochs_dd", 5, ...
"epochs_dd", 3, ...
"len_tr", 4096*2, ...
"mu_dd", 1e-1, ...
"mu_tr", 0.4, ...
"mu_dd",3.005e-03, ...
"mu_tr",1.063e-01, ...
"order", 25, ...
"sps", 2, ...
"decide", 0, ...
@@ -43,36 +39,54 @@ function output = mpi_recipe_dev(Scpe_sig_raw, Symbols, Tx_bits, options)
eq_ffe = FFE(eq_settings{:});
% showLevelScatter(Scpe_sig_raw, Symbols, ...
% "fsym", options.fsym, ...
% "fignum", options.dataTable.run_id, ...
% "normalize", true);
showLevelScatter(Scpe_sig_raw, Symbols, ...
"fsym", options.fsym, ...
"fignum", 400, ...
"normalize", true);
%%
% tic
% ffe_results = ffe(eq_ffe, options.M, Scpe_sig, Symbols, Tx_bits, ...
% "precode_mode", options.duob_mode, ...
% 'showAnalysis', options.debug_plots, ...
% "postFFE", [], ...
% "eth_style_symbol_mapping", 0);
% toc
% ffe_results.metrics.print("description",'FFE');
% output.ffe_package = ffe_results;
% Scpe_sig_raw.spectrum("normalizeTo0dB",1,"fft_length",4096*4,"fignum",401);
%%
eq_ffe_dcr = FFE_DCremoval_adaptive_mu(eq_settings{:}, ...
"dc_buffer_len",dc_buffer_len, ...
"ffe_buffer_len",ffe_buffer_len,...
"smoothing_buffer_length",smoothing_buffer_length,...
"smoothing_buffer_update",smoothing_buffer_update);
tic
ffe_results_dcr = ffe(eq_ffe_dcr, options.M, Scpe_sig, Symbols, Tx_bits, ...
"precode_mode", options.duob_mode, ...
'showAnalysis', options.debug_plots, ...
"postFFE", [], ...
"eth_style_symbol_mapping", 0);
toc
ffe_results_dcr.metrics.print("description",'FFE DCR');
output.ffe_dcr_package = ffe_results_dcr;
%options.dataTable.sir;
%% NORMAL FFE
if 1
ffe_results = ffe(eq_ffe, options.M, Scpe_sig, Symbols, Tx_bits, ...
"precode_mode", options.duob_mode, ...
'showAnalysis', options.debug_plots, ...
"postFFE", [], ...
"eth_style_symbol_mapping", 0);
ffe_results.metrics.print("description",sprintf('Normal FFE; SIR %d dB',options.dataTable.sir));
output.ffe_package = ffe_results;
end
%% MPI Reduction
if 1
% dc_buffer_len = 0;
% ffe_buffer_len = 0;
% smoothing_buffer_length = options.userParameters.smoothing_length;
% smoothing_buffer_update = 1;
% eq_ffe_dcr = FFE_DCremoval_adaptive_mu(eq_settings{:}, ...
% "dc_buffer_len",dc_buffer_len, ...
% "ffe_buffer_len",ffe_buffer_len,...
% "smoothing_buffer_length",smoothing_buffer_length,...
% "smoothing_buffer_update",smoothing_buffer_update);
eq_ = FFE_DCremoval("epochs_tr",5,"epochs_dd",3,"len_tr",4096*2,"mu_dd",...
0.0002,"mu_tr",0,"order",25,"sps",2,"decide",0,...
"mu_dc",0.005,"dc_buffer_len",1);
ffe_results_dcr = ffe(eq_, options.M, Scpe_sig, Symbols, Tx_bits, ...
"precode_mode", options.duob_mode, ...
'showAnalysis', options.debug_plots, ...
"postFFE", [], ...
"eth_style_symbol_mapping", 0);
ffe_results_dcr.metrics.print("description",'FFE DCR');
output.ffe_dcr_package = ffe_results_dcr;
end
end

View File

@@ -23,7 +23,8 @@ end
end
% Ensure the figure is ready before calling spectrum
eq_noise.spectrum("displayname", options.displayname, "fignum", fig.Number, "normalizeTo0dB", 1,"color",options.color);
eq_noise = eq_noise - mean(eq_noise.signal);
eq_noise.spectrum("displayname", options.displayname, "fignum", fig.Number, "normalizeTo0dB", 0,"color",options.color,"fft_length",4096*2);
if ~isnan(options.postfilter_taps)
% Hold on to the figure for further plotting

View File

@@ -38,6 +38,8 @@ end
eq_signal = max(min(eq_signal,3),-3);
eq_signal = eq_signal .* -1;
%%% histogram
clf
if isempty(ref_symbol_uncoded)
@@ -47,6 +49,15 @@ end
received_sd = NaN(numel(constellation),numel(ref_symbols));
lvlcol = linspecer(numel(constellation));
lvlcol = cbrewer2('RdBu',numel(constellation)+4);
% remove 4 colors from the middle to avoid the bright central colors
mid = ceil(size(lvlcol,1)/2);
rm_idx = mid + (-1:2); % two before mid and two after (2x2 removal centered)
rm_idx = max(1,min(size(lvlcol,1),rm_idx));
lvlcol(rm_idx,:) = [];
lvlcol = lvlcol(1:numel(constellation),:);
for lvl = 1:numel(constellation)
class_mask = ref_symbols == constellation(lvl);
received_sd(lvl,class_mask) = eq_signal(class_mask);
@@ -71,7 +82,15 @@ end
% DB lobe is drawn separately so the DB-level structure stays visible.
db_constellation = unique(ref_symbols);
classes = unique(ref_symbol_uncoded);
lvlcol = linspecer(numel(classes));
% lvlcol = linspecer(numel(classes));
lvlcol = cbrewer2('RdBu',numel(classes)+4);
% remove 4 colors from the middle to avoid the bright central colors
mid = ceil(size(lvlcol,1)/2);
rm_idx = mid + (-1:2); % two before mid and two after (2x2 removal centered)
rm_idx = max(1,min(size(lvlcol,1),rm_idx));
lvlcol(rm_idx,:) = [];
lvlcol = lvlcol(1:numel(sir_group_labels),:);
for db_lvl = 1:numel(db_constellation)
db_mask = ref_symbols == db_constellation(db_lvl);

View File

@@ -21,15 +21,19 @@ arguments
options.clear (1,1) logical = true
options.windowLength (1,1) double {mustBePositive, mustBeInteger} = 500
options.xLimits double = []
options.yLimits (1,2) double = [-3 3]
options.yLimits (1,2) double = [-2.5 2.5]
options.showStdAnnotations (1,1) logical = true
options.scatterAlpha (1,1) double {mustBeGreaterThanOrEqual(options.scatterAlpha, 0), mustBeLessThanOrEqual(options.scatterAlpha, 1)} = 0.2
options.scatterSize (1,1) double {mustBePositive} = 1
options.avgLineMaxPoints (1,1) double {mustBePositive, mustBeInteger} = 1000
options.avgLineSmoothWindow (1,1) double {mustBePositive, mustBeInteger} = 1
end
fsym = resolveSymbolRate(rxInput, refSymbols, options);
[symbols_for_lvl, avg_for_lvl, xAxisUs, info] = prepareLevelScatterData(rxInput, refSymbols, fsym, options);
if options.showPlot
plotLevelScatter(symbols_for_lvl, avg_for_lvl, refSymbols, xAxisUs, options);
info.plot = plotLevelScatter(symbols_for_lvl, avg_for_lvl, refSymbols, xAxisUs, options);
end
end
@@ -73,6 +77,7 @@ info.shifts = [];
info.fsym = fsym;
info.shiftFs = fsym;
info.varianceByLevel = [];
info.plot = struct();
end
function [symbols_for_lvl, avg_for_lvl, info] = prepareSignalInput(rxSignal, refSymbols, fsym, options, info)
@@ -250,50 +255,95 @@ else
end
end
function plotLevelScatter(symbols_for_lvl, avg_for_lvl, refSymbols, xAxisUs, options)
function plotInfo = plotLevelScatter(symbols_for_lvl, avg_for_lvl, refSymbols, xAxisUs, options)
plotInfo = struct();
if isempty(symbols_for_lvl)
return
end
if isnan(options.fignum)
figure;
figHandle = figure;
else
figure(options.fignum);
figHandle = figure(options.fignum);
if options.clear
clf;
end
end
hold on
ax = gca;
hold(ax, "on");
numLevels = size(symbols_for_lvl, 1);
cols = cbrewer2("Paired", 2*numLevels);
cols = cbrewer2("RdBu", numLevels);
% cols = linspecer(numLevels);
xLimits = getXLimits(options.xLimits, xAxisUs, symbols_for_lvl);
for levelIdx = 1:numLevels
scatter(xAxisUs, symbols_for_lvl(levelIdx, :), 10, ".", ...
"MarkerEdgeColor", cols((2*levelIdx)-1, :), ...
"MarkerEdgeAlpha", 0.5);
if 1
for levelIdx = numLevels:-1:1
scatter(ax, xAxisUs, symbols_for_lvl(levelIdx, :), options.scatterSize, ".", ...
"MarkerEdgeColor", cols(levelIdx, :), ...
"MarkerEdgeAlpha", options.scatterAlpha);
end
end
for levelIdx = 1:numLevels
plot(xAxisUs, avg_for_lvl(levelIdx, :), ...
"LineWidth", 1, ...
"Color", cols(2*levelIdx, :));
[xReduced, yReduced] = reduceAverageLineForPlot( ...
xAxisUs, avg_for_lvl(levelIdx, :), ...
options.avgLineMaxPoints, options.avgLineSmoothWindow);
plot(ax, xReduced, yReduced, ...
"LineWidth", 2, ...
"Color", cols(levelIdx, :));
end
refValues = numericSignal(refSymbols);
yline(unique(refValues), "HandleVisibility", "off");
% refValues = unique(numericSignal(refSymbols));
% for refIdx = 1:numel(refValues)
% yline(ax, refValues(refIdx), "--", ...
% "Color", [0.35 0.35 0.35], ...
% "LineWidth", 0.75, ...
% "HandleVisibility", "off");
% end
if options.showStdAnnotations
annotateLevelStd(symbols_for_lvl, avg_for_lvl, xAxisUs, options.xLimits);
end
xlabel('Time in $\mu$s');
ylabel('Normalized Amplitude');
xlim(getXLimits(options.xLimits, xAxisUs, symbols_for_lvl));
ylim(options.yLimits);
grid on
xlabel(ax, 'Time in $\mu$s');
ylabel(ax, 'Normalized Amplitude');
xlim(ax, xLimits);
ylim(ax, options.yLimits);
grid(ax, "on");
figure(figHandle);
drawnow;
end
function [xReduced, yReduced] = reduceAverageLineForPlot(xAxisUs, yTrace, maxPoints, smoothWindow)
valid = isfinite(xAxisUs) & isfinite(yTrace);
xValid = xAxisUs(valid);
yValid = yTrace(valid);
if isempty(xValid)
xReduced = [];
yReduced = [];
return
end
[xValid, uniqueIdx] = unique(xValid, "stable");
yValid = yValid(uniqueIdx);
if smoothWindow > 1
yValid = smoothdata(yValid, "movmean", smoothWindow);
end
numOut = min(maxPoints, numel(xValid));
if numOut >= numel(xValid)
xReduced = xValid;
yReduced = yValid;
return
end
xReduced = linspace(xValid(1), xValid(end), numOut);
yReduced = interp1(xValid, yValid, xReduced, "pchip");
end
function xLimits = getXLimits(configuredLimits, xAxisUs, symbols_for_lvl)
if ~isempty(configuredLimits)
xLimits = configuredLimits;
@@ -308,12 +358,12 @@ end
lastFilledColumn = find(filledColumns, 1, "last");
xMax = xAxisUs(lastFilledColumn);
xLimits = [0, 1.05*xMax];
xLimits = [0, 1*xMax];
end
function annotateLevelStd(symbols_for_lvl, avg_for_lvl, xAxisUs, configuredXLimits)
xLimits = getXLimits(configuredXLimits, xAxisUs, symbols_for_lvl);
xText = xLimits(1) + 0.96*diff(xLimits);
xText = xLimits(1) + 0.2*diff(xLimits);
for levelIdx = 1:size(symbols_for_lvl, 1)
levelSamples = symbols_for_lvl(levelIdx, :);
@@ -328,9 +378,9 @@ for levelIdx = 1:size(symbols_for_lvl, 1)
yText = median(levelSamples(~isnan(levelSamples)), 'omitnan');
end
label = ['std = ', sprintf('%.3f', levelStd)];
label = ['$\sigma^2_',sprintf('%d', levelIdx),'$ = ', sprintf('%.3f', levelStd)];
text(xText, yText, label, ...
'Interpreter', 'none', ...
'Interpreter', 'latex', ...
'HorizontalAlignment', 'right', ...
'VerticalAlignment', 'middle', ...
'FontSize', 10, ...

View File

@@ -25,6 +25,10 @@ function batchResults = runBatch(workerFcn, jobs, options)
jobs = normalizeJobs(jobs);
nJobs = numel(jobs);
batchResults = cell(1, nJobs);
jobDurations = nan(1, nJobs);
lastJobDuration = nan;
batchStart = tic;
effectiveWorkerCount = 1;
h = [];
if nJobs == 0
@@ -34,28 +38,45 @@ function batchResults = runBatch(workerFcn, jobs, options)
if options.waitbar
h = waitbar(0, char(options.waitbarMessage));
cleanupWaitbar = onCleanup(@() closeWaitbar(h));
updateWaitbar(options.waitbar, h, 0, nJobs, jobDurations, ...
lastJobDuration, 0, effectiveWorkerCount);
end
switch mode
case processingMode.parallel
pool = setupParallelPool(options.numWorkers, options.idleTimeout, options.cancelExistingQueue);
effectiveWorkerCount = min(pool.NumWorkers, nJobs);
futures = parallel.FevalFuture.empty(nJobs, 0);
for jobIdx = 1:nJobs
fprintf('[%s] Submitted.\n', jobs(jobIdx).label);
futures(jobIdx) = parfeval(pool, workerFcn, 1, jobs(jobIdx).args{:});
futures(jobIdx) = parfeval(pool, @runTimedJob, 3, workerFcn, jobs(jobIdx).args);
end
consumedIdx = false(nJobs, 1);
for completedCount = 1:nJobs
try
[jobIdx, jobResult] = fetchNext(futures);
[jobIdx, jobResult, jobRuntime, jobError] = fetchNext(futures);
consumedIdx(jobIdx) = true;
batchResults{jobIdx} = jobResult;
fprintf('[%s] Completed (%d/%d).\n', jobs(jobIdx).label, completedCount, nJobs);
jobDurations(jobIdx) = jobRuntime;
lastJobDuration = jobRuntime;
if ~isempty(options.resultHandler)
options.resultHandler(jobResult, jobs(jobIdx), jobIdx);
if isempty(jobError)
batchResults{jobIdx} = jobResult;
fprintf('[%s] Completed (%d/%d, runtime %s).\n', ...
jobs(jobIdx).label, completedCount, nJobs, formatDuration(jobRuntime));
if ~isempty(options.resultHandler)
options.resultHandler(jobResult, jobs(jobIdx), jobIdx);
end
else
batchResults{jobIdx} = jobError;
if ~isempty(options.errorHandler)
options.errorHandler(jobError, jobs(jobIdx), jobIdx);
else
defaultErrorHandler(jobError, jobs(jobIdx), jobIdx);
end
end
catch fetchErr
errorJobIdx = findErroredFuture(futures, consumedIdx);
@@ -74,21 +95,28 @@ function batchResults = runBatch(workerFcn, jobs, options)
end
end
updateWaitbar(options.waitbar, h, completedCount, nJobs);
updateWaitbar(options.waitbar, h, completedCount, nJobs, ...
jobDurations, lastJobDuration, toc(batchStart), effectiveWorkerCount);
end
case processingMode.serial
for jobIdx = 1:nJobs
jobStart = tic;
try
fprintf('[%s] Running.\n', jobs(jobIdx).label);
jobResult = workerFcn(jobs(jobIdx).args{:});
jobDurations(jobIdx) = toc(jobStart);
lastJobDuration = jobDurations(jobIdx);
batchResults{jobIdx} = jobResult;
fprintf('[%s] Completed (%d/%d).\n', jobs(jobIdx).label, jobIdx, nJobs);
fprintf('[%s] Completed (%d/%d, runtime %s).\n', ...
jobs(jobIdx).label, jobIdx, nJobs, formatDuration(jobDurations(jobIdx)));
if ~isempty(options.resultHandler)
options.resultHandler(jobResult, jobs(jobIdx), jobIdx);
end
catch ME
jobDurations(jobIdx) = toc(jobStart);
lastJobDuration = jobDurations(jobIdx);
batchResults{jobIdx} = ME;
if ~isempty(options.errorHandler)
@@ -98,7 +126,8 @@ function batchResults = runBatch(workerFcn, jobs, options)
end
end
updateWaitbar(options.waitbar, h, jobIdx, nJobs);
updateWaitbar(options.waitbar, h, jobIdx, nJobs, ...
jobDurations, lastJobDuration, toc(batchStart), effectiveWorkerCount);
end
otherwise
@@ -149,16 +178,69 @@ function jobs = normalizeJobs(jobs)
end
end
function updateWaitbar(useWaitbar, h, completedCount, totalCount)
function [jobResult, jobRuntime, jobError] = runTimedJob(workerFcn, jobArgs)
jobStart = tic;
jobError = [];
try
jobResult = workerFcn(jobArgs{:});
catch ME
jobResult = [];
jobError = ME;
end
jobRuntime = toc(jobStart);
end
function updateWaitbar(useWaitbar, h, completedCount, totalCount, jobDurations, lastJobDuration, elapsedSeconds, effectiveWorkerCount)
if ~useWaitbar || ~isgraphics(h)
return
end
waitbar(completedCount / totalCount, h, ...
sprintf('Completed %d/%d jobs', completedCount, totalCount));
completedDurations = jobDurations(~isnan(jobDurations));
if isempty(completedDurations)
averageJobTimeText = 'calculating...';
lastJobTimeText = 'calculating...';
remainingTimeText = 'calculating...';
else
averageJobSeconds = mean(completedDurations);
remainingJobs = totalCount - completedCount;
remainingSeconds = averageJobSeconds * remainingJobs / max(1, effectiveWorkerCount);
averageJobTimeText = formatDuration(averageJobSeconds);
lastJobTimeText = formatDuration(lastJobDuration);
remainingTimeText = formatDuration(remainingSeconds);
end
message = sprintf(['Completed %d/%d jobs\n' ...
'Elapsed total: %s\n' ...
'Last job time: %s\n' ...
'Avg. time/job: %s\n' ...
'Estimated remaining: %s'], ...
completedCount, totalCount, formatDuration(elapsedSeconds), ...
lastJobTimeText, averageJobTimeText, remainingTimeText);
waitbar(completedCount / totalCount, h, message);
drawnow;
end
function text = formatDuration(seconds)
if isempty(seconds) || isnan(seconds) || isinf(seconds)
text = 'unknown';
return
end
seconds = max(0, seconds);
hours = floor(seconds / 3600);
minutes = floor(mod(seconds, 3600) / 60);
wholeSeconds = floor(mod(seconds, 60));
if hours > 0
text = sprintf('%d:%02d:%02d', hours, minutes, wholeSeconds);
else
text = sprintf('%02d:%02d', minutes, wholeSeconds);
end
end
function closeWaitbar(h)
if isgraphics(h)
delete(h);

View File

@@ -19,66 +19,85 @@ end
ax = gca;
% ---------------------------------------------------------
% Extract *only* real data lines from ax.Children
% Extract real data objects from ax.Children
% ---------------------------------------------------------
children = ax.Children;
isLine = arrayfun(@(h) isa(h,'matlab.graphics.chart.primitive.Line'), children);
lines = children(isLine);
isScatter = arrayfun(@(h) isa(h,'matlab.graphics.chart.primitive.Scatter'), children);
% Remove helper lines (e.g. yline, fit overlays)
lines = lines(~strcmp({lines.Tag},'ConstantLine'));
isConstantLine = arrayfun(@(h) isprop(h,'Tag') && strcmp(h.Tag,'ConstantLine'), children);
n = numel(lines);
if n == 0
return
end
dataObjects = children((isLine | isScatter) & ~isConstantLine);
n = numel(dataObjects);
% ---------------------------------------------------------
% Fixed color palette (deterministic across figures)
% ---------------------------------------------------------
try
cmap = linspecer(n);
catch
cmap = lines(n).Color; %#ok<NASGU>
cmap = linespecer_fallback(n);
if n > 0
try
cmap = linspecer(n);
catch
cmap = linespecer_fallback(n);
end
end
markers = {'o','s','o','o','^','v','d','>'};
lw = 0.8;
ms = 4;
ms = 2;
% ---------------------------------------------------------
% Apply line + marker styling
% Apply line/scatter + marker styling
% ---------------------------------------------------------
for i = 1:n
ln = lines(n-i+1); % preserve plotting order
ln.LineWidth = lw;
if options.setcolors
ln.Color = cmap(i,:);
end
dataObj = dataObjects(n-i+1); % preserve plotting order
if isa(dataObj,'matlab.graphics.chart.primitive.Line')
dataObj.LineWidth = lw;
if options.setmarkers
if strcmp(ln.Marker,'none')
ln.Marker = markers{mod(i-1,numel(markers))+1};
end
ln.MarkerSize = ms;
if options.setcolors
ln.MarkerEdgeColor = cmap(i,:);
dataObj.Color = cmap(i,:);
end
if options.setmarkers
if strcmp(dataObj.Marker,'none')
dataObj.Marker = markers{mod(i-1,numel(markers))+1};
end
dataObj.MarkerSize = ms;
if options.setcolors
dataObj.MarkerEdgeColor = cmap(i,:);
end
dataObj.MarkerFaceColor = [1 1 1];
end
elseif isa(dataObj,'matlab.graphics.chart.primitive.Scatter')
if options.setcolors
dataObj.CData = cmap(i,:);
dataObj.MarkerEdgeColor = cmap(i,:);
markerFaceColor = dataObj.MarkerFaceColor;
hasNoFace = ischar(markerFaceColor) && strcmp(markerFaceColor,'none');
if ~hasNoFace
dataObj.MarkerFaceColor = cmap(i,:);
end
end
if options.setmarkers
if strcmp(dataObj.Marker,'none')
dataObj.Marker = markers{mod(i-1,numel(markers))+1};
end
dataObj.SizeData = ms^2;
end
ln.MarkerFaceColor = [1 1 1];
end
end
% ---------------------------------------------------------
% Optional smoothing / fitting overlay
% ---------------------------------------------------------
if options.polyfit
if options.polyfit && n > 0
hold on
for i = 1:n
ln = lines(n-i+1);
x = ln.XData(:);
y = ln.YData(:);
dataObj = dataObjects(n-i+1);
x = dataObj.XData(:);
y = dataObj.YData(:);
valid = isfinite(x) & isfinite(y);
if sum(valid) < options.polyorder+1
@@ -112,7 +131,15 @@ if options.polyfit
yf = polyval(p,xf);
end
lightcol = ln.Color + 0.4*(1-ln.Color);
if isa(dataObj,'matlab.graphics.chart.primitive.Line')
basecol = dataObj.Color;
else
basecol = dataObj.CData(1,:);
if numel(basecol) ~= 3
basecol = cmap(i,:);
end
end
lightcol = basecol + 0.4*(1-basecol);
lightcol(lightcol>1)=1;
plot(xf,yf,'-','Color',lightcol,...

View File

@@ -3,9 +3,13 @@ arguments
% Default to the path in your example if no argument is provided
filename (1,1) string = 'C:\Users\Silas\Documents\Dissertation\00_Examples\tikz\textfig.tikz';
options.cleanfigure = false;
options.cleanTargetResolution = 600;
options.cleanScalePrecision (1,1) double = 1;
end
if options.cleanfigure
cleanfigure;
cleanfigure( ...
'targetResolution', options.cleanTargetResolution, ...
'scalePrecision', options.cleanScalePrecision);
end
matlab2tikz(char(filename), ...
'width', '\fwidth', ...
@@ -38,4 +42,4 @@ matlab2tikz(char(filename), ...
% 'tick label style={/pgf/number format/fixed, /pgf/number format/1000 sep={}}' ...
% });
end
end