Initialize a Room Impulse Response using reverberation time(T60) - matlab

I am doing Speech dereverberation using Non-negative matrix factorization.
To be precise, I am working on this paper by Nasser(paris.cs.illinois.edu/pubs/nasser-icassp2015.pdf) which involves obtaining optimal solution for a Room Impulse Response(Equation 10). So, for that I need to initialize H first. He has mentioned in the paper that "Each row of H was initialized identically using a linearly decaying envelope"(Section 4, at the end of page 3). I need to initialize an impulse response(H) such that its reverberation time(T60) is 300 ms. Let the length of H be 10.
This is what I tried but its an arbitrary solution.
x=1:10;
h = exp(-x/2);
H = repmat(h,600,1);
This will give me a H of dimension 600 * 10.
But, I don't understand how to use T60 for the initialization in MATLAB.

Hmmm. If you're trying to create a reverberation effect, then H should just be a vector, it seems to me that you have a matrix with 10 columns. When creating a reverb effect, you generally get your impulse response and convolve it with you audio signal. In this case, h seems pretty arbitrary and I don't know if it will give you the amount of reverb you are looking for. However, if you wanted to implement h as an impulse response for a reverb, all you have to do is convolve your audio signal with ythe impulse response.
[x, fs] = audioread('myaudio.wav');
y = conv(x,h);
If you had an impulse response from a recording and an impulse response from the room the recording was made, you could apply deconvolution to remove the reverb using the deconv function in Matlab.
You should be able to work out a formula so that h is just a exponentially decaying vector that takes roughly 300ms to die (although actually hearing that may be tricky)
If you want to get really advanced with your impulse response calculations, I recommend trying an image source approach to creating your impulse response. Check out the following paper(old, but golden);
http://www.umiacs.umd.edu/~ramani/cmsc828d_audio/AllenBerkley79.pdf
If you're interested in blind deconvolution, this might be of interest to you.
https://www.academia.edu/1370250/Predictive_deconvolution_and_kurtosis_maximization_for_speech_dereverberation
A slight caveat, deconvolution and room reverberation is a very tricky business. The image source model given above, while interesting and effective, doesn't really capture the complexity of reverberation and dereverberation. There are several things that can affect the sound (standing waves, etc) I can't guarantee you that simply calculating the RT60 using just a decaying exponential vector and deconvolution will yield amazing results. Still though, wort a shot and lots of fun!

Related

How to recreate an instrument sound from a .WAV file by using FFT and findpeaks() in MATLAB?

I want to generate my own samples of a Kick, Clap, Snare and Hi-Hat sounds in MATLAB based on a sample I have in .WAV format.
Right now it does not sound at all correct, and I was wondering if my code does not make sense? Or if it is that I am missing some sound theory.
Here is my code right now.
[y,fs]=audioread('cp01.wav');
Length_audio=length(y);
df=fs/Length_audio;
frequency_audio=-fs/2:df:fs/2-df;
frequency_audio = frequency_audio/(fs/2); //Normalize the frequency
figure
FFT_audio_in=fftshift(fft(y))/length(fft(y));
plot(frequency_audio,abs(FFT_audio_in));
The original plot of y.
My FFT of y
I am using the findpeaks() function to find the peaks of the FFT with amplitude greater than 0.001.
[pk, loc] = findpeaks(abs(FFT_audio_in), 'MinPeakHeight', 0.001);
I then find the corresponding normalized frequencies from the frequency audio (positive ones) and the corresponding peak.
loc = frequency_audio(loc);
loc = loc(length(loc)/2+1:length(loc))
pk = pk(length(pk)/2+1:length(pk))
So the one sided, normalized FFT looks like this.
Since it looks like the FFT, I think I should be able to recreate the sound by summing up sinusoids with the correct amplitude and frequency. Since the clap sound had 21166 data points I use this for the for loop.
for i=1:21116
clap(i) = 0;
for j = 1:length(loc);
clap(i) = bass(i) + pk(j)*sin(loc(j)*i);
end
end
But this results in the following sound, which is nowhere near the original sound.
What should I do differently?
You are taking the FFT of the entire time-period of the sample, and then generating stationary sinewaves for the whole duration. This means that the temporal signature of the drum is gone. And the temporal signature is the most characteristic of percussive unvoiced instruments.
Since this is so critical, I suggest you start there first instead of with the frequency content.
The temporal signature can be approximated by the envelope of the signal. MATLAB has a convenient function for this called envelope. Use that to extract the envelope of your sample.
Then generate some white-noise and multiply the noise by the envelope to re-create a very simple version of your percussion instrument. You should hear a clear difference between Kick, Clap, Snare and Hi-Hat, though it won't sound the same as the original.
Once this is working, you can attempt to incorporate frequency information. I recommend taking the STFT to get a spectrogram of the sound, so you can see how it the frequency spectrum changes over time.

How to generate smooth filtered envelope on EMG data in Matlab

I'm new to analysing EMG data and would appreciate some carefully explained help.
I would like to generate a smooth, linear enevelope signal of my EMG data (50kHz sampling rate) like the one published in this paper: https://openi.nlm.nih.gov/detailedresult.php?img=PMC3480942_1743-0003-9-29-3&req=4
My end goal is to be able to analyze the relationship between EMG activity (output) and action potentials fired from upstream neurons (putative input) recorded at the same time.
Even though this paper lists the filtering methods out quite clearly, I do not understand what they mean or how to perform them in matlab, which is the analysis tool I have available to me.
In the code I have written so far, I can dc offset as well as rectify my data:
x = EMGtime_data
y = EMGvoltage_data
%dc offset
y2=detrend(y)
% Rectification of the EMG signal
rec_y=abs(y2);
plot(x, rec_y)
But then I am not sure how to proceed.
I have tried the envelope function, but it is not as smooth as I would like:
For instance, if I used the following:
envelope(y_rec,2000,'rms')
I get this (which also doesn't seem to care that the data is rectified):
Even if I were to accept the envelope function, I'm not sure how to access just the processed envelope data to adjust the plot (i.e. change the y-range), or analyse the data further for on-set and off-set of the signal since the results of this function seem to be coupled with the original trace.
I have also come across fastrms.m, which seems promising. Unfortunately, I do not understand how to implement this function since the general explanation is over my head and the example code is lacking any defined variable (so I don't know where to integrate my own data!)
The example code from fastrms.m file exchange is here
Fs = 200; T = 5; N = T*Fs; t = linspace(0,T,N);
noise = randn(N,1);
[a,b] = butter(5, [9 12]/(Fs/2));
x = filtfilt(a,b,noise);
window = gausswin(0.25*Fs);
rms = fastrms(x,window,[],1);
plot(t,x,t,rms*[1 -1],'LineWidth',2);
xlabel('Time (sec)'); ylabel('Signal')
title('Instantaneous amplitude via RMS')
I will be eternally grateful for help in understanding how to filter and smooth EMG data!
In order to analysis EMG signals in time domain, researcher use The combination of rectification and low pass filtering which is also called finding the “linear envelope” of the signal.
And as mentioned in both the above sentence and your attached article image's explanation, in order to plot overlaid signal, you could simply low pass filter your signal at specific frequency.
In your attached article the said signal was filtered at 8 HZ.
For better understanding the art of EMG signal analysis , i think this document could help you a lot (link)

MATLAB using FFT to find steady state response to a periodic input force (mass spring damper system)

Lets say I have a mass-spring-damper system...
here is my code (matlab)...
% system parameters
m=4; k=256; c=1; wn=sqrt(k/m); z=c/2/sqrt(m*k); wd=wn*sqrt(1-z^2);
% initial conditions
x0=0; v0=0;
%% time
dt=.001; tMax=2*pi; t=0:dt:tMax;
% input
F=cos(t); Fw=fft(F);
% impulse response function
h=1/m/wd*exp(-z*wn*t).*sin(wd*t); H=fft(h);
% convolution
convolution=Fw.*H; sol=ifft(convolution);
% plot
plot(t,sol)
so I can successfully retrieve a plot, however I am getting strange responses I also programmed a RK4 method that solves the system of differential equations so I know how the plot SHOULD look like, and the plot I am getting from using FFT has an amplitude of a like 2 when it should have an amplitude of like .05.
So, how can I solve for the steady state response for this system using FFT. I want to use FFT because it is about 3 orders of magnitude faster than numerical integration methods.
Keep in mind I am defining my periodic input as cos(t) which has a period of 2*pi that is why I only used FFT over the time vector that spanned 0 to 2*pi (1 period). I also noticed if I changed the tMax time to a multiple of 2*pi, like 10*pi, I got a similar looking plot but the amplitude was 4 rather than 2, either way still not .05!. maybe there is some kind of factor I need to multiply by?
also I plotted : plot(t,Fw) expecting to see one peak at 1 since the forcing function is cos(t), yet I did not see any peaks (maybe I shouldn't be plotting Fw vs t)
I know it is possible to solve for the steady state response using fourier transform / fft, I am just missing something! I need help and understanding!!
The original results
Running the code you provided and comparing the result with the RK4 code posted in your other question, we get the following responses:
where the blue curve represents the FFT based implementation, and the red curve represents your alternate RK4 implementation. As you have pointed out, the curves are quite different.
Getting the correct response
The most obvious problem is of course the amplitude, and the main sources of the amplitude discrepancies of the code posted in this question are the same as the ones I indicated in my answer to your other question:
The RK4 implementation performs a numeric integration which correctly scales the summed values by the integration step dt. This scaling is lacking from the FFT based implementation.
The impulse response used in the FFT based implementation is consistent with the driving force being scaled by the mass m, a factor which was missing from the RK4 implementation.
Fixing those two issues results in responses which are a little closer, but still not identical. As you probably found out given the changes in the posted code of your other question, another thing that was lacking was zero padding of the input and of the impulse response, without which you were getting a circular convolution rather than a linear convolution:
f=[cos(t),zeros(1,length(t)-1)]; %force f
h=[1/m/wd*exp(-z*wn*t).*sin(wd*t),zeros(1,length(t)-1)]; %impulse response
Finally the last element to ensure the convolution yields good result is to use a good approximation to the infinite length impulse response. How long is long enough depends on the rate of decay of the impulse response. With the parameters you provided, the impulse response would have died down to 1% of its original values after approximately 11*pi. So extending the time span to tMax=14*pi (to include a full 2*pi cycle after the impulse response has died down), would probably be enough.
Obtaining the steady-state response
The simplest way to obtain the steady-state response is then to discard the initial transient. In this process we discard a integer number of cycles of the reference driving force (this of course requires knowledge of the driving force's fundamental frequency):
T0 = tMax-2*pi;
delay = min(find(t>T0));
sol = sol(delay:end);
plot([0:length(sol)-1]*dt, sol, 'b');
axis([0 2*pi]);
The resulting responses are then:
where again the blue curve represents the FFT based implementation, and the red curve represents your alternate RK4 implementation. Much better!
An alternate method
Computing the response for many cycles waiting for the transient response to die down and extracting the remaining samples corresponding
to the steady state might appear to be a little wasteful, despite the fact that the computation is still fairly fast thanks to the FFT.
So, let's go back a little and look at the problem domain. As you are probably aware,
the mass-spring-damper system is governed by the differential equation:
where f(t) is the driving force in this case.
Note that the general solution to the homogeneous equation has the form:
The key is then to realize that the general solution in the case where c>0 and m>0 vanishes in the steady state (t going to infinity).
The steady-state solution is thus only dependent on the particular solution to the non-homogenous equation.
This particular solution can be found by the method of undetermined coefficients, for a driving force of the form
by correspondingly assuming that the solution has the form
Substituting in the differential equation yields the equations:
thus, the solution can be implemented as:
EF0 = [wn*wn-w*w 2*z*wn*w; -2*z*wn*w wn*wn-w*w]\[1/m; 0];
sol = EF0(1)*cos(w*t)+EF0(2)*sin(w*t);
plot(t, sol);
where w=2*pi in your case.
Generalization
The above approach can be generalized for more arbitrary periodic driving forces by expressing the driving force as a
Fourier Series (assuming the driving force function satisfies the Dirichlet conditions):
The particular solution can correspondingly be assumed to have the form
Solving for the particular solution can be done in a way very similar to the earlier case. This result in the following implementation:
% normalize
y = F/m;
% compute coefficients proportional to the Fourier series coefficients
Yw = fft(y);
% setup the equations to solve the particular solution of the differential equation
% by the method of undetermined coefficients
k = [0:N/2];
w = 2*pi*k/T;
A = wn*wn-w.*w;
B = 2*z*wn*w;
% solve the equation [A B;-B A][real(Xw); imag(Xw)] = [real(Yw); imag(Yw)] equation
% Note that solution can be obtained by writing [A B;-B A] as a scaling + rotation
% of a 2D vector, which we solve using complex number algebra
C = sqrt(A.*A+B.*B);
theta = acos(A./C);
Ywp = exp(j*theta)./C.*Yw([1:N/2+1]);
% build a hermitian-symmetric spectrum
Xw = [Ywp conj(fliplr(Ywp(2:end-1)))];
% bring back to time-domain (function synthesis from Fourier Series coefficients)
x = ifft(Xw);
A final note
I purposely avoided the undamped c=0 case in the above derivation. In this case, the oscillation never die down and the general solution to the homogeneous equation does not have to be the trivial one.
The final "steady-state" in this case may or may not have the same period as the driving force. As a matter of fact, it may not be periodic at all if the period oscillations from the general solution is not related to the period of the driving force through a rational number (ratio of integers).

How to measure power spectral density in matlab?

I am trying to measure the PSD of a stochastic process in matlab, but I am not sure how to do it. I have posted the exact same question here, but I thought I might have more luck here.
The stochastic process describes wind speed, and is represented by a vector of real numbers. Each entry corresponds to the wind speed in a point in space, measured in m/s. The points are 0.0005 m apart. How do I measure and plot the PSD? Let's call the vector V. My first idea was to use
[p, w] = pwelch(V);
loglog(w,p);
But is this correct? The thing is, that I'm given an analytical expression, which the PSD should (in theory) match. By plotting it with these two lines of code, it looks all wrong. Specifically it looks as though it could need a translation and a scaling. Other than that, the shapes of the two are similar.
UPDATE:
The image above actually doesn't depict the PSD obtained by using pwelch on a single vector, but rather the mean of the PSD of 200 vectors, since these vectors stems from numerical simulations. As suggested, I have tried scaling by 2*pi/0.0005. I saw that you can actually give this information to pwelch. So I tried using the code
[p, w] = pwelch(V,[],[],[],2*pi/0.0005);
loglog(w,p);
instead. As seen below, it looks much nicer. It is, however, still not perfect. Is that just something I should expect? Taking the squareroot is not the answer, by the way. But thanks for the suggestion. For one thing, it should follow Kolmogorov's -5/3 law, which it does now (it follows the green line, which has slope -5/3). The function I'm trying to match it with is the Shkarofsky spectral density function, which is the one-dimensional Fourier transform of the Shkarofsky correlation function. Is it not possible to mark up math, here on the site?
UPDATE 2:
I have tried using [p, w] = pwelch(V,[],[],[],1/0.0005); as I was suggested. But as you can seem it still doesn't quite match up. It's hard for me to explain exactly what I'm looking for. But what I would like (or, what I expected) is that the dip, of the computed and the analytical PSD happens at the same time, and falls off with the same speed. The data comes from simulations of turbulence. The analytical expression has been fitted to actual measurements of turbulence, wherein this dip is present as well. I'm no expert at all, but as far as I know the dip happens at the small length scales, since the energy is dissipated, due to viscosity of the air.
What about using the standard equation for obtaining a PSD? I'd would do this way:
Sxx(f) = (fft(x(t)).*conj(fft(x(t))))*(dt^2);
or
Sxx = fftshift(abs(fft(x(t))))*(dt^2);
Then, if you really need, you may think of applying a windowing criterium, such as
Hanning
Hamming
Welch
which will only somehow filter your PSD.
Presumably you need to rescale the frequency (wavenumber) to units of 1/m.
The frequency units from pwelch should be rescaled, since as the documentation explains:
W is the vector of normalized frequencies at which the PSD is
estimated. W has units of rad/sample.
Off the cuff my guess is that the scaling factor is
scale = 1/0.0005/(2*pi);
or 318.3 (m^-1).
As for the intensity, it looks like taking a square root might help. Perhaps your equation reports an intensity, not PSD?
Edit
As you point out, since the analytical and computed PSD have nearly identical slopes they appear to obey similar power laws up to 800 m^-1. I am not sure to what degree you require exponents or offsets to match to be satisfied with a specific model, and I am not familiar with this particular theory.
As for the apparent inconsistency at high wavenumbers, I would point out that you are entering the domain of very small numbers and therefore (1) floating point issues and (2) noise are probably lurking. The very nice looking dip in the computed PSD on the other hand appears very real but I have no explanation for it (maybe your noise is not white?).
You may want to look at this submission at matlab central as it may be useful.
Edit #2
After inspecting documentation of pwelch, it appears that you should pass 1/0.0005 (the sampling rate) and not 2*pi/0.0005. This should not affect the slope but will affect the intercept.
The dip in PSD in your simulation results looks similar to aliasing artifacts
that I have seen in my data when the original data were interpolated with a
low-order method. To make this clearer - say my original data was spaced at
0.002m, but in the course of cleaning up missing data, trying to save space, whatever,
I linearly interpolated those data onto a 0.005m spacing. The frequency response
of linear interpolation is not well-behaved, and will introduce peaks and valleys
at the high wavenumber end of your spectrum.
There are different conventions for spectral estimates - whether the wavenumber
units are 1/m, or radians/m. Single-sided spectra or double-sided spectra.
help pwelch
shows that the default settings return a one-sided spectrum, i.e. the bin for some
frequency ω will include the power density for both +ω and -ω.
You should double check that the idealized spectrum to which you are comparing
is also a one-sided spectrum. Otherwise, you'll need to half the values of your
one-sided spectrum to get values representative of the +ω side of a
two-sided spectrum.
I agree with Try Hard that it is the cyclic frequency (generally Hz, or in this case 1/m)
which should be specified to pwelch. That said, the returned frequency vector
from pwelch is also in those units. Analytical
spectral formulae are usually written in terms of angular frequency, so you'll
want to be sure that you evaluate it in terms of radians/m, but scale back to 1/m
for plotting.

Time of Arrival estimation of a signal in Matlab

I want to estimate the time of arrival of GPR echo signals using Music algorithm in matlab, I am using the duality property of Fourier transform.
I am first applying FFT on the obtained signal and then passing these as parameters to pmusic function, i am still getting the result in frequency domain.?
Short Answer: You're using the wrong function here.
As far as I can tell Matlab's pmusic function returns the pseudospectrum of an input signal.
If you click on the pseudospectrum link, you'll see that the pseudospectrum of a signal lives in the frequency domain. In particular, look at the plot:
(from Matlab's documentation: Plotting Pseudospectrum Data)
Notice that the result is in the frequency domain.
Assuming that by GPR you mean Ground Penetrating Radar, then try radar or sonar echo detection approach to estimate the two way transit time.
This can be done and the theory has been published in several papers. See, for example, here:
STAR Channel Estimation in DS-CDMA Systems
That paper describes spatiotemporal estimation (i.e. estimation of both time and direction of arrival), but you can ignore the spatial part and just do temporal estimation if you have a single-antenna receiver.
You probably won't want to use Matlab's pmusic function directly. It's always quicker and easier to write these sorts of functions for yourself, so you know what is actually going on. In the case of MUSIC:
% Get noise subspace (where M is number of signals)
[E, D] = eig(Rxx);
[lambda, idx] = sort(diag(D), 'descend');
E = E(:, idx);
En = E(:,M+1:end);
% [Construct matrix S, whose columns are the vectors to search]
% Calculate MUSIC null spectrum and convert to dB
Z = 10*log10(sum(abs(S'*En).^2, 2));
You can use the Phased array system toolbox of MATLAB if you want to estimate the DOA using different algorithms using a single command. Such as for Root MUSIC it is phased.RootMUSICEstimator phased.ESPRITEstimator.
However as Harry mentioned its easy to write your own function, once you define the signal subspace and receive vector, you can directly apply it in the MUSIC function to find its peaks.
This is another good reference.
http://ieeexplore.ieee.org/stamp/stamp.jsp?arnumber=1143830