How to normlize audio file in Matlab - matlab

I have a couple of audio files that want to normalize at .-1dB, any idea how may I do that.
PS: I'm not asking how to read them, consider they are all saved in the Workspace as : A1 A2 A3 etc
UPDATE
thanks to Neil for his comment, here an example of two files , as you can see the signal aren't on the same level , ( that causes problems when try to any their PSD, so I would like to get all the file at the same level as far I know that called normalization. I can do that in Audacity but not in Matlab, because I don't know and the mathematics behind it.
thanks for your help

Normalising an audio waveform involves:
Choosing the desired norm. You have more choices than just the maximum offset, but that is the simplest. If your representation is sample values in range -1.0 to 1.0, then normalising to -1dB is actually saying you want all values to be between -0.891 and 0.891 (from Wikipedia article on Decibel)
Finding the current absolute maximum value. You can use e.g. max(abs( A1(:) ) ) for that
Multiplying all values such that the maximum is now limited to the new top value. Multiplication is the correct operation due to the representation used by most raw audio signals.
So, in theory, you want something like:
A1_norm = A1 * 0.891 / max( abs( A1(:) ) );

Related

Dimensionality reduction using PCA - MATLAB

I am trying to reduce dimensionality of a training set using PCA.
I have come across two approaches.
[V,U,eigen]=pca(train_x);
eigen_sum=0;
for lamda=1:length(eigen)
eigen_sum=eigen_sum+eigen(lamda,1);
if(eigen_sum/sum(eigen)>=0.90)
break;
end
end
train_x=train_x*V(:, 1:lamda);
Here, I simply use the eigenvalue matrix to reconstruct the training set with lower amount of features determined by principal components describing 90% of original set.
The alternate method that I found is almost exactly the same, save the last line, which changes to:
train_x=U(:,1:lamda);
In other words, we take the training set as the principal component representation of the original training set up to some feature lamda.
Both of these methods seem to yield similar results (out of sample test error), but there is difference, however minuscule it may be.
My question is, which one is the right method?
The answer depends on your data, and what you want to do.
Using your variable names. Generally speaking is easy to expect that the outputs of pca maintain
U = train_x * V
But this is only true if your data is normalized, specifically if you already removed the mean from each component. If not, then what one can expect is
U = train_x * V - mean(train_x * V)
And in that regard, weather you want to remove or maintain the mean of your data before processing it, depends on your application.
It's also worth noting that even if you remove the mean before processing, there might be some small difference, but it will be around floating point precision error
((train_x * V) - U) ./ U ~~ 1.0e-15
And this error can be safely ignored

Issues with creating a 30kHz soundwave in MATLAB

I want to create a 30kHz sound with MATLAB ( after which I use the Earthworks microphone ( M50 ) to test / analyse the audio replay (sound) produced from the synthetised signal stored by MATLAB in a .WAV file ).
I use the following code, but whether it is some wrong, and if I want to create another 50kHz wave, how should I modify the code?
Fs = 96200;
toneFreq1 = 30000;
nSeconds = 20;
f1 = sin( linspace( 0, nSeconds*toneFreq1*2*pi, round( nSeconds * Fs ) ) );
sound( f1, Fs )
wavwrite( f1, Fs, 24, '30khz.wav' );
First, most soundcards are not able to play back using your Fs. Typically, they offer 88200 or 96000 Hz, so you should choose one of them.
Second, due to Nyquist-Shannon theorem you can't create a frequency higher than half the sampling rate. I.e. with Fs=96000 the highest possible frequency is theoretically 48000 Hz, but then you need to use cos instead of sin.
Update: You are creating, playing back, recording, and analysing a sound. So, you have various sources of error.
My two points above correct your problems with creating the sound. The following matlab program shows clearly that the synthetic signal comprises exactly the sine wav you intended to create. So, the problem your original question was about, is solved:
clear
Fs = 96000;
toneFreq1 = 30000; % change between 0 and Fs/2=48000
nSeconds = 20;
f1 = cos( linspace (0, nSeconds*toneFreq1*2*pi, round(nSeconds*Fs) ) );
freqz( f1, length(f1) )
Thus, the new spectrogram image of your modified question reflects other problems that are due to playing back, recording, and/or analysing.
It is hard to say, what problem you face. I just can give you some hints:
1) Most probable, your amplifier and/or loudspeaker are not able to reproduce frequencies much above 20kHz. You should start with frequencies between 8 and 12kHz, then you are able to hear them. If you are older than, say 40 years, it could be hard for you to hear frequencies above ca. 15kHz. But even if you are 20 years old you're not able to hear frequencies above ca. 18 to 20kHz (at least you need huge amplification to hear them).
2) Your microphone is able to convert these high frequencies into an electrical signal, but it is possible that either your microphone amplifier or your sound card is bandwidth-limited to say 22 or 24kHz.
3) Your program that converts the measured signal into a spectrogram might have bugs.
4) The segmentation at the beginning and end of the measured signal also introduces artifacts into the spectrum.
If you need further help, you should post your recording and analysis code. But I guess that with my hints you are able to find the problem on your own. Nonetheless, it would be interesting to inform us about your results.

Resample factors are too large

I have a large vector of recorded data which I need to resample. The problem I encounter is that when using resample, I get the following error:
??? Error using ==> upfirdn at 82 The product of the downsample factor
Q and the upsample factor P must be less than 2^31.
Now, I understand why this is happening - my two sampling rates are very close together, so the integer factors need to be quite large (something like 73999/74000). Unfortunately this means that the appropriate filter can't be created by MATLAB. I also tried resampling just up, with the intention of then resampling down, but there is not enough memory to do this to even 1 million samples of data (mine is 93M).
What other methods could I use to properly resample this data?
An interpolated polyphase FIR filter can be used to interpolate just the new set of sample points without using an upsampling+downsampling process.
But if performance is completely unimportant, here's a Quick and Dirty windowed-Sinc interpolator in Basic.
here's my code, I hope it helps :
function resig = resamplee(sig,upsample,downsample)
if upsample*downsample<2^31
resig = resample(sig,upsample,downsample);
else
sig1half=sig(1:floor(length(sig)/2));
sig2half=sig(floor(length(sig)/2):end);
resig1half=resamplee(sig1half,floor(upsample/2),length(sig1half));
resig2half=resamplee(sig2half,upsample-floor(upsample/2),length(sig2half));
resig=[resig1half;resig2half];
end

Quantization of .wav file

I am attempting to quantize a 16 bit .wav file to a lower bit rate using Matlab. I've opened the file using wavread() but I am unsure of how to proceed from here. I know that somehow I need to "round" each sample value to (for example) a 7 bit number. Here's the code that's reading the file:
[file,rate,bits] = wavread('smb.wav');
file is a 1 column matrix containing the values of each sample. I can loop through each item in that matrix like so:
for i=1 : length(file)
% not sure what to put here..
end
Could you point me in the right direction to quantize the data?
If you have int16 data, varying from -32768 to +32767, it can be as simple as
new_data = int8(old_data./2^8);
That won't even require a for loop.
For scaled doubles it would be
new_data = int8(old_data.*2^7);
The wavread documentation suggests that you might even be able retrieve the data in that format to begin with:
[file,rate,bits] = wavread('smb.wav','int8');
EDIT: Changing the bit rate:
After rereading the question, I realize that you also mentioned a lower bit rate which implies reducing the sample rate, not the quantization of the data. If that is the case, you should look at the documentation for downsample, decimate, and/or resample. They are all built in MATLAB functions that change the bit rate.
downsample(file,2)
would half the bit rate, for example.

retrieve data at specific loop values

I was wondering how i could achieve the following: I have a vector (scalar) called TimeSteps. TimeSteps increments according to the length of a vector (nBins_max) which will normally be set at a fixed length (but i may change it occasionally).
To declare a 5 full system rotations i would use:
TimeSteps = 5*nBins_max;
I would like to retrieve data for each rotation of my system. in pseduo-code i'm looking to achieve something like the following:
where TimeSteps = each multiple of nBins_max
retrieve data
end
I could set this manually at each number of timesteps i'm interested in, however, due to the number of rollers in some of my systems this could prove to be tedious and potentially error prone! Also, timesteps varies considerably in it's range, sometimes 1*nBins_max, sometimes 1000*nBins_max, perhaps more than this!
Any pointers or general help is appreciated!
Thanks for reading
Richard
The modulus is zero at each multiple of nBins_max:
where mod(TimeSteps, nBins_max)==0
retrieve data
end
Hope that helps?