I am attempting to use trapz to find the area under the curve.
My x data represents datetime, and my y data represents acceleration as a f(x). Accelerometer readings are in the form of SI.
Example data within x ( HH:mm:ss.SSS ) :
'01:06:48.330'
'01:06:48.352'
'01:06:48.374'
Example data within y ( accelerometer value * 9.81 ):
8.73750256159470
8.59619296907904
8.63520263017352
When I enter the following command (using the whole array of data ):
velocity = trapz(x,y);
I get back a duration array which looks like this:
velocity =
duration
00:00:13
I am not entirely too sure I understand what 00:00:13 means. When I calculate for velocity, I'd expect to see something like 9.81 m/s , or 5m/s. Am I misusing the function or should I convert the duration array to a different object type?
The reason you expect m/s output from integrating acceleration is simply because you're doing a particular calculation involving (m/s^2)*s, i.e. y axis * x axis.
Let's use a simple example, where we first convert to seconds and then integrate.
x = datetime( {'00:00', '00:01', '00:02'}, 'inputformat', 'HH:mm' ); % Time
y = [1 2 4]; % Acceleration (m/s^2)
x_elapsed_seconds = datenum(x-min(x))*24*60*60; % Datenum returns days, convert to secs
z = trapz( x_elapsed_seconds, y ); % Velocity = 270 m/s
We can verify that, for this example, 270m/s is correct because there are simply 2 trapeziums in the calculation:
Trapezium from 1m/s^2 to 2m/s^2 lasting 1min = 60secs: 60*(1+2)/2 = 60*1.5 = 90 m/s
Trapezium from 2m/s^2 to 4m/s^2 lasting 1min = 60secs: 60*(2+4)/2 = 60*3 = 180 m/s
We sum the trapezium areas for the result: 90 + 180 = 270 as expected. This is why it's always best to use a simple example for verification before using real world data.
Datetimes are usually tricky in MATLAB. I would convert it to seconds before doing any integrals. Here is an example solution.
x=['01:06:48.330'; '01:06:48.352'; '01:06:48.374'];
datetime(x,'Format','HH:mm:ss.SSS');
secvec = datevec(x);
secvec = 3600*secvec(:,4)+60*secvec(:,5)+secvec(:,6); % times measured in seconds
y = [8.73750256159470; 8.59619296907904; 8.63520263017352]; % accelerations in m/s^2
trapz(secvec,y)
>> ans = 0.380216002428058 % Gained velocity, measured in m/s
Related
I want to generate a sine signal y(t) with a time dependent frequency f(t) in Matlab.
I've already tried to realise this using the sine function of Matlab:
h = 0.0001;
npoints = 150/h;
for i = 1:1:npoints
f(i) = 2 - 0.01*i*h;
y(i) = 0.5*sin(2*3.1415*f(i)*i*h)+0.5;
end
where the frequency is decreasing with time and h is the time step width.
My problem:
The signal y(t) doesn't look I expected it to look like. There appears a bump in the amplitude at a distinct time (have a look at the plot below).
Does anyone know why this happens and how to generate this sine signal correctly?
what about
y(i) = 0.5*real(exp(1i*2*pi*f(i)*i*h))+0.5;
You will get the plot below
If you just need a chirp signal starting from 2Hz down to 0.5Hz, the following should do the job
f_start = 2; % start frequency
f_end = 0.5; % end frequency
endtime = 150; % seconds
timestep = 0.0001;
times = timestep:timestep:endtime;
y = chirp(times,f_start,endtime,f_end);
and if you plot it you get
figure(2);plot(times,y);
You can achieve the same manually using below
f_start = 2; % start frequency
f_end = 0.5; % end frequency
timestep = 0.0001;
T = 150;
rate_of_change = (f_start - f_end)/T;
times = timestep:timestep:T;
y = sin(2*pi*(f_start*times - times.^2*rate_of_change/2));
It might be useful to read the following Wikipedia page on Chirp signal.
At 100 you have sin(2*pi*N), which is 0. Change f a little bit, say to 2.0123-... and it goes to the top.
As for the general probably unexpected shape, consider what function you are using in the end (= substitute f back in the formula). You see that you have something of the form y = ...sin(Ai-B*i^2)..., which has a minimum at 100.
The easiest solution here is to simply offset frequency a little more, and use something like f(i) = 3.1 - ..., which has a minimum outside of your considered range.
It looks like there isn't actually a "bump in frequency", but at the 100 value on the x-axis the entire signal is shifted by 180 degrees. Bear in mind that the amplitude still reaches 0 and does not become smaller (e.g. from 0.25 to 0.75)
This is because the i value becomes so high that the value of f(i) changes sign.
Another indicator of this is that the frequency starts to increase again after the shift instead of gradually becoming even lower.
Why do you start off with the value of 2 in f(i)?
Sorry for asking for clarification here, but I cannot post it as a comment.
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!
I'm trying to multiply sin waves / cosine waves recursively but I'm not sure why my answers are so different. Y2 in blue is what I'm trying to get but the FOR loop which is Y in red is what is produced any idea how to fix the FOR loop Y? see plot and code below ?
Fs = 8000;% Sampling frequency
t=linspace(0,1,Fs);
y=zeros(1,length(t));
y = .5*sin(2*pi*2*t);
for ii=1:1:3
y=y.*y;
end
plot(y,'r')
hold on
y2=(.5*sin(2*pi*2*t)).* (.5*sin(2*pi*2*t)).*(.5*sin(2*pi*2*t)); %should look like this
plot(y2,'b') %both plots should look like this
PS: I'm using octave 3.8.1 which is like matlab
You're multiplying eight times here
y = .5*sin(2*pi*2*t);
for ii=1:1:3
y=y.*y;
ii=1:1:3 is inclusive, so you do y=y.*y three times.
First time it becomes y = y^2,
Second time it become y^4 = y^2*y*2
Third time it becomes y^8 = y^4*y^4
This would be a solution:
Fs = 8000;% Sampling frequency
t=linspace(0,1,Fs);
y=zeros(1,length(t));
y = .5*sin(2*pi*2*t);
result = ones(1,length(t));
for ii=1:1:3
result=result.*y;
end
plot(result,’r’)
hold on
y2=(.5*sin(2*pi*2*t)).* (.5*sin(2*pi*2*t)).*(.5*sin(2*pi*2*t)); %should look like this
plot(y2,'b') %both plots should look like this
In all iteration, y.*y make square of updated y.
Fs = 8000;% Sampling frequency
t=linspace(0,1,Fs);
y=ones(1,length(t));
x = .5*sin(2*pi*2*t);
for ii=1:1:3
y=y.*x;
end
plot(y,'r')
hold on
y2=(.5*sin(2*pi*2*t)).* (.5*sin(2*pi*2*t)).*(.5*sin(2*pi*2*t)); %should look like this
plot(y2,'b') %both plots should look like this
Maybe, you want this code.
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
I would like to perform a frame based analysis on the following curve Which expresses the relation between time and concentration (x-axis: time in minutes; y-axis: concentration in Mbq):
For the above curve I would like to perform frame based sampling by splitting the curve into 19 frames:
19 frames:
4 frames : Each of 15 seconds time interval
2 frames : Each of 30 seconds time interval
2 frames : Each of 60 seconds time interval
11 frames : Each of 200 seconds time interval
I have written the following interpolation function for the frame analysis. c_t is where my signal which was expressed in the figure above is stored:
function c_i = Frame_analysis(a1,a2,a3,b1,b2,b3,td,tmax,k1,k2,k3)
t= 0:6:3000; % The original sample time, in seconds
t_i =[0:15:60,90:30:120,180:60:240,440:200:2240];% The interpolated sample time for first 4 frames of 15 second interval
K_1 = (k1*k2)/(k2+k3);
K_2 = (k1*k3)/(k2+k3);
%DV_free= k1/(k2+k3);
c_t = zeros(size(t));
ind = (t > td) & (t < tmax);
c_t(ind)= conv(((t(ind) - td) ./ (tmax - td) * (a1 + a2 + a3)),(K_1*exp(-(k2+k3)*t(ind)+K_2)),'same');
% Y_i = interp1(t,c_t(ind), t_i); % Interpolation for first frame
ind = (t >= tmax);
c_t(ind)=conv((a1 * exp(-b1 * (t(ind) - tmax))+ a2 * exp(-b2 * (t(ind) - tmax))) + a3 * exp(-b3 * (t(ind) - tmax)),(K_1*exp(-(k2+k3)*t(ind)+K_2)),'same');
c_i = interp1(c_t(ind),t_i);% Interpolation for Next consequtive frames
figure;
plot(t_i,c_i);
axis([0 3000 -2000 80000]);
xlabel('Time[secs]');
ylabel('concentration [Mbq]');
title('My signal');
%plot(t,c_tnp);
end
When I run the code, I have obtained a curve without any interpolation as you can see from figure expressed below:
Where have I made a mistake in my code and how can I possibly perform a better interpolation for obtaining different frames in my Output curve expressed in first figure?
Following are the input values which i have provided manually
Frame_analysis(2501,18500,65000,0.5,0.7,0.3,3,8,0.014,0.051,0.07)
There are multiple issues here, and it will be up to you to decide how to address them.
This is what I can provide:
You do not specify an x-coordinate for your plot command. That can be done, however, Matlab will use the index of the vector for the x-axis. Example: if you have
y = 1:2:6;
plot(y);
hold on;
y = 1:1:6;
plot(y);
you'll see the difference.
How does this apply to your case? You specify a vector of higher resolution (t_i, compared to t), but in your plot command you do not provide this new vector for the x-coordinate.
Your definition of c_t provides very very small values (on the order of 10^-77). And from t > 60, your output is indifferent from 0.
How does that effect your interpolation?
You specify that for the interval [0 60] you want step-sizes of 15 - that does not give you a lot of resolution:
You might want to change to something like:
t_i =[0:0.5:60,90:30:120,180:60:240,440:200:2240];
Which will give you this plot:
In either case, I do not understand why you chose a data range above 60 (all the way until 3000) for the data you are trying to plot. This explains why you do not see anything with your axis limits axis([0 3000 -2000 80000]); that by far exceed the range of y-values and obscures the non-zero data entries for small x.