MATLAB 函数 sunsal1 解释:盲源分离问题的求解
该函数为 sunsal1,用于解决盲源分离问题。以下是每一条语句的含义:
-
function [z,res_p,res_d] = sunsal1(M,y,varargin)- 定义函数
sunsal1,其输入参数为M、y和varargin,输出参数为z、res_p和res_d。
- 定义函数
-
if (rem(length(varargin),2)==1)- 判断
varargin的长度是否为奇数,若为奇数则抛出错误。
- 判断
-
else- 若
varargin的长度为偶数,则进入循环。
- 若
-
for i=1:2:(length(varargin)-1)- 遍历
varargin中的每一对参数。
- 遍历
-
switch upper(varargin{i})- 根据参数名选择不同的操作。
-
case 'AL_ITERS'- 当参数名为 'AL_ITERS' 时,将其值赋给变量
AL_iters。
- 当参数名为 'AL_ITERS' 时,将其值赋给变量
-
if (AL_iters <= 0 )- 判断
AL_iters是否为正整数,若不是则抛出错误。
- 判断
-
case 'LAMBDA'- 当参数名为 'LAMBDA' 时,将其值赋给变量
lambda。
- 当参数名为 'LAMBDA' 时,将其值赋给变量
-
if (sum(sum(lambda < 0)) > 0 )- 判断
lambda是否为正数,若不是则抛出错误。
- 判断
-
case 'POSITIVITY'- 当参数名为 'POSITIVITY' 时,将其值赋给变量
positivity。
- 当参数名为 'POSITIVITY' 时,将其值赋给变量
-
case 'ADDONE'- 当参数名为 'ADDONE' 时,将其值赋给变量
addone。
- 当参数名为 'ADDONE' 时,将其值赋给变量
-
case 'TOL'- 当参数名为 'TOL' 时,将其值赋给变量
tol。
- 当参数名为 'TOL' 时,将其值赋给变量
-
case 'VERBOSE'- 当参数名为 'VERBOSE' 时,将其值赋给变量
verbose。
- 当参数名为 'VERBOSE' 时,将其值赋给变量
-
case 'X0'- 当参数名为 'X0' 时,将其值赋给变量
x0。
- 当参数名为 'X0' 时,将其值赋给变量
-
if (size(x0,1) ~= p) | (size(x0,1) ~= N)- 判断
x0是否与M和y的维度相同,若不同则抛出错误。
- 判断
-
otherwise- 如果参数名无法识别,则抛出错误。
-
Nlambda = size(lambda);- 计算
lambda的大小。
- 计算
-
if Nlambda == 1- 如果
lambda是标量,则将其扩展成与M和y相同大小的矩阵。
- 如果
-
lambda = lambda*ones(p,N);- 将
lambda扩展成与M和y相同大小的矩阵。
- 将
-
elseif Nlambda ~= N- 如果
lambda的大小与y的大小不同,则抛出错误。
- 如果
-
lambda = repmat(lambda(:)',p,1);- 将
lambda扩展成与M和y相同大小的矩阵。
- 将
-
norm_y = sqrt(mean(mean(y.^2)));- 计算
y的均方根值。
- 计算
-
M = M/norm_y;- 将
M和y除以均方根值,以便进行后续计算。
- 将
-
y = y/norm_y; -
lambda = lambda/norm_y^2; -
if sum(sum(lambda == 0)) && strcmp(positivity,'no') && strcmp(addone,'no')- 判断是否使用最小二乘法求解,若是则直接计算并返回结果。
-
z = pinv(M)*y; -
res_p = 0; -
res_d = 0; -
return -
SMALL = 1e-12;- 定义一个很小的数。
-
B = ones(1,p);- 定义一个大小为 1×p 的全 1 矩阵。
-
a = ones(1,N);- 定义一个大小为 1×N 的全 1 矩阵。
-
if strcmp(addone,'yes') && strcmp(positivity,'no')- 判断是否使用约束条件
sum(x) = 1,若是则进行计算。
- 判断是否使用约束条件
-
F = M'*M;- 计算
M的转置与M的乘积。
- 计算
-
if rcond(F) > SMALL- 判断矩阵
F是否可逆。
- 判断矩阵
-
IF = inv(F);- 如果
F可逆,则计算其逆矩阵IF。
- 如果
-
z = IF*M'*y-IF*B'*inv(B*IF*B')*(B*IF*M'*y-a);- 计算
z的值。
- 计算
-
res_p = 0;- 将主问题的残差设置为 0。
-
res_d = 0;- 将对偶问题的残差设置为 0。
-
return -
mu_AL = 0.01;- 定义一个小的常数。
-
mu = 10*mean(lambda(:)) + mu_AL;- 计算
mu的值。
- 计算
-
[UF,SF] = svd(M'*M);- 对
M的转置与M的乘积进行奇异值分解。
- 对
-
sF = diag(SF);- 获取奇异值矩阵的对角线元素。
-
IF = UF*diag(1./(sF+mu))*UF';- 计算矩阵
IF。
- 计算矩阵
-
Aux = IF*B'*inv(B*IF*B');- 计算
Aux矩阵。
- 计算
-
x_aux = Aux*a;- 计算
x_aux的值。
- 计算
-
IF1 = (IF-Aux*B*IF);- 计算
IF1矩阵。
- 计算
-
yy = M'*y;- 计算
M的转置与y的乘积。
- 计算
-
if x0 == 0- 如果没有提供初始解,则将
x初始化为IF*M'*y。
- 如果没有提供初始解,则将
-
z = x;- 将
z初始化为x。
- 将
-
d = 0*z;- 将拉格朗日乘数
d初始化为全 0 矩阵。
- 将拉格朗日乘数
-
tol1 = sqrt(N*p)*tol;- 计算主问题的容忍度。
-
tol2 = sqrt(N*p)*tol;- 计算对偶问题的容忍度。
-
i=1;- 将迭代次数初始化为 1。
-
res_p = inf;- 将主问题的残差初始化为无穷大。
-
res_d = inf;- 将对偶问题的残差初始化为无穷大。
-
maskz = ones(size(z));- 将
maskz初始化为全 1 矩阵。
- 将
-
mu_changed = 0;- 将
mu_changed初始化为 0。
- 将
-
while (i <= AL_iters) && ((abs (res_p) > tol1) || (abs (res_d) > tol2))- 进行迭代,直到达到最大迭代次数或满足容忍度。
-
if mod(i,10) == 1- 每 10 次迭代保存一下
z。
- 每 10 次迭代保存一下
-
z0 = z; -
z = soft(x-d,lambda/mu);- 计算
z的值。
- 计算
-
if strcmp(positivity,'yes')- 判断是否使用非负性约束。
-
maskz = (z >= 0);- 计算
maskz的值。
- 计算
-
z = z.*maskz;- 将
z乘以maskz,以满足非负性约束。
- 将
-
if strcmp(addone,'yes')- 判断是否使用约束条件
sum(x) = 1。
- 判断是否使用约束条件
-
x = IF1*(yy+mu*(z+d))+x_aux;- 计算
x的值。
- 计算
-
else- 如果没有使用约束条件
sum(x) = 1,则计算x的值。
- 如果没有使用约束条件
-
x = IF*(yy+mu*(z+d)); -
d = d -(x-z);- 更新拉格朗日乘数
d。
- 更新拉格朗日乘数
-
if mod(i,10) == 1- 每 10 次迭代计算一下残差。
-
re_error=norm(y-M*z); -
res_p = norm(x-z,'fro'); -
res_d = mu*norm(z-z0,'fro'); -
if strcmp(verbose,'yes')- 如果
verbose参数为 'yes',则打印出当前的迭代信息。
- 如果
-
fprintf(' i = %f, res_p = %f, res_d = %f, re_error= %f ',i,res_p,res_d, re_error); -
if res_p > 10*res_d- 如果主问题的残差大于对偶问题的残差,则更新
mu的值。
- 如果主问题的残差大于对偶问题的残差,则更新
-
mu = mu*2; -
d = d/2; -
mu_changed = 1; -
elseif res_d > 10*res_p- 如果对偶问题的残差大于主问题的残差,则更新
mu的值。
- 如果对偶问题的残差大于主问题的残差,则更新
-
mu = mu/2; -
d = d*2; -
mu_changed = 1; -
if mu_changed- 如果
mu已经改变,则重新计算IF、Aux、x_aux和IF1。
- 如果
-
IF = UF*diag(1./(sF+mu))*UF'; -
Aux = IF*B'*inv(B*IF*B'); -
x_aux = Aux*a; -
IF1 = (IF-Aux*B*IF); -
mu_changed = 0; -
i=i+1;- 将迭代次数加一。
-
end -
end
该函数使用交替方向乘子法 (ADMM) 求解盲源分离问题,并提供了一些可选参数,例如迭代次数、正则化参数和容忍度。该函数返回分离后的信号 z,以及主问题和对偶问题的残差 res_p 和 res_d。
原文地址: https://www.cveoy.top/t/topic/nSDI 著作权归作者所有。请勿转载和采集!