更改快速傅里叶逆变换(ifft)以使用任意波形而不是正弦波来创建新信号

时间:2018-01-15 19:23:22

标签: matlab fft octave ifft

我知道逆快速傅里叶变换(ifft)将多个正弦波与从信号上的fft获得的数据相加。 有没有办法使用任意波形而不是仅仅使用正弦波来使用新型快速傅里叶逆变换(ifft)创建信号?

我没有尝试重新创建原始信号。我尝试使用基于从源信号fft计算的(频率,幅度,相位)数据的给定任意波形,使用新型逆快速傅里叶变换(ifft)来创建新信号。

任意波形是一个采样信号,它将取代fft中使用的正弦波的一个周期。也就是说,信号将根据fft给出的值进行缩放,重复和移位。

请参阅下面的简单示例:我将应用FFT的信号是人类音频信号,大约60秒,在44100个样本(大阵列),所以我试图看看我是否可以使用/改变ifft命令以某种方式使用/基于任意波形创建新信号。

PS:我使用Octave 4.0,它类似于Matlab,用于创建新信号的任意波形信号将被改变以产生不同的信号。

clear all,clf reset, clc,tic

fs=44100 % Sampling frequency
len_of_sig=2; %length of signal in seconds
t=linspace(0,2*pi*len_of_sig,fs*len_of_sig);
afp=[.5,2.43,pi/9;.3,3,pi/2;.3,4.3,pi/3];  %represents Amplitude,frequency,phase data array

%1 create source signal
ya=0;
for zz=1:size(afp,1)
  ya = ya+afp(zz,1)*sin(afp(zz,2)*t+afp(zz,3));
end

%2 create source frequency domain data
ya_fft = fft(ya);

%3 rebuild original source signal
mag = abs(ya_fft);
phase = unwrap(angle(ya_fft));
ya_newifft=ifft(mag.*exp(i*phase));
ifft_sig_combined_L1=ifft(mag.*exp(i*phase),length(ya_newifft)); 

%4 %%%-----begin create arbitrary waveform to use ---- 
gauss = @(t, t0, g) exp(-((t-t0)/g).^2); % a simple gaussian

t_arbitrary=0:1:44100; % sampling
t_arbitrary_1 = 10000; % pulses peak positions (s)
t_arbitrary_2 = 30000; % pulses peak positions (s)

g = 2000; % pulses width (at 1/e^2) (s)

lilly = gauss(t_arbitrary, t_arbitrary_1, g) - (.57*gauss(t_arbitrary, t_arbitrary_2, g)); %different amplitude peaks
%%%%-----End arbitrary waveform to use---- 

%5 plot
t_sec=t./(2*pi); %converts time in radians to seconds
t_arbitrary_sec=t_arbitrary./length(lilly); %converts time in radians to seconds

subplot(4,1,1);
plot(t_sec,ya,'r')
title('1) source signal')

subplot(4,1,2);
plot(t_sec,ifft_sig_combined_L1)
title('2) rebuilt source signal using ifft')

subplot(4,1,3);
plot(t_arbitrary_sec,lilly,'r')
title('3) arbitrary waveform used to create new signal')

Plot Updated

在下面添加了一个简单信号的工作流程图,看看是否能更好地解释它:

Section 1) The audio signal is read into an array
Section 2) FFT is done on the signal
Section 3 Red) Normally Inverse FFT uses sin waves to rebuild the signal see signal in red
Section 3 Blue) I want to use an arbitrary signal wave instead to rebuild the signal using the FFT data calculated in (Section 2)
Section 4) New signals created using a new type of Inverse FFT (Section 3).
Please note the new type of Inverse FFT final signal (in blue ) must use the FFT data taken from the original signal.
The signal Sample rate tested should be 44100 and the length of the signal in seconds should be 57.3 seconds long.  I use these numbers to test that the array can handle large amounts and that the code can handle non even numbers in seconds.

Work-flow

3 个答案:

答案 0 :(得分:1)

让我们从一个函数lilly开始,它采用频率,幅度和相位(所有标量)以及信号长度N,并计算正弦波为预期用于反向DFT(见下面的注释2):

function out = lilly(N,periods,amp,phase)
persistent t
persistent oneperiod
if numel(t)~=N
   disp('recomputung "oneperiod"');
   t = 0:N-1;
   oneperiod = cos(t * 2 * pi / N);
end
p = round(t * periods + phase/(2*pi)*N);
p = mod(p,N) + 1;
out = amp * oneperiod(p);

我已经编写了这个函数,它使用一个表示自波的单个周期的采样信号。

以下函数使用lilly函数计算逆DFT(参见下面的注释1):

function out = pseudoifft(ft)
N = length(ft);
half = ceil((N+1)/2);
out = abs(ft(1)) + abs(ft(half)) * ones(1,N);
for k=2:half-1
   out = out + lilly(N,k-1,2*abs(ft(k)),angle(ft(k)));
end
out = out/N;

现在我测试验证它实际上是否计算逆DFT:

>> a=randn(1,256);
>> b=fft(a);
>> c=pseudoifft(b);
recomputung "oneperiod"
>> max(abs(a-c))
ans =  0.059656
>> subplot(2,1,1);plot(a)
>> subplot(2,1,2);plot(c)

enter image description here

由于round函数,误差相对较大:我们对信号进行二次采样而不是插值。如果您需要更高的精确度(我认为不太可能),您应该使用interp1而不是使用round(p)进行索引。

接下来,我们将lilly函数中的正弦替换为示例信号:

function out = lilly(N,periods,amp,phase)
persistent t
persistent oneperiod
if numel(t)~=N
   disp('recomputung "oneperiod"');
   t = 0:N-1;
   %oneperiod = cos(t * 2 * pi / N);
   gauss = @(t,t0,g) exp(-((t-t0)/g).^2); % a simple gaussian
   t1 = N/4;   % pulses peak positions (s)
   t2 = 3*N/4; % pulses peak positions (s)
   g = N/20;   % pulses width (at 1/e^2) (s)
   oneperiod = gauss(t,t1,g) - (.57*gauss(t,t2,g)); %different amplitude peaks
   oneperiod = circshift(oneperiod,[1,-round(N/4)]); % this will make it look more like cos
end
p = round(t * periods + phase/(2*pi)*N);
p = mod(p,N) + 1;
out = amp * oneperiod(p);

函数pseudoifft现在创建一个由您的基础组成的函数:

>> c=pseudoifft(b);
recomputung "oneperiod"
>> subplot(2,1,2);plot(c)

enter image description here

让我们看一个更简单的输入:

>> z=zeros(size(a));
>> z(10)=1;
>> subplot(2,1,1);plot(pseudoifft(z))
>> z(19)=0.2;
>> subplot(2,1,2);plot(pseudoifft(z))

enter image description here

注1 :在您的问题中,您特别要求使用FFT。 FFT只是计算正向和反向DFT的每种有效方式。上面的代码计算O(n ^ 2)中的逆DFT,FFT将在O(n log n)中计算相同的结果。不幸的是,FFT是一种基于DFT中使用的复指数的属性的算法,如果要用任何其他函数替换复指数,则不可能使用相同的算法。

注2 :我在逆DFT中使用余弦函数。它当然应该是一个复杂的指数。但我只是假设被逆变换的数据是共轭对称的。如果正向变换的输入是真实的(逆变换的输出也必须是真实的,两个频率的复杂分量由于共轭对称性而抵消),情况总是如此。

答案 1 :(得分:0)

IFFT只是实现IDFT的一种方式。 IDFT只是在孔径中为整数周期的正弦波形的加权和。

如果需要,您几乎可以使用任何DFT或IDFT算法或源代码,并将sin()函数替换为您想要进行波形合成的任何其他函数。如果您愿意,您甚至可以针对不同的频率使用不同的波形,或者将合成频率更改为非整数周期光圈。

答案 2 :(得分:0)

(逆)快速傅里叶变换依赖于正弦函数的特殊属性,允许人们在时域和频域之间移动,计算成本(O(n.log(n)))比任意值低得多波形(O(n ^ 2))。如果将基波波形从正弦曲线更改为其他波形,通常情况下,您无法再获得FFT的计算优势。

在您的情况下,听起来您可能希望生成与原始信号具有相同频谱的信号,但在时域中不一定是相同的包络。我认为你已经在代码中实现了,最简单的方法就是改变FFT输出中每个频率仓的相位,然后采用逆FFT。这将生成一个时域信号,其外观与输入信号完全不同,但每个频率仓中的功率相同。

您可能需要记住的一个细微之处在于如何更改阶段以使输出信号保持实值,而不是涉及复数。您可以将傅立叶变换视为产生一组正负频率。对于实值信号,相应的正负频率必须具有彼此复共轭的幅度。假设您的输入信号是实值的,您的FFT将具有此属性,但您需要安排您应用的随机相位仍保留正负频率之间的这种关系。在实践中,这意味着您只有大约一半的随机相位可供选择 - 零频率分频器中没有一个,而FFT的所有正频率(前n / 2个条目)各一个,其他相位条目k的相位是(nk)条目的-1倍。