generate signal with seasonal and diurnal component - matlab

This is a rather vague question but here we go - I would like to generate a time series for hourly measurements of one year, so for 2011 ti would 8760 values within the series. To make it easier to understand what I am trying to do I will use a real world example:
If we had a time series of hourly air temperature measurements an then plotted the entire series it would look similar to a bell shaped curve i.e.
a = 0; b = 30;
x = a + (b-a) * rand(1, 8760);
m = (a + b)/2;
s = 12;
p1 = -.5 * ((x - m)/s) .^ 2;
p2 = (s * sqrt(2*pi));
f = exp(p1) ./ p2;
plot(x,f,'.')
with the maximum values occurring in mid summer and lowest values during the winter. However, by zooming in on specific days we would see that the temperature also fluctuates between the day and the evening where maximum temperatures would occur at approximately 15:00 and minimum temperature at approximately 06:00.
So, my question is how would I generate this series, i.e. a time series which had a maximum value of say 30 degrees in mid summer i.e. value (8760/2) and also had the daily pattern mentioned above incorporated into the overall pattern?

The obvious way to do this would be to add together 2 sine waves, one for the diurnal variations and one for the annual variations.
Whether or not a sine wave is close enough to a bell-shaped curve for your liking I don't know, but I could make a vague argument that since the variation in annual and diurnal temperatures is (in part) a product of (approximately) circular motions you should be using sine waves anyway.
If you need help generating the sine waves update your question.

If I understand the question correctly, you'd like to have a superposition of the two series of known shape, right? If so, you just have to add them up. The important part is to shift the daily temperature fluctuation signal so that its mean is 0, provided the "year" curve expresses the average temperature.

Related

How to average values in plot, to make a plot with fewer values

I have a script that plots wind speed in m/s (measured every second) against time in minutes over a period of 24 hours. I want to make a new plot that instead of plotting wind speed each second, averages the wind speed over a period of 10 minutes and then plots this against the time.
Here is a sample image of my data:
Any ideas of how I can do this?
You can use a Moving Average filter using the smooth function as suggested by m.s. in a comment. This is fairly simple:
y = smooth(x,span);
This uses a symmetric smoothing filter, so the span (i.e. the number of samples it takes for smoothing) must be odd: take the current sample plus n before and n after the current sample. That way you still have one sample for every second, they are just smoothed to damp noise and measurement errors.
If you want to reduce the number of points, such that only one point every 10 minutes exists, you can do the following: You take the first 10min * 60s = 600 samples of the vector and put them in the first column of a new matrix. Then take the next 600 samples and put them in the second column, and so on. Now you can column-wise take the mean of the matrix. That way you have a new vector where every element is the mean of 600 samples.
In MATLAB this is easily possible:
X = reshape(x,600,[]); % create matrix with 600 elements per column
y = mean(X,1); % take column-wise mean

Time delay estimation using crosscorrelation

I have two sensors seperated by some distance which receive a signal from a source. The signal in its pure form is a sine wave at a frequency of 17kHz. I want to estimate the TDOA between the two sensors. I am using crosscorrelation and below is my code
x1; % signal as recieved by sensor1
x2; % signal as recieved by sensor2
len = length(x1);
nfft = 2^nextpow2(2*len-1);
X1 = fft(x1);
X2 = fft(x2);
X = X1.*conj(X2);
m = ifft(X);
r = [m(end-len+1) m(1:len)];
[a,i] = max(r);
td = i - length(r)/2;
I am filtering my signals x1 and x2 by removing all frequencies below 17kHz.
I am having two problems with the above code:
1. With the sensors and source at the same place, I am getting different values of 'td' at each time. I am not sure what is wrong. Is it because of the noise? If so can anyone please provide a solution? I have read many papers and went through other questions on stackoverflow so please answer with code along with theory instead of just stating the theory.
2. The value of 'td' is sometimes not matching with the delay as calculated using xcorr. What am i doing wrong? Below is my code for td using xcorr
[xc,lags] = xcorr(x1,x2);
[m,i] = max(xc);
td = lags(i);
One problem you might have is the fact that you only use a single frequency. At f = 17 kHz, and an estimated speed-of-sound v = 340 m/s (I assume you use ultra-sound), the wavelength is lambda = v / f = 2 cm. This means that your length measurement has an unambiguity range of 2 cm (sorry, cannot find a good link, google yourself). This means that you already need to know your distance to better than 2 cm, before you can use the result of your measurement to refine the distance.
Think of it in another way: when taking the cross-correlation between two perfect sines, the result should be a 'comb' of peaks with spacing equal to the wavelength. If they overlap perfectly, and you displace one signal by one wavelength, they still overlap perfectly. This means that you first have to know which of these peaks is the right one, otherwise a different peak can be the highest every time purely by random noise. Did you make a plot of the calculated cross-correlation before trying to blindly find the maximum?
This problem is the same as in interferometry, where it is easy to measure small distance variations with a resolution smaller than a wavelength by measuring phase differences, but you have no idea about the absolute distance, since you do not know the absolute phase.
The solution to this is actually easy: let your source generate more frequencies. Even using (band-limited) white-noise should work without problems when calculating cross-correlations, and it removes the ambiguity problem. You should see the white noise as a collection of sines. The cross-correlation of each of them will generate a comb, but with different spacing. When adding all those combs together, they will add up significantly only in a single point, at the delay you are looking for!
White Noise, Maximum Length Sequency or other non-periodic signals should be used as the test signal for time delay measurement using cross correleation. This is because non-periodic signals have only one cross correlation peak and there will be no ambiguity to determine the time delay. It is possible to use the burst type of periodic signals to do the job, but with degraded SNR. If you have to use a continuous periodic signal as the test signal, then you can only measure a time delay within one period of the periodic test signal. This should explain why, in your case, using lower frequency sine wave as the test signal works while using higher frequency sine wave does not. This is demonstrated in these videos: https://youtu.be/L6YJqhbsuFY, https://youtu.be/7u1nSD0RlwY .

how to apply fourier analyis to a vector of 736 temp readings (one every 3 hours for 3 months) [closed]

Closed. This question does not meet Stack Overflow guidelines. It is not currently accepting answers.
This question appears to be off-topic because it lacks sufficient information to diagnose the problem. Describe your problem in more detail or include a minimal example in the question itself.
Closed 8 years ago.
Improve this question
I have a vector of 736 temperature readings, one for every 3rd hour between jun-aug, therefore 8 per day for jun-aug.
I need to apply a Fourier analysis to this vector. I have normalized it. I have searched all over (because I really don't understand matlab) and all I see are these analysis with signs where you already have a sampling to compare it to (like 1000Hz keeps coming up). the sampling interval is 3hrs and the length of sampling is 90 days. I don't know how to do this. any help would REALLY help.
thank you, I am desperate.
The FFT operation is actually agnostic of the input sampling rate. The sampling rate is only used after the FFT is performed to interpret the frequencies of the output.
So, basically you can take the FFT of your vector and it will transform your 736 samples at discrete time instants into 736 samples at discrete frequencies. These frequencies are given by
F(k) = Fs * k / Nfft
Where Fs is the sampling rate and Nfft is the number of FFT points. The output vector from the FFT will be complex. In most cases, you will want to take the magnitude of the output to produce values proportional to the amount of energy at each frequency.
The MATLAB code may look like this:
x = %your input vector
Nfft = length(x);
Fs = 1 / (60 * 60 * 3); %1 / 3hrs
Xk = fft(x);
k = 0 : Nfft-1;
Fk = Fs * k / Nfft; %frequency vector
%plot frequency versus magnitude in dB scale
Plot(Fk, 20 * log10(abs(Xk)));
There are several other issues you need to be aware of:
Assuming your input is real-valued, the second half of the FFT output vector will be a mirror image of the first half. In this case, only the first half of the output is needed, giving you frequencies from 0 to Fs/2
Fs/2, the Nyquist rate, is the maximum frequency that can be represented by a signal sampled at Fs. So, for example, if there are temperature fluctuations within the 3 hours between samples, this information is not accurately captured by a 3hr sampling period.
I've left out a lot of details, but I tried to just give you enough info to get a frequency-magnitude plot without complicating things unnecessarily.

interpolation of fortnightly annual temperature data into hourly measurements in matlab

I have a dataset of annual temperature measurements recorded at fortnightly intervals. The data looks similar to the following:
t = 1:14:365;
% GENERATE DATA
y = 1 + (30-1).*rand(1,length(t));
y1 = 20*sin(2*pi*t/max(t)); % Annual variation °C
y1(y1<0) = [];
tt = 365/14;
time = 1:tt:365;
plot(time,y1,'-o');
where it clearly follows a annual temperature cycle.
From this I am wondering if it is possible to add a sine function (which would represent a diurnal temperature range) onto the data? For example, from the fortnightly data, if we were to interpolate the series to have 8760 measurements i.e. hourly measurements, for the series to be believable it would need to be characterized by a diurnal temperature cycle in addition to the annual temperature cycle. Furthermore, the diurnal temperature cycle would need to be a function of the temperature measurements at that time i.e. would be greater in the summer than in winter. So maybe it would be better to firstly use linear interpolation to get the data to represents hourly intervals and then add the sine function. Is there a method for writing this into a script? or does anyone have an opinion on how to accurately achieve this?
You could first interpolate your data (down to 1 hours) using something like
x = 1:inv(24):365;
T_interp = interp1(t,y1,x,'spline');
Check out Matlab documentation for interp1 (example 2)
and then add a sine onto it. The following a sine of period 1 (24 hours) with amplitude A, with a minimum at 3am.
T_diurn = -A*sin(2*pi*x+(3/24)*2*pi);
Then
T_total = T_diurn + T_interp;
First: you know that good-looking plots are the most misleading things in existence? Interpolating data gathered every 14 days so that it will look like data collected every hour is considered at least bad practice most circles...
Having said that, I would use splines to do the interpolation -- they are a lot more flexible when it comes to changing from fortnightly and hourly to some arbitrary other combination, plus the annual temperature variation will be a lot smoother.
Here's how:
% Create spline through data
pp = spline(time, y1);
% define diurnal variation (this one is minimal at 4 AM)
T_diurn = #(t) -A*cos(2*pi*(t-(4/24)));
% plot example
t = 150 : 1/24 : 250;
plot( t, ppval(pp,t)+T_diurn(t) , 'b')

analyse time series at a specific frequency

I have a long data set of water temperature:
t = 1/24:1/24:365;
y = 1 + (30-1).*rand(1,length(t));
plot(t,y)
The series extends for one year and the number of measurements per day is 24 (i.e. hourly). I expect the water temperature to follow a diurnal pattern (i.e. have a period of 24 hours), therefore I would like to evaluate how the 24 hour cycle varies throughout the year. Is there a method for only looking at specific frequencies when analyzing a signal? If so, I would like to draw a plot showing how the 24 hour periodicity in the data varies through the year (showing for example if it is greater in the summer and less in the winter). How could I do this?
You could use reshape to transform your data to a 24x365 matrix. In the new matrix every column is a day and every row a time of day.
temperature=reshape(y,24,365);
time=(1:size(temperature,1))-1;
day=(1:size(temperature,2))-1;
[day,time]=meshgrid(day,time);
surf(time,day,temperature)
My first thought would be fourier transformation. This will give you a frequency spectrum.
At high frequencies (> 1/d) you would have the pattern for a day, at low frequencies the patter over longer times. (see lowpass and highpass filter)
Also you could go for a frequency/time visualization that will show how the frequencies change over a year.
A bit more work - but you could write a simple model and create a Kalman filter for it.