Continue to Site

Eng-Tips is the largest engineering community on the Internet

Intelligent Work Forums for Engineering Professionals

  • Congratulations cowski on being selected by the Eng-Tips community for having the most helpful posts in the forums last week. Way to Go!

Sampling and Reproduction of an audio signal

Status
Not open for further replies.

tj80

Computer
Nov 24, 2002
3
Hi all,

I'm trying to go about the task of samping a small piece of an audio signal and then reproducing that piece an arbitrary amount of times (repeating the same audio over and over I suppose you could say). I'm working in C++.

The way I'm going about doing it is like so (using an example):

1. I have a sinusoidal signal with a period of 765.62Hz (a tricky frequency), sampled at 32000Hz. I grab approx. 33 ms of it, which corresponds to approx. 2^10 or 1024 samples. I perform a 1024 point FFT of it. This gives me 1024 real values which make an even spectrum and 1024 imaginary values which make an odd spectrum (this is consistent with fourier transform properties).

2. I then go through each sample in the fft and perform a phase shifting of that sample. I'm following the theory that a time shift of m samples in the time domain corresponds to a phase shift of exp^-j*w*m in the frequency domain. So my equations are like this:
Code:
(remember A*exp^j*w*m = A*cos(w*m) + A*j*sin(w*m))

for (i = 0; i < 1024; i++) { // 1024 samples in the fft

  frequency = (i* sampleRate) / 1024
  totalTimeShift = timeShift / sampleRate     (for reproducing the original signal just once the timeShift in this case is 1024 samples)
  phaseShiftAngle = 2 * pi * frequency * totalTimeShift

  realValue[i] = (realValue[i] * cos(phaseShiftAngle)) + (imaginaryValue[i] * sin(phaseShiftAngle))

  imaginaryValue[i] = (imaginaryValue[i] * cos(phaseShiftAngle)) - (realValue[i] * sin(phaseShiftAngle))
}
3. Next, I do an ifft of my phase shifted fft signal, and then stick the resulting 1024 sample time domain signal next to the original 1024 samples.

The problem I am having is that, for some strange reason, the phase of the signal is always perfect but the amplitudes are always flipped. For example, if the original sinusoid sample goes up-down-up-down, then the phase-shifted signal will always go down-up-down-up. And I can't figure out why!

The problem is not my fft or ifft, because I have done a straight fft and ifft of a signal and always got the original signal back. It most likely has something to do with my phase shifting calculations and also the fact that the period of the sinusoid is quite tricky to work with.

Any ideas? Thanks in advance.
 
Replies continue below

Recommended for you

Hello tj80
Let's look at the circular time shift property of the DFT transform.
x(n-l) (modulo N) <--DFT--> X(k)*exp(-j*2*pi*k*l/N)

Where:
x (small) is the signal in the time doamin,
n is the index of samples in the time domain
l is the circular time shift (number of samples)
N is the number of samples, 1024 in your case
X (big) is the signal is the frequency doamin
k is the index of samples in the frequency domain

Note that the time shift is circular of modulo N. Than means it repeats itself every 1024 delay samples.

As I understood (correct me if I am wrong), you wanted to perform a circular timeshift on your signal, by doing the following steps:
applying a DFT transform (using FFT) on your signal, phase shifting the signal in the frequency domain (constant phase), and then to perform an inverse DFT to have the signal back in the time domain.

From your code I see that you multiplied by
exp(j*2*pi*k*l/N) , instead of exp(-j*2*pi*k*l/N). that means you circularly advancedes your samples in the time domain instead of circularly delay it. Maybe this is your problem. Check the minus sign before the -j*2*pi*k*l/N

Try to circularly advance it in the time domain and compare the results.

 
Allow me to suggest another rhing. As a test, enter a sequence of numbers 1, 2, 3 up to 1024 (instead of your sinosoid), and apply your routine on this squence. Verify that your routine actually performs the circular shifting property on this sequence.
 
Chatman is correct.
Another way to look at it would be in vector form the resulting vector would rotate clockwise instead of anti-clockwise if you use j*2PI.K/N instead of -j 2PI.K/N.

Simple way to fix this without changing too much code would be to change your imaginary coeff's , multiply all of them by -1.
 
thank you both for your great replies, and yes you are both correct in understanding what I am trying to do.

Thanks for the suggestion to multiply the imaginary coeffs by -1, I'll try this, but in the meantime my question is:

for the code line:
Code:
imaginaryValue[i] = (imaginaryValue[i] * cos(phaseShiftAngle)) - (realValue[i] * sin(phaseShiftAngle))

if the phase shift angle was zero and we were multiplying the imaginary coeffs by -1, is it correct or not correct to deduce that the imaginary value would end up changing sign (+ve to -ve or vice versa)? is that how is it supposed to work for no phase shift?
 
First of all I see that I was wrong, and that you do multiply by exp(-j*2*pi*k*l/N), instead of exp(j*2*pi*k*l/N) (as I said in my previous answer).

If the phase shift angle is zero, it doesn't matter if you multiply the imaginary coefficient by +1 or -1. In both cases your samples won't change. That is because there was no circular delay or circular advance to the input samples.

Do a test. Try to enter a sequence from 1 to 1024, apply your routine, and see what's happened.

If the variable 'timeShift' is 2, you should get:
1023, 1024, 1, 2 ... , 1022
That is becuase you circularly delayed the input samples

If the 'timeShift' variable is -2 you should get 3, 4, ... , 1024, 1, 2
In this case you circularly advances your samples.

If timeShift is zero, the result is then: 1, 2, .. , 1024. No change in the samples.

Also, make sure that all the numbers after inverse FFT, have zero imaginary part.

Hope it helps
 
ok I did try this:

setting the 'timeShift' to +2 produced numbers of

1023, 1024, 1, ... , 1021, 1022

setting the 'timeShift' to 0 produced numbers of

1, 2, 3, ..., 1023, 1024

setting the 'timeShift' to -2 produced numbers of

2, 3, 4, ... , 1022, 1023, 0, 1

The -2 shift appears to be wrong (rounding error?), but the others are okay.


 
Did you use the electrical engineers Fourier transform or the mathematicians or physicists Fourier transform (FT)? Chatman mentions that you used the EE version, however, I think that is based on seeing your phase shifting code done in the frequency domain. You shifted by negative phase, not positive phase. That could be an issue.
The EE and other FT differ in the assumption of what the signal is therefore what the kernel must be. We EE's like to have our signals as exp ^ jwt, thus leaving the kernel to be exp ^ -jwt. In doing so, a time shift is a negative phase shift. Group delay for a EE is groupDelay = -dPhi / dw, where w is frequency, and Phi is the phase shift. This may be involved in having to use an arbitrary sign reversal.
If you are using C++ then you could use the built in std:complex and the sign error would not occur and you might get better performance, especially if you use a std:valarray and operate on the entire array, instead of element by element. Also prefix notation could give you a MIPS improvement, depending on your compiler and optimization setting. Try for( iFft = 0; iFft != 1024; ++i ) instead.
In conclusion:
1) A time delay is a shift to the right. A sine wave, say:
sin(wt),
shifted to the right be 10 degrees would be:
sin(wt-10).
So you need to subtract 10 degrees in the frequency domain. You code hard coded a multiplication by a negative phaseShiftAngle.
2)You may have used the original (non EE) FT.
3) Your FT may put the first element as the most negative frequency. This would put your DC at your 513th point, not at your first point. When you calculated your intended phase shift, you assumed i = 0 meant DC. That is probably incorrect, depending on your FT code.


 
Status
Not open for further replies.

Part and Inventory Search

Sponsor