3

I know that an inverse fast Fourier transform (ifft) sums multiple sine waves together from data obtain from doing an fft on a signal. Is there a way to create a signal using a new type of inverse fast Fourier transform (ifft) using an arbitrary waveform instead of just using sine waves?

I'm not trying to re-create the original signal. I'm trying to create a new signal using a new type of inverse fast Fourier transform (ifft) using a given arbitrary waveform based on the (frequency, amplitude, phase) data calculated from the fft from the source signal.

The arbitrary waveform is a sampled signal that will replace one period of the sine wave used in the fft. That is, the signal is to be scaled, repeated, and shifted according to the values given by the fft.

See simple example below: the signals I will be applying FFT to are human audio signals about 60 seconds long at 44100 samples (large arrays) so I'm trying to see if I can use / alter the ifft command in some way to create a new signal using / based on an arbitrary waveform.

PS: I'm using Octave 4.0 which is similar to Matlab and the arbitrary waveform signal used to create a new signal will be changed to create different signals.

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

Added a work-flow chart below with simple signals to see if that explains it better:

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

Cris Luengo
  • 55,762
  • 10
  • 62
  • 120
Rick T
  • 3,349
  • 10
  • 54
  • 119
  • 1
    You are probably thinking about wavelets. Fourier transform is way more than "sines". Its about reprojecting your data onto a different orthonormal basis, and sine waves have that property under the transform. Its very far from an arbitrary choice. – Ander Biguri Jan 15 '18 at 19:36
  • @AnderBiguri are you saying I'm not able to do this with IFFT? I'm not trying to re-create the original signal, I just want to use / alter the inverse fast Fourier transform (ifft) so it creates a signal using an arbitrary waveform instead of just using sine waves. – Rick T Jan 15 '18 at 20:11
  • If you are just triying to generate a new singal, why the complication? just generate it randomly from some values – Ander Biguri Jan 15 '18 at 20:51
  • @AnderBiguri it's not a random signal it's based on the (fft) frequency, amplitude, phase of a vocal signal. It's not random. – Rick T Jan 15 '18 at 20:58
  • 6
    The FFT (and by extension the inverse FFT, which is the same algorithm with a few minor tweaks) computes the DFT in a very efficient manner. The premise of the algorithm fails as soon as you replace the complex exponential basis with any other basis. However, you could implement a naive DFT and replace the basis with your own. – Cris Luengo Jan 15 '18 at 21:02
  • I've read both your question and your code and it's not clear to me what you want. Do you want to use the Gaussians to approximate arbitrary signals? If so, then that's just a simple least squares problem. If not, I'd need a more clear statement on what exactly you are trying to do. – AnonSubmitter85 Jan 16 '18 at 03:18
  • @AnonSubmitter85 I added a work-flow diagram with images and text to see if that explains it. I'm trying to create a signal using an inverse fast Fourier transform (ifft) using an arbitrary waveform signal instead of using sine waves. – Rick T Jan 22 '18 at 19:07
  • 1
    @RickT But if you are not using the bases of the Fourier Transform, what good are the FFT coefficients? You might as well just make the coefficients up. – AnonSubmitter85 Jan 24 '18 at 19:11
  • @AnonSubmitter85 `I guess with that logic if we want to exchange currency in another country we should just make the numbers up as we go ;-)` I'm not trying to re-create the signal I'm trying to create a new signal using the FFT coefficients taken from the original signal and applied to the arbitrary signal. ... – Rick T Jan 24 '18 at 20:54
  • @RickT Then just create a matrix with the waveforms you want to use as a basis and multiply the FFT coefficients by it. – AnonSubmitter85 Jan 24 '18 at 22:31
  • @AnonSubmitter85 One may also wish to use resample to evaluate the phased shifted version of the sampled basis signal. – Pui Ho Lam Jan 26 '18 at 05:10

3 Answers3

1

Let's start with a function lilly that takes a frequency, an amplitude and a phase (all scalars), as well as a signal length N, and computes a sine wave as expected for the inverse DFT (see note 2 below):

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);

I have written this function such that it uses a sampled signal representing a single period of the since wave.

The following function uses the lilly function to compute an inverse DFT (see note 1 below):

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;

Now I test to verify that it actually computes the inverse 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

The error is relatively large, due to the round function: we're subsampling the signal instead of interpolating. If you need more precision (not likely I think) you should use interp1 instead of indexing using round(p).

Next, we replace the sine in the lilly function with your example signal:

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);

The function pseudoifft now creates a function composed of your basis:

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

enter image description here

Let's look at a simpler input:

>> 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


Note 1: In your question you specifically ask to use the FFT. The FFT is simply a every efficient way of computing the forward and inverse DFT. The code above computes the inverse DFT in O(n^2), the FFT would compute the same result in O(n log n). Unfortunately, the FFT is an algorithm built on the properties of the complex exponential used in the DFT, and the same algorithm would not be possible if one were to replace that complex exponential with any other function.

Note 2: I use a cosine function in the inverse DFT. It should of course be a complex exponential. But I'm just taking a shortcut assuming that the data being inverse-transformed is conjugate symmetric. This is always the case if the input to the forward transform is real (the output of the inverse transform must be real too, the complex components of two frequencies cancel out because of the conjugate symmetry).

Cris Luengo
  • 55,762
  • 10
  • 62
  • 120
  • That looks very interesting. Did I miss where my arbitrary waveform called lilly was included in your code? I included the arbitrary waveform called lilly to test with the arbitrary waveform won't be an equation like you created it will be an array (and yes it will be periodic I included a work-flow image above). – Rick T Jan 29 '18 at 13:56
  • You only gave an example for one non-periodic waveform, without giving an indication of how it would be scaled or translated, so I couldn't use that as an example. I used a generating function to keep the solution general. You can replace that with an array of waveforms, one for each frequency. Or you can stick in there a way to scale and translate one sampled waveform. I can't help with that because I don't know what waveform you'll be using. The example you gave is just two Gaussian bell curves. – Cris Luengo Jan 29 '18 at 14:12
  • I think that's the problem everyone wants to just test it with a simple equation they create and that they know how to adjust. But aren't sure how to to use it with the arbitrary waveform / array called `lilly` I included. The waveform is labelled `%%%-----Begin create arbitrary waveform to use ---- %%%%-----End arbitrary waveform to use---- ` not sure how to make it stick out more than that. – Rick T Jan 29 '18 at 14:48
  • 1
    @RickT: yes, I saw that, but it wasn't clear how you wanted to scale it. The coin did drop for me a while back, I think that I now figured out what you want. You want to use that signal instead of one period of the cosine. So you'll repeat it `freq` times, subsampled by that same amount. Now it all makes a lot more sense! Maybe I'll have a bit of time today to try this out. – Cris Luengo Jan 29 '18 at 14:57
  • Exactly! I tried to show that in the image / work-flow chart. – Rick T Jan 29 '18 at 15:01
  • @RickT: I've edited the post according to what I now think is what you want to do. I must admit, it makes a lot more sense now than before. :) – Cris Luengo Jan 29 '18 at 18:46
0

An IFFT is just a way to implement a IDFT. An IDFT is just a weighted sum of sinusoidal waveforms that are integer periodic in aperture.

If you want, you can take almost any DFT or IDFT algorithm or source code, and replace the sin() function with whatever other function you want for waveform synthesis. You can even use different waveforms for different frequencies, or change the synthesis frequencies to non-integer-periodic-in-aperture, if you wish.

hotpaw2
  • 70,107
  • 14
  • 90
  • 153
  • That's great and it sounds like what I'm trying to do but how does one convert my `arbitrary waveform array` called `lilly` to do this? I haven't found an example for my case. People say use wavelets but I'm not trying to re-create the signal using the `arbitrary waveform array` called `lilly` I'm trying to create a new signal using the frequency, amp, phase taken from the source signal using the `arbitrary waveform array` called `lilly` – Rick T Jan 16 '18 at 05:51
0

The (inverse) Fast Fourier Transform relies on special properties of sinusoidal functions which allow one to move between the time-domain and frequency domain with a much lower computational cost (O(n.log(n))) than for arbitrary waveforms (O(n^2)). If you change the basis waveforms from sinusoids to something else, in general, you can no longer get the computational advantages of the FFT.

In your case, is sounds like you may want to generate a signal that has the same frequency spectrum as your original signal, but not necessarily the same envelope in the time-domain. As I think you've already implemented in your code, the easiest way to do that is simply to change the phase of each frequency-bin in the output of your FFT, and take the inverse FFT. That will generate a time-domain signal that has quite different appearance from your input signal, but will have the same amount of power in each frequency bin.

One subtlety you may need bear in mind is how to change the phases so that the output signal remains real-valued, rather than involving complex numbers. You can think of the Fourier transform as producing a set of positive and negative frequencies. For a real-valued signal, the corresponding positive and negative frequencies must have amplitudes that are complex conjugates of each other. Assuming that your input signal is real-valued, your FFT will already have this property, but you'll need to arrange that the random phases you apply still preserve this relationship between positive and negative frequencies. In practice, this will mean that you only have about half as many random phases to choose - none for zero-frequency bin, and one each for all the positive frequencies (the first n/2 entries) of your FFT, with the other phases being such that the phase at entry k is -1 times that of the entry at (n-k).

rwp
  • 1,786
  • 2
  • 17
  • 28
  • `I'm not trying to re-create the original signal. I'm trying to create a new signal using a given arbitrary waveform based on the (frequency, amplitude, phase) data calculated from the fft from the source signal.` It would be a `new type of ifft`. See work-flow digram image – Rick T Jan 27 '18 at 10:52
  • Can you explain a little more, in mathematical terms, what you mean by a signal that is described by a set of frequencies, amplitudes & phases, but does not use sinusoidal basis functions? – rwp Jan 27 '18 at 11:18
  • This goes along with the work-flow diagram above and uses "mathematical" terms like fft and new type of ifft. 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). – Rick T Jan 27 '18 at 11:27
  • I'm still not clear what mathematical properties you want the new signal to have. Maybe it would help to consider: * Why do you need to compute the FFT in the first place (i.e. what properties of the input signal are you wanting to extract)? * What properties of the input signal do you want to preserve in the output (e.g. spectral shape), and what properties are you going to allow to change? – rwp Jan 27 '18 at 18:10