DTMF, DFT window length - matlab

We've got an assignment in school to create a DTMF decoder, but are having trouble understanding what needs to be done, and how. First of all we need to calculate the energy of the signal using convolution. We do it by making use of the window length and the absolute value of the input signal:
SmoothEnergyOfInputSignal = conv(abs(X), ones(1,winlen)/winlen); %moving average
Now, we don't know how to get the proper window length. The smoothed energy is used to segment the signal, and later to determine the different frequencies in the signal making use of basis vectors(?)
The dtmf-pulses are at least 40ms separated by at least 40ms of silence.
The sampling frequency is at 8kHz and our signal is about 17601 samples long.
We thought that by doing fs*0.04 we'd get the window length. 0.04=40ms, but now the smoothed energy signal is shifted so the segments go beyond the maximum samples of the input signal.
[Sound, fs] = audioread('dtmf_all.wav');
winlen = fs*0.04
E = conv(abs(Sound),ones(1, winlen)/winlen)
Long story short: How do we calculate the "correct" window length?
Thanks in advance.
EDIT: The instructions were updated, and we're not supposed to use convolution. We're supposed to use filter()

Related

Matlab: finding phase difference using cpsd

From my understanding, when using the cpsd function as such:
[Pxy,f] = cpsd(x,y,window,Ns,NFFT,Fs);
matlab chops the time series data into smaller windows with size specified by you. And the windows are shifted by Ns data point. The final [Pxy, f] are an average of results obtained from each individual window. Please correct me if I am wrong about this process.
My question is, if I use angle(Pxy) at a specific frequency, say 34Hz. Does that give me the phase difference between signal x and y at the frequency 34Hz?
I am having doubt about this because if Pxy was an average between each individual window, and because each individual was offset by a window shift, doesn't that mean the averaged Pxy's phase is affected by the window shift?
I've tried to correct this by ensuring that the window shift corresponds to an integer of full phase difference corresponding to 34Hz. Is this correct?
And just a little background about what I am doing:
I basically have numerous time-series pressure measurement over 60 seconds at 1000Hz sampling rate.
Power spectrum analysis indicates that there is a peak frequency at 34 Hz for each signal. (averaged over all windows)
I want to compare each signal's phase difference from each other corresponding to the 34Hz peak.
FFT analysis of individual window reveals that this peak frequency moves around. So I am not sure if cpsd is the correct way to be going about this.
I am currently considering trying to use xcorr to calculate the overall time lag between the signals and then calculate the phase difference from that. I have also heard of hilbert transform, but I got no idea how that works yet.
Yes, cpsd works.
You can test your result by set two input signals, such as:
t=[0:0.001:5];
omega=25;
x1=sin(2*pi*omega*t);
x2=sin(2*pi*omega*t+pi/3);
you can check whether the phase shift calculated by cpsd is pi/3.

What is a spectrogram and how do I set its parameters?

I am trying to plot the spectrogram of my time domain signal given:
N=5000;
phi = (rand(1,N)-0.5)*pi;
a = tan((0.5.*phi));
i = 2.*a./(1-a.^2);
plot(i);
spectrogram(i,100,1,100,1e3);
The problem is I don't understand the parameters and what values should be given. These values that I am using, I referred to MATLAB's online documentation of spectrogram. I am new to MATLAB, and I am just not getting the idea. Any help will be greatly appreciated!
Before we actually go into what that MATLAB command does, you probably want to know what a spectrogram is. That way you'll get more meaning into how each parameter works.
A spectrogram is a visual representation of the Short-Time Fourier Transform. Think of this as taking chunks of an input signal and applying a local Fourier Transform on each chunk. Each chunk has a specified width and you apply a Fourier Transform to this chunk. You should take note that each chunk has an associated frequency distribution. For each chunk that is centred at a specific time point in your time signal, you get a bunch of frequency components. The collection of all of these frequency components at each chunk and plotted all together is what is essentially a spectrogram.
The spectrogram is a 2D visual heat map where the horizontal axis represents the time of the signal and the vertical axis represents the frequency axis. What is visualized is an image where darker colours means that for a particular time point and a particular frequency, the lower in magnitude the frequency component is, the darker the colour. Similarly, the higher in magnitude the frequency component is, the lighter the colour.
Here's one perfect example of a spectrogram:
Source: Wikipedia
Therefore, for each time point, we see a distribution of frequency components. Think of each column as the frequency decomposition of a chunk centred at this time point. For each column, we see a varying spectrum of colours. The darker the colour is, the lower the magnitude component at that frequency is and vice-versa.
So!... now you're armed with that, let's go into how MATLAB works in terms of the function and its parameters. The way you are calling spectrogram conforms to this version of the function:
spectrogram(x,window,noverlap,nfft,fs)
Let's go through each parameter one by one so you can get a greater understanding of what each does:
x - This is the input time-domain signal you wish to find the spectrogram of. It can't get much simpler than that. In your case, the signal you want to find the spectrogram of is defined in the following code:
N=5000;
phi = (rand(1,N)-0.5)*pi;
a = tan((0.5.*phi));
i = 2.*a./(1-a.^2);
Here, i is the signal you want to find the spectrogram of.
window - If you recall, we decompose the image into chunks, and each chunk has a specified width. window defines the width of each chunk in terms of samples. As this is a discrete-time signal, you know that this signal was sampled with a particular sampling frequency and sampling period. You can determine how large the window is in terms of samples by:
window_samples = window_time/Ts
Ts is the sampling time of your signal. Setting the window size is actually very empirical and requires a lot of experimentation. Basically, the larger the window size, the better frequency resolution you get as you're capturing more of the frequencies, but the time localization is poor. Similarly, the smaller the window size, the better localization you have in time, but you don't get that great of a frequency decomposition. I don't have any suggestions here on what the most optimal size is... which is why wavelets are preferred when it comes to time-frequency decomposition. For each "chunk", the chunks get decomposed into smaller chunks of a dynamic width so you get a mixture of good time and frequency localization.
noverlap - Another way to ensure good frequency localization is that the chunks are overlapping. A proper spectrogram ensures that each chunk has a certain number of samples that are overlapping for each chunk and noverlap defines how many samples are overlapped in each window. The default is 50% of the width of each chunk.
nfft - You are essentially taking the FFT of each chunk. nfft tells you how many FFT points are desired to be computed per chunk. The default number of points is the largest of either 256, or floor(log2(N)) where N is the length of the signal. nfft also gives a measure of how fine-grained the frequency resolution will be. A higher number of FFT points would give higher frequency resolution and thus showing fine-grained details along the frequency axis of the spectrogram if visualised.
fs - The sampling frequency of your signal. The default is 1 Hz, but you can override this to whatever the sampling frequency your signal is at.
Therefore, what you should probably take out of this is that I can't really tell you how to set the parameters. It all depends on what signal you have, but hopefully the above explanation will give you a better idea of how to set the parameters.
Good luck!

MATLAB Code Clarification

I recently visited this page in order to determine the frequency from signal data in MATLAB:
Determine frequency from signal data in MATLAB
And in this page, an answerer responded with the following code:
[maxValue,indexMax] = max(abs(fft(signal-mean(signal))));
From what I can see, a Fast Fourier Transform is taken on a signal named signal, its magnitude is kept by using 'abs', and the max value is computed. The max value will be in maxValue, and the indexMax will contain the position of the maxValue. However, can someone explain what is meant by signal-mean, and what the purpose of it?
It basically normalize the vector signal so it has mean zero (subtracts the mean from signal). So signal - mean(signal) looks like signal except that is shifted on the y axis so it has a zero mean. Hope it is clear.
In the example you posted in the link, the mean of the signal is around -2, so by subtracting the mean you end up with a the signal shifted up around the y=0 axis.
As stated in vsoftco's answer, signal-mean(signal) subtracts the mean of the signal.
However, the key point is: why is this is done? If you don't subtract the mean, it's very likely that the maximum peak in the FFT appears at frequency 0 (DC component). But you don't want to detect that as the "frequency" of your signal, even if it truly is the highest spectral component. So you remove that zero-frequency component by subtracting the mean. That way, the max operation will detect the maximum non-zero frequency component, which is probably what you want.

Time delay estimation using crosscorrelation

I have two sensors seperated by some distance which receive a signal from a source. The signal in its pure form is a sine wave at a frequency of 17kHz. I want to estimate the TDOA between the two sensors. I am using crosscorrelation and below is my code
x1; % signal as recieved by sensor1
x2; % signal as recieved by sensor2
len = length(x1);
nfft = 2^nextpow2(2*len-1);
X1 = fft(x1);
X2 = fft(x2);
X = X1.*conj(X2);
m = ifft(X);
r = [m(end-len+1) m(1:len)];
[a,i] = max(r);
td = i - length(r)/2;
I am filtering my signals x1 and x2 by removing all frequencies below 17kHz.
I am having two problems with the above code:
1. With the sensors and source at the same place, I am getting different values of 'td' at each time. I am not sure what is wrong. Is it because of the noise? If so can anyone please provide a solution? I have read many papers and went through other questions on stackoverflow so please answer with code along with theory instead of just stating the theory.
2. The value of 'td' is sometimes not matching with the delay as calculated using xcorr. What am i doing wrong? Below is my code for td using xcorr
[xc,lags] = xcorr(x1,x2);
[m,i] = max(xc);
td = lags(i);
One problem you might have is the fact that you only use a single frequency. At f = 17 kHz, and an estimated speed-of-sound v = 340 m/s (I assume you use ultra-sound), the wavelength is lambda = v / f = 2 cm. This means that your length measurement has an unambiguity range of 2 cm (sorry, cannot find a good link, google yourself). This means that you already need to know your distance to better than 2 cm, before you can use the result of your measurement to refine the distance.
Think of it in another way: when taking the cross-correlation between two perfect sines, the result should be a 'comb' of peaks with spacing equal to the wavelength. If they overlap perfectly, and you displace one signal by one wavelength, they still overlap perfectly. This means that you first have to know which of these peaks is the right one, otherwise a different peak can be the highest every time purely by random noise. Did you make a plot of the calculated cross-correlation before trying to blindly find the maximum?
This problem is the same as in interferometry, where it is easy to measure small distance variations with a resolution smaller than a wavelength by measuring phase differences, but you have no idea about the absolute distance, since you do not know the absolute phase.
The solution to this is actually easy: let your source generate more frequencies. Even using (band-limited) white-noise should work without problems when calculating cross-correlations, and it removes the ambiguity problem. You should see the white noise as a collection of sines. The cross-correlation of each of them will generate a comb, but with different spacing. When adding all those combs together, they will add up significantly only in a single point, at the delay you are looking for!
White Noise, Maximum Length Sequency or other non-periodic signals should be used as the test signal for time delay measurement using cross correleation. This is because non-periodic signals have only one cross correlation peak and there will be no ambiguity to determine the time delay. It is possible to use the burst type of periodic signals to do the job, but with degraded SNR. If you have to use a continuous periodic signal as the test signal, then you can only measure a time delay within one period of the periodic test signal. This should explain why, in your case, using lower frequency sine wave as the test signal works while using higher frequency sine wave does not. This is demonstrated in these videos: https://youtu.be/L6YJqhbsuFY, https://youtu.be/7u1nSD0RlwY .

i am trying to write a code to cross correlate a transmitted signal with a received signal to determine the number of samples delay

Cross correlation is to be used to measure distance to an aircraft by transmitting a
known wide-band signal and correlating the transmitted signal with incoming signals
received via the radar reception dish
The transmitted signal x(n) is of length N=512 while the received signal y(n) is of length N=2048.
y(n)=kx(n-d)+w(n); where 'kx(n-d)' is x(n) delayed by d samples and attenuated by a factor k, and w(n) is reception noise.
i am trying to write a MATLAB program to cross correlate x(n) with the y(n) to determine the value of d, the number of samples delay.
And also Determine a suitable sampling frequency if the distance to the aircraft is to be
determined within 50 km to an accuracy of 50 m, given that the transmitted
and received data is travelling at the speed of light.
The easiest way to do this is with the "xcorr" function. This is part of the Signal Processing toolbox for matlab, but should be available for GNU Octave here. I have not checked if the octave script is completely MATLAB compatible.
You can use the xcorr function as:
[correlation,lags] = xcorr(x,y);
The lag value can be found using
delay = lags(find(correlation==max(correlation)))
At the speed of light, the signal will be travelling at 3 x 10^8 m/s, so to have a resolution of 50m, you should be sampling at at least (3e8/50m) = 6MHz. At this sampling rate, each lag will be 1/6000000 second. If you multiply your delay by this value, you get your total time intervel between transmission and reception of the signal. Multiply this time intervel by the speed of light to get your distance.
You can use generalized Cross correlation -Phase transform GCC PHAT
The following is the MATLAB code for it
function time=GCCPHAT_testmode(b1,b2)
b1f=fft(b1);
b2f=fft(b2);
b2fc=conj(b2f);
neuma=(b1f).*(b2fc);
deno=abs((b1f).*(b2fc));
GPHAT=neuma./deno;
GPHATi=ifft(GPHAT);
[maxval ind]= max(GPHATi);
samp=ind
end
we can ignore the 'find' function in matlab, the command could be changed to
delay = lags(correlation==max(correlation))
'xcorr' suits for vectors with long length;
'gcc' prefer frame by frame.
Aj463's comment above is good, indeed GCC-PHAT is better than unweighted correlation for estimating delay of wide-band signals.
I would suggest a small improvement to the code posted above: to add a small value epsilon to the denominator, epsilon -> 0, in order to avoid eventual division by zero.
Thus, I would change the line
deno=abs((b1f).*(b2fc));
to
deno=abs((b1f).*(b2fc)) + epsilon;