more and more
This commit is contained in:
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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, ...
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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,...
|
||||
|
||||
@@ -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
|
||||
|
||||
Reference in New Issue
Block a user