Related
The aim is to solve the below equations and plot m with time, i.e. dm/dt
k is unknown and needs to be estimated. For the parameter estimation, the below values for m versus t can be used. This is a dummy dataset, as I would like to get an idea if this problem is solvable. If needed, an initial guesstimate for k can be provided 6e-5 m2/bar.hr.
I have added an initial idea for the code, but not sure if my implementation of the A(H) and P(H) functions in the odes is correct. Also I need a way to estimate for k whilst fitting to the provided m vs t data.
function dydt = diffunTAR(~,y,k, h, A_H, P_H, rho_h, rho_o, wo)
dydt = zeros (2,1);
D = 2.64/1000 %mm/1000 to convert to m
r=D/2
rho_o = 1320 %kg/m3
rho_h = 1000 % kg/m3
wo=648/1000000 %weight component 1 in mg converted to kg
h= 1.5/1000 %1.5mm expressed in m
function A_H= pi*(D/2)^2 + (2/r)*(1+(rho_o/rho_h*y(2)))*(wo/rho_o);
end
function P_H = 5004.6*y(2) + 150.39;
end
%dV/dt
dydt(1)= (k/h)* function A_H* function P_H;
%dH/dt
dydt(2)= (rho_h*k/wo*h)*function A_H*function P_H;
end
tspan = linspace(0,21*24); %time in hrs for 21 days
y0 = [0 6.4800e-04];
[t,y]=ode45(#(t,y) diffunTAR(t,y, k, h, A_H0, rho_h, rho_o, wo), tspan, y0);
updated code after help
function dydt = diffunTAR(~,y,k,h,rho_h,rho_o,wo,L,r)
dydt = zeros (2,1);
%dV/dt
dydt(1)= k/h* AH * PH;
%dH/dt
dydt(2)= (rho_h*k/wo*h) * AH * PH;
AH
PH
function PH
(5004.6*y(2))+150.3;
end
function AH
pi*(r^2)+(2/r)*(1+(rho_o/rho_h*y(2)))*(wo/rho_o);
setInitialConditions (AH, 2*pi*(r)*L+2*pi*(r)^2);
end
end
D = 2.64/1000 %mm/1000 to convert to m
r=D/2
L = 10.6/100 %cm/100 to convert to m
wo=648/1000000 %weight osmotic tablets in mg converted to kg
k=6e-5 %guess for permeability
h= 1.5/1000 %1.5mm expressed in m
rho_o = 1320 %kg/m3
rho_h = 1000 % kg/m3
tspan = linspace(0,21*24); %time in hrs for 21 days
y0 = [0 6.4800e-04];
[t,y]=ode45(#(t,y) diffunTAR(t,y,k,h,rho_h,rho_o,wo,L,r), tspan, y0);
I have been trying to optimise some code that takes input signal in the form of a 2D array and convolves it with a gaussian of a certain FWHM. The size of this 2D signal array is (671, 2001), and I am convolving along the second axis - the time axis. Where,
time = 0:0.5:1000
nt = length(time) # nt = 2001
I am convolving with a gaussian of FWHM of 150, corrosponding to a standard deviation of about 63.7. I then pad the initial signal by 3 times the FWHM, setting the new values before the original start index as 0 and the new values after the original end index as the signal at the last time point.
Hence, nt = 3801 after padding.
My MATLAB code calculates this convolution in 117.5043 seconds. This is done through a nested for loop over each of the axis - should be slow in MATLAB. The main bit of theMATLAB code is as follows,
for it = 1:nt
% scan convolution mask across time
kernal = preb*exp(-b*(tc-tc(it)).^2); % convolution mask - Gaussian
N(it) = sum(kernal)*dt; % normalise
kernal = kernal/N(it); % ensure convolution integrates to 1
% calculate convolution for each row
for iq = 1:Nq
WWc(iq,it) = dt*sum((WWc0(iq,1:nt).').*kernal(1:nt));
end
end
I have rewritten this in Julia, except using circulant matrices to construct a gaussian kernal, this effectivley removes the foor loop over time, and the kernal to be applied over all time is now fully defined by one matrix. I then either loop over the rows and multiply this kernal by the signal of each row, or use the mapslices function. The main bit of code in Julia is as follows,
K = Circulant(G.Fx) # construct circulant matrix of gaussian function G.Fx
conv = zeros(nr, nt) # init convolved signal
#for i=1:nr # If using a loop instead of mapslice
# conv[i, :] = transpose(sC[i, :]) * K
#end
conv = mapslices(x -> K*x, sC; dims=2)
In Julia this convolution takes 368 seconds (almost 3 times as slow as MATLAB), despite using circulant matrices to skip a foor loop and reducing it down to multiplying two arrays of size (1, 3801) and (3801, 3801) for each row.
output of #time:
368.047741 seconds (19.37 G allocations: 288.664 GiB, 14.30% gc time, 0.03% compilation time)
Both are run on the same computer, should Julia not outperform MATLAB here?
UPDATE:
Playing around with the Julia code some more, I have rewritten the matrix multiplication in terms of loops, but it is still slow. The convolution is performed within a function although calls two external constructor types - Gaussian or Lorentzian depending on an input flag. I also load SpecialMatrices.jl for the Circulant constructor. I am new to Julia and not sure if that would make it slow. When using the #time macro on independent bits of the function, it is apparent that every part is really fast up until it hits the loop at the end that actually calculations the convolution. This loop is incredibly slow either way I do it, be that using matrix multiplication over the circulant kernel, a double nested loop in combination with the sum() function, or a triple nested loop that does the sum itself.
using MAT
using SpecialMatrices
wd = " "
inputfile = matopen(wd*"/Signal.mat")
signal = read(inputfile, "pdW")
close(inputfile)
inputfile = matopen(wd*"/Vectors.mat")
qAng = read(inputfile, "qAng")
tvec = read(inputfile, "tt")
struct Gaussian
Fx:: AbstractVector{Float64}
sigma:: Float64
height:: Float64
fwhm:: Float64
function Gaussian(fwhm:: Float64, x:: StepRangeLen{Float64}, x0:: Float64)
sigma = fwhm/2sqrt(2log(2))
height = 1/sigma*sqrt(2pi)
Fx = height .* exp.( (-1 .* (x .- x0).^2)./ (2*sigma^2))
new(Fx, sigma, height, fwhm)
end
end
struct Lorentzian
Fx:: AbstractVector{Float64}
gamma:: Float64
fwhm:: Float64
function Lorentzian(fwhm:: Float64, x:: StepRangeLen{Float64}, x0:: Float64)
gamma = fwhm/2
Fx = 1 ./ ((pi * gamma) .* (1 .+ ((x .- x0)./ gamma).^2 ))
new(Fx, gamma, fwhm)
end
end
function convolve(S:: Array{Float64}, fwhm:: Float64, time:: Array{Float64}, type:: Int)
nr:: Int64, nc:: Int64 = size(S)
nt:: Int64 = length(time)
dt:: Float64 = sum(diff(time, dims=2))/(length(time)-1)
duration:: Float64 = fwhm*3 # must pad three time FHWM to deal with edges
if dt != diff(time, dims=2)[1] ; error("Non-linear time range."); end
if nr != nt && nc != nt; error("Inconsistent dimensions."); end
if nc != nt; S = transpose(S); nr, nc = nc, nr; end # column always time axis
tmin:: Float64 = minimum(time); tmax:: Float64 = maximum(time)
tconv_min:: Float64 = tmin - duration ; tconv_max:: Float64 = tmax + duration
tconv = tconv_min:dt:tconv_max # extended convoluted time vector
ntc:: Int64 = length(tconv)
padend:: Int64 = (duration/dt) # index at which 0 padding ends and signal starts
padstart:: Int64 = (padend + tmax / dt) # index where signal ends and padding starts
type == 0 ? Kv = Gaussian(fwhm, tconv, tconv[1]) : Kv = Lorentzian(fwhm, tconv, tconv[1])
println("Convolving signal with a $(typeof(Kv)) function with FWHM: $(Kv.fwhm) fs.")
K:: Array{Float64} = Circulant(Kv.Fx) # construct kernel from circ matrix
sC = zeros(Float64, nr, ntc)
sC[1:nr, 1:padend] .= S[1:nr, 1] # extended and pad signal
sC[1:nr, padend:padstart] .= S
sC[1:nr, padstart:end] .= S[1:nr, end]
println("""
Signal padded by 3*FWHM ( $(duration) fs ) forwards and backwards.
Original time length: $(nt), Extended time: $(ntc), Diff: $(ntc-nt) steps.
Padded signal size: $(size(sC)).
Kernel size: $(size(K[1, :])).
""")
conv = zeros(Float64, nr, ntc)
for t in 1:ntc
for q in 1:nr
#conv[q, t] = sum(sC[q, 1:ntc] .* K[t, :])*dt
conv[q, t] = 0.0
for j in 1:ntc
conv[q, t] += sC[q, j] * K[t, j] * dt
end
end
end
return conv, tconv
end
fwhm = 100.0
conv, tconv = convolve(signal, fwhm, tvec, 0)
UPDATE 2:
Working fast code, w a wrapper for convolving a random signal.
using LinearAlgebra
using SpecialMatrices
function wrapper()
signal = rand(670, 2001)
tvec = 0:0.5:1000
fwhm = 150.0
Flag = 0
conv = convolve(signal, tvec, fwhm, Flag)
end
function Gaussian(x:: StepRangeLen{Float64}, x0:: Float64, fwhm:: T) where {T<:Union{Float64, Int64}}
sigma = fwhm/2sqrt(2log(2))
height = 1/sigma*sqrt(2pi)
Fx = height .* exp.( (-1 .* (x .- x0).^2)./ (2*sigma^2))
Fx = Fx./sum(Fx)
end
function Lorentzian(x:: StepRangeLen{Float64}, x0:: Float64, fwhm:: T) where {T<:Union{Float64, Int64}}
gamma = fwhm/2
Fx = 1 ./ ((pi * gamma) .* (1 .+ ((x .- x0)./ gamma).^2 ))
Fx = Fx./sum(Fx)
end
function generate_kernel(tconv:: StepRangeLen{Float64}, fwhm:: Float64, centre:: Float64, ctype:: Int64)
if ctype == 0
K = Gaussian(tconv, centre, fwhm)
elseif cytpe == 1
K = Lorentzian(tconv, centre, fwhm)
else
error("Only Gaussian and Lorentzian functions currently available.")
end
K = Matrix(Circulant(K))
return K
end
function convolve(S:: Matrix{Float64}, time:: StepRangeLen{Float64}, fwhm:: Float64, ctype:: Int64)
nr:: Int64, nc:: Int64 = size(S)
dt:: Float64 = sum(diff(time, dims=1))/(length(time)-1)
nt:: Int64 = length(time)
duration:: Float64 = fwhm*3 # must pad three time FHWM to deal with edges
tmin:: Float64 = minimum(time); tmax:: Float64 = maximum(time)
if dt != diff(time, dims=1)[1] ; error("Non-linear time range."); end
if nr != nt && nc != nt; error("Inconsistent dimensions."); end
if nc != nt; S = copy(transpose(S)); nr, nc = nc, nr; end # column always time axis
tconv_min:: Float64 = tmin - duration ; tconv_max:: Float64 = tmax + duration
tconv = tconv_min:dt:tconv_max # extended convoluted time vector
ntc = length(tconv)
padend:: Int64 = (duration/dt) # index at which 0 padding ends and signal starts
padstart:: Int64 = (padend + tmax / dt) # index where signal ends and padding starts
K = generate_kernel(tconv, fwhm, tconv[padend], ctype)
sC = zeros(Float64, nr, ntc)
sC[1:nr, 1:padend] .= #view S[1:nr, 1] # extended and pad signal
sC[1:nr, padend:padstart] .= S
sC[1:nr, padstart:end] .= #view S[1:nr, end]
conv = zeros(Float64, nr, ntc)
conv = convolution_integral(sC, K, dt)
S .= conv[:, 1:nt] # return convoluted signal w same original size
return S
end
function convolution_integral(signal:: Matrix{Float64}, kernel:: Matrix{Float64}, dt:: Float64)
LinearAlgebra.BLAS.set_num_threads(Sys.CPU_THREADS)
conv = signal * kernel
conv .*= dt
return conv
end
using BenchMarktools:
julia> #btime wrapper();
128.438 ms (11125 allocations: 300.24 MiB)
There is some strange slicing of the padded signal in the sense that the padding at early time flips to the end of the time extension after convolution. Something to do with the centering of the gaussian kernel I think. For now I just slice the the array back into it's original dimensions without the padding and get the result I expect.
my correlation coefficient values are:
corr=[0.54 0.81 0.21 0.61 0.52 0.47 -0.42 -0.20].
The corresponding time for these correlation coefficient values are:
T=[00:00 - 00:27:02 00:27:02 - 00:35:02 00:35:02 - 00:47:02 00:47 - 00:59:55 01:05:02 - 01:12 01:15 - 01:25 01:27 - 01:35 01:35 - 01:45 ].
The time is given in hour: minute: second format.I want to plot the correlation coefficient values against time. Also, I want to get a 95% confidence line. The example is given in the link https://www.researchgate.net/post/plotting_correlation_coefficient_values_against_time. any help will be appreciated. thanks
first I'm splitting the date strings into start & end times and then I'm converting them to numbers:
coeffs = [0.54 0.81 0.21 0.61 0.52 0.47 -0.42 -0.20];
T = {'00:00 - 00:27:02', '00:27:02 - 00:35:02', '00:35:02 - 00:47:02', '00:47 - 00:59:55', '01:05:02 - 01:12', '01:15 - 01:25', '01:27 - 01:35', '01:35 - 01:45'};
% split to start and end times
startEndTimes = cellfun(#(str) strsplit(str,' - '),T,'UniformOutput',0);
startTimes = cellfun(#(c) c{1},startEndTimes,'UniformOutput',0);
endTimes = cellfun(#(c) c{2},startEndTimes,'UniformOutput',0);
% add seconds where missing
missingSecondsIdx = cellfun(#length,startTimes) == 5;
startTimes(missingSecondsIdx) = cellfun(#(str) [str ':00'],startTimes(missingSecondsIdx),'UniformOutput',0);
missingSecondsIdx = cellfun(#length,endTimes) == 5;
endTimes(missingSecondsIdx) = cellfun(#(str) [str ':00'],endTimes(missingSecondsIdx),'UniformOutput',0);
% convert time strings to numbers
startTimeNums = datenum(startTimes,'HH:MM:SS');
EPS = 1e-4;
endTimeNums = datenum(endTimes,'HH:MM:SS') - EPS;
% interpolate coefficients on "continous" time vector
contTime = linspace(startTimeNums(1),endTimeNums(end),200);
repCoeffs = repmat(coeffs,[2 1]);
repCoeffs = repCoeffs(:);
allTimes = [startTimeNums';endTimeNums'];
allTimes = allTimes(:);
contCoeffs = interp1(allTimes,repCoeffs,contTime);
% plot
plot(contTime,contCoeffs,'b')
hold on;
plot(startTimeNums,coeffs,'og')
plot(endTimeNums,coeffs,'*r')
datetick('x','HH:MM')
xlabel('TIME [HH:MM]')
ylabel('CORRELATION COEFFICIENTS')
Update my modified code -> the wrong point is marked! see the colorbar! :)
Input_Matrix = textread('Rainflow_Input1.txt')
[zeilen,spalten]=size(Input_Matrix)
x = Input_Matrix(:,1)
y = Input_Matrix(:,2)
z = Input_Matrix(:,3)
colorbar('location','Manual', 'position', [0.93 0.1 0.02 0.81]);
az = 0;
el = 90;
view(az, el);
%scatter3(x,y,z,'filled')%Problem i dont know to make it filled
view(0,90)% view from above !!!http://de.mathworks.com/help/matlab/ref/view.html
a = 30;%markersize
scatter3(x, y, z, a, z, 'filled');
view(0, 90)
idx = find(max(z)) ;
hold on
plot3(x(idx),y(idx),z(idx),'*r')
colorbar
datacursormode on
How can I figure out the highest value in my diagram? I want to mark it in my diagram. So the x y and z value should be displayed from the highest value -> z!. Thank you for your help guys. I really appreciate it.
Input_Matrix = textread('Rainflow_Input1.txt')
[zeilen,spalten]=size(Input_Matrix)
x = Input_Matrix(:,1)
y = Input_Matrix(:,2)
z = Input_Matrix(:,3)
colorbar('location','Manual', 'position', [0.93 0.1 0.02 0.81]);
az = 0;
el = 90;
view(az, el);
%scatter3(x,y,z,'filled')%Problem i dont know to make it filled
view(0,90)% view from above !!!http://de.mathworks.com/help/matlab/ref/view.html
a = 30;%markersize
scatter3(x, y, z, a, z, 'filled');
view(0, 90)
colorbar;
datacursormode on
;
My input:
-220.8 228 50045
-222 201.6 50045
-220.2 198 200176
-224.4 196.8 200176
-220.8 192 200176
-221.4 190.8 50044
-226.2 176.4 200176
-199.2 156 50044
-201.6 153.6 50045
-219 147.6 50044
-252.6 133.2 50044
-210 129.6 200176
-250.8 127.2 50044
-201 126 50044
-229.2 124.8 50044
-183 123.6 200176
-168 122.4 200176
-275.4 118.8 200176
-261 13.2 400352
-259.8 13.2 200176
-258.6 13.2 200176
-257.4 13.2 290176
The maximum value (of z I assume) of your data will be m in index ind
[m,ind]=max(z);
If you are worried that there are more than one, you can then always do
indexes=find(z==m);
To mark them, after the call to scatter3 do a hold on and call scatter3 just with the maximum valued data, and another format e.g. '*' and maybe some other color
Following is the graph that I used to calculate the PMV at points: A, B, C, D, E
%This is the code I used to calculate the PMV at points: A, B, C, D, E.
%Where:
%ta=tr=interior temperature setting (22°C, 23°C, 27°C) (variable);
%va=0,2 m/s (invariable);
%RH=50% (invariable);
%W=0 (invariable);
%Met= energy metabolism (1,2 met or 1,4 met) (variable);
%Iclo= static clothing insulation (0,5 clo or 1,0 clo) (variable).
ta=22.0;
tr=22.0;
va=0.2; %air speed
RH=50; %relative humidity
W=0;%mechanical work
Met=1.2;%energy metabolism in met (1 met=58.2 W/m2)
Iclo=0.5;%static clothing insulation
%preparation of variables
PHI=RH/100;%hygrometric dimensionless degree
Icl=Iclo*.155;%Conversion from clo to m2K/W
M=Met*58.15;%conversion of metabolism in unit of measurement of SI
Iclr=Icldyn_7730(va, Icl, M); %calculation of dynamic clothing insulation
vw=0.0052*(M-58);
vr=va+vw;
PMV_Fanger=PMV_evaluator( M,W,ta,tr,vr,PHI,Iclr );
Observation: the functions I called are the following: "Icldyn_7730"
function [ Icldyn ] = Icldyn_7730(va, Iclst, M)
%calculation of dynamic clothing insulation
%Input data
% va, air speed, m/s
% Iclst, static clothing insulation
% M, metabolism in W/m2
vw=0.0052*(M-58);
if vw>0.7
vw=0.7;
end
vr=va+vw;
%Static cloting insulation conversion m2K/W to clo
Iclo = Iclst/0.155;
%Clothing area factor
if Iclst <=0.078
fcl= 1.00 + 1.290 * Iclst;
else
fcl= 1.05 + 0.645 * Iclst;
end
%Static boundary layer thermal insulation in quiet air in m2K/W
Iast = 0.111;
%Total static insulation
Itotst= Iclst + Iast / fcl;
%Clothing insulation correction for wind (vr) and and walking (vw)
vraux= vr;
if vraux > 3.5
vraux=3.5;
end
if vraux < 0.15
vraux=0.15;
end
vwaux=vw;
if vwaux>0.7
vwaux=0.7;
end
CorIt=exp(-0.281*(vraux-0.15)+0.044*(vraux-0.15)^2-0.492*vwaux+0.176*vwaux^2);
if CorIt>1
CorIt=1;
end
CorIa=exp(-0.533*(vraux-0.15)+0.069*(vraux-0.15)^2-0.462*vwaux+0.201*vwaux^2);
if CorIa>1
CorIa=1;
end
Itr = Itotst * CorIt;
Iar = CorIa * Iast;
if Iclo<=0.6
Itr= ((0.6-Iclo) * Iar + Iclo * Itr) / 0.6;
end
Itdyn = Itr;
Iadyn = Iar;
Icldyn = Itdyn - Iadyn / fcl;
end
and "PMV_evaluator"
function [ PMV ] = PMV_evaluator( M,W,ta,tr,vr,PHI,Icl )
%Function for the calculation of the PMV index
% Input data
% M, metabolic rate in W/m2
% W, mechanical work in W/m2
% ta, air temperature in °C
% tr, mean radiant temperature in °C
% vr, rwlative air velocity in m/s
% PHI, hygrometric ratio dimensionless
% Icl in m2K/W (dynamic clothing insulation )
if (ta >=0)
ps = exp (16.6536-4030.183 / (235 + ta ));
else
ps = 0.6105* exp (21.875*ta / (265.5 + ta ));
end;
TAA = ta+273.0;
TRA = tr+273.0;
TCLA = TAA + (35.5-ta) / (3.5*Icl+0.1);
hcf = 12.1 * sqrt(vr);
%Clothing area factor
if Icl <=0.078
fcl= 1.00 + 1.290 * Icl;
else
fcl= 1.05 + 0.645 * Icl;
end
% Start of the loop for the evaluation of clothing surface temperature}
P1 = Icl * fcl;
P2 = P1 * 3.96;
P3 = P1 * 100;
P4 = P1 * TAA;
P5 = 308.7 - 0.028 * (M-W) + P2 * (TRA/100)^4;
XN = TCLA/100;
XF = XN;
EPS = 0.00015;
CONV = 100;
N=1;
while (CONV>EPS)
XF = (XF+XN)/2;
hcn = 2.38 * ((abs(100*XF - TAA))).^0.25;
if (hcf<=hcn)
hc = hcn;
else
hc = hcf;
end
XN = (P5+P4*hc-P2*XF^4)/(100+P3*hc);
CONV=abs(XF-XN);
end
tcl = 100*XN-273;
% End of the loop for the evaluation of clothing surface temperature}
%Skin diffusion heat loss
HL1=3.05*0.001*(5733-6.99*(M-W)-1000*PHI*ps);
%Sweat heat loss
if (M-W)>58.15
HL2= 0.42 * ((M-W)-58.15);
else
HL2=0;
end
%Respiration latent heat loss
HL3= 1.7*0.00001 * M * (5867-1000*PHI*ps);
%Respiration dry heat loss
HL4= 0.0014 * M * (34-ta);
%Radiative heat loss
HL5= 3.96 * fcl * ((0.01*tcl+2.73)^4-(0.01*tr+2.73)^4);
%Convective heat loss
HL6= fcl * hc * (tcl-ta);
%Thermal sensation transformation coefficient}
TS= 0.303 * exp(-0.036*M) + 0.028;
PMV= TS * (M-W-HL1-HL2-HL3-HL4-HL5-HL6);
end
How can I create a table like the following with MATLAB?
The data in the table are the values of PMV. They have been obtained from the individual calculations of MATLAB.
Consider using the table variable introduced in the later versions of matlab, this variable allows for disparate data sources. The full matlab help has an example where the a set of categorical row names occupies the first column while a set of headers occupies the top.
The writetable commmand in matlab will also write a table variable (rows/columns/headers etc) to an excel spreadsheet.
Verbosing zhqiat's answer, your table could be generated by the following code:
data = [-1.5924 -0.2152 -1.1426 0.0421; -1.5924 -0.2152 -1.1426 0.0421; -1.2319 0.0313 -0.8241 0.2595; 0.2329 1.0332 0.4686 1.1427; 0.2329 1.0332 0.4686 1.1427];
row_names = {'A', 'B', 'C', 'D', 'E'};
var_names = {'met1d2_clo0d5', 'met1d2_clo1d0', 'met1d4_clo0d5', 'met1d4_clo1d0'};
var_description = {'M = 1.2 met - 0.5 clo', 'M = 1.2 met - 1. clo', 'M = 1.4 met - 0.5 clo', 'M = 1.4 met - 1.0 clo' };
testtable = array2table(data, 'VariableNames', var_names, 'RowNames', row_names);
testtable.Properties.VariableDescriptions = var_description;
This would result in something like this:
Screenshot of Matlab-Table
We all might got your question wrong. So please try to refine it, if the right answers are missing.