注释:代码转载自 https://sites.google.com/site/zaiyang0248/publication
一、均匀线阵主程序
% test of SPA in the ULA case
clear all
close all
clc
K = 3; % source number
M = 30; % array length
N = 200; % snapshot number
sigma = 1; % noise variance
% true frequency and power
f = [.1; .11; .5];
p = [3; 3; 1];
A = exp(1i*2*pi*kron((0:M-1)',f'));
S = sqrt(diag(p))*exp(1i*2*pi*rand(K,N));
% S(K,:) = S(1,:); % sources 1 & K coherent
E = diag(sqrt(sigma/2)) * (randn(M,N)+1i*randn(M,N));
% observed snapshots
Y = A*S + E;
% parameter estimation using SPA
tic
mode = 1; % noise variance mode, 1: equal; 2: different
[freq_est, pow_est] = SPA(Y, mode);
toc
% MSE
MSE = norm(f - sort(freq_est(1:K)))^2 / K;
% plot result
figure(100), semilogy(f, p, 'ko'), hold on;
semilogy(freq_est, pow_est, 'rx', 'MarkerSize', 5);
xlabel('Frequency');
ylabel('Power');
legend('Truth', 'Estimate');
title(strcat('Frequency MSE = ', num2str(MSE)));
二、稀疏线阵主程序
% test of SPA in the SLA case
clear all
close all
clc
K = 6;
Omega = [1; 2; 5; 7];
M = max(Omega);
L = length(Omega);
T = 200;
% true frequency and power
f = [.1; .18; .4; .55; .7; .85];
p = [2; 2; 2; 1; 1; 1];
% observed snapshots
X = exp(1i*2*pi*kron(Omega-1,f'));
S = diag(sqrt(p))*exp(1i*2*pi*rand(K,T));
sigma = .1;
E = sqrt(sigma/2) * (randn(L,T)+1i*randn(L,T));
Y = X*S + E;
% parameter estimation using SPA
tic
mode = 1; % noise variance mode, 1: equal; 2: different
[freq_est, pow_est] = SPA(Y, mode, Omega);
toc
% MSE
MSE = norm(f - sort(freq_est(1:K)))^2 / K;
% plot result
figure(100), plot(f, p, 'ko'), hold on;
plot(freq_est, pow_est, 'rx', 'MarkerSize', 5);
xlabel('Frequency');
ylabel('Power');
% axis([0,1,0,3]);
legend('Truth', 'Estimate');
title(strcat('Frequency MSE = ', num2str(MSE)));
三、SPA函数
function [freq, pow] = SPA(Y, mode_noise, Omega)
% [freq, pow] = SPA(Y, mode_noise, Omega)
%
% SPA implements the sparse and parametric approach (SPA) for linear array
% signal processing.
%
% Input
% Y: observation
% mode_noise: 1 if equal noise variances;
% 2 if different noise variances,
% default value: 2
% Omega: index set of SLA, valid only in the SLA case, sorted ascendingly
%
% Output:
% freq: frequency estimate
% pow: power estimate
% sigma: noise variance estimate
%
% Reference: Z. Yang, L. Xie, and C. Zhang, "A discretization-free sparse
% and parametric approach for linear array signal processing",
% IEEE Trans. Signal Processing, 2014
%
% Written by Zai Yang, April 2013
if nargin < 3 || max(Omega) == length(Omega) % ULA
Omega = [];
else
if length(Omega) ~= size(Y,1)
error('Dimension of Omega not match!');
end
end
if nargin < 2
mode_noise = 2;
end
[M, N] = size(Y);
if N > 1
Rhat = Y * Y' / N;
end
cvx_quiet true
cvx_precision default
% solve the SDP (or estimate R)
if N >= M && cond(Rhat) < 1e8 % nonsingular
[u, sig] = SPA_nonsing(Rhat, mode_noise, Omega);
elseif N == 1 % single snapshot
[u, sig] = SPA_SMV(Y, mode_noise, Omega);
else % multisnapshots and singular
[u, sig] = SPA_singu(Rhat, mode_noise, Omega);
end
% postprocessing and parameter estimation
[freq, pow] = PostProc(u);
end
function [u, sig] = SPA_nonsing(Rhat, mode_noise, Omega)
% SPA when Rhat is nonsingular
if isempty(Omega) % ULA
M = size(Rhat, 1);
Rhatinv = inv(Rhat);
TconjR = zeros(M,1);
TconjR(1) = trace(Rhatinv);
for j = 2:M
TconjR(j) = 2*sum(diag(Rhatinv,j-1));
end
Rhathalf = sqrtm(Rhat);
switch mode_noise
case 1, % equal noise variances
cvx_solver sdpt3
cvx_begin sdp
variable x(M,M) hermitian,
variable u(M) complex,
[x Rhathalf; Rhathalf toeplitz(u)] >= 0,
minimize trace(x) + real(TconjR'*u);
cvx_end
sig = 0;
case 2, % different noise variances
cvx_solver sdpt3
cvx_begin sdp
variable x(M,M) hermitian,
variable u(M) complex,
variable sig(M),
sig >= 0,
toeplitz(u) >= 0,
[x Rhathalf; Rhathalf toeplitz(u)+diag(sig)] >= 0,
minimize trace(x) + real(TconjR'*u) + real(diag(Rhatinv)')*sig;
cvx_end
otherwise,
error('error!');
end
return
end
%% SLA
M = max(Omega);
Mbar = length(Omega);
Rhatinv = inv(Rhat);
Rhatinv_expand = zeros(M);
Rhatinv_expand(Omega, Omega) = Rhatinv;
TconjR = zeros(M,1);
TconjR(1) = trace(Rhatinv_expand);
for j = 2:M
TconjR(j) = 2*sum(diag(Rhatinv_expand,j-1));
end
S = zeros(Mbar, M);
S(:, Omega) = eye(Mbar);
Rhathalf = sqrtm(Rhat);
switch mode_noise
case 1, % equal noise variances
cvx_solver sdpt3
cvx_begin sdp
variable x(Mbar,Mbar) hermitian,
variable u(M) complex,
toeplitz(u) >= 0,
[x Rhathalf; Rhathalf S*toeplitz(u)*S'] >= 0,
minimize trace(x) + real(TconjR'*u);
cvx_end
sig = 0;
case 2, % different noise variances
cvx_solver sdpt3
cvx_begin sdp
variable x(Mbar,Mbar) hermitian,
variable u(M) complex,
variable sig(Mbar),
sig >= 0,
toeplitz(u) >= 0,
[x Rhathalf; Rhathalf S*toeplitz(u)*S'+diag(sig)] >= 0,
minimize trace(x) + real(TconjR'*u) + real(diag(Rhatinv)')*sig;
cvx_end
otherwise,
error('error!');
end
end
function [u, sig] = SPA_SMV(Y, mode_noise, Omega)
% SPA in the single-snapshot case
if isempty(Omega) % ULA
M = length(Y);
Y2n = norm(Y);
switch mode_noise
case 1, % equal noise variances
cvx_solver sdpt3
cvx_begin sdp
variable x,
variable u(M) complex,
toeplitz(u) >= 0,
[x Y2n*Y'; Y2n*Y toeplitz(u)] >= 0,
minimize x + M*real(u(1));
cvx_end
sig = 0;
case 2, % different noise variances
cvx_solver sdpt3
cvx_begin sdp
variable x,
variable u(M) complex,
variable sig(M),
sig >= 0,
toeplitz(u) >= 0,
[x Y2n*Y'; Y2n*Y toeplitz(u)+diag(sig)] >= 0,
minimize x + M*real(u(1)) + sum(sig);
cvx_end
otherwise,
error('error!');
end
return
end
%% SLA
M = max(Omega);
Mbar = length(Omega);
Y2n = norm(Y);
S = zeros(Mbar, M);
S(:, Omega) = eye(Mbar);
switch mode_noise
case 1, % equal noise variances
cvx_solver sdpt3
cvx_begin sdp
variable x
variable u(M) complex,
toeplitz(u) >= 0,
[x Y2n*Y'; Y2n*Y S*toeplitz(u)*S'] >= 0,
minimize x + Mbar*real(u(1));
cvx_end
sig = 0;
case 2, % different noise variances
cvx_solver sdpt3
cvx_begin sdp
variable x
variable u(M) complex,
variable sig(Mbar),
sig >= 0,
toeplitz(u) >= 0,
[x Y2n*Y'; Y2n*Y S*toeplitz(u)*S'+diag(sig)] >= 0,
minimize x + Mbar*real(u(1)) + sum(sig);
cvx_end
otherwise,
error('error!');
end
end
function [u, sig] = SPA_singu(Rhat, mode_noise, Omega)
% SPA when Rhat is singular
if isempty(Omega) % ULA
M = size(Rhat,1);
switch mode_noise
case 1, % equal noise variances
cvx_solver sdpt3
cvx_begin sdp
variable x(M,M) hermitian,
variable u(M) complex,
toeplitz(u) >= 0,
[x Rhat; Rhat toeplitz(u)] >= 0,
minimize trace(x) + M*real(u(1));
cvx_end
sig = 0;
case 2, % different noise variances
cvx_solver sdpt3
cvx_begin sdp
variable x(M,M) hermitian,
variable u(M) complex,
variable sig(M),
sig >= 0,
toeplitz(u) >= 0,
[x Rhat; Rhat toeplitz(u)+diag(sig)] >= 0,
minimize trace(x) + M*real(u(1)) + sum(sig);
cvx_end
otherwise,
error('error!');
end
return
end
%% SLA
M = max(Omega);
Mbar = length(Omega);
S = zeros(Mbar, M);
S(:, Omega) = eye(Mbar);
switch mode_noise
case 1, % equal noise variances
cvx_solver sdpt3
cvx_begin sdp
variable x(Mbar,Mbar) hermitian,
variable u(M) complex,
toeplitz(u) >= 0,
[x Rhat; Rhat S*toeplitz(u)*S'] >= 0,
minimize trace(x) + Mbar*real(u(1));
cvx_end
sig = 0;
case 2, % different noise variances
cvx_solver sdpt3
cvx_begin sdp
variable x(Mbar,Mbar) hermitian,
variable u(M) complex,
variable sig(Mbar),
sig >= 0,
toeplitz(u) >= 0,
[x Rhat; Rhat S*toeplitz(u)*S'+diag(sig)] >= 0,
minimize trace(x) + Mbar*real(u(1)) + sum(sig);
cvx_end
otherwise,
error('error!');
end
end
function [freq, amp] = PostProc(u)
% [freq, amp] = PostProc(u)
% PostProc implements the postprocessing procedure given the solution u.
% The result is sorted in the descending order of amp
prec = 1e-4; % can be tuned appropriately
eigval = sort(real(eig(toeplitz(u))));
if eigval(1) > 0
sigma_in_u = eigval(1);
u(1) = u(1) - sigma_in_u;
eigval = eigval - sigma_in_u;
else
sigma_in_u = 0;
end
K = sum(eigval > prec*eigval(end));
M = length(u);
% solve h
h = toeplitz([conj(u(2)); u(1:M-1)], conj(u(2:K+1))) \ (-u(1:M));
% solve the zeros of H(z) in the form of exp(-1i * 2 * pi * theta)
r = roots([1; h]);
% r = r ./ abs(r);
% solve the amper vector
mat = flipud(vander([r; zeros(M-K,1)]).');
amp = mat(:, 1:K) \ u;
[amp, idx] = sort(real(amp), 'descend');
Khat = sum(amp>0);
amp = amp(1:Khat);
% determine the frequency
freq = - phase(r(idx(1:Khat))) / (2*pi);
freq = mod(freq, 1);
end