├── LICENSE ├── README.md ├── func_1bMM_ML.m ├── func_CQML.m ├── func_lowbSamp.m ├── func_newton.m ├── func_unqtML.m ├── main_comp_mse_vs_snr_multi_bits.m └── zadoff_chu.m /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2022 fqliu 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # coarsely-quantized-ML-channel-estimation-algorithm 2 | These codes are for the paper that published on IEEE COMML: F. Liu, X. Shang, Y. Cheng and G. Zhang, "Computationally Efficient Maximum Likelihood Channel Estimation for Coarsely Quantized Massive MIMO Systems," in IEEE Communications Letters, vol. 26, no. 2, pp. 444-448, Feb. 2022, doi: 10.1109/LCOMM.2021.3133705. 3 | -------------------------------------------------------------------------------- /func_1bMM_ML.m: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fqliu/coarsely-quantized-ML-channel-estimation-algorithm/a812d2ede673677156c82a4b2e30b8b0ed2100ae/func_1bMM_ML.m -------------------------------------------------------------------------------- /func_CQML.m: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fqliu/coarsely-quantized-ML-channel-estimation-algorithm/a812d2ede673677156c82a4b2e30b8b0ed2100ae/func_CQML.m -------------------------------------------------------------------------------- /func_lowbSamp.m: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fqliu/coarsely-quantized-ML-channel-estimation-algorithm/a812d2ede673677156c82a4b2e30b8b0ed2100ae/func_lowbSamp.m -------------------------------------------------------------------------------- /func_newton.m: -------------------------------------------------------------------------------- 1 | function gamma = func_newton(T_rr, T_lr, T_ri, T_li, gamma_pre, Temp_R, Temp_I) 2 | %% Newton's method to solve the problem in Eq. (8) 3 | dif = 1; 4 | iter = 0; 5 | while(dif > 1e-3) 6 | 7 | CC1 = T_rr * gamma_pre - Temp_R; 8 | CC2 = T_lr * gamma_pre - Temp_R; 9 | CC3 = T_ri * gamma_pre - Temp_I; 10 | CC4 = T_li * gamma_pre - Temp_I; 11 | 12 | 13 | temp1 = normpdf(CC1); 14 | temp2 = normpdf(CC2); 15 | 16 | temp3 = normpdf(CC3); 17 | temp4 = normpdf(CC4); 18 | 19 | temp5 = 0.5 * erfc(-1/sqrt(2) * CC1) - 0.5 * erfc(-1/sqrt(2) * CC2); 20 | temp6 = 0.5 * erfc(-1/sqrt(2) * CC3) - 0.5 * erfc(-1/sqrt(2) * CC4); 21 | temp7 = T_rr .* temp1 - T_lr .* temp2; 22 | temp8 = T_ri .* temp3 - T_li .* temp4; 23 | 24 | 25 | TT = temp7 ./ temp5 + temp8 ./ temp6; 26 | 27 | grad_1 = -sum(sum(TT)); 28 | 29 | grad_2 = - sum(sum((-T_rr.^2 .* CC1 .* temp1 + T_lr.^2 .* CC2.*temp2) ./ temp5)); 30 | 31 | 32 | grad_2 = grad_2 - sum(sum((-T_ri.^2 .* CC3 .* temp3 + T_li.^2 .* CC4 .* temp4)./temp6)); 33 | grad_2 = grad_2 + sum(sum(TT.^2)); 34 | 35 | gamma = gamma_pre - grad_1 / grad_2; 36 | 37 | dif = abs(gamma - gamma_pre) / abs(gamma_pre); 38 | 39 | gamma_pre = gamma; 40 | iter = iter +1; 41 | end 42 | 43 | 44 | 45 | -------------------------------------------------------------------------------- /func_unqtML.m: -------------------------------------------------------------------------------- 1 | function h = func_unqtML(Y, X) 2 | %% Input 3 | % Y : received signal matrix 4 | % X : transmit signal matrix 5 | %% Output 6 | % h : estimated real-valued channel vector 7 | 8 | H = Y * X' / (X * X'); 9 | 10 | h = H(:); 11 | 12 | h = [real(h); imag(h)]; -------------------------------------------------------------------------------- /main_comp_mse_vs_snr_multi_bits.m: -------------------------------------------------------------------------------- 1 | clear all; 2 | close all; 3 | clc; 4 | 5 | Nr = 64; %% receive antenna number 6 | Nt = 32; %% transmit antenna number 7 | K = 64; %% pilot length 8 | SNR_dB = -10:5:15; %% SNR 9 | SNR = 10.^(SNR_dB / 10); 10 | 11 | Pnt = 1 ./ SNR; %% noise power (the transmit power is normalized as 1) 12 | MonteC = 10; %% Monte Carlo trail number 13 | 14 | %% Rayleigh Fading Channel Model 15 | 16 | H = randn(Nr,Nt) + 1i* randn(Nr,Nt); 17 | H = H/sqrt(2); 18 | h_true = H(:); 19 | h_true = [real(h_true); imag(h_true)]; 20 | H_fro = norm(H,'fro')^2; 21 | 22 | 23 | %% MSE vector for different quantizaton bit number 24 | 25 | mse_1bit_mc = zeros(length(SNR), MonteC); 26 | mse_2bit_mc = zeros(length(SNR), MonteC); 27 | mse_3bit_mc = zeros(length(SNR), MonteC); 28 | mse_4bit_mc = zeros(length(SNR), MonteC); 29 | mse_unqt_mc = zeros(length(SNR), MonteC); 30 | 31 | %% Zadoff-Zhu sequence / Orthogonal Pilots 32 | x = zadoff_chu(K); 33 | S0 = zeros(K,K); 34 | ind = 1:K; 35 | for jj = 1:K 36 | ind = mod(ind,K) + 1; 37 | S0(:,jj) = x(ind); 38 | end 39 | 40 | for i = 1 : length(SNR) 41 | Pn = Pnt(i); 42 | 43 | %% Thresholds used for 1-bit quantization 44 | h_max = sqrt(1 + Pn)/sqrt(2); 45 | ht = -h_max : 2*h_max/7 : h_max; 46 | ht = ht.'; 47 | 48 | for j = 1: MonteC 49 | % [i, j] 50 | %% Thresholds used for 1-bit quantization 51 | t_bar = zeros(2*K*Nr,1); 52 | kro = ones(K,1); 53 | tem = ht(randi(8, Nr, 1)); 54 | t_bar(1:K*Nr) = kron(kro, tem); 55 | tem = ht(randi(8,Nr,1)); 56 | t_bar(K*Nr+1:2*K*Nr) = kron(kro, tem); 57 | 58 | %% Received Signal Model 59 | % qpsk_signal = randi(4,Nt,K); 60 | % X = pskmod(qpsk_signal - 1, 4, pi/4); %% Random QPSK pilots 61 | X = S0(randperm(Nt),:); %% Random Orthogonal Pilots 62 | X = X / sqrt(Nt); %% normalize the transmit power to 1 63 | N = random('norm',0,sqrt(Pn/2),Nr,K) + 1i * random('norm',0,sqrt(Pn/2),Nr,K); %% Noise matrix 64 | Y_unqt = H * X + N; 65 | y_unqt = Y_unqt(:); 66 | y_bar = [real(y_unqt); imag(y_unqt)]; 67 | 68 | %% 1-bit 69 | z_bar = sign(y_bar - t_bar); 70 | y_lowb = z_bar(1 : K*Nr) + 1i * z_bar(K*Nr+1 : 2*K*Nr); 71 | Y_lowb = reshape(y_lowb, Nr, K); 72 | h_1bit = func_1bMM_ML(z_bar, X, Nr, t_bar); 73 | mse_1bit_mc(i, j) = sum((h_1bit - h_true).^2); 74 | 75 | 76 | %% 2-bit 77 | [y_lowb, thres_r, thres_l] = func_lowbSamp(y_bar, 2); 78 | h_2bit = func_CQML(thres_l, thres_r, y_lowb, X, Nr); 79 | mse_2bit_mc(i, j) = sum((h_2bit - h_true).^2); 80 | 81 | 82 | %% 3-bit 83 | [y_lowb, thres_r, thres_l] = func_lowbSamp(y_bar, 3); 84 | h_3bit = func_CQML(thres_l, thres_r, y_lowb, X, Nr); 85 | mse_3bit_mc(i, j) = sum((h_3bit - h_true).^2); 86 | 87 | %% 4-bit 88 | [y_lowb, thres_r, thres_l] = func_lowbSamp(y_bar, 4); 89 | h_4bit = func_CQML(thres_l, thres_r, y_lowb, X, Nr); 90 | mse_4bit_mc(i, j) = sum((h_4bit - h_true).^2); 91 | 92 | %% Unquantized case 93 | h_unqt = func_unqtML(Y_unqt, X); 94 | mse_unqt_mc(i, j) = sum((h_unqt - h_true).^2); 95 | 96 | end 97 | 98 | end 99 | 100 | %% Compute the NMSE 101 | mse_1bit = mean(mse_1bit_mc, 2)/H_fro; 102 | mse_2bit = mean(mse_2bit_mc, 2)/H_fro; 103 | mse_3bit = mean(mse_3bit_mc, 2)/H_fro; 104 | mse_4bit = mean(mse_4bit_mc, 2)/H_fro; 105 | mse_unqt = mean(mse_unqt_mc, 2)/H_fro; 106 | 107 | %% Plot figure 108 | fx=@(x) 10*log10(x); 109 | A=[0.13 0.55 0.13;0.60 0.20 0.98]; 110 | figure(1); 111 | hold on; 112 | plot(SNR_dB,fx(mse_1bit),'-*','COLOR',A(1,:),'LineWidth',1.5,'MarkerSize',14); 113 | plot(SNR_dB,fx(mse_2bit),'-ks','LineWidth',1.5,'MarkerSize',14); 114 | plot(SNR_dB,fx(mse_3bit),'-kd','LineWidth',1.5,'MarkerSize',14); 115 | plot(SNR_dB,fx(mse_4bit),'-ko','LineWidth',1.5,'MarkerSize',14); 116 | plot(SNR_dB,fx(mse_unqt),'-r>','LineWidth',1.5,'MarkerSize',14); 117 | grid on; 118 | set(gca, 'FontSize', 14); 119 | lg = legend('1bMM-ML','CQML:2-bit','CQML:3-bit','CQML:4-bit','UnqtML'); 120 | lg.FontSize = 14; 121 | xlabel('SNR (dB)','FontSize',14); 122 | ylabel('MSE (dB)','FontSize',14); 123 | 124 | -------------------------------------------------------------------------------- /zadoff_chu.m: -------------------------------------------------------------------------------- 1 | function x = zadoff_chu(N) 2 | % x = chu(N), generate the Chu sequence of length N 3 | 4 | if mod(N,2)==0 5 | x = exp(1i * pi * (1:N).^2 /N); 6 | else 7 | x = exp(1i * pi * (2:(N+1)) .* (1:N) /N); 8 | end 9 | 10 | x = x.'; --------------------------------------------------------------------------------