Max velocity on 1/3 octave band from Acceleration-Time data
조회 수: 7 (최근 30일)
이전 댓글 표시
I have acceleration time data taken by accelerometer. I need to find the peak velocity of each frequency on the 1/3 octave band range (4, 5, 6.3, 8 etc). im confused whether should i do since im new into matlab. ive done several script (help from GPT), but weird results.
댓글 수: 2
채택된 답변
Mathieu NOE
2025년 3월 3일
hello again
so I decided to make already some modifications in your code , and test it with synthetic data (at least you know what the result should be so it's easier to chase down the most evident mistakes)
as usual with fft , you have to pay attention how to normalize your fft output so for example a sinewave of amplitude 1 (peak amplitude) should give you the same amplitude once fft'ed. that was the major hurdle in your code .
the others mods are less critical , for example when doing the time integration, there is always the risk that the output is not zero-mean even though you have applied a bandpass filter on the incoming signal. Beware that transients can cause drift . So I prefer to simply do the bandpass filtering after the cumtrapz operation, so we are on the safe side and we know that now the output signal is balanced. In a further refinement you could even remove some of the signal that correspond to the transient time response of the bandpass filter.
with the example below a unitary amplitude (sine) acceleration signal at 10 Hz is used. Converted to velocity the amplitude becomes 1/(2*pi*10) = 0.016 (whatever the units are) which is what we obtain in both fft and 1/3 octave bands
%% 1. Load Acceleration Data
% filename = 'Imperial_Valley.asc'; % Change to your actual filename
% data = readmatrix(filename, 'FileType', 'text');
% acc = data(:,1) * 10; % Convert cm/s² to mm/s²
% some synthetic data to test the code
N = 1e4;
Fs = 200; % Sampling frequency (adjust if needed)
dt = 1 / Fs; % Time step
t = (0:N-1) * dt;
acc = sin(2*pi*10*t); % a unitary amplitude, 10 Hz sine wave
%% 2. Define Parameters
Fs = 200; % Sampling frequency (adjust if needed)
N = length(acc);
dt = 1 / Fs; % Time step
t = (0:N-1) * dt;
freqs = [4, 5, 6.3, 8, 10, 12.5, 16, 20, 25, 31.5, 40, 50, 63]; % 1/3-octave bands
%% 3. Apply High-Pass Filter (Remove Low-Frequency Drift)
d_hp = designfilt('highpassiir', 'FilterOrder', 4, ...
'HalfPowerFrequency', 0.5, 'SampleRate', Fs);
acc_filtered = filtfilt(d_hp, acc);
%% 4. Compute FFT-Based Velocity Spectrum
N_pad = 2^nextpow2(N); % Zero-padding for better frequency resolution
Y = abs(fft(acc, N_pad))/N; % /!\ normalized fft !!
select = (1:N_pad/2);
Y = Y(select)*2; % Single-sided spectrum
f = (select - 1)*Fs/N_pad;
% remove freq = 0 data
ind = f>0;
f = f(ind);
Y = Y(ind);
% % debug plot
% figure, plot(f, abs(Y))
% Convert acceleration to velocity in frequency domain
omega = 2 * pi * f;
V_fft = Y ./ omega;
%% 5. Compute 1/3-Octave Band Velocity Levels
velocity_levels = zeros(size(freqs));
for i = 1:numel(freqs)
% Define 1/3 octave band edges
lower_freq = freqs(i) / (2^(1/6));
upper_freq = freqs(i) * (2^(1/6));
% Design bandpass filter for the current band
d = designfilt('bandpassiir', 'FilterOrder', 4, ...
'HalfPowerFrequency1', lower_freq, ...
'HalfPowerFrequency2', upper_freq, ...
'SampleRate', Fs);
% % Apply filter
% filtered_signal = filtfilt(d, acc_filtered);
% Convert acceleration to velocity (integrate)
velocity_signal = cumtrapz(t, acc_filtered); % Integration
% Apply filter after integration (to remove DC / drift mostly)
velocity_signal = filtfilt(d, velocity_signal);
% Get peak velocity for this band
velocity_levels(i) = max(abs(velocity_signal));
end
%% 6. Plot FFT Velocity Spectrum
figure;
plot(f, V_fft, 'b');
xlabel('Frequency (Hz)');
ylabel('Velocity (mm/s)');
title('FFT-Based Velocity Spectrum');
grid on;
xlim([0, max(freqs) + 5]);
%% 7. Plot 1/3-Octave Band Velocity Spectrum
figure;
semilogx(freqs, velocity_levels, 'o-r'); % Log scale for better visibility
xlabel('Frequency (Hz)');
ylabel('Peak Velocity (mm/s)');
title('1/3-Octave Band Velocity Spectrum');
grid on;
댓글 수: 2
William Rose
2025년 3월 19일
@Mathieu NOE provided a very thoughtful and good answer that took a real effort. It is nice to "accept" an answer in that case, so I am accepting his answer on your behalf.
Mathieu NOE
2025년 3월 19일
hello @William Rose
that's very kind , I really appreciate, - but you too has spend time on the topic so I hope @Gerald will at least vote for your contribution !
all the best for both of you
추가 답변 (1개)
William Rose
2025년 3월 3일
One thing I noticed is that the line
V_fft = Y ./ (1i * omega);
doesn't do what you want. It makes a 2000x2000 array. Do
V_fft = Y ./ (1i * omega');
instead.
I made a simulated velocity waveform with three pure sinusoids, each with amplitude=1, at frequencies 10, 20, and 40 Hz. Remember that this is assumed to be velocity in cm/s.
Fs=200; dt=1/Fs; t=(0:2000)'*dt;
v=cos(2*pi*10*t)+cos(2*pi*20*t)+cos(2*pi*40*t);
I computed the acceleration and saved the result as a file.
a=diff(v)/dt;
save('Imperial_Valley0.asc','a','-ascii')
I imported the simulated data file with load() instead of readmatrix() since I got funny results with readmatrix().
I removed the zero-padding because it does not increase the true frequency resolution. Zero-padding the time-domain signal results in a spectrum which is, in effect, interpolated to a higher sampling rate (in the frequency domain) from the spectrum of the non-zero-padded signal. But this seeming improvement in frequency reoslution is only due to interpolation, and therefore gives a misleading indicaiton of the actual frequency resolution. To get a true improvement in frequency resolution, you need to sample for a longer period of time.
The use of filtfilt() with a high-pass filter, to remove low frequency drift, gives bad results, at least for my simulated data file. See plot below of the simulated acceleration signal, before and after filfilt().

Therefore I recommend using
acc_filtered=detrend(acc,2);
to remove quadratic trend (or 3, to remove cubic trend, etc) from the signal. If you plot the acceleration signal before and after detrend(), you will see that the unwanted start and end transients, which occur with filtfilt(), do not occur with detrend().
More later.
댓글 수: 14
Mathieu NOE
2025년 3월 5일
편집: Mathieu NOE
2025년 3월 5일
ok , good to know
just as I mentionned above the octave analysis can be done with filters (as you do) , which is the most precise method , but more and more the octave is simply derived from fft (see for example : Octave Analysis in ObserVIEW - FFT and Filter-based - Vibration Research)
to come back to your code , and to test it with 3 tones like @William Rose , my simple suggestion here is to simply discard the transients introduced by the filters (here I arbitrary choose to remove 20% at both ends)
NB that the ocatve plot is no more "poluted" by low DC / drift
all the best
%% 1. Load Acceleration Data
% filename = 'Imperial_Valley.asc'; % Change to your actual filename
% data = readmatrix(filename, 'FileType', 'text');
% acc = data(:,1) * 10; % Convert cm/s² to mm/s²
% some synthetic data to test the code
N = 1e4;
Fs = 200; % Sampling frequency (adjust if needed)
dt = 1 / Fs; % Time step
t = (0:N-1)' * dt;
% acc = sin(2*pi*10*t); % a unitary amplitude, 10 Hz sine wave
acc = sin(2*pi*10*t)+sin(2*pi*20*t)+sin(2*pi*40*t); % unitary amplitude sine waves
%% 2. Define Parameters
Fs = 200; % Sampling frequency (adjust if needed)
N = length(acc);
dt = 1 / Fs; % Time step
t = (0:N-1) * dt;
freqs = [4, 5, 6.3, 8, 10, 12.5, 16, 20, 25, 31.5, 40, 50, 63]; % 1/3-octave bands
%% 3. Apply High-Pass Filter (Remove Low-Frequency Drift)
d_hp = designfilt('highpassiir', 'FilterOrder', 4, ...
'HalfPowerFrequency', 0.5, 'SampleRate', Fs);
acc_filtered = filtfilt(d_hp, acc);
%% 4. Compute FFT-Based Velocity Spectrum
N_pad = 2^nextpow2(N); % Zero-padding for better frequency resolution
Y = abs(fft(acc_filtered, N_pad))/N; % /!\ normalized fft !!
select = (1:N_pad/2);
Y = Y(select)*2; % Single-sided spectrum
f = (select - 1)*Fs/N_pad;
% remove freq <1 Hz data (up to you to change the cut off freq)
ind = f>1;
f = f(ind);
Y = Y(ind);
% Convert acceleration to velocity in frequency domain
omega = 2 * pi * f;
V_fft = Y(:) ./ omega(:);
%% 5. Compute 1/3-Octave Band Velocity Levels
velocity_levels = zeros(size(freqs));
for i = 1:numel(freqs)
% Define 1/3 octave band edges
lower_freq = freqs(i) / (2^(1/6));
upper_freq = freqs(i) * (2^(1/6));
% Design bandpass filter for the current band
d = designfilt('bandpassiir', 'FilterOrder', 4, ...
'HalfPowerFrequency1', lower_freq, ...
'HalfPowerFrequency2', upper_freq, ...
'SampleRate', Fs);
% Apply filter
filtered_signal = filtfilt(d, acc_filtered);
% Convert acceleration to velocity (integrate)
velocity_signal = cumtrapz(t, filtered_signal); % Integration
% Apply HP filter after integration (to remove DC / drift mostly)
velocity_signal = filtfilt(d_hp, velocity_signal);
% Get peak velocity for this band
% remove the initial and end transients from observation
ind1 = round(0.2*N); % discard the first 20% samples
ind2 = round(0.8*N); % discard the last 20% samples
velocity_levels(i) = max(abs(velocity_signal(ind1:ind2)));
end
%% 6. Plot FFT Velocity Spectrum
figure;
plot(f, V_fft, 'b');
xlabel('Frequency (Hz)');
ylabel('Velocity (mm/s)');
title('FFT-Based Velocity Spectrum');
grid on;
xlim([0, max(freqs) + 5]);
%% 7. Plot 1/3-Octave Band Velocity Spectrum
figure;
semilogx(freqs, velocity_levels, 'o-r'); % Log scale for better visibility
xlabel('Frequency (Hz)');
ylabel('Peak Velocity (mm/s)');
title('1/3-Octave Band Velocity Spectrum');
grid on;
참고 항목
카테고리
Help Center 및 File Exchange에서 Vibration Analysis에 대해 자세히 알아보기
Community Treasure Hunt
Find the treasures in MATLAB Central and discover how the community can help you!
Start Hunting!