Matlab - interp1 produces "strange" results - matlab

To give a context, my endgoal is the following: Calculate correlation between room temperature and outdoor temperature.
I measured room temperature with a sensor and want to check the correlation with outdoor temperature. The sample sizes don't have the same size so I wanted to change that by using interpolation.
Google said I could do it with Matlab (never used before). I achieved now that I don't get an error BUT values that before were "-2.1" are now something like -732.3503.
This is how the outdoor temperature file looked like:
This is how the indoor temperature file looked like:
I changed the date column to datenum like this:
My outdoor temperature file look now like this:
And the indoor temperature file like this:
My interpolation function is this:
t = table2array(H1_Bath_datenum(:,1)); % get time samples from Y
%Interpolate (linearly, with extrapolation) X2 values onto time samples t
%X2 = [t, interp1(H1_Dillenburg_1_datenum(:,1), H1_Dillenburg_1_datenum(:,2), t, 'linear', 'extrap')];
d = table2array(H1_Dillenburg_1_datenum(:,1));
e=table2array(H1_Dillenburg_1_datenum(:,2));
X2 = double([t, interp1(d, e, t, 'linear','extrap')]);
My problem is now, that the temperature values (row 2) are not "normal" numbers (don't know how you call them):
Does anybody have an idea, why this is the case and how I can avoid it or at least change it?
Thanks already!

Related

Different results using filter object and z,p,k implementation

I'm comparing the output of digital filtering using MATLAB filter object and zero-pole-gain method, and they are not quite the same. I'll appreciate if anyone could point me out in the right direction, and to know what exactly matlab does, because it seems it doesn't use b-a coefficients nor zero-pole-gain method. Here there are my results and the test script (download data.txt):
srate=64;
freqrange=[0.4 3.5];
file='data.txt';
load(file);
file=split(file,'.');
file=file{1};
data=eval(file);
st=srate*60;
ed=srate*60*2;
data=data(st:ed);%1 minute data
m=numel(data);
x=data;
R=0.1;%10% of signal
Nr=50;
NR=min(round(m*R),Nr);%At most 50 points
x1=2*x(1)-flipud(x(2:NR+1));%maintain continuity in level and slope
x2=2*x(end)-flipud(x(end-NR:end-1));
x=[x1;x;x2];
[xx,dbp]=bandpass(x,freqrange,srate);%same result if use filter(dbp,xx)
data_fil=xx(NR+1:end-NR);
[z,p,k]=dbp.zpk;
[sos, g] = zp2sos(z, p, k);
xx=filtfilt(sos, g, x);
data_fil_zpk=xx(NR+1:end-NR);
f=figure('Numbertitle','off','Name','test_filters','units','normalized','outerposition',[0 0
1 1],'menubar','none','Visible','on');
plot([data data_fil data_fil_zpk])
legend('raw','dbp filter','zpk filter')
title('raw vs dbp vs zpk')
error=norm(data_fil-data_fil_zpk)/norm(data_fil)*100
d1=fvtool(dbp);
set(d1,'Name','MR_dbp');
d2=fvtool(sos);
set(d2,'Name','MR_zpk');
and here there is the result I obtain:
as you can see, the filtered signals are almost the same. At this point I'm lost at what exactly matlab does.
Here you can see the magnitude response plots:
They have the same shape, so they are filtering, but in the case of the z-p-k one, max magnitude is around 60 dB while the other is 0db. Why does this happens? Does that means that zpk is amplifying the frequencies?
Finally, you can the the PSD plot for both filtered signals (first dbp, second zpk):
Once again we can see the filter is filtering but you can also see a greater value in the first peak of the second plot (zpk filter)...

comparing generated data to measured data

we have measured data that we managed to determine the distribution type that it follows (Gamma) and its parameters (A,B)
And we generated n samples (10000) from the same distribution with the same parameters and in the same range (between 18.5 and 59) using for loop
for i=1:1:10000
tot=makedist('Gamma','A',11.8919,'B',2.9927);
tot= truncate(tot,18.5,59);
W(i,:) =random(tot,1,1);
end
Then we tried to fit the generated data using:
h1=histfit(W);
After this we tried to plot the Gamma curve to compare the two curves on the same figure uing:
hold on
h2=histfit(W,[],'Gamma');
h2(1).Visible='off';
The problem s the two curves are shifted as in the following figure "Figure 1 is the generated data from the previous code and Figure 2 is without truncating the generated data"
enter image description here
Any one knows why??
Thanks in advance
By default histfit fits a normal probability density function (PDF) on the histogram. I'm not sure what you were actually trying to do, but what you did is:
% fit a normal PDF
h1=histfit(W); % this is equal to h1 = histfit(W,[],'normal');
% fit a gamma PDF
h2=histfit(W,[],'Gamma');
Obviously that will result in different fits because a normal PDF != a gamma PDF. The only thing you see is that for the gamma PDF fits the curve better because you sampled the data from that distribution.
If you want to check whether the data follows a certain distribution you can also use a KS-test. In your case
% check if the data follows the distribution speccified in tot
[h p] = kstest(W,'CDF',tot)
If the data follows a gamma dist. then h = 0 and p > 0.05, else h = 1 and p < 0.05.
Now some general comments on your code:
Please look up preallocation of memory, it will speed up loops greatly. E.g.
W = zeros(10000,1);
for i=1:1:10000
tot=makedist('Gamma','A',11.8919,'B',2.9927);
tot= truncate(tot,18.5,59);
W(i,:) =random(tot,1,1);
end
Also,
tot=makedist('Gamma','A',11.8919,'B',2.9927);
tot= truncate(tot,18.5,59);
is not depending in the loop index and can therefore be moved in front of the loop to speed things up further. It is also good practice to avoid using i as loop variable.
But you can actually skip the whole loop because random() allows to return multiple samples at once:
tot=makedist('Gamma','A',11.8919,'B',2.9927);
tot= truncate(tot,18.5,59);
W =random(tot,10000,1);

How tick labels on one of the plot's axis can be multiplied in MATLAB?

I am currently trying to make 'nice looking' axis on my plot in Matlab. The values are samples where each is taken every 20ms. So on X axis I'd like to have time in ms. My general code for plotting data is very simple:
plot(1:size( data.matrix,1), data.matrix(:,1),'b');
So far I've been able to correctly display sample numbers on this axis:
Code:
set(gca,'XTick',(1:size(data.matrix,1))*20);
Result (a):
In the given example the number of samples equals 184, that makes:
time = 184 * 20ms = 3680ms
Because changing the XTick value didn't do much of a change, I've tested XTickLabel property:
Code:
set(gca,'XTickLabel',ceil(linspace(0,size(data.matrix,1)*20,10)));
Result (b):
Code:
set(gca,'XTickLabel',0:ceil((size(data.matrix,1)*20)/10):size(data.matrix,1)*20);
Result (c):
As you may see, the results aren't the worst one. But this is not what I am trying to achieve. My goal is to have values like this:
So it simply first plot's (result a) X axis multiplied by 20.
Can someone please tell me how to achieve this?
when you use :
plot(1:size( data.matrix,1), data.matrix(:,1),'b');
The first parameter 1:size( data.matrix,1) create a vector of consecutive integers representing the indices of your data points. Two things are wrong with that:
1) You do not need to specify it. Matlab plot function called with only the Y data will create this vector automatically and use it to plot the data.
2) These indices represent the position of your data in an array, they have no physical meaning (like "time" for your case).
The solution is to create a proper 'time' vector and send it as the first parameter to the plot function. This way Matlab will take care of the tick management and you don't have to temper with the manual xtick settings.
Look at the two ways of doing it in the example below and everything will be clear:
%// build a simple index "X" vector (as you were doing)
x_index = 1:size(data.matrix,1) ;
%// build a properly scaled time vector
timeInterval = 20 ; % in milliseconds
x_time = ( 0:size(data.matrix,1)-1 ) * timeInterval ;
plot( x_index , data.matrix(:,1) ) %// this will do like in your example
plot( x_time , data.matrix(:,1) ) %// this will do what you want
Can you not just do?
set(gca,'XTickLabel',(1:size(data.matrix,1))*20*20);

Simulating spatial PDEs in Modelica - Accessing variable values at specific times

This question is somewhat related to a previous question of mine, where I didn't quite get the right solution. Link: Earlier SO-thread
I am solving PDEs which are time variant with one spatial dimension (e.g. the heat equation - see link below). I'm using the numerical method of lines, i.e. discretizing the spatial derivatives yielding a system of ODEs which are readily solved in Modelica (using the Dymola tool). My problems arise when I simulate the system, or when I plot the results, to be precise. The equations themselves appear to be solved correctly, but I want to express the spatial changes in all the discretized state variables at specific points in time rather than the individual time-varying behavior of each discrete state.
The strategy leading up to my problems is illustrated in this Youtube tutorial, which by the way is not made by me. As you can see at the very end of the tutorial, the time-varying behavior of the temperature is plotted for all the discrete points in the rod, individually. What I would like is a plot showing the temperature through the rod at a specific time, that is the temperature as a function of the spatial coordinate. My strategy to achieve this, which I'm struggling with, is: Given a state vector of N entries:
Real[N] T "Temperature";
..I would use the plotArray Dymola function as shown below.
plotArray( {i for i in 1:N}, {T[i] for i in 1:N} )
Intuitively, this would yield a plot showing the temperature as a function of the spatial coordiate, or the number in the line of discrete units, to be precise. Although this command yields a result, all T-values appear to be 0 in the plot, which is definitely not the case. My question is: How can I successfully obtain and plot the temperatures at all the discrete points at a given time? Thanks in advance for your help.
The code for the problem is as indicated below.
model conduction
parameter Real rho = 1;
parameter Real Cp = 1;
parameter Real L = 1;
parameter Real k = 1;
parameter Real Tlo = 0;
parameter Real Thi = 100;
parameter Real Tinit = 30;
parameter Integer N = 10 "Number of discrete segments";
Real T[N-1] "Temperatures";
Real deltaX = L/N;
initial equation
for i in 1:N-1 loop
T[i] = Tinit;
end for;
equation
rho*Cp*der(T[1]) = k*( T[2] - 2*T[1] + Thi) /deltaX^2;
rho*Cp*der(T[N-1]) = k*( Tlo - 2*T[N-1] + T[N-2]) /deltaX^2;
for i in 2:N-2 loop
rho*Cp*der(T[i]) = k*( T[i+1] - 2*T[i] + T[i-1]) /deltaX^2;
end for
annotation (uses(Modelica(version="3.2")));
end conduction;
Additional edit: The simulations show clearly that for example T[3], that is the temperature of discrete segment no. 3, starts out from 30 and ends up at 70 degrees. When I write T[3] in my command window, however, I get T3 = 0.0 in return. Why is that? This is at the heart of the problem, because the plotArray function would be working if I managed to extract the actual variable values at specific times and not just 0.0.
Suggested solution: This is a rather tedious solution to achieve what I want, and I hope someone knows a better solution. When I run the simulation in Dymola, the software generates a .mat-file containing the values of the variables throughout the time of the simulation. I am able to load this file into MATLAB and manually extract the variables of my choice for plotting. For the problem above, I wrote the following command:
plot( [1:9]' , data_2(2:2:18 , 10)' )
This command will plot the temperatures (as the temperatures are stored together with their derivates in the data_2 array in the .mat-file) against the respetive number of the discrete segment/element. I was really hoping to do this inside Dymola, that is avoid using MATLAB for this. For this specific problem, the amount of variables was low on account of the simplicity of this problem, but I can easily image a .mat-file which is signifanctly harder to navigate through manually like I just did.
Although you do not mention it explicitly I assume that you enter your plotArray command in Dymola's command window. That won't work directly, since the variables you see there do not include your simulation results: If I simulate your model, and then enter T[:] in Dymola's command window, then the printed result is
T[:]
= {0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0}
I'm not a Dymola expert, and the only solution I've found (to actively store and load the desired simulation results) is quite cumbersome:
simulateModel("conduction", resultFile="conduction.mat")
n = readTrajectorySize("conduction.mat")
X = readTrajectory("conduction.mat", {"Time"}, n)
Y = readTrajectory("conduction.mat", {"T[1]", "T[2]", "T[3]"}, n)
plotArrays(X[1, :], transpose(Y))

Selecting certain time range in Matlab

I have a project to do and im facing some problems. Please help me. Im not so good at matlab yet.
Basically, I have a set of movement data (data.mat) which were recorded for 3 days non stop. And I need to:
1. select only certain certain moments (time range) of this whole set of data
2. divide these moments into small 2.56 seconds parts
3. make FFT of each small parts , to see the movement in frequency domain, and select only 5-25 Hz
4. find a few biggest frequency peaks
I wrote a code for making FFT and peaks for whole my data "Data.mat" and it is working.
This is my code:
load('Data.mat');
P=data1(,2); %
Fs=100
Ts=1/Fs
L=length(P)
t = (0:L-1)*Ts;
nfft = 256
figure(1) % raw signal plotting
plot(t,P);
y = fft(P,nfft)/L; % FFT
ymag = abs(y(1:length(y)/2+1));
ft = Fs/2*linspace(0,1,nfft/2+1);
figure(2) % FFT plotting
plot(ft,2*abs(y(1:nfft/2+1)))
indx=ft>= 5 & ft<= 25; % only 5-25Hz
ftsub=ft(indx);
ymagsub=ymag(indx);
% highest peaks
[pks,locs] = findpeaks(ymagsub,'MinPeakHeight',0.02)
plot(ftsub,ymagsub,ftsub(locs),pks,'rv','MarkerFaceColor','r')
Now Im trying to select only certain moments of the data but I have problems with it.
E.g. lets say, I want select only time range: 13-03-2013 9:20:00-9:45:00 AM
I have tried:
t_start =datenum('13-03-2013 9:20:00 AM', 'dd-mm-yyyy HH:MM:SS AM');
t_end = datenum('13-03-2013 9:45:00 AM', 'dd-mm-yyyy HH:MM:SS AM');
rows=find(P>= t_start & P<= t_end);
but I get answer:
rows=
Empty matrix: 0-by-1
Whats wrong? If this code is wrong, how to select certain time range then?
And how to select into 2.56 seconds ?
Please help me, Ive been trying to find the solution since weeks, im really depressed now.
For this line to work properly:
rows=find(P>= t_start & P<= t_end); P must be a series of times in MATLAB datenum format.
I'm guessing P is your actual data - so it doesn't work because find simply compares the numeric values in P against the numeric date values - your "P" values aren't date-tagged in MATLAB. The important things to remember is that the output of datenum is simply a number, so MATLAB will allow you to compare it against other numbers even if the result doesn't make real-world sense.
Your options are:
If your data contains a timestamp, load that, check that it is in the correct format (convert back with datestr for a sanity check). This may be the first column of your data. Perform the find on the time values and then use that to plot/extract the appropriate parts of P.
Construct a time vector - using what you know about the time of the first data point + the sampling rate, and do the same. Similar to your t but in datenums. This will also work if your data acquisition means you only have the times in time-since-start-of-file plus a start time.
Then it's just something like:
r=find(t>= t_start & t<= t_end);
plot(t(r),P(r);