matlab - 使用 Matlab 进行 PCA 声音压缩
问题描述
我正在尝试使用 PCA(主成分分析)构建声音压缩器。
输入声音始终是单声道声音,因此生成的矩阵是sampledData
代码中调用的列矩阵。
压缩声音需要将矩阵转换为 2D 矩阵。因此,需要按以下方式对样本进行分组:
这里分组大小为 3,声音由 7 个样本组成
[sample1 sample2 sample3
sample4 sample5 sample6
sample7 0 0 ]
分组大小较低(=矩阵所需的列数)例如 10 或较高的分组大小(例如 100 或更多)会发生什么变化?
[sampledData, sampleRate] = audioread("soundFile.wav");
data = sampledData;
groupingSize = 10; %Number of columns wanted from the data
%Make data size a multiple of groupingSize and fill with 0
data(end + 1:groupingSize*ceil(numel(data)/groupingSize))=0;
%Make data a matrix of x rows and groupingSize columns
data = transpose(reshape(data,groupingSize,[]));
这是我用于声音压缩的剩余代码。percentagePC
不幸的是,当小于 100时出现错误,表示compressed
矩阵的列数需要与 的倒数的行数具有相同的列数eigenVec
。
为了说明,我使用groupingSize = 100
which 给我一个 100 列的压缩矩阵,它eigenVec
是一个 100 行和 100 列的矩阵。如果我设置percentagePC = 90
然后得到一个 90 列的压缩矩阵(我保留 90% 的最有用的数据),所以为了能够将两个矩阵相乘,我理论上需要将矩阵的大小减少eigenVec
10 列。根据 PCA,这是正确的推理吗?
percentagePC = 90; %Percentage of principal component to keep
[rows, cols] = size(data);
%get eigenvalues and eigenvector by centering data matrix and getting its covariance
dataCR =(data-ones(size(data,1),1)*mean(data))./(ones(size(data,1),1)*std(data,1));
dataCov = cov(dataCR);
[eigenVec, eigenVal] = eig(dataCov);
%Sort eigenvectors (desc)
[~, index] = sort(diag(eigenVal), 'descend');
eigenVec = eigenVec(:, index);
%principal components calculation
P = zeros(rows,cols);
for i = 1:cols
P(:,i) = dataCR * eigenVec(:,i);
end
%Number of principal components wanted according to percentagePC
iterations = ceil((groupingSize*percentagePC)/100);
compressed = zeros(rows,iterations);
for i = 1: iterations
compressed (:,i) = P(:,i);
end
%Fuse principal components between each other to get final compressed signal
final_compressed = zeros(rows*iterations,1);
z=1;
z = 1;
for i = 1:iterations:rows*iterations
for j = 1:iterations
final_compressed(i+j-1,1) = P(z,j);
end
z = z + 1;
end
% Decompression of compressed signal
decompressed = compressed * (eigenVec^(-1)); % /!\ ERROR IS HERE /!\
[rowsD,colsD] = size(decompressed);
final_decompressed = zeros(rowsD*colsD,1);
z = 1;
for i = 1:colsD:rowsD*colsD
for j = 1:colsD
final_decompressed(i+j-1,1) = decompressed(z,j);
end
z = z + 1;
end
filenameC = fullfile('compress.wav');
filenameD = fullfile('decompress.wav');
audiowrite(filenameC, final_compressed/max(abs(final_compressed)), round(sampleRate/(groupingSize/iterations)));
audiowrite(filenameD, decompressed, sampleRate);
解决方案
推荐阅读
- c++ - 我应该避免在循环中重复访问相同的方法吗?
- python - 有什么好的方法可以优化这个 python 代码的速度吗?
- c# - 将 XML 从流反序列化到列表
- angular - 错误类型错误:无法读取未定义的属性“firstName”
- r - 对于在 R 中保存单个大对象,是 saveRDS 还是保存更快?
- excel - 在特定目录中打开文件
- arrays - Scala:使用数组中的值在另一个数组中搜索
- javascript - JSON & Javascript:使用 createElement() 和 appendChild() 时,如何显示超链接和图标而不是 url 文本地址?
- google-analytics - Google Analytics (gtag.js) 跟踪按钮点击
- swagger - 如何使用 Swagger Codegen 排除某些操作/HTTP 动词?