classdef PAMmapper %PAMMAPPER Summary of this class goes here % Detailed explanation goes here properties M unipolar thresholds levels scaling eth_style end methods function obj = PAMmapper(M, unipolar, options) %PAMMAPPER Construct an instance of this class % Detailed explanation goes here arguments M unipolar options.eth_style = 0; end obj.M = M; obj.unipolar = unipolar; obj.thresholds = obj.get_demodulation_thresholds(); obj.levels = obj.get_levels(); obj.scaling = rms(obj.get_levels()); obj.eth_style = options.eth_style; end function out = map(obj,signal_in) if isa(signal_in,'Signal') signal_in.signal = obj.map_(signal_in.signal); % signal_in = signal_in.normalize("mode","rms"); lbdesc = ['Map bat stream to PAM ',num2str(obj.M),' symbols']; signal_in = signal_in.logbookentry(lbdesc,obj); out = signal_in; else out = obj.map_(signal_in); end end function signal_out = demap(obj,signal_in) issignalclass = 0; if isa(signal_in,'Signal') signalclass = signal_in; signal_in = signal_in.signal; issignalclass = 1; end signal_out = obj.demap_(signal_in); if issignalclass lbdesc = ['Demap PAM ',num2str(obj.M),' symbols to bit stream']; signal_in = signalclass; signal_in = signal_in.logbookentry(lbdesc,obj); signal_in.signal = signal_out; signal_out = signal_in; end end function pam_sig = map_(obj,bitpattern) switch obj.M case 2 % 2-ASK: BPSK / OOK if ~obj.eth_style pam_sig = bitpattern(:,1); if obj.unipolar==0 pam_sig=2*pam_sig-1; end else pam_sig = -2*bitpattern(:,1) + 1; end case 4 % 4-ASK: if ~obj.eth_style pam_sig=2*bitpattern(:,1)+(bitpattern(:,1)==bitpattern(:,2)); if obj.unipolar==0 pam_sig=2*pam_sig-3; end else pam_sig = (2*bitpattern(:,1)-1).*(-2*bitpattern(:,2)+3); end pam_sig = pam_sig/sqrt(5); case 6 if ~obj.eth_style m = 1; if size(bitpattern,2)>size(bitpattern,1) bitpattern = bitpattern'; %vector aufrecht stellen end % LUT based mapping for k = 1:5:fix(length(bitpattern)/5)*5 pam_sig(m:m+1,1) = obj.thresholds(bin2dec(int2str(bitpattern(k:k+4)'))+1,:); m = m+2; end else bitsPerSymbol = reshape(bitpattern,5,[]).'; % reorder 5 bits per symbol normFactor = 1; %====================32 QAM===================% %=============================================% % Coding % % 01000 01001 |11001 11000 % % | % % 01010 01110 01100 |11100 11110 11010 % % | % % 01011 01111 01101 |11101 11111 11011 % % --------------------|------------------- % % 00011 00111 00101 |10101 10111 10011 % % | % % 00010 00110 00100 |10100 10110 10010 % % | % % 00000 00001 |10001 10000 % %=============================================% % modulate three LSB first in first Quadrant % first bit inverts real part if 0 % second bit inverts imaginary part if 0 LSB_symbols = normFactor*(... +(1+1i) *(bitsPerSymbol(:,3)==1 & bitsPerSymbol(:,4)==0 & bitsPerSymbol(:,5)==1)... +(3+1i) *(bitsPerSymbol(:,3)==1 & bitsPerSymbol(:,4)==1 & bitsPerSymbol(:,5)==1)... +(5+1i) *(bitsPerSymbol(:,3)==0 & bitsPerSymbol(:,4)==1 & bitsPerSymbol(:,5)==1)... +(1+3i) *(bitsPerSymbol(:,3)==1 & bitsPerSymbol(:,4)==0 & bitsPerSymbol(:,5)==0)... +(3+3i) *(bitsPerSymbol(:,3)==1 & bitsPerSymbol(:,4)==1 & bitsPerSymbol(:,5)==0)... +(5+3i) *(bitsPerSymbol(:,3)==0 & bitsPerSymbol(:,4)==1 & bitsPerSymbol(:,5)==0)... +(1+5i) *(bitsPerSymbol(:,3)==0 & bitsPerSymbol(:,4)==0 & bitsPerSymbol(:,5)==1)... +(3+5i) *(bitsPerSymbol(:,3)==0 & bitsPerSymbol(:,4)==0 & bitsPerSymbol(:,5)==0)); Re = real(LSB_symbols); Im = imag(LSB_symbols); % if first bit== 0 => invert real part % if second bit== 0 => invert imag part modData2 = Re.*(bitsPerSymbol(:,1)*2-1) + 1i*Im.*(bitsPerSymbol(:,2)*2-1); Re = real(modData2(1:end/2)); Im = imag(modData2(1:end/2)); pam_sig = zeros(length(Re)*2,1); pam_sig(1:2:length(Re)*2) = Re; pam_sig(2:2:length(Im)*2) = Im; end pam_sig = pam_sig/sqrt(10); case 8 % 8-ASK: if ~obj.eth_style x1 = bitpattern(:,1); x2 = (bitpattern(:,1)==bitpattern(:,3)); x3 = x2~=bitpattern(:,2); pam_sig = 4*x1 + 2*x2 + x3; if obj.unipolar==0 pam_sig=2*pam_sig-7; end else pam_sig = (bitpattern(:,1)*2-1).*(4+(2*bitpattern(:,2)-1).*(-2*bitpattern(:,3)+3)); end pam_sig = pam_sig/sqrt(21); case 16 % 16-ASK: x1 = bitpattern(:,1); x2 = (bitpattern(:,1)==bitpattern(:,4)); x3 = x2~=bitpattern(:,3); x4 = x3~=bitpattern(:,2); pam_sig = 8*x1 + 4*x2 + 2*x3 + x4; if obj.unipolar==0 pam_sig=2*pam_sig-15; end end end function thres = get_demodulation_thresholds(obj) %simply get the obj.thresholdseshold values for PAM %28.03.2023 - Silas Oett. - Extracted from digi_demod.m % % switch obj.M % case 2 % thres = 0; % case 4 % thres = [-2 0 2]; % case 6 % thres = [-3 5;-1 5;-3 -5;-1 -5;-5 3;-5 1;-5 -3;-5 -1;-1 3;-1 1;-1 -3;-1 -1;-3 3;-3 1;-3 -3;-3 -1;3 5;1 5;3 -5;1 -5;5 3;5 1;5 -3;5 -1;1 3;1 1;1 -3;1 -1;3 3;3 1;3 -3;3 -1]; % case 8 % thres = [-6 -4 -2 0 2 4 6]; % case 16 % thres = [-10 -8 -6 -4 -2 0 2 4 6 8 10]; % end switch obj.M case 2 % 2-ASK if obj.unipolar thres=0.5; else %bi polar thres=0; end case 4 % 4-ASK if obj.unipolar==0 thres=[-2,0,2]; elseif obj.unipolar==1 thres=[0.5,1.5,2.5]; end thres = thres .* 1/sqrt(5); case 6 %PAM 6 thres = [-3 5;-1 5;-3 -5;-1 -5;-5 3;-5 1;-5 -3;-5 -1;-1 3;-1 1;-1 -3;-1 -1;-3 3;-3 1;-3 -3;-3 -1;3 5;1 5;3 -5;1 -5;5 3;5 1;5 -3;5 -1;1 3;1 1;1 -3;1 -1;3 3;3 1;3 -3;3 -1]; % thres = [-4 -2 0 2 4]; % thres = thres ./ sqrt(10); case 8 % 8-ASK if obj.unipolar==0 thres=-6:2:6; elseif obj.unipolar==1 thres=0.5:6.5; end thres=thres./sqrt(21); case 16 % 16-ASK if obj.unipolar==0 && scale_mode==1 thres=-14:2:14; elseif obj.unipolar==1 && scale_mode==1 thres=0.5:14.5; end end end function levels = get_levels(obj) switch obj.M case 2 levels = [-1 1]; case 4 levels = [-3 -1 1 3]; case 6 levels = [-5 -3 -1 1 3 5]; case 8 levels = [-7 -5 -3 -1 1 3 5 7]; case 16 levels = [-11 -9 -7 -5 -3 -1 1 3 5 7 9 11]; end end function [data_out] = demap_(obj,data_in) data_in= data_in'; if obj.M ~= 6 % create output if ~isempty(obj.thresholds) a = squeeze(repmat(real(data_in),[1 1 length(obj.thresholds)])); %Eingangssignal in 3 spalten b = squeeze(repmat(reshape(obj.thresholds(:).',[1 1 length(obj.thresholds)]),[1 length(data_in) 1])); %Threshold in 3 Spalten comp_real = a > b; %check for each symbol/ sampling if it exeeds the obj.thresholdseshold 1, 2 or 3 comp_real=repmat(real(data_in),[1 1 length(obj.thresholds)]) > repmat(reshape(obj.thresholds(:).',[1 1 length(obj.thresholds)]),[1 length(data_in) 1]); else comp_real=[]; end s1=size(comp_real,1); s2=size(comp_real,2); end switch obj.M case 2 % 2-ASK if ~obj.eth_style data_out=comp_real(:,:,1); else data_out=abs(comp_real(:,:,1)-1); end case 4 % 4-ASK if ~obj.eth_style data_out=[comp_real(:,:,2); ones(s1,s2) - comp_real(:,:,1) + comp_real(:,:,3)]; else data_out= [(data_in>=0); (abs(data_in)<=1)]; end case 6 if ~obj.eth_style % data_in = data_in/(sqrt(mean(abs(data_in).^2))); data_in = data_in*sqrt(10); %data_in = data_in*sqrt((5^2 + 3^2 + 1^2 + 5^2 + 3^2 + 1^2)/6); if size(data_in,2) > 1 data_in = data_in.'; end if length(data_in)/2 ~= round(length(data_in)/2) data_in = [data_in;0]; end m = 1; for n = 1:2:length(data_in) dist = sqrt((data_in(n)-obj.thresholds(:,1)).^2+(data_in(n+1)-obj.thresholds(:,2)).^2); [~,dd_idx] = min(dist); % dec_out(n:n+1) = LUT(dd_idx,:); data_out(m:m+4) = bitget(dd_idx-1,5:-1:1); m = m+5; end else data_in= data_in'; rxSym = data_in(1:2:end) + 1i*data_in(2:2:end); % 16×1 % Decode the sign bits (bits 1 & 2). rxBit1 = double(real(rxSym) > 0); rxBit2 = double(imag(rxSym) > 0); % Undo the quadrant inversion and normalization. rxSym_corr = abs(real(rxSym)) + 1i*abs(imag(rxSym)); normFactor = 1/sqrt(10); rxSym_unscaled = rxSym_corr / normFactor; cand = [1+1i, 3+1i, 5+1i, 1+3i, 3+3i, 5+3i, 1+5i, 3+5i]; candBits = [1 0 1; 1 1 1; 0 1 1; 1 0 0; 1 1 0; 0 1 0; 0 0 1; 0 0 0]; d = abs(rxSym_unscaled - cand).^2; % 32×8 distances [~, idx] = min(d, [], 2); rxLSB = candBits(idx,:); % 32×3 decodedSymbols = [rxBit1, rxBit2, rxLSB]; data_out = reshape(decodedSymbols.', [], 1).'; end case 8 % 8-ASK if ~obj.eth_style data_out=[comp_real(:,:,4); comp_real(:,:,1)-comp_real(:,:,3)+comp_real(:,:,5)-comp_real(:,:,7); 1-comp_real(:,:,2)+comp_real(:,:,6)]; else data_out = [(data_in>=0); (abs(data_in)>(4/sqrt(21))); (abs(data_in)>=(2/sqrt(21)))&(abs(data_in)<=(6/sqrt(21)))]; end case 16 % 16-ASK data_out=[comp_real(:,:,8); comp_real(:,:,1)-comp_real(:,:,3)+comp_real(:,:,5)-comp_real(:,:,7)+comp_real(:,:,9)-comp_real(:,:,11)+comp_real(:,:,13)-comp_real(:,:,15); comp_real(:,:,2)-comp_real(:,:,6)+comp_real(:,:,10)-comp_real(:,:,14); 1-comp_real(:,:,4)+comp_real(:,:,12)]; end data_out = data_out'; end function [data_out] = decide_pamlevel(obj,data_in,options) arguments obj data_in Signal options.symbol_levels = [] end %A) normally return the preproduct of the decision a = squeeze(repmat(real(data_in.signal),[1 1 length(obj.thresholds)])); %Eingangssignal in 3 spalten b = squeeze(repmat(reshape(obj.thresholds(:).',[1 1 length(obj.thresholds)]),[1 length(data_in.signal) 1])); %Threshold in 3 Spalten comp_real = a > b; %check for each symbol/ sampling if it exeeds the obj.thresholdseshold 1, 2 or 3 data_out = data_in; data_out.signal = sum(comp_real,2); %Option: return the actual level values/ just map onto given %symbol levels if ~isempty(options.symbol_levels) data_out.signal = options.symbol_levels(data_out.signal+1); end end function [out] = separate_pamlevels(obj,data_in) %data_in is Signal class %A) normally return the preproduct of the decision a = squeeze(repmat(real(data_in.signal),[1 1 length(obj.thresholds)])); %Eingangssignal in 3 spalten b = squeeze(repmat(reshape(obj.thresholds(:).',[1 1 length(obj.thresholds)]),[1 length(data_in.signal) 1])); %Threshold in 3 Spalten comp_real = a > b; %check for each symbol/ sampling if it exeeds the obj.thresholdseshold 1, 2 or 3 comp_real_sum = sum(comp_real,2); out = NaN(length(data_in),length(obj.thresholds)+1); for idx = 1:length(data_in) out(idx,comp_real_sum(idx)+1) = data_in.signal(idx); end end function [Signal_out] = quantize(obj,Signal_in) constellation = obj.get_levels(); constellation = constellation ./ rms(constellation); issignalclass = 0; if isa(Signal_in,'Signal') issignalclass = 1; Sig_class = Signal_in; Signal_in = Signal_in.signal; end [~,high_dim_sig] = max(size(Signal_in)); [~,high_dim_const] = max(size(constellation)); if high_dim_sig == high_dim_const Signal_in = Signal_in'; end dist = abs(Signal_in - constellation); [~,symbol_idx] = min(dist,[],2); % decision for closest constellation point Signal_out = constellation(symbol_idx); Signal_out = reshape(Signal_out,size(Signal_in)); if issignalclass Sig_class.signal = Signal_out; Signal_out = Sig_class; end end function bitmap = showBitMapping(obj) bitmap = obj.demap([obj.levels ./ obj.scaling]'); end end end