2

我编写了一个简单的 matlab / octave 函数来创建每个分量具有独立幅度、频率和相位的正弦曲线之和。有没有更干净的方法来写这个?

## Create a sum of cosines with independent amplitude, frequency and
## phase for each component:
##   samples(t) = SUM(A[i] * sin(2 * pi * F[i] * t + Phi[i])
## Return samples as a column vector.
##
function signal = sum_of_cosines(A = [1.0], 
                                 F = [440], 
                                 Phi = [0.0], 
                                 duration = 1.0, 
                                 sampling_rate = 44100)
  t = (0:1/sampling_rate:(duration-1/sampling_rate));
  n = length(t);
  signal = sum(repmat(A, n, 1) .* cos(2*pi*t' * F + repmat(Phi, n, 1)), 2);
endfunction

特别是,对 repmat() 的调用似乎有点笨拙——是否有一些漂亮的矢量化技术等着我学习?

4

3 回答 3

4

这是一样的吗?

signal = cos(2*pi*t' * F + repmat(Phi, n, 1)), 2) * A';

然后也许

signal = real(exp(j*2*pi*t'*F) * (A .* exp(j*Phi))');

如果您受内存限制,这应该可以很好地工作:

e_jtheta = exp(j * 2 * pi * F / sampling_rate);
phasor = A .* exp(j*Phi);
samples = zeros(duration,1);
for k = 1:duration
    samples(k) = real((e_jtheta .^ k) * phasor');
end
于 2013-10-09T17:38:26.343 回答
1

对于行向量A, F, 和Phi, 所以你可以bsxfun用来摆脱repmat, 但可以说它看起来更难看:

signal = cos(bsxfun(@plus, 2*pi*t' * F, Phi)) * A';
于 2013-10-09T18:19:33.097 回答
0

呵呵。当我使用长度(A)= 10000 调用上述任何矢量化版本时,八度音程会填满 VM 并停止(或者至少是缓慢的爬行——我没有耐心等待它完成。

结果,我回到了简单的迭代版本:

function signal = sum_of_cosines(A = [1.0], 
                                 F = [440], 
                                 Phi = [0.0], 
                                 duration = 1.0, 
                                 sampling_rate = 44100)
  t = (0:1/sampling_rate:(duration-1/sampling_rate));
  n = length(t);
  signal = zeros(n, 1);
  for i=1:length(A)
    samples += A(i) * cos(2*pi*t'*F(i) + Phi(i));
  endfor
endfunction

这个版本的运行速度非常快,并教会了我如何尝试“优雅”。

PS:这并没有减少我对@BenVoigt 和@chappjc 给出的答案的欣赏——我从两者身上学到了一些有用的东西!

于 2013-10-10T06:14:22.870 回答