Save samples that repeat every 300 ms - matlab

I want to sample an audio signal. I have a wav file 5 seconds long. I want save samples every 300 ms.
I use function audioread in MATLAB that read samples containing in file, this is my code:
[signal,fs]=audioread('file.wav');
dt = 1/fs;
N = length(signal);
t = 0:dt:(N-1)*dt;
plot(t,signal)
ms=t*1000;
How can I do save in an array samples that are repeated every 300 ms?

Let's assume your wav file has a sampling rate of fs = 44100 (which is quite common), i.e. you have 44100 samples per second. Now, you want to have one sample each 0.3 s. You have to calculate the corresponding number of samples to "skip" with respect to your original sampling rate, i.e. skip = 0.3 * fs = 13230 in this case. Now, you can simply access each skip'th element in your original signal (and also time interval t).
Here's some code to do the work, and visualize the above:
% Artificial data
signal = sin(linspace(0, 2*pi, 5 * 44100));
fs = 44100;
dt = 1 / fs;
N = length(signal);
t = 0:dt:(N-1)*dt;
% "Re-sampling" parameters
dt_new = 0.3;
skip = dt_new * fs;
% Extract every skip'th value from original time interval and signal
t_new = t(1:skip:end).'
signal_new = signal(1:skip:end);
% Some visualization
figure(1);
hold on;
plot(t, signal);
plot(t_new, signal_new, 'r.', 'MarkerSize', 15);
hold off;
We get the following output, the original signal is blue, the red points are the samples at every 0.3 s:
If you have a look at t_new, you see, that the sampling points exactly match your desired interval of 0.3 s:
t_new =
0.00000
0.30000
0.60000
0.90000
1.20000
1.50000
1.80000
2.10000
2.40000
2.70000
3.00000
3.30000
3.60000
3.90000
4.20000
4.50000
4.80000
Hope that helps!
EDIT: There's also a resample function available in the Signal Processing Toolbox. I'm not sure, if this function is useful here, since the new sampling rate would be fs_new = 1 / 0.3 = 3.3333, but resample only accepts integers. Maybe, there's another more sophisticated (toolbox) function to do the job automatically.

Related

How to get the full Fourier spectrum in MATLAB?

I created a 6-bit quantizer and passed a signal through it, but when I plot the DFT, it peaks at 200 MHz and then stops; I'm not seeing the whole spectrum. What's preventing me in my code from getting the rest of the points at the higher frequencies?
Here is my code:
bits = 6; %6-bit
fs = 400e6; %sampling frequency
amp = 1; %amplitude
f = 200e6; %actual frequency
vpp = 2; peak-to-peak voltage
LSB = vpp/(2^bits); %least-significant bit
cycles = 1000;
duration = cycles/f;
values = 0:1/fs:duration;
party = LSB:LSB:(vpp-LSB); %partition
blocker = 0:1:(2^bits - 1); %codebook
biblocker = fliplr(decimaltobinary(blocker)); %I created a function that converts decimal to binary
qtone = amp + amp*sin(2*pi*f*values); %tone
[index, q] = quantization(qtone,party,blocker); %I created a quantizing function
ftq = fft(q)/length(q); % Fourier Transform (Scaled)
qf = linspace(0, 1, fix(length(q))/2+1)*(fs/2); % Frequency Vector
qi = 1:length(qf); % Index Vector
qa = abs(ftq(qi))*2/.7562;
figure
plot(qf/1e6, qa) % One-Sided Amplitude Plot
xlim([100 500]);
xlabel('Frequency [MHz]')
ylabel('Amplitude')
Here is what I get:
Since you selected your sampling frequency, fs = 400e6 i.e. 400 MHz, you can only observe the spectrum up to 200e6, half of the sampling frequency. You can read the theory behind it using Nyquist Sampling Theorem.
As a solution you need to set your twice the frequency you want to observe on the spectrum. It is impossible to observe whole frequency, you need to set a finite frequency limit.
For base-band sampled data, everything in the spectrum above half the sample rate is redundant, just aliases for the spectrum below half the sample rate. So there's no need to display the same spectrum repeated.
When sampling for a finite length of time (less than the age of the Earth, etc.), you have to sample at a rate higher than twice the highest frequency in the signal. 2X (400Msps for a 200MHz signal) often won't work.
qf = linspace(0, 1, fix(length(q)))*(fs);

How can I create n sine waves from the elements of an n-by-m matrix?

I'm writing a program on MATLAB that generates 13 waveforms of varying amplitude, duration, and frequency. Each waveform is repeated 5 times, which means I have 65 'trials' in total.
The total length of each trial = 1.5 ms. The sampling frequency = 4 kHz. I would like the wave to begin at 0.5 ms. Prior to the onset of the wave, and following its offset, I would like the amplitude to be zero (i.e. a 'flatline' prior to and following the wave).
I have created a 65x3 matrix where the columns denote the frequency ('hz'), amplitude ('a'), and duration (ms) of the 65 sine waves. Each row denotes a single wave.
I would like to use the information contained in this 65x3 matrix to generate 65 sine waves of amplitude 'a', frequency 'hz', and duration 'ms'. To be specific: each wave should be created using the parameters (hz,a,ms) specified in the nth row of the matrix. E.g. if row 1 = 100, 1, 50... this means I would like to generate a 100 Hz sine wave (amplitude = 1) lasting 50 ms.
I have attempted to construct a for loop to solve this problem. However, the loop returns a number of errors, and I'm not sure how to resolve them. I have adapted the code to the point where no errors are returned; however, my latest attempt seems to generate 65 waves of equal duration, when in fact the duration of each wave should be that which is stated in vector 'ms'.
Here is my latest, albeit newbie and still unsuccessful, attempt: (note that 'trials' represents the 65x3 matrix discussed above; mA = amplitude).
hz=trials(:,1); mA=trials(:,2); ms=trials(:,3);
trials_waves=zeros(65,500); % the max duration (= 500ms); unsure of this part?
for n = 1:size(order,1)
trials_waves = mA*sin(2*pi*hz*0:ms);
end
Apologies if the information provided is scarce. This is the first time I have asked a question on this website. I can provide more information if needed.
Thank you for your help.
Best,
H
Looks like you've got a good start, I'll try to help you get further towards your solution.
Make a Sine Wave
For starters, let's make a sine wave with variable rate, amplitude, and length.
Fs = 4e3; % sample rate of 4 kHz
Sr = 100; % example rate
Sa = 1; % amplitude
St = 10e-3; % signal duration is 10 ms
% To create a sine wave in MATLAB, I'm going to first create a vector of time,
% `t`, and then create the vector of sine wave samples.
N = St * Fs; % number of samples = duration times sample rate;
t = (1:N) * 1/Fs; % time increment is one over sample rate
% Now I can build my sine wave:
Wave = Sa * sin( 2 * pi * Sr * t );
figure; plot(t, Wave);
Note! This is barely enough time for a full wavelength, so be careful with slow rates and short time lengths.
Make many Sine Waves
To turn this into a loop, I need to index into vectors of input variables. Using my previous example:
Fs = 4e3; % sample rate of 4 kHz
Sr = [100 200 300]; % rates
Sa = [1 .8 .5]; % amplitudes
St = [10e-3 20e-3 25e-3]; % signal durations
nWaves = length(Sr);
N = max(St) * Fs; % number of samples = duration times sample rate;
t = (1:N) /Fs; % time increment is one over sample rate
% initialize the array
waves = zeros(nWaves, N);
for iWaves = 1:nWaves
% index into each variable
thisT = (1:St(iWaves) * Fs) * 1/Fs;
myWave = Sa(iWaves) * sin( 2 * pi * Sr(iWaves) * thisT );
waves(iWaves,1:length(myWave)) = myWave;
end
figure; plot(t, waves);
You still have one more piece, zero padding the front end of your signals, there's lots of ways to do it, one way would be to build the signal the way I've described and then concatenate an appropriate number of zeros to the front of your signal array. Feel free to ask a new question if you get stuck. Good luck!

Dividing a signal in channels

I have a signal in time domain (6000 samples from -100 to 1100 ps). I have to convert it into frequency domain and divide it into 100 channels, and find the center frequency of each channel.
I am not good in "MATLAB" so how to do that, help will be appreciated.
Based on my understanding of the question, you want to represent your signal in the frequency domain. Please study some tutorials on FFT to increase your understanding of the FFT details. A good start is this tutorial: FFT Tutorial using Matlab, which I used to write the code below.
close all;
clear all;
clc;
Fs = 5; % Sampling frequency (in THz)
Ts = 1/5; % Sampling period (in ps)
x = randn(1, 6000); % A random signal of 6000 points
t = [-100:Ts:1100-Ts]; % 6000 time points (in ps)
% Plot signal in time domain
figure;plot(t,x);
xlabel('Time (ps)'); ylabel('Signal');
N = 100; % Number of FFT points
X = fftshift(fft(x, N)); % Compute and shift FFT
absX = abs(X); % Compute absolute FFT values
% Frequency centers (frequency components) depend on the values of N and Fs
frequency_centers = Fs * [-N/2:N/2-1]/N;
% Plot signal in frequency domain
figure;plot(frequency_centers, absX);
xlabel('Frequency (THz)'); ylabel('abs FFT');
The variable frequency_centers shows the frequency components.
Since you have 6000 time samples, from -100 to 1100 ps, the sampling period is Ts = 1200/6000 = 0.2 ps and Fs = 1/Ts = 5 THz. Also, note that in order to have 6000 time samples (and not 6001), you need to drop one boundary time value (here I dropped 1100).

inverse fast fourier transform for frequency range

My problem is to obtain original signal from amplitude spectrum (fft) based on inverse fft but only for some frequency range ex. 8-12 Hz. Could anyone help me? I try to used:
xdft=fft(x);
ixdft=ifft(xdft(a:b)), %where xdft(a:b) is |Y(f)| for freq 8-12 Hz.
But it doesn't want to work.
You can set all the values of xdft to zero except those you want, i.e.,
xdft = fft(x);
xdft = xdft(1:ceil(length(xdft) / 2));
xdft(1:a) = 0;
xdft(b+1:end) = 0;
ixdft = ifft(xdft, 'symmetric');
The reason I have taken only half of the original FFT'd data is that your result will be symmetric about Fs / 2 (where Fs is the sample rate), and if you don't do the same thing to the frequencies either side of the centre, you will get a complex signal out. Instead of doing the same thing to both sides manually, I've just taken one side, modified it, and told ifft that it has to reconstruct the data for the full frequency range by appending a mirror image of what you pass it; this by done by calling it with the 'symmetric' option.
If you need to figure out what a and b should be for some frequency, you can first create a vector of the frequencies at which you've performed the FFT, then find those frequencies that are within your range, like so:
xdft = fft(x);
xdft = xdft(1:ceil(length(xdft) / 2));
f = linspace(0, Fs / 2, length(xdft));
keepInd = f >= 8 & f <= 12; % Keep frequencies between 8 and 12 Hz
xdft(~keepInd) = 0;
Note that I've actually omitted the use of the two variables a and b altogether in this example and opted for logical indexing, and that Fs is the sample rate.

How would i down-sample a .wav file then reconstruct it using nyquist? - in MATLAB

This is all done in MATLAB 2010
My objective is to show the results of: undersampling, nyquist rate/ oversampling
First i need to downsample the .wav file to get an incomplete/ or impartial data stream that i can then reconstuct.
Heres the flow chart of what im going to be doing So the flow is analog signal -> sampling analog filter -> ADC -> resample down -> resample up -> DAC -> reconstruction analog filter
what needs to be achieved:
F= Frequency
F(Hz=1/s) E.x. 100Hz = 1000 (Cyc/sec)
F(s)= 1/(2f)
Example problem: 1000 hz = Highest
frequency 1/2(1000hz) = 1/2000 =
5x10(-3) sec/cyc or a sampling rate of
5ms
This is my first signal processing project using matlab.
what i have so far.
% Fs = frequency sampled (44100hz or the sampling frequency of a cd)
[test,fs]=wavread('test.wav'); % loads the .wav file
left=test(:,1);
% Plot of the .wav signal time vs. strength
time=(1/44100)*length(left);
t=linspace(0,time,length(left));
plot(t,left)
xlabel('time (sec)');
ylabel('relative signal strength')
**%this is were i would need to sample it at the different frequecys (both above and below and at) nyquist frequency.*I think.***
soundsc(left,fs) % shows the resaultant audio file , which is the same as original ( only at or above nyquist frequency however)
Can anyone tell me how to make it better, and how to do the sampling at verious frequencies?
heres the .wav file http://www.4shared.com/audio/11xvNmkd/piano.html
EDIT:
%Play decimated file ( soundsc(y,fs) )
%Play Original file ( soundsc(play,fs ) )
%Play reconstucted File ( soundsc(final,fs) )
[piano,fs]=wavread('piano.wav'); % loads piano
play=piano(:,1); % Renames the file as "play"
t = linspace(0,time,length(play)); % Time vector
x = play;
y = decimate(x,25);
stem(x(1:30)), axis([0 30 -2 2]) % Original signal
title('Original Signal')
figure
stem(y(1:30)) % Decimated signal
title('Decimated Signal')
%changes the sampling rate
fs1 = fs/2;
fs2 = fs/3;
fs3 = fs/4;
fs4 = fs*2;
fs5 = fs*3;
fs6 = fs*4;
wavwrite(y,fs/25,'PianoDecimation');
%------------------------------------------------------------------
%Downsampled version of piano is now upsampled to the original
[PianoDecimation,fs]=wavread('PianoDecimation.wav'); % loads piano
play2=PianoDecimation(:,1); % Renames the file as "play
%upsampling
UpSampleRatio = 2; % 2*fs = nyquist rate sampling
play2Up=zeros(length(PianoDecimation)*UpSampleRatio, 1);
play2Up(1:UpSampleRatio:end) = play2; % fill in every N'th sample
%low pass filter
ResampFilt = firpm(44, [0 0.39625 0.60938 1], [1 1 0 0]);
fsUp = (fs*UpSampleRatio)*1;
wavwrite(play2Up,fsUp,'PianoUpsampled');
%Plot2
%data vs time plot
time=(1/44100)*length(play2);
t=linspace(0,time,length(play2));
stem(t,play2)
title('Upsampled graph of piano')
xlabel('time(sec)');
ylabel('relative signal strength')
[PianoUpsampled,fs]=wavread('PianoUpsampled.wav'); % loads piano
final=PianoUpsampled(:,1); % Renames the file as "play"
%-------------------------------------------------------------
%resampleing
[piano,fs]=wavread('piano.wav'); % loads piano
x=piano(:,1); % Renames the file as "play"
m = resample(x,3,2);
Original:
http://www.4shared.com/audio/11xvNmkd/piano.html
New:
http://www.4shared.com/audio/nTRBNSld/PianoUs.html
The easiest thing to do is change sample rates by an integer factor. Downsampling consists of running the data through a low-pass filter followed by discarding samples, while upsampling consists of inserting samples then running the data through a low pass filter (also known as a reconstruction filter or interpolating filter). Aliasing occurs when the filtering steps are skipped or poorly done. So, to show the effect of aliasing, I suggest you simply discard or insert samples as required, then create a new WAV file at the new sample rate. To discard samples, you can do:
DownSampleRatio = 2;
%# Normally apply a low pass filter here
leftDown = left(1:DownSampleRatio:end); %# extract every N'th sample
fsDown = fs/DownSampleRatio;
wavwrite(leftDown, fsDown, filename);
To create samples you can do:
UpSampleRatio = 2;
leftUp = zeros(length(left)*UpSampleRatio, 1);
leftUp(1:UpSampleRatio:end) = left; %# fill in every N'th sample
%# Normally apply a low pass filter here
fsUp = fs*UpSampleRatio;
wavwrite(leftUp, fsUp, filename);
You can just play back the written WAV files to hear the effects.
As an aside, you asked for improvements to your code - I prefer to initialize the t vector as t = (0:(length(left)-1))/fs;.
The DSP technique you need is called decimation.