Time Plot on X-axis in Matlab - matlab

sorry if this question has been asked before.
I'm collecting data from a sensor which gives me a reading every millisecond which gives 864000 readings per 24 hours.
When I plot this I can only get it to show sample number, what I'm looking for is a plot that has every hour shown, for example 13:00:00:00 for 1pm, so every 36000 data points, and when I zoom in between data points I want it to show the exact time at that point, such as 13:25:30:60 etc.
I assume the best way to do this is to create another variable with just time on it and plot my variables against this? Any other ideas would be much appreciated

You can have two arrays:
One containing your samples, say y.
And another one containing datetimes corresponding to each sample, say x.
Then you can use:
plot(x,y)

Related

Creating a sinusoidal wave in matlab

I want to create a sinusoidal wave that has the following properties :
a sine wave with f=400Hz amp=1 from 0 to 2s
a sine wave with f=200Hz amp=1 from 2 to 3s
a sine wave with f=800Hz amp=2 from 3 to 5s
Here is my matlab Code :
t=linspace(0,5,5000);
x=zeros(1,length(t));
n1=0:1999;
n2=2000:2999;
n3=3000:4999;
x(1:2000)=1*sin(2*pi*400*n1);
x(2001:3000)=1*sin(2*pi*200*n2);
x(3001:5000)=2*sin(2*pi*800*n3);
plot(t,x)
and here is the plot that I had, still it looks not logical at all,
So I would like to know the error in my code
In this type of problem, where you're naturally looking at physical quantities, it's very helpful to be consistent with this all the way through your calculations.
Specifically, you specify Hz (1/seconds), a physical unit, so when you calculate everything else, you need to be consistent with that.
To do this in your equation, it's most straightforward to put time directly in the sin function, like sin(2*pi*f*t). But since you want to break the array apart using different n, it probably easiest to do that and then use t=linspace(0,5,50000) and dt = 5.0/50000 or dt = t(2) - t(1), and sin(2*pi*400*dt*n1). Read this as dt*n1 converts the integers in n1 to time in seconds.
Note the physical units too: 400 in above is actually 400Hz, and the time is in seconds, so the units of 2*pi*400*dt*n1 and 2*pi*f*t are Hz * s = 1, that is, the units cancel, which is what you need.
There is a tendency for programmers to want to define away some unit, like say seconds=1. This is possible and technically correct and can save a multiplication or two. It almost always leads to errors.
Note also that you should change from t=linspace(0,5,5000) to something like t=linspace(0,5,50000). The reason should now be clear: you're looking at frequencies from 400-800Hz, or almost 1kHz, or 1 oscillation per millisecond. To see a sine wave, you'll need to get in a few data points per oscillation, and 50000 points in 5 seconds will now give about 10 points per millisecond, which is barely enough to see a reasonable sine wave. Or, however you want to think of the calculation, somehow you need to be sure you sample at a high enough rate.
That is, the specific error that your encountering is that by using integers instead of fractions of a second for your time array, you're taking much too large of steps for the sin function. That's always a possible problems with the sin function, but even if you did plot a sin that looked like a sin (say, by using a frequency like 0.003Hz instead of 400Hz) it would still be incorrect because it wouldn't have the proper time axis. So you need to both get the units correct, and make sure that you get enough data per oscillation to see the sine wave (or whatever it is you happen to be looking for).

Quantizing timeline data for averaging and histograms

I have some raw spreadsheet data that's in a format, like:
12/7/2016 3:07:00, 88.05,
12/7/2016 3:08:00, 89.10,
12/7/2016 3:13:00, 87.00,
etc
These data points are not sampled at a regular interval, but are randomly collected throughout the day.
Using Google Sheets I'm able to graph this easily onto a Timeline chart. This puts the values at the correct position on the timeline and takes the uneven sampling intervals into account.
I would like to generate a histogram of the timeline data while taking into account the timestamps and calculate an average value over a timeframe. I believe if I simply run this through the built-in histogram chart or select my data values and run it through an averaging function, it will be skewed by the uneven sampling intervals.
What's the easiest way to quantize the sampling intervals (ideally within Google Sheets) for generating my histogram and averaging?
or
Is there a built-in method to generate histograms/averaging of values while taking timestamp data into account, eliminating the need for quantized data?
You can calculate the appropriate average as follows (assuming your data is in the range A2:B50)
=sum(arrayformula((A3:A50-A2:A49)*(B3:B50+B2:B49)/2))/(A50-A2)
This formula implements the Trapezoidal rule: the value assigned to each time interval is the average of observed values at the ends of that interval.
There isn't a built-in "weighted histogram" tool, so it appears that needs re-sampling to create a representative histogram. Here is one way to resample. Let's say you want 20 samples; then in C2 enter
=arrayformula(A2+(row(1:20)-1)*(A50-A2)/19)
to get 20 uniformly distributed time values. (Division by 19 because of the fence-post distinction.) Then in D2,
=arrayformula(vlookup(C2:C21, A2:B50, 2))
will lookup a value for each sample time. Then you can build a histogram from column D.

finding power spectrum of signal using two approaches

I am trying to find power spectrum of the signal. The length of the signal is 100000, sample frequency is 1000Hz,and the number of points is 100000. I found the power spectrum using two approaches. The first one is by taking all the length as one part and found power spectrum for it while the second approach is by dividing the signal into 100*1000and find spectrum for each row then get the mean for all rows. My problem is that I must get the same answer in both approaches but I got different answers. I do not know what is the error in my code.
N=100000;
SF=1000;
a=0.1;
b=0.3;
amplitude1=1;
amplitude2=0.5;
t=0:1/SF:100;
f1=SF*a;
f2=SF*b;
A=amplitude1*sin(2*pi*f1*t)+amplitude2*sin(2*pi*f2*t);
Y=2*randn(1,length(A))+A;
bin=[0 :N/2];
fax_Hz=(bin*SF)/N;
FFT=fft(Y);
spectra=2/(SF*length(Y))*(FFT.*conj(FFT));
plot(fax_Hz,spectra(1,1:50001));
D=reshape(Y(1,1:100000),[100,1000]);
M=length(D(1,:));
for i=1:100
FFT_1(i,:)=fft(D(i,:));
S(i,:)=(2/(SF*M))*(FFT_1(i,:).*conj(FFT_1(i,:)));
end
S_f=mean(S);
figure
plot (S_f);
I just update the code. I do not know but when I added noise to signal the two plots looks shifted.
The main problem is with reshape you are working with each row being a separate sequence. Reshape however fills the first column before moving to the second one.
You can use the following instead.
D=reshape(A(1,1:100000),[1000,100]).';
Normalization is another problem. You can either use ifft instead of fft as it is normalized by default (not sure why). Or alternatively keep your normalization and instead of using mean you should can use sum, maybe that is due to a mistake you might have made. There still seems to be a small discrepancy in the amplitudes, not sure where that is coming from.
At the end to plot use the following:
bin=[0 :N];
fax_Hz=(bin*SF)/N;
FFT=ifft(A);
spectra=FFT.*conj(FFT);
plot(fax_Hz,spectra); hold on
D=reshape(A(1,1:100000),[1000,100]).';
M=length(D(1,:));
for i=1:100
FFT_1(i,:)=ifft(D(i,:));
S(i,:)=FFT_1(i,:).*conj(FFT_1(i,:));
end
S_f=mean(S);
plot(fax_Hz(1:100:end-1), S_f);
Note: the fax_Hz(1:100:end-1) is a hacky way of getting the length of the vectors to be the same.

Spectrum Derivative in MATLAB, the end point problem

I am trying to take the derivative of the a spectrum with 125 bands using the following lines:
dW=diff(wavelength);
dR=diff(data);
df=dR./dW;
problem is in the next step i want to compare it with original spectrum numerically and also visually by plotting, but the size of df is 124 however my original wavelength is 125. Question is do i have to remove the first or the last band? however the output of some spectral analysis software is not changing the size. taking the average of bands also does not work, it make the graph to show crazy behavior.
diff is basically:
Y = [X(2)-X(1) X(3)-X(2) ... X(m)-X(m-1)]
which means it has to be one shorter than your input (you can't subtract something from nothing, right?).
What you have to do of course depends on what you want to do, but the least "meaning-altering" approach (kind of keeping causality with respect to sampling times) would be to prepend your dW and dR with a single arbitrary value.
By the way, your ratio df=dR./dW might have a lot of NaNs if dW has zeros (which happens as soon as two consecutive data values are the same).

Position of high correlation using matlab

I have a signal that more or less repeats itself (not exactly the same from one to the next, see plot to the left). If I use autocorrelation I get a number of maximums (right plot), but it doesn't tell me where (which sample number) the correlation is high. It gives me the lags but I lose information on the position, that is, the sample number in my original data where the signal occurs. For example in the auto-corr. plot, the second peak at sample 500 should correspond to the signal at about sample 750 in the data plot. I could do this by using a small window that moves over the data trace and find the maximums but it takes too much time. Is there a faster way of doing this in matlab? thanks.
I think you're misinterpreting autocorrelation. The correlation peak at 5000 is not due to a single location in the time series, but rather to the fact that the entire time series is similar to itself, when offset by 5000 samples. As much of that peak is due to the time series peak at 18000 as it is to the time series peak at 7500. Your autocorrelation will get very strange if, for example, you do not have a truly periodic time series (that is, if the interval between pulses is nonuniform).
If you can isolate one example of your pulse, and choose the location you want as your t=0, then a correlation of that one pulse with the time series will give you just what you want. Each pulse will light up clearly, at the time location at which it occurs. Then you just need a peak finder.
Yes, you could get the indices of the elements with the maximum amplitude using
treshold = max(a)/2
ind = find(a>=treshold)
where a is the matrix containing the correlation result.