function [symbols_for_lvl,avg_for_lvl] = show2Dconstellation(eq_signal,ref_symbols,options) arguments eq_signal ref_symbols options.fignum (1,1) double = NaN % Default to NaN if not provided options.displayname (1,:) char = '' % Default to an empty string if not provided options.color = []; options.clear = true; options.rasterize = false; options.raster_resolution (1,1) double = 1000; options.raster_markersize (1,1) double = 1; options.raster_clim = []; end plot_shit = 1; if isa(eq_signal,'Signal') eq_signal = eq_signal.signal; end if isa(ref_symbols,'Signal') ref_symbols = ref_symbols.signal; end if plot_shit % Determine the figure number to use or create a new figure if isnan(options.fignum) fig = figure; % Create a new figure and get its handle else fig = figure(options.fignum); % Use the specified figure number if options.clear clf; end end end rx_symbols = eq_signal; %./ rms(eq_signal); correct_symbols = ref_symbols; col = cbrewer2('Paired',numel(unique(correct_symbols))*3); useDefaultColormap = isempty(options.color); scatterColor = options.color; ccnt = -1; levels = unique(correct_symbols); M = numel(levels); symbols_for_lvl = NaN(numel(levels),length(correct_symbols)); start = 1; ende = length(correct_symbols); for l = 1:numel(levels) ccnt = ccnt+2; level_amplitude = levels(l); symbols_for_lvl(l,correct_symbols==level_amplitude) = rx_symbols(correct_symbols==level_amplitude); statistical_mean(l) = mean(symbols_for_lvl(l,:),'omitnan'); end tx_even = correct_symbols(1:2:end); tx_odd = correct_symbols(2:2:end); rx_even = rx_symbols(1:2:end); rx_odd = rx_symbols(2:2:end); D_even = tx_even - rx_even; D_odd = tx_odd - rx_odd; D = sqrt(D_even.^2 + D_odd.^2); [X,Y] = meshgrid(levels, levels); [X_,Y_] = meshgrid(statistical_mean, statistical_mean); plot_xlim = [floor(min(X_(:)))-1, ceil(max(X_(:)))+1]; plot_ylim = [floor(min(Y_(:)))-1, ceil(max(Y_(:)))+1]; hold on; if isempty(options.displayname) displayName = ['Even/Odd PAM-',num2str(M)]; else displayName = options.displayname; end if useDefaultColormap cols = flip(cbrewer2('RdYlBu',100)); cols=(cbrewer2("RdYlBu",4096)); % cols(45:55,:) = []; colormap(gca,cols); if isempty(options.raster_clim) cLim = [0 max(D).*0.45]; else cLim = options.raster_clim; end if cLim(2) <= cLim(1) cLim(2) = cLim(1) + eps; end clim(cLim); % colormap(gca,'hsv'); if options.rasterize nBins = options.raster_resolution; xEdges = linspace(plot_xlim(1),plot_xlim(2),nBins+1); yEdges = linspace(plot_ylim(1),plot_ylim(2),nBins+1); xBin = discretize(rx_even,xEdges); yBin = discretize(rx_odd,yEdges); valid = ~isnan(xBin) & ~isnan(yBin) & isfinite(D); countImg = accumarray([yBin(valid), xBin(valid)],1,[nBins nBins],@sum,0); dImg = accumarray([yBin(valid), xBin(valid)],D(valid),[nBins nBins],@mean,NaN); countImgRaw = countImg; markerRadius = max(0, round((options.raster_markersize - 1) / 2)); if markerRadius > 0 kernel = ones(2*markerRadius+1); countImg = conv2(countImg,kernel,'same'); weightedD = dImg; weightedD(~isfinite(weightedD)) = 0; weightedD = conv2(weightedD .* countImgRaw,kernel,'same'); dWeight = conv2(isfinite(dImg) .* countImgRaw,kernel,'same'); dImg = weightedD ./ dWeight; end colorIdx = round((dImg-cLim(1)) ./ diff(cLim) * (size(cols,1)-1)) + 1; colorIdx = min(max(colorIdx,1),size(cols,1)); density = log1p(countImg); if max(density(:)) > 0 density = density ./ max(density(:)); end rgbImg = ones(nBins,nBins,3); for rgbIdx = 1:3 colorPlane = reshape(cols(colorIdx,rgbIdx),nBins,nBins); colorPlane(~isfinite(dImg)) = 1; rgbImg(:,:,rgbIdx) = (1-density) + density .* colorPlane; end hImg = image(linspace(plot_xlim(1),plot_xlim(2),nBins), ... linspace(plot_ylim(1),plot_ylim(2),nBins), ... rgbImg); hImg.HandleVisibility = 'off'; set(gca,'YDir','normal'); uistack(hImg,'bottom'); plot(nan,nan,'.','DisplayName',displayName,'MarkerEdgeColor',col(2,:)); else sz = ones(1,length(D)).*1; scatter(rx_even,rx_odd,sz,D,'.','DisplayName',displayName); end rxLevelColor = col(6,:); else if options.rasterize nBins = options.raster_resolution; xEdges = linspace(plot_xlim(1),plot_xlim(2),nBins+1); yEdges = linspace(plot_ylim(1),plot_ylim(2),nBins+1); xBin = discretize(rx_even,xEdges); yBin = discretize(rx_odd,yEdges); valid = ~isnan(xBin) & ~isnan(yBin); countImg = accumarray([yBin(valid), xBin(valid)],1,[nBins nBins],@sum,0); markerRadius = max(0, round((options.raster_markersize - 1) / 2)); if markerRadius > 0 kernel = ones(2*markerRadius+1); countImg = conv2(countImg,kernel,'same'); end density = log1p(countImg); if max(density(:)) > 0 density = density ./ max(density(:)); end rgbImg = ones(nBins,nBins,3); for rgbIdx = 1:3 rgbImg(:,:,rgbIdx) = (1-density) + density .* scatterColor(rgbIdx); end hImg = image(linspace(plot_xlim(1),plot_xlim(2),nBins), ... linspace(plot_ylim(1),plot_ylim(2),nBins), ... rgbImg); hImg.HandleVisibility = 'off'; set(gca,'YDir','normal'); uistack(hImg,'bottom'); plot(nan,nan,'.','DisplayName',displayName,'MarkerEdgeColor',scatterColor); else scatter(rx_even,rx_odd,5*ones(1,length(D)),'.','DisplayName',displayName,'MarkerEdgeColor',scatterColor); end rxLevelColor = scatterColor; end scatter(X_(:), Y_(:), 2, 'x', 'LineWidth', 10, 'MarkerEdgeColor', rxLevelColor,'DisplayName',[displayName, ' Rx Levels']); scatter(X(:), Y(:), 2, 'x', 'LineWidth', 10, 'MarkerEdgeColor', col(4,:),'DisplayName','Tx Levels'); xlim(plot_xlim); ylim(plot_ylim); decisionBoundaries = (levels(1:end-1) + levels(2:end)) / 2; ax = gca; xticks(levels); yticks(levels); xticklabels(compose('%g',levels)); yticklabels(compose('%g',levels)); try ax.XAxis.MinorTickValues = decisionBoundaries; ax.YAxis.MinorTickValues = decisionBoundaries; end ax.XMinorTick = 'on'; ax.YMinorTick = 'on'; ax.XMinorGrid = 'on'; ax.YMinorGrid = 'on'; ax.GridLineStyle = '--'; ax.MinorGridLineStyle = ':'; ax.GridColor = [0.65 0.65 0.65]; ax.MinorGridColor = [0.35 0.35 0.35]; ax.GridAlpha = 0.35; ax.MinorGridAlpha = 0.45; legend xlabel('even symbols'); ylabel('odd symbols'); axis equal; grid on; grid minor; ax.Layer = 'top'; end