Hello I want to calculate realtime FFT plot of my input. With the following code i create a record and calculation. The point is that the calculation is takes to much time to get i nice plot update.
Fs = 44100; % sampling frequency in Hz
T = 1/5; % length of one interval signal in sec
t = 0:1/Fs:T-1/Fs; % time vector
nfft = 2^nextpow2(Fs); % n-point DFT
f = (0:nfft/2)'*Fs/nfft; % Frequency vector
%# prepare plots
figure
hrec(1) = subplot(211);
tplot(1) = plot(t, nan(size(t)), 'Color','b', 'Parent',hrec(1));
xlabel('Time [s]'), ylabel('Amplitude')
hrec(2) = subplot(212);
spec(2) = semilogx(f,nan(size(f)),'Color','b', 'Parent',hrec(2));
xlabel('Frequency [Hz]'), ylabel('Magnitude [dB]'), %XScale('log');
set(hrec, 'Box','on', 'XGrid','on', 'YGrid','on');set(hrec(2), 'XScale','log', 'Xlim',[20 20000]);
% specgram(sig, nfft, Fs);
% prepare audio recording
recObj = audiorecorder(Fs,16,1,0);
% Record
disp('Start Recording...')
for i=1:20
recordblocking(recObj, T);
%# get data and compute FFT
sig = getaudiodata(recObj);
fftMag = 20*log10( abs(fft(sig,nfft)) ); fftMag = fftMag(1:ceil((nfft+1)/2));
% update plots
set(tplot(1),'YData',sig);
set(spec(2), 'YData', fftMag);
title(hrec(1), num2str(i,'Interval = %d'))
drawnow % force MATLAB to flush any queued displays
end
disp('Done.')
So I create a parallel computed calculation:
% Record for 10 intervals of 1sec each
disp('Start speaking...')
for i =1:20
parfor ii=1:2
if ii == 1
recordblocking(recObj, T);
elseif ii == 2
%# get data and compute FFT
sig = getaudiodata(recObj);
fftMag = 20*log10( abs(fft(sig,nfft)) ); fftMag = fftMag(1:ceil((nfft+1)/2));recordblocking(recObj, T);
% update plots
set(tplot(1),'YData',sig);
set(spec(2), 'YData', fftMag);
title(hrec(1), num2str(i,'Interval = %d'))
drawnow %# force MATLAB to flush any queued displays
end
end
end
disp('Done.')
i get now Errors:
Error using audiorecorder/getaudiodata (line 742) Recorder is empty.
Error in parallel_function (line 466)
F(base, limit);
Error in par_plotupdate (line 25) parfor ii=1:2
How do I fix this, because i don't get this error when i don't use the parallel for loop. The last error comes i think from lack of information the first iteration. So i get an a-synchronized loop? or do i make it to difficult…
Thanks
Here is a implementation using asynchron recording. This way recording the audio data runs in the background and the execution of the code is only paused when no data is available. With nearly 100% of the cpu time available to process the data, it came out that processing was possible faster than real-time. This is why I did not use the parallel computing toolbox to further speed-up the process.
Fs = 44100; % sampling frequency in Hz
T = 1/5; % length of one interval signal in sec
t = 0:1/Fs:T-1/Fs; % time vector
nfft = 2^nextpow2(Fs); % n-point DFT
f = (0:nfft/2)'*Fs/nfft; % Frequency vector
%# prepare plots
figure
hrec(1) = subplot(211);
tplot(1) = plot(t, nan(size(t)), 'Color','b', 'Parent',hrec(1));
xlabel('Time [s]'), ylabel('Amplitude')
hrec(2) = subplot(212);
spec(2) = semilogx(f,nan(size(f)),'Color','b', 'Parent',hrec(2));
xlabel('Frequency [Hz]'), ylabel('Magnitude [dB]'), %XScale('log');
set(hrec, 'Box','on', 'XGrid','on', 'YGrid','on');set(hrec(2), 'XScale','log', 'Xlim',[20 20000]);
% specgram(sig, nfft, Fs);
% prepare audio recording
recObj = audiorecorder(Fs,16,1,0);
N=20;
% Record
disp('Start Recording...')
%set up one continuous recording for all N loops. Each loop processes T seconds of data
recObj.record(N*T);
%avoid empty recorder;
pause(.1);
for idx=1:N
%we are continuously recording and this iteration of the loop should process the data from startindex to endindex
startindex=1+(idx-1)*Fs*T;
endindex=(idx)*Fs*T;
audioData=recObj.getaudiodata();
%if not enough data is available, wait.
while size(audioData,1)<endindex
%amount of missing data can be caluclated, wait that time
pause((endindex-size(audioData,1))/Fs);
audioData=recObj.getaudiodata();
end
fprintf('processing index %d to %d\n',startindex,endindex);
%# get data and compute FFT
sig =audioData(startindex:endindex,:);
%If you want to use parallel computing, submit the next line to a worker (http://www.mathworks.com/help/distcomp/createtask.html). Keep in mind that workers can not update your UI, you have to get the results back from the workers.
fftMag = 20*log10( abs(fft(sig,nfft)) ); fftMag = fftMag(1:ceil((nfft+1)/2));
% update plots
set(tplot(1),'YData',sig);
set(spec(2), 'YData', fftMag);
title(hrec(1), num2str(idx,'Interval = %d'))
drawnow % force MATLAB to flush any queued displays
end
disp('Done.')
Related
I am developing a 1v peak-to-peak sine wave with a 60hz frequency. I am doing this in order to ground truth certain methods of measuring sound. I am running into trouble in using and plotting various methods for developing a PSD. I have code below. Running this plots a fine sine wave and the RMS value of the data is .71 (good!). I expect to see a PSD plot with 1v energy at 60hz and no energy outside that band. I'm not getting that and am not sure why. For reference, I am a biologist - this is all Greek to me but I'm trying my best. Code:
Fs = 32000; % samples per second
dt = 1/Fs; % seconds per sample
StopTime = .5; % seconds
t = (0:dt:StopTime-dt)'; % seconds
%%Sine wave:
Fc = 60; % hertz
x = cos(2*pi*Fc*t);
% Plot the signal versus time:
figure;
plot(t,x);
xlabel('time (in seconds)');
title('Signal versus Time');
NFFT = 8192; %
NOVERLAP = round(0.75*NFFT);
w = hanning(NFFT);
[sensor_spectrum, freq] = pwelch(x,w,NOVERLAP,NFFT,fs);
figure;
plot (freq, sensor_spectrum );
I am trying to get the output of a Gaussian pulse going through a coax cable. I made a vector that represents a coax cable; I got attenuation and phase delay information online and used Euler's equation to create a complex array.
I FFTed my Gaussian vector and convoluted it with my cable. The issue is, I can't figure out how to properly iFFT the convolution. I read about iFFt in MathWorks and looked at other people's questions. Someone had a similar problem and in the answers, someone suggested to remove n = 2^nextpow2(L) and FFT over length(t) instead. I was able to get more reasonable plot from that and it made sense to why that is the case. I am confused about whether or not I should be using the symmetry option in iFFt. It is making a big difference in my plots. The main reason I added the symmetry it is because I was getting complex numbers in the iFFTed convolution (timeHF). I would truly appreciate some help, thanks!
clc, clear
Fs = 14E12; %1 sample per pico seconds
tlim = 4000E-12;
t = -tlim:1/Fs:tlim; %in pico seconds
ag = 0.5; %peak of guassian
bg = 0; %peak location
wg = 50E-12; %FWHM
x = ag.*exp(-4 .* log(2) .* (t-bg).^2 / (wg).^2); %Gauss. in terms of FWHM
Ly = x;
L = length(t);
%n = 2^nextpow2(L); %test output in time domain with and without as suggested online
fNum = fft(Ly,L);
frange = Fs/L*(0:(L/2)); %half of the spectrum
fNumMag = abs(fNum/L); %divide by n to normalize
% COAX modulation ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
%phase data
mu = 4*pi*1E-7;
sigma_a = 2.9*1E7;
sigma_b = 5.8*1E6;
a = 0.42E-3;
b = 1.75E-3;
er = 1.508;
vf = 0.66;
c = 3E8;
l = 1;
Lso = sqrt(mu) /(4*pi^3/2) * (1/(sqrt(sigma_a)*a) + 1/(b*sqrt(sigma_b)));
Lo = mu/(2*pi) * log(b/a);
%to = l/(vf*c);
to = 12E-9; %measured
phase = -pi*to*(frange + 1/2 * Lso/Lo * sqrt(frange));
%attenuation Data
k1 = 0.34190;
k2 = 0.00377;
len = 1;
mldb = (k1 .* sqrt(frange) + k2 .* frange) ./ 100 .* len ./1E6;
mldb1 = mldb ./ 0.3048; %original eqaution is in inch
tfMag = 10.^(mldb1./-10);
% combine to make in complex form
tfC = [];
for ii = 1: L/2 + 1
tfC(ii) = tfMag(ii) * (cosd(phase(ii)) + 1j*sind(phase(ii)));
end
%END ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
%convolute both h and signal
fNum = fNum(1:L/2+1);
convHF = tfC.*fNum;
convHFMag = abs(convHF/L);
timeHF = ifft(convHF, length(t), 'symmetric'); %this is the part im confused about
% Ignore,
% tfC(numel(fNum)) = 0;
% convHF = tfC.*fNum;
% convHFMag = abs(convHF/n);
% timeHF = ifft(convHF);
%% plotting
% subplot(2, 2, 1);
% plot(t, Ly)
% title('Gaussian input');
% xlabel('time in seconds')
% ylabel('V')
% grid
subplot(2, 2, 1)
plot(frange, abs(tfC(1: L/2 + 1)));
set(gca, 'Xscale', 'log')
title('coax cable model')
xlabel('Hz')
ylabel('|H(s)|V/V')
grid
ylim([0 1.1])
subplot(2, 2, 2);
plot(frange, convHFMag(1:L/2+1), '.-', frange, fNumMag(1:L/2+1)) %make both range and function the same lenght
title('The input signal Vs its convolution with coax');
xlabel('Hz')
ylabel('V')
legend('Convolution','Lorentzian in frequecuency domain');
xlim([0, 5E10])
grid
subplot(2, 2, [3, 4]);
plot(t, Ly, t, timeHF)
% plot(t, real(timeHF(1:length(t)))) %make both range and function the same lenght
legend('Input', 'Output')
title('Signal at the output')
xlabel('time in seconds')
ylabel('V')
grid
It's important to understand deeply the principles of the FFT to use it correctly.
When you apply Fourier transform to a real signal, the coefficients at negative frequencies are the conjugate of the ones at positive frequencies. When you apply FFT to a real numerical signal, you can show mathematically that the conjugates of the coefficients that should be at negative frequencies (-f) will now appear at (Fsampling-f) where Fsampling=1/dt is the sampling frequency and dt the sampling period. This behavior is called aliasing and is present when you apply fft to a discrete time signal and the sampling period should be chosen small enaough for those two spectra not to overlap Shannon criteria.
When you want to apply a frequency filter to a signal, we say that we keep the first half of the spectrum because the high frequencies (>Fsampling/2) are due to aliasing and are not characteristics of the original signal. To do so, we put zeros on the second half of the spectra before multiplying by the filter. However, by doing so you also lose half of the amplitude of the original signal that you will not recover with ifft. The option 'symmetric' enable to recover it by adding in high frequencis (>Fsampling/2) the conjugate of the coefficients at lower ones (<Fsampling/2).
I simplified the code to explain briefly what's happening and implemented for you at line 20 a hand-made symmetrisation. Note that I reduced the sampling period from one to 100 picoseconds for the spectrum to display correctly:
close all
clc, clear
Fs = 14E10; %1 sample per pico seconds % CHANGED to 100ps
tlim = 4000E-12;
t = -tlim:1/Fs:tlim; %in pico seconds
ag = 0.5; %peak of guassian
bg = 0; %peak location
wg = 50E-12; %FWHM
NT = length(t);
x_i = ag.*exp(-4 .* log(2) .* (t-bg).^2 / (wg).^2); %Gauss. in terms of FWHM
fftx_i = fft(x_i);
f = 1/(2*tlim)*(0:NT-1);
fftx_r = fftx_i;
fftx_r(floor(NT/2):end) = 0; % The removal of high frequencies due to aliasing leads to losing half the amplitude
% HER YOU APPLY FILTER
x_r1 = ifft(fftx_r); % without symmetrisation (half the amplitude lost)
x_r2 = ifft(fftx_r, 'symmetric'); % with symmetrisation
x_r3 = ifft(fftx_r+[0, conj(fftx_r(end:-1:2))]); % hand-made symmetrisation
figure();
subplot(211)
hold on
plot(t, x_i, 'r')
plot(t, x_r2, 'r-+')
plot(t, x_r3, 'r-o')
plot(t, x_r1, 'k--')
hold off
legend('Initial', 'Matlab sym', 'Hand made sym', 'No sym')
title('Time signals')
xlabel('time in seconds')
ylabel('V')
grid
subplot(212)
hold on
plot(f, abs(fft(x_i)), 'r')
plot(f, abs(fft(x_r2)), 'r-+')
plot(f, abs(fft(x_r3)), 'r-o')
plot(f, abs(fft(x_r1)), 'k--')
hold off
legend('Initial', 'Matlab sym', 'Hand made sym', 'No sym')
title('Power spectra')
xlabel('frequency in hertz')
ylabel('V')
grid
Plots the result:
Do not hesitate if you have further questions. Good luck!
---------- EDIT ----------
The amplitude of discrete Fourier transform is not the same as the continuous one. If you are interested in showing signal in frequency domain, you will need to apply a normalization based on the convention you have chosen. In general, you use the convention that the amplitude of the Fourier transform of a Dirac delta function has amplitude one everywhere.
A numerical Dirac delta function has an amplitude of one at an index and zeros elsewhere and leads to a power spectrum equal to one everywhere. However in your case, the time axis has sample period dt, the integral over time of a numerical Dirac in that case is not 1 but dt. You must normalize your frequency domain signal by multiplying it by a factor dt (=1picoseceond in your case) to respect the convention. You can also note that this makes the frequency domain signal homogeneous to [unit of the original multiplied by a time] which is the correct unit of a Fourier transform.
i should find the minimum bandwidth that can be used for the song to still be distinguishable by a listener
and this is my code so far
% A.Read the song and assign vules
[y, fs] = wavread('Dog Woof.wav');
time = (1:length(y))/30000;
plot(time, y); % ploting the sin wave of the song
title('Sound waves');
xlabel('Time');
ylabel('Frequency');
% B.Simple rate will be the fs value
fs
% C.Bandwidth
[UPPER, LOWER] = bandwidth(y)
I studies on Digital Signal Filtering and I have a file includes some signal data. I wrote Matlab Program to get 23 to 27 Hz from original signal. but filtered signal is different. my desire filter is bandpass but my code work like low pass filter.
this is my code :
clc;
clear all;
load('SignalFile.mat');
%number of sample
SampleNumber = 60000;
%create hamming window
hamm = hamming((SampleNumber))'; %'
% there is 4 data in SignalFile.mat
for pl=1:4
% get name of data in signalFile.mat
data = eval(['mydata' num2str(pl)]);
[n,c] = size(data);
nk=SampleNumber;
% there is 2 signal in each data. but main signal exists on data(1:nk,1);
% nk is Sample Number.
mydata = data(1:nk,1) ;
encodedata = data(1:nk,2);
% Sample Rate my this file equal to data length / 4 ->> ~ 39000 sample
% per second.
fs = floor(n/4); % Sampling rate [Hz]
noSamples = nk; % Number of samples
f = 0 : fs/noSamples : fs - fs/noSamples; % Frequency vector
figure;
subplot(2,2,1);
plot(mydata);
x_fft = abs(fft(mydata));
subplot(2,2,2);
plot(f,x_fft);
xlim([1 100]);
centerf = 25; % 25 Hz Center
bw=2; %Bandwisth
fc=pi*centerf; %Center Frequency
L = nk; %sample number;
%Compute Filter
hsuup=(-(L-1)/2:(L-1)/2);
hideal1=hamm.*(2*(fc+bw)*(sin(2*(fc+bw)*hsuup/fs)./(2*(2*fc+bw)*hsuup/fs)));
hideal2=hamm.*(2*(fc-bw)*(sin(2*(fc-bw)*hsuup/fs)./(2*(2*fc+bw)*hsuup/fs)));
h_bpf=(hideal1-hideal2);
% transform mydata to Ferequency Domain
comp_sig_fft=fft(mydata)'; %'
% transform Filter Windows to Ferequency Domain
h_bpf_fft=fft(h_bpf);
% Filter Signal
s_fft=comp_sig_fft.*h_bpf_fft;
%
band_passed_signal=real(ifft(s_fft));
subplot(2,2,3);
plot(band_passed_signal);
x_fft = abs(fft(band_passed_signal));
subplot(2,2,4);
plot(f,x_fft);
xlim([1 100]);
end
is there any idea?
best regards.
my datafile uploaded here :
http://wikisend.com/download/574638/SignalFile.mat
result Images :
https://www.imageupload.co.uk/image/ZLzM
if you look at image, you can find under 20hz signal exists in filtered signal yet.
Need help since kind of lost on this. I am trying to graph the code below i have in which I made a white noise and used STFT to do the bandpass filtering but now I need to graph the signal in to two graphs for each channel. The result should be graphs. For graph 1a., the horizontal axis should be frequency, the vertical axis should be amplitude. For (2).b, the horizontal axis should be time, the vertical axis should be frequency, and express the amplitude using color.
function newwhitenoise()
L = 5000; %Sample length for the random signal
Pause = 10000; %Sample Pause Gap
mu = 0;
sigma = 2;
%Need to see left signal is not displaying
Left_signal = sigma*randn(L,1) + mu;
Right_signal = sigma*randn(L,1) + mu;
Long_signal = [Left_signal zeros(L,1); zeros(Pause,2); zeros(L,1) Right_signal];
%Player Object
soundRecord(Long_signal);
disp([Left_signal zeros(L,1)]);
%sound(Long_signal, Fs);
%Plots subplots in graph
%figure
%subplot(211);
%plot(Left_signal, 'b'); grid on;
%subplot(212);
%plot(Right_signal, 'r'); grid on;
end
function signalplayer(signal)
%load(signal);
fs = 44100; %Sample Frequency
obj = audioplayer(signal,fs);
play(obj);
end
function soundRecord (signal)
fs = 44100; %Sample Frequency
recObj = audiorecorder(44100, 16, 2);
get(recObj)
%save sound to wave file
%filename = 'location.flac';
audiowrite('input.wav',signal, fs);
if ~exist('inFile')
inFile = 'input.wav';
end
if ~exist('outFile')
outFile = 'output.wav';
end
if ~exist('frameWidth')
frameWidth = 4096; % size of FFT frame, better be a power of 2
end
frameHop = frameWidth/2;
analWindow = hanning(frameWidth);
[inBuffer, Fs] = wavread(inFile);
x = [inBuffer(:,1); linspace(0, 0, frameWidth)']; % use left channel only, zeropad one frame at the end
clear inBuffer;
numSamples = length(x);
numFrames = floor(numSamples/frameHop)-1;
% disp(frameWidth);
% disp(numSamples);
% disp(frameHop);
% disp(numFrames);
% disp(size(analWindow));
% disp(size(transpose(analWindow)));
y = linspace(0, 0, numSamples)';
n = 0; % init sample pointer. unlike MATLAB, i like counting from 0
for frameIndex = 1:numFrames
xWindowed = x(n+1:n+frameWidth) .* analWindow; % get and window the input audio frame
X = fft(fftshift(xWindowed)); % do the FFT
Y = X; % copy the input spectrum to output
% do whatever processing to Y that you like
yWindowed = fftshift(real(ifft(Y))); % convert back to time domain, toss the imaginary part
%disp(size(x(1:frameWidth)));
%disp(size(yWindowed));
y(n+1:n+frameWidth) = y(n+1:n+frameWidth) + yWindowed;
n = n + frameHop;
end
wavwrite(y, Fs, 'output.wav');
For graph 1 try pwelch and for graph 2 try spectrogram.
pwelch is basically the average of the squared magnitude of the STFT. The spectrogram function returns the STFT of the signal thus it operates on the signal in the time domain.
Both functions are called with the same input parameters and when called with no output, plot the result on the current axes.
If you want the frequency axis to be the vertical (y) in graph 2, use the option 'yaxis' in the call for spectrogram. I suggest you look at the documentation of both functions.