
1. 原始信號f是什么?我采集的是原始信號f還是y = Af得到的y?
記原始信號為f,我們在sensor方得到的原始信號就是n*1的信號f,而在receiver方采集到的信號是y。針對y=Af做變換時,A(m*n )是一個隨機矩陣(真的很隨機,不用任何正交啊什么的限定)。通過由隨機矩陣變換內積得到y,我們的目標是從y中恢復f。由於A是m*n(m<n)的,所以原信號f(n*1)信號被壓縮到y(m*1)。
2. 有的地方寫 y =Ax, 有的地方寫 y=Dx,這里A和D只是符號的區別嗎?壓縮感知問題中的字典是什么?
不是只有符號區別!詳見開始我寫的參考文獻中公式(4)(5),f可以通過矩陣分解(SVD/QR)得到正交矩陣的線性組合,即:f = ψx
這里ψ是n*n的正交矩陣,x是與ψ內積能夠得到f的n*1向量,相當於系數。這里終於出現了稀疏的定義!!!假定x是稀疏的(注意是x而非f)!
為什么要把f分解呢?因為A是非常隨機的隨機矩陣啊!竟然隨機!?這樣如果A非常稀疏,那么y還能恢復的出來?
對!所以我們要將f分解為正交陣和向量的線性組合。
好,帶入y=Af,得y = Aψx
因為A是隨機矩陣,ψ是n*n的正交矩陣,所以A乘以ψ相當於給A做了一個旋轉變換,其結果Aψ還是一個隨機矩陣。這里的Aψ才是D,也就是字典!於是乎,形成了y = Dx,D = Aψ
其中x假設是稀疏的,但並非最初的采樣值,D是恢復(重建)矩陣。
這就是D與A的區別。
3. 為什么在MP和OMP算法中,要用一個隨機矩陣乘以一個正交傅里葉矩陣?
在“壓縮感知” 之 “Hello World”這篇文章中,我們采用OMP算法求取稀疏矩陣x,用了一個隨機矩陣A和傅里葉正變換矩陣ψ相乘得到字典D,但事實上這只是一個例子而已,我們還可以有很多其他選擇,包括隨機矩陣的選取和什么樣的正交陣,都可以有變化。
上面我們假定了y=Dx中x是稀疏的,就可以應用壓縮感知的理論,通過Matching pursuit或者basis pursuit進行x重建了。
重建之后呢,由於x並非原始信號f,只需將ψ與恢復出的信號x進行內積,就可以恢復出原始信號f。
4.有幾種常用的測量方式?
三種:
A. 產生一個隨機矩陣(Gaussian /Bernoulli Distribution),與原始信號f相乘
B. 在fourier變換域采樣
C. 線積分(即拉當變換(Radon)),廣泛用於斷層掃描。在不同方向對信號(想成圖像好了)做積分,形成的不同曲線即為不同測量。
5. 有誤差或者噪聲的時候Compressive Sensing還管用嗎?
在實際情況中呢,我們獲得的數據含有噪聲。相應的,用含有噪聲的模型:
這里噪聲e可以假定具有高斯分布或者什么分布具體情況具體分析。
實際樣本的目標函數有以下兩種:
這兩種目標函數的本質是一樣的,
- 對於第一種,約束項就是誤差。當誤差小於一個threshold(δ)時,即AE這個噪聲符合理論前提條件時,進行optimize
- 對於第二種,就直接把誤差項寫入目標函數(loss function)
6. 壓縮感知問題怎樣確定稀疏度?
稀疏度是CS中一個很頭痛的問題,這里僅給出基本思路,因為我也沒有具體實踐過。
Method:
% 1-D信號壓縮傳感的實現(正交匹配追蹤法Orthogonal Matching Pursuit)
% 測量數M>=K*log(N/K),K是稀疏度,N信號長度,可以近乎完全重構
% 編程人--香港大學電子工程系 沙威 Email: wsha@eee.hku.hk
% 編程時間:2008年11月18日
% 文檔下載: http://www.eee.hku.hk/~wsha/Freecode/freecode.htm
% 參考文獻:Joel A. Tropp and Anna C. Gilbert
% Signal Recovery From Random Measurements Via Orthogonal Matching
% Pursuit,IEEE TRANSACTIONS ON INFORMATION THEORY, VOL. 53, NO. 12,
% DECEMBER 2007.
clc;clear
%% 1. 時域測試信號生成
K=7; % 稀疏度(做FFT可以看出來)
N=256; % 信號長度
M=64; % 測量數(M>=K*log(N/K),至少40,但有出錯的概率)
f1=50; % 信號頻率1
f2=100; % 信號頻率2
f3=200; % 信號頻率3
f4=400; % 信號頻率4
fs=800; % 采樣頻率
ts=1/fs; % 采樣間隔
Ts=1:N; % 采樣序列
x=0.3*cos(2*pi*f1*Ts*ts)+0.6*cos(2*pi*f2*Ts*ts)+0.1*cos(2*pi*f3*Ts*ts)+0.9*cos(2*pi*f4*Ts*ts); % 完整信號,由4個信號疊加而來
%% 2. 時域信號壓縮傳感
Phi=randn(M,N); % 測量矩陣(高斯分布白噪聲)64*256的扁矩陣,Phi也就是文中說的D矩陣
s=Phi*x.'; % 獲得線性測量 ,s相當於文中的y矩陣
%% 3. 正交匹配追蹤法重構信號(本質上是L_1范數最優化問題)
%匹配追蹤:找到一個其標記看上去與收集到的數據相關的小波;在數據中去除這個標記的所有印跡;不斷重復直到我們能用小波標記“解釋”收集到的所有數據。
m=2*K; % 算法迭代次數(m>=K),設x是K-sparse的
Psi=fft(eye(N,N))/sqrt(N); % 傅里葉正變換矩陣
T=Phi*Psi'; % 恢復矩陣(測量矩陣*正交反變換矩陣)
hat_y=zeros(1,N); % 待重構的譜域(變換域)向量
Aug_t=[]; % 增量矩陣(初始值為空矩陣)
r_n=s; % 殘差值
for times=1:m; % 迭代次數(有噪聲的情況下,該迭代次數為K)
for col=1:N; % 恢復矩陣的所有列向量
product(col)=abs(T(:,col)'*r_n); % 恢復矩陣的列向量和殘差的投影系數(內積值)
end
[val,pos]=max(product); % 最大投影系數對應的位置,即找到一個其標記看上去與收集到的數據相關的小波
Aug_t=[Aug_t,T(:,pos)]; % 矩陣擴充
T(:,pos)=zeros(M,1); % 選中的列置零(實質上應該去掉,為了簡單我把它置零),在數據中去除這個標記的所有印跡
aug_y=(Aug_t'*Aug_t)^(-1)*Aug_t'*s; % 最小二乘,使殘差最小
r_n=s-Aug_t*aug_y; % 殘差
pos_array(times)=pos; % 紀錄最大投影系數的位置
end
hat_y(pos_array)=aug_y; % 重構的譜域向量
hat_x=real(Psi'*hat_y.'); % 做逆傅里葉變換重構得到時域信號
%% 4. 恢復信號和原始信號對比
figure(1);
hold on;
plot(hat_x,'k.-') % 重建信號
plot(x,'r') % 原始信號
legend('Recovery','Original')
norm(hat_x.'-x)/norm(x) % 重構誤差


好了,有了OMP算法,開始對應解釋代碼:
for col=1:N; % 恢復矩陣的所有列向量
product(col)=abs(T(:,col)'*r_n); % 恢復矩陣的列向量和殘差的投影系數(內積值)
end
這個循環是讓矩陣T的每一列與殘差求內各,T一共有N列,這里得到N個內積值存在product里面。內積值最大的即為相關性最強T(:,col)為M*1列向量,r_n初如化為s,是M*1列向量,這里讓T(:,col)轉置后再與r_n相乘,即一個1*M的行向量與一個M*1的列向量相乘,根據矩陣運算規則結果為一個數(即1*1的矩陣)。
[val,pos]=max(product); 這句話的關鍵是得到pos,即得到T中的哪一列與殘差r_n的內積值最大,也就是哪一列與殘差r_n相關性最強。此即英文步驟中的第二步。Aug_t=[Aug_t,T(:,pos)]; 此即英文步驟中的第三步,將剛剛得到的與殘差r_n內積值最大的列存到Aug_t中,這個矩陣隨着循環次數(迭代次數)的變換而變化,是M*times的矩陣。
T(:,pos)=zeros(M,1); 這一句是為了下一次迭代做准備的,這次找到了與殘差最相關的列,將殘差更新后,下次再找與殘差僅次於這一列的T的另外一列;
aug_y=(Aug_t'*Aug_t)^(-1)*Aug_t'*s; 這一句即英文步驟中的第四步,這句加上后面一句也是困擾了我好久兩句代碼,所以得說說:
首先我們針對的是s=T*hat_y,現在是已知s要求hat_y,現在假如說矩陣T為N*N方陣且滿秩(即N個未知數,N個獨立的方程),那么很容易知道hat_y=T^-1 * s,其中T^-1表示矩陣T的逆矩陣。但是現在T是一個M*N的扁矩陣,矩陣T沒有常規意義上的逆矩陣,這里就有“廣義逆”的概念(詳情參見國內矩陣分析教材),hat_y的解可能是不存在的,我們這里要求的是最小二乘解aug_y,最小二乘解aug_y將使s-T*aug_y這個列向量2范數最小。
對於用矩陣形式表達的線性方程組:
它的最小二乘解為:
其中
即為矩陣G的最小二乘廣義逆(廣義逆的一種)。
有了這些知識背景后代碼就容易理解了,在第三步中,得到矩陣T中的與殘差r_n最相關的列組成的矩陣Aug_t,而第四步實際上就是在求方程組Aug_t*Aug_y=s的最小二乘解。
pos_array(times)=pos; 把與T中與殘差最相關的列號記下來,恢復時使用。
到此,主要的for循環就說完了。
hat_x=real(Psi'*hat_y.');此即: 這里用hat_x以與原如信號x區分,x為原信號,hat_x為恢復的信號。代碼中對hat_y取了轉置是因為hat_y應該是個列向量,而在代碼中的前面hat_y=zeros(1,N); 將其命成了行向量,所以這里轉置了一下,沒什么大不了的。