% Diesen PLot habe ich in der Diss als Tabelle % Create a compact 3-column by 4-row MPI time-signal figure table in LaTeX. % % Use these plots from 04_Experimental_Evaluation/tikz/mpi/: % - columns: SIR = 20 dB, 30 dB, 50 dB % - rows: path length = 1 m, 20 m, 300 m, 1000 m % - file pattern: mpi_timesignal_m__db.tikz % % Use a tabular layout with thin black table gridlines: % - \arrayrulewidth = 0.2pt % - \arrayrulecolor{black} % - vertical and horizontal rules around all cells % - rotated row labels for 1 m, 20 m, 300 m, 1000 m % - center the rotated row labels vertically against the plot cells % - use a dedicated left-column macro so the SIR 20 dB plots are slightly wider: % - left column fwidth = 0.255\textwidth % - inner columns fwidth = 0.240\textwidth % - all fheight = 0.102\textheight % % For the TikZ plot files used in the table: % - leftmost/SIR 20 dB plots keep the y-label: % ylabel={Norm. Amplitude} % - SIR 30 dB and 50 dB plots have no y-label: % ylabel={} % - SIR 30 dB and 50 dB plots hide y ticks: % ytick=\empty % - axis labels and tick labels use scriptsize: % every axis/.append style={font=\scriptsize} % xlabel style={font=\color{white!15!black}\scriptsize} % ylabel style={font=\color{white!15!black}\scriptsize} % - sigma annotation node boxes use tiny: % \node[font=\tiny, ...] % - node boxes: % inner sep=0.5pt % at (axis cs:10,...) % sigma labels use normal math subscripts, e.g. $\sigma^2_2$, not $\sigma^2\_2$ % - all plotted line widths and grid style widths were normalized as needed: % addplot line width=1.0pt % - grid should be visually off: % remove xmajorgrids and ymajorgrids % keep style definitions available: % grid style={line width=0.4pt, solid, color=black!20} % minor grid style={line width=0.2pt, solid, color=black!10} % % db = DBHandler("type","mysql","dataBase",'labor'); % savePath = 'W:\labdata\ECOC Silas\ecoc_2025\'; for sirval = [20,30,50] for pathlen = [1,20,300,1000] fp = QueryFilter(); % fp.where('Runs', 'run_id','EQUALS', 987); M = 4; fp.where('Runs', 'pam_level','EQUALS', M); % fp.where('Runs', 'symbolrate','NOT_EQUAL', 112e9); fp.where('Runs', 'fiber_length','EQUALS', 0); fp.where('Runs', 'is_mpi','EQUALS', 1); fp.where('Runs', 'interference_path_length','EQUALS', pathlen); % fp.where('Runs', 'loop_id','GREATER_THAN', 11); fp.where('Runs', 'sir','GREATER_EQUAL',sirval); fp.where('Runs','run_id','GREATER_EQUAL',3153); % Sort results by SIR value ascending and reorder corresponding rows [dataTable,sql_query] = db.queryDB(fp, db.getTableFieldNames('Runs')); [~, idx] = sort(dataTable.sir, 'ascend', 'MissingPlacement', 'last'); dataTable = dataTable(idx, :); dataTable = dataTable(1,:); dataTable_ = dataTable; [~, uniqueIdx] = unique(dataTable.run_id); % Get unique run_id indices % dataTable.SIR = -7 - round(dataTable.power_mpi_interference); fsym = dataTable.symbolrate; M = double(dataTable_.pam_level); duob_mode = db_mode.(strrep(char(dataTable_.db_mode),'"','')); Tx_signal = load([savePath, char(dataTable_.tx_signal_path),'.mat']); Tx_signal = Tx_signal.Digi_sig; Tx_bits = load([savePath, char(dataTable_.tx_bits_path)]); Tx_bits = Tx_bits.Bits; Symbols_mapped = PAMmapper(M,0).map(Tx_bits); Symbols_mapped.fs = dataTable_.symbolrate; Symbols = load([savePath, char(dataTable_.tx_symbols_path)]); Symbols = Symbols.Symbols; Scpe_sig_raw = load([savePath, char(dataTable_.rx_raw_path(1))]); Scpe_sig_raw = Scpe_sig_raw.Scpe_sig_raw; Scpe_sig_raw = Scpe_sig_raw.normalize("mode","rms"); % Scpe_sig_raw.plot("displayname",['Scope Signal (Run ID: ',num2str(dataTable_.run_id)],"fignum",dataTable_.run_id,"clear",0); % % Scpe_sig_raw.spectrum("normalizeTo0dB",1); disp(num2str(dataTable_.interference_path_length)); % Scpe_sig_raw.eye(dataTable.symbolrate,dataTable.pam_level); [separated_levels_sig, avg_sig, plotInfo] = showLevelScatter(Scpe_sig_raw, Symbols, ... "fsym", fsym, ... "syncFs", 2*fsym, ... "fignum", sirval+pathlen, ... "normalize", true, ... "debug_plots", false, ... "showPlot", true, ... "showStdAnnotations", true, ... "yLimits", [-2.5 2.5], ... "xLimits",[0 25],... "scatterAlpha", 0.25, ... "scatterSize", 1, ... "avgLineMaxPoints", 500, ... "avgLineSmoothWindow", 5); title(sprintf("%d m, %d db", pathlen,sirval)); exportDir = "C:/Users/Silas/Documents/6971e0b65b380ca6d71c837f/04_Experimental_Evaluation/tikz/mpi"; exportName = string(sprintf("mpi_timesignal_v2_%dm_%d_db", pathlen,sirval)); pngFile = fullfile(exportDir, exportName + "-1.png"); tikzFile = fullfile(exportDir, exportName + ".tikz"); pngTikzPath = "04_Experimental_Evaluation/tikz/mpi/" + exportName + "-1.png"; figure(sirval + pathlen); exportNakedPlotWithTikz(gca, pngFile, tikzFile, pngTikzPath, 150); end end %% % std_levels = std(separated_levels_sig,0,2,'omitnan'); % mean_levels = mean(separated_levels_sig,2,'omitnan'); % std_tot = std(Scpe_sig_raw.signal,0,1,'omitnan'); % % var_levels = std_levels.^2; % p = polyfit(mean_levels, var_levels, 1); % % var_slope = p(1); % var_offset = p(2);c function exportNakedPlotWithTikz(sourceAx, pngFile, tikzFile, pngTikzPath, resolutionDpi) outputDir = fileparts(pngFile); if ~exist(outputDir, "dir") mkdir(outputDir); end exportScatterLayerPng(sourceAx, pngFile, resolutionDpi); linePlots = collectTikzLinePlots(sourceAx); textAnnotations = collectTikzTextAnnotations(sourceAx); writeTikzPngAxis(tikzFile, pngTikzPath, sourceAx, linePlots, textAnnotations); end function exportScatterLayerPng(sourceAx, pngFile, resolutionDpi) sourceFig = ancestor(sourceAx, "figure"); xLimits = sourceAx.XLim; yLimits = sourceAx.YLim; scatterHandles = findGraphicsObjectsByType(sourceAx, "scatter"); exportFig = figure( ... "Visible", "off", ... "Color", "white", ... "Units", sourceFig.Units, ... "Position", sourceFig.Position); cleanupFigure = onCleanup(@() close(exportFig)); exportAx = copyobj(sourceAx, exportFig); exportAx.Units = "normalized"; exportAx.Position = [0 0 1 1]; exportAx.XLim = xLimits; exportAx.YLim = yLimits; exportAx.XLimMode = "manual"; exportAx.YLimMode = "manual"; stripAxesToScatterOnly(exportAx); hideAxesInkForRasterExport(exportAx); fprintf("Exporting scatter PNG with XLim=[%g %g], YLim=[%g %g], scatter objects=%d: %s\n", ... xLimits(1), xLimits(2), yLimits(1), yLimits(2), numel(scatterHandles), pngFile); drawnow; exportFig.PaperPositionMode = "auto"; print(exportFig, char(pngFile), "-dpng", sprintf("-r%d", resolutionDpi)); end function stripAxesToScatterOnly(ax) plotObjects = findall(ax); for objIdx = 1:numel(plotObjects) obj = plotObjects(objIdx); if obj == ax || ~isvalid(obj) continue end objType = string(get(obj, "Type")); if lower(objType) ~= "scatter" delete(obj); end end end function hideAxesInkForRasterExport(ax) ax.Visible = "on"; ax.Color = "white"; ax.Box = "off"; ax.XGrid = "off"; ax.YGrid = "off"; ax.XMinorGrid = "off"; ax.YMinorGrid = "off"; ax.XTick = []; ax.YTick = []; ax.XColor = "white"; ax.YColor = "white"; ax.Title.String = ""; ax.XLabel.String = ""; ax.YLabel.String = ""; end function handles = findGraphicsObjectsByType(parentHandle, objectType) allHandles = findall(parentHandle); matches = false(size(allHandles)); for handleIdx = 1:numel(allHandles) currentHandle = allHandles(handleIdx); if ~isvalid(currentHandle) continue end matches(handleIdx) = lower(string(get(currentHandle, "Type"))) == lower(string(objectType)); end handles = allHandles(matches); end function linePlots = collectTikzLinePlots(sourceAx) lineHandles = findGraphicsObjectsByType(sourceAx, "line"); lineHandles = flipud(lineHandles(:)); linePlots = repmat(struct( ... "xData", [], ... "yData", [], ... "color", [], ... "lineWidth", []), numel(lineHandles), 1); validLineCount = 0; for lineIdx = 1:numel(lineHandles) lineHandle = lineHandles(lineIdx); xData = lineHandle.XData(:); yData = lineHandle.YData(:); validSamples = isfinite(xData) & isfinite(yData); if ~any(validSamples) continue end validLineCount = validLineCount + 1; linePlots(validLineCount).xData = xData(validSamples); linePlots(validLineCount).yData = yData(validSamples); linePlots(validLineCount).color = lineHandle.Color; linePlots(validLineCount).lineWidth = lineHandle.LineWidth; end linePlots = linePlots(1:validLineCount); end function textAnnotations = collectTikzTextAnnotations(sourceAx) textHandles = findGraphicsObjectsByType(sourceAx, "text"); textHandles = flipud(textHandles(:)); xLimits = sourceAx.XLim; yLimits = sourceAx.YLim; textAnnotations = repmat(struct( ... "x", [], ... "y", [], ... "text", "", ... "anchor", "center"), numel(textHandles), 1); validTextCount = 0; for textIdx = 1:numel(textHandles) textHandle = textHandles(textIdx); labelText = string(textHandle.String); if strlength(strtrim(labelText)) == 0 continue end textPosition = textHandle.Position; if textPosition(1) < xLimits(1) || textPosition(1) > xLimits(2) || ... textPosition(2) < yLimits(1) || textPosition(2) > yLimits(2) continue end validTextCount = validTextCount + 1; textAnnotations(validTextCount).x = textPosition(1); textAnnotations(validTextCount).y = textPosition(2); textAnnotations(validTextCount).text = labelText; textAnnotations(validTextCount).anchor = matlabTextAlignmentToTikzAnchor( ... textHandle.HorizontalAlignment, textHandle.VerticalAlignment); end textAnnotations = textAnnotations(1:validTextCount); end function writeTikzPngAxis(tikzFile, pngTikzPath, sourceAx, linePlots, textAnnotations) outputDir = fileparts(tikzFile); if ~exist(outputDir, "dir") mkdir(outputDir); end xLimits = sourceAx.XLim; yLimits = sourceAx.YLim; fid = fopen(tikzFile, "w"); if fid < 0 error("plot_mpi_timesignal:TikzOpenFailed", ... "Could not open TikZ export file: %s", tikzFile); end cleanupFile = onCleanup(@() fclose(fid)); axisOptions = { " every axis/.append style={font=\scriptsize}," "width=\fwidth," "height=\fheight," "at={(0\fwidth,0\fheight)}," "scale only axis," "axis on top," "xmin=" + formatPgfNumber(xLimits(1)) + "," "xmax=" + formatPgfNumber(xLimits(2)) + "," "xlabel style={font=\color{white!15!black}\small}," "xlabel={Time in $\mu$s}," "ymin=" + formatPgfNumber(yLimits(1)) + "," "ymax=" + formatPgfNumber(yLimits(2)) + "," "ylabel style={font=\color{white!15!black}\small}," "ylabel={Normalized Amplitude}," "axis background/.style={fill=white}," "xmajorgrids," "ymajorgrids," "grid style={line width=0.4pt, dotted, color=black!20}," "scaled ticks=false," "tick label style={/pgf/number format/fixed, /pgf/number format/1000 sep={}}," "legend columns=1" }; fprintf(fid, "%% This file was generated by plot_mpi_timesignal.m.\n"); fprintf(fid, "%%\n"); for lineIdx = 1:numel(linePlots) fprintf(fid, "%s\n", formatTikzColorDefinition(lineIdx, linePlots(lineIdx).color)); end if ~isempty(linePlots) fprintf(fid, "%%\n"); end fprintf(fid, "%s\n\n", "\begin{tikzpicture}"); fprintf(fid, "%s\n", "\begin{axis}[%"); for optionIdx = 1:numel(axisOptions) fprintf(fid, "%s\n", axisOptions{optionIdx}); end fprintf(fid, "%s\n", "]"); graphicsLine = sprintf( ... "\\addplot [forget plot] graphics [xmin=%s, xmax=%s, ymin=%s, ymax=%s] {%s};", ... formatPgfNumber(xLimits(1)), ... formatPgfNumber(xLimits(2)), ... formatPgfNumber(yLimits(1)), ... formatPgfNumber(yLimits(2)), ... char(strrep(pngTikzPath, "\", "/"))); fprintf(fid, "%s\n\n", graphicsLine); writeTikzLinePlots(fid, linePlots); writeTikzTextAnnotations(fid, textAnnotations); fprintf(fid, "%s\n\n", "\end{axis}"); fprintf(fid, "%s", "\end{tikzpicture}%"); end function valueText = formatPgfNumber(value) valueText = string(sprintf("%.15g", value)); end function colorDefinition = formatTikzColorDefinition(colorIdx, rgbColor) colorDefinition = sprintf( ... "\\definecolor{mycolor%d}{rgb}{%.5f,%.5f,%.5f}%%", ... colorIdx, rgbColor(1), rgbColor(2), rgbColor(3)); end function writeTikzLinePlots(fid, linePlots) for lineIdx = 1:numel(linePlots) fprintf(fid, "\\addplot [color=mycolor%d, line width=%.1fpt, forget plot]\n", ... lineIdx, linePlots(lineIdx).lineWidth); fprintf(fid, " table[row sep=crcr]{%%\n"); for sampleIdx = 1:numel(linePlots(lineIdx).xData) fprintf(fid, "%s\t%s\\\\\n", ... formatPgfNumber(linePlots(lineIdx).xData(sampleIdx)), ... formatPgfNumber(linePlots(lineIdx).yData(sampleIdx))); end fprintf(fid, "};\n\n"); end end function writeTikzTextAnnotations(fid, textAnnotations) for textIdx = 1:numel(textAnnotations) fprintf(fid, "\\node[font=\\scriptsize, anchor=%s, fill=white, draw=black!40, rounded corners=2pt, inner sep=2pt]\n", ... textAnnotations(textIdx).anchor); fprintf(fid, " at (axis cs:%s,%s) {%s};\n\n", ... formatPgfNumber(textAnnotations(textIdx).x), ... formatPgfNumber(textAnnotations(textIdx).y), ... escapeTikzText(textAnnotations(textIdx).text)); end end function anchor = matlabTextAlignmentToTikzAnchor(horizontalAlignment, verticalAlignment) horizontalAlignment = string(horizontalAlignment); verticalAlignment = string(verticalAlignment); if horizontalAlignment == "left" horizontalAnchor = "west"; elseif horizontalAlignment == "right" horizontalAnchor = "east"; else horizontalAnchor = ""; end if verticalAlignment == "top" verticalAnchor = "north"; elseif verticalAlignment == "bottom" verticalAnchor = "south"; else verticalAnchor = ""; end if strlength(horizontalAnchor) > 0 && strlength(verticalAnchor) > 0 anchor = verticalAnchor + " " + horizontalAnchor; elseif strlength(horizontalAnchor) > 0 anchor = horizontalAnchor; elseif strlength(verticalAnchor) > 0 anchor = verticalAnchor; else anchor = "center"; end end function textOut = escapeTikzText(textIn) textOut = char(textIn); % textOut = strrep(textOut, "\", "\textbackslash{}"); textOut = strrep(textOut, "{", "\{"); textOut = strrep(textOut, "}", "\}"); textOut = strrep(textOut, "%", "\%"); textOut = strrep(textOut, "&", "\&"); textOut = strrep(textOut, "#", "\#"); textOut = strrep(textOut, "_", "\_"); % textOut = strrep(textOut, "$", "\$"); end