clc
%================================================
%已知抽样值以△为单位
%================================================
x = 2047                        %抽样值/量化单位△
pcmcode = pcmEnCode(x)                %调用pcmCode()函数实现PCM编码
amp = pcmDeCode(pcmcode)            %调用pcmDecode()函数实现PCM译码
amp = pcmDecode(pcmcode)
%qerror = x-amp                      %求量化误差
%================================================
%已知抽样值为实际电压值，则需先转换为以△为单位
%================================================
% M = 5;                              %设置量化范围 -5~+5
% delta = M/2^11;                     %求量化单位△
% y = +2.5                              %设置抽样值/V
% y0 = round(y/delta)                 %将抽样值转换为以△为单位
% pcmcode = pcmCode(y0)                %PCM编码
% amp=pcmDecode(pcmcode);             %PCM译码
% amp = amp*delta                     %转换为实际电压值
% qerror=y-amp                       %求量化误差


function pcmcode = pcmEnCode(s)
    start_t=[0,2.^(4:11)];
    width_t=[1,1,2,4,8,16,32,64];
    pcm=0;
    if s>0 
        pcm=pcm+bitshift(1,7);
    else
        s=abs(s)
    end
    for i = 0:7
        if s < start_t(i+2)
            pcm=pcm+bitshift(i,4);
            pcm=pcm+floor((s-start_t(i+1))/width_t(i+1));
            break
        end
    end
    pcmcode=dec2bin(pcm,8);
end

function amp = pcmDeCode(pcmcode)
    start_t=[0,2.^(4:11)];
    width_t=[1,1,2,4,8,16,32,64];
    code=bin2dec(pcmcode);
    isNeg=0;
    if code < 128
        isNeg=1;
    k=bitshift(bitand(code,0b01111111),-4);
    amp=start_t(k+1) ...
       + double(mod(bitand(code,0b01111111),16)) ...
       * width_t(k+1);
    if isNeg=1 amp=-amp;end
end

%PCM译码函数
function amp = pcmDecode(pcmcode)
    code_table=[0,2.^(4:11)];           %段落起始电平表
    delta=[1,1,2,4,8,16,32,64];         %段内量化间隔表
    codeDec=bin2dec(pcmcode);           %二进制编码字符串转换为十进制数值
    ucode=bitand(codeDec,0b01111111);   %屏蔽极性位
    k=bitshift(ucode,-4);               %右移4位，提取段落码
    x0=code_table(k+1);                 %查表求段落起始电平
    m=bitand(ucode,0b00001111);         %提取段内码
    x1=double(m)*delta(k+1);            %求段内量化电平
    dV=x0+x1+delta(k+1)/2;              %译码输出电平 
    if codeDec<=128                     %处理极性
        amp=-dV;
    else 
        amp=dV;
    end
end
