How to obtain damping ratio from frequency response function (accelerance) in Matlab - matlab

I want to find the natural frequencies and its damping ratio's of a test sample that is excited by use of an impact hammer and the response is measured by an accelerometer. So far I have got the Frequency Response Function (the Accelerance) by fourier transforming the input and output data. The Accelerance transfer function has a logarithmic scale. Now I got stuck what to do next. How do I obtain the natural frequencies and its damping ratio? The code so far:
N = 125000; %number of datapoints
fs = 12500; %sampling frequency
ts = 1/fs;
%set the x-axis of graph
x_max = (N-1)*ts;
x_axis = 0:ts:x_max;
%data
Time = data(1,:);
Force = data(2,:);
Acceleration = data(3,:);
Input = abs(fft(Force)); %FFT input force
Output = abs(fft(Acceleration)); %FFT output acceleration
%Accelerance transfer function
Accelerance = Output./Input;
Accelerance_dB = 20*log10(Accelerance); %Accelerance with logarithmic scale
I hope someone can help me!

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);

Using IFFT to get original signal and Parseval's Theorem

I have a current signal (extracted in csv) which I obtained from cadence simulation over 30ns time. I have removed DC offset and applied windowing function before FFT. And normalized FFT by sqrt(N). I have shift zero-frequency component to center of my desired spectrum with fftshift(X). I got my desired FFT. I also want to get back to my original windowed signal by ifft but it is not showing my windowed signal instead it is showing only a version of the window function that I used. My sample signal is real not complex.
I have another question. My power before FFT and after FFT is same. How can I show in graph in an intelligent way to show Parseval's theroem?
I have also added my MATLAB code without the uploading csv and making the vectors. my y value is Current_wo_dc
MATLAB Code:
N = length(Current_wo_dc);
ts = 1.0e-12;
Fs = 1/ts;
tmax = (N-1)*ts;
tm = 0:ts:tmax;
f = -Fs/2:Fs/(N-1):Fs/2;
fn=hanning(N); % hanning window function
Z = Current_wo_dc'.*fn;
Power_Z = sum(Z.^2); % power in time domain
%FFT
fftY = fft(Z);
y = fftshift(fftY);
Y = abs(y);
a3 = Y/sqrt(N);
Power_fftY = sum(fftY.*conj(fftY))/length(fftY); % power in frequency domain
%IFFT:
I = ifftshift(fftshift(Z));
II = I*sqrt(N);
%PSD
psd = a3.^2;
psd_db = 10*log10(psd);
subplot(311), plot(Z); % windowed signal
subplot(312), plot(a3); % fft across frequency bin not shifted along frequency
subplot(313), plot(II); % ifft

period of sawtooth from measurements

I have a series of 2D measurements (time on x-axis) that plot to a non-smooth (but pretty good) sawtooth wave. In an ideal world the data points would form a perfect sawtooth wave (with partial amplitude data points at either end). Is there a way of calculating the (average) period of the wave, using OCTAVE/MATLAB? I tried using the formula for a sawtooth from Wikipedia (Sawtooth_wave):
P = mean(time.*pi./acot(tan(y./4))), -pi < y < +pi
also tried:
P = mean(abs(time.*pi./acot(tan(y./4))))
but it didn't work, or at least it gave me an answer I know is out.
An example of the plotted data:
I've also tried the following method - should work - but it's NOT giving me what I know is close to the right answer. Probably something simple and wrong with my code. What?
slopes = diff(y)./diff(x); % form vector of slopes for each two adjacent points
for n = 1:length(diff(y)) % delete slope of any two points that form the 'cliff'
if abs(diff(y(n,1))) > pi
slopes(n,:) = [];
end
end
P = median((2*pi)./slopes); % Amplitude is 2*pi
Old post, but thought I'd offer my two-cent's worth. I think there are two reasonable ways to do this:
Perform a Fourier transform and calculate the fundamental
Do a curve-fitting of the phase, period, amplitude, and offset to an ideal square-wave.
Given curve-fitting will likely be difficult because of discontinuities in saw-wave, so I'd recommend Fourier transform. Self-contained example below:
f_s = 10; # Sampling freq. in Hz
record_length = 1000; # length of recording in sec.
% Create noisy saw-tooth wave, with known period and phase
saw_period = 50;
saw_phase = 10;
t = (1/f_s):(1/f_s):record_length;
saw_function = #(t) mod((t-saw_phase)*(2*pi/saw_period), 2*pi) - pi;
noise_lvl = 2.0;
saw_wave = saw_function(t) + noise_lvl*randn(size(t));
num_tsteps = length(t);
% Plot time-series data
figure();
plot(t, saw_wave, '*r', t, saw_function(t));
xlabel('Time [s]');
ylabel('Measurement');
legend('measurements', 'ideal');
% Perform fast-Fourier transform (and plot it)
dft = fft(saw_wave);
freq = 0:(f_s/length(saw_wave)):(f_s/2);
dft = dft(1:(length(saw_wave)/2+1));
figure();
plot(freq, abs(dft));
xlabel('Freqency [Hz]');
ylabel('FFT of Measurement');
% Estimate fundamental frequency:
[~, idx] = max(abs(dft));
peak_f = abs(freq(idx));
peak_period = 1/peak_f;
disp(strcat('Estimated period [s]: ', num2str(peak_period)))
Which outputs a couple of graphs, and also the estimated period of the saw-tooth wave. You can play around with the amount of noise and see that it correctly gets a period of 50 seconds till very high levels of noise.
Estimated period [s]: 50

Power spectral density of FFT

I have a piece of code that gets the FFT of a part of the signal and I'm now trying to get the PSD,
Fs = 44100;
cj = sqrt(-1);
%T=.6;
dt = 1/Fs;
left=test(:,1);
right=test(:,2);
time = 45;
interval =.636;
w_range = time*Fs: (time+interval)*Fs-1;
I = left(w_range);
Q = right(w_range);
n = interval * Fs;
f = -Fs/2:Fs/n:Fs/2-Fs/n;
s = I+cj.*Q;
% Smooth the signal ss = smooth(s,201);
sf = (fftshift(fft(ss(1:n)))); %FFT of signal
figure(1) plot(f,((20*log10((abs(sf))./max(abs(sf))))))
From my understanding, in order to get the PSD I just need to raise sf to the power of 2, or is there anything more I need to perform?
Technically yes, you can obtain the power-spectral density (PSD) of a periodic signal by taking the squared-magnitude of its FFT. Note that if you are going to plot it on a logarithmic decibel scale, there is really no difference between 20*log10(abs(sf)) or 10*log10(abs(sf).^2).
There is however generally more to it in the sense that the PSD estimate computed in this way tends to have a fairly large variance. There are a number of techniques which can be used to improve the estimate. A simple one consists of applying a window to sections of data, perform the FFT, then averaging the resulting PSDs (i.e. averaging the squared-magnitudes).
You are perfectly right. You just have to built the square of the absolute values.

Spectrogram and what it is

I am very interested to know how the top right figure in :http://en.wikipedia.org/wiki/Spectrogram
is generated (the script) and how to analyse it i.e what information does it convey?I would appreciate a simplified answer with minimum mathematical jargons. Thank you.
The plot shows time along the horizontal axis, and frequency along the vertical axis. With pixel color showing the intensity of each frequency at each time.
A spectrogram is generated by taking a signal and chopping it into small time segments, doing a Fourier series on each segment.
here is some matlab code to generate one.
Notice how plotting the signal directly, it looks like garbage, but plotting the spectrogram, we can clearly see the frequencies of the component signals.
%%%%%%%%
%% setup
%%%%%%%%
%signal length in seconds
signalLength = 60+10*randn();
%100Hz sampling rate
sampleRate = 100;
dt = 1/sampleRate;
%total number of samples, and all time tags
Nsamples = round(sampleRate*signalLength);
time = linspace(0,signalLength,Nsamples);
%%%%%%%%%%%%%%%%%%%%%
%create a test signal
%%%%%%%%%%%%%%%%%%%%%
%function for converting from time to frequency in this test signal
F1 = #(T)0+40*T/signalLength; #frequency increasing with time
M1 = #(T)1-T/signalLength; #amplitude decreasing with time
F2 = #(T)20+10*sin(2*pi()*T/signalLength); #oscilating frequenct over time
M2 = #(T)1/2; #constant low amplitude
%Signal frequency as a function of time
signal1Frequency = F1(time);
signal1Mag = M1(time);
signal2Frequency = F2(time);
signal2Mag = M2(time);
%integrate frequency to get angle
signal1Angle = 2*pi()*dt*cumsum(signal1Frequency);
signal2Angle = 2*pi()*dt*cumsum(signal2Frequency);
%sin of the angle to get the signal value
signal = signal1Mag.*sin(signal1Angle+randn()) + signal2Mag.*sin(signal2Angle+randn());
figure();
plot(time,signal)
%%%%%%%%%%%%%%%%%%%%%%%
%processing starts here
%%%%%%%%%%%%%%%%%%%%%%%
frequencyResolution = 1
%time resolution, binWidth, is inversly proportional to frequency resolution
binWidth = 1/frequencyResolution;
%number of resulting samples per bin
binSize = sampleRate*binWidth;
%number of bins
Nbins = ceil(Nsamples/binSize);
%pad the data with zeros so that it fills Nbins
signal(Nbins*binSize+1)=0;
signal(end) = [];
%reshape the data to binSize by Nbins
signal = reshape(signal,[binSize,Nbins]);
%calculate the fourier transform
fourierResult = fft(signal);
%convert the cos+j*sin, encoded in the complex numbers into magnitude.^2
mags= fourierResult.*conj(fourierResult);
binTimes = linspace(0,signalLength,Nbins);
frequencies = (0:frequencyResolution:binSize*frequencyResolution);
frequencies = frequencies(1:end-1);
%the upper frequencies are just aliasing, you can ignore them in this example.
slice = frequencies<max(frequencies)/2;
%plot the spectrogram
figure();
pcolor(binTimes,frequencies(slice),mags(slice,:));
The inverse Fourier transform of the fourierResult matrix, will return the original signal.
Just to add to Suki's answer, here is a great tutorial that walks you through, step by step, reading Matlab spectrograms, touching on only enough math and physics to explain the main concepts intuitively:
http://www.caam.rice.edu/~yad1/data/EEG_Rice/Literature/Spectrograms.pdf