Simulating non-linear SDE in Matlab - matlab

I have this non-linear process that sort of looks like GBM, but is not because of the square-root noise. Both Mu's are constants, and l (in front of one Mu, and sigma) is a parameter. Sigma is a constant too. N is a population that increases.
This is not easily solved analytically.
Ultimately, I'm interested in starting off a bunch of these guys in Matlab with "continous" time steps, vary the parameter l for each process, and see what that looks like.
Since I've never done anything with SDE's in Matlab, I am a little lost. I've had a look at the different SDE solvers, but I can't seem to make them work. As said, I'm not hoping to solve anything, just manipulate different population sizes, time, and this parameter l.
Anyone who can point me in the right direction?

Based on Desmond J. Higham I ended up with this, sort of ugly looking approach. It's quite slow. If anyone had any suggestions as to how I would vectorize or include a SDE solver, such as SDETools to simulate it faster, I would be very grateful.
clear;
clc;
clf
T = 35;
N = 2^12;
Delta = T/N;
lambda = 0.1;
sigma = 4;
Xzero = 1;
P = 500;
Xem = zeros(1,N+1);
Xem(1) = Xzero;
for i = 1:P
for j = 1:N
if log(Xem(j)) < 0
Xem(j) = nan;
end
Winc = sqrt(Delta)*randn;
Xem(j+1) = Xem(j) + lambda*Delta*Xem(j) + sigma*sqrt(Xem(j))*Winc;
end
plot(0:Delta:T,log(Xem))
xlabel('t','FontSize',16), ylabel('X','FontSize',16)
hold on;
end

Related

Generating iterative sequence without using for-loop

I want to generate a random series x with length N through the following rule related to non-central chi-square distribution:
xn+1~χν2(λxn)
where ν is a given constant representing degrees of freedom, λ is also pre-specified and the multiplication of λ and xn is the non-centrality parameter, x1 is supposed to be given.
I wrote the following code to generate such sequence and time the running with x1=0.04, ν=0.005, λ=100 and N=1e5:
tic;
N = 1e5;
x = zeros(1,N);
x(1) = 0.04;
nu = 0.005;
lambda = 100;
for i = 1:N-1
x(i+1) = ncx2rnd(nu,lambda*x(i));
end
toc;
To illustrate my question, I have tested another example, which is different from above. Here I considered generating N=1e5 samples from the distribution χν2(λ) with ν=0.005 and λ=100:
tic;
N = 1e5;
x = zeros(1,N);
nu = 0.005;
lambda = 100;
for i = 1:N
x(i) = ncx2rnd(nu,lambda);
end
toc;
tic;
N = 1e5;
nu = 0.005;
lambda = 100;
x = ncx2rnd(nu,lambda*ones(1,N));
toc;
These two approaches work equivalently. However, it turns out that the second approach which does not use for-loop is much faster than the first one. The difference between both examples is, in the second example, the rule to generate some sample does not require the information of previous samples, which is not the case in the first, therefore all samples can be generated simultaneously without using for-loop. Based on this I wonder whether avoiding for-loop would accelerate the code execution. So would there be any MATLAB built-in function to generate random series shown in the first example without using for-loop when the rule of dependence on previous samples is explicit? If the rule is linear I know the function filter would be a possible choice, what about cases like the first example?
Logically it's impossible to calculate something iterative without doing the iterations. If x(n+1) is dependent on x(n) then you must calculate x(n) first, there is no "clever trick" here.
That just leaves us to optimise the calculation within the loop, specifically ncx2rnd. As with most MATLAB in-built functions, it is already fairly concise and performant, but there are some things to consider. Note that what I'm about to suggest involves using edit ncx2nrd to look inside this in-built function which contains code under MathWorks copyright, I'm simply noting observations about how it works.
There are some input checks to handle incorrectly sized inputs and/or inputs with negative values. If you can take the burden of validation on yourself (i.e. you know your inputs are valid) then you can reduce the function to its single mathematical operation:
% function r = ncx2rnd(v,delta)
r = 2.*randg(poissrnd(delta./2, sizeOut)) + 2.*randg(v./2,sizeOut);
Running this standalone saves around 20% of the processing time, which was for input validation (with a nominal N=1e5).
In the MathWorks syntax, delta is equal to your lambda*x(i), the other term including v is independent of your x, so you could compute it outside of the loop, i.e. vectorising one of the calls to randg. Again using N=1e5 this brings the total time saving to around 25%.
The result would mean this change to your example:
% Common inputs
N = 1e5;
nu = 0.1;
lambda = 0.1;
% Baseline example
x = zeros(1,N);
x(1) = 0.04;
for i = 1:N-1
x(i+1) = ncx2rnd(nu,lambda*x(i));
end
% ~25% faster alternative, with no input validation and partially vectorised
x = zeros(1,N);
x(1) = 0.04;
vTerm = 2.*randg(nu./2, [1,N]);
for i = 1:N-1
x(i+1) = 2.*randg(poissrnd(lambda*x(i)./2, [1,1])) + vTerm(i);
end

Loopless Gaussian mixture model in Matlab

I have several Gaussian distributions and I want to draw different values from all of them at the same time. Since this is basically what a GMM does, I have looked into Matlab GMM implementation (gmrnd) and I have seen that it performs a simple loop over all the components.
I would like to implement it in a faster way, but the problem is that 3d matrices are involved. A simple code (with loop) would be
n = 10; % number of Gaussians
d = 2; % dimension of each Gaussian
mu = rand(d,n); % init some means
U = rand(d,d,n); % init some covariances with their Cholesky decomposition (Cov = U'*U)
I = repmat(triu(true(d,d)),1,1,n);
U(~I) = 0;
r = randn(d,n); % random values for drawing samples
samples = zeros(d,n);
for i = 1 : n
samples(:,i) = U(:,:,i)' * r(:,i) + mu(:,i);
end
Is it possible to speed it up? I do not know how to deal with the 3d covariances matrix (without using cellfun, which is much slower).
Few improvements (hopefully are improvements) could be suggested here.
PARTE #1 You can replace the following piece of code -
I = repmat(triu(true(d,d)),[1,1,n]);
U(~I) = 0;
with bsxfun(#times,..) one-liner -
U = bsxfun(#times,triu(true(d,d)),U)
PARTE #2 You can kill the loopy portion of the code again with bsxfun(#times,..) like so -
samples = squeeze(sum(bsxfun(#times,U,permute(r,[1 3 2])),2)) + mu
I'm not fully convinced this is faster, but it gets rid of the loop. It would be interesting to see benchmarking results if you can do that. I also think this code makes is rather ugly and it's a bit hard to deduce what's going on, but I'll let you decide between readability and performance.
Anyway, I decided to define a big n*d dimensional Gaussian where each block d of variates are independent of each other (as in the original). This allows defining the covariance as a block diagonal matrix, for which I use blkdiag. From there, it is a matter of applying bsxfun to remove the need for looping.
Using the same random seed, I can recover the same samples as your code:
%// sampling with block diagonal covariance matrix
rng(1) %// set random seed
Ub = mat2cell(U, d, d, ones(n,1)); %// 1-by-1-by-10 cell of 2-by-2 matrices
C = blkdiag(Ub{:});
Ns = 1; %// number of samples
joint_samples = bsxfun(#plus, C'*randn(d*n, Ns), mu(:));
new_samples = reshape(joint_samples, [d n]); %// or [d n Ns] if Ns > 1
%//Compare to original
rng(1) %// set same seed for repeatability
r = randn(d,n); % random values for drawing samples
samples = zeros(d,n);
for i = 1 : n
samples(:,i) = U(:,:,i)' * r(:,i) + mu(:,i);
end
isequal(samples, new_samples) %// true

Scale Space for solving Sum of Gaussians

I'm attempting to use scale space implementation to fit n Gaussian curves to peaks in a noisy time series digital signal (measuring voltage).
To test it I created the following sample sum of three gaussians with noise (0.2*rand, sorry no picture, i'm new here)
amp = [2; 0.9; 1.3];
mu = [19; 23; 28];
sigma = [4.8; 1.3; 2.5];
x = linspace(1,50,1000);
for n=1:3, y(n,:) = A(n)*exp(-(x-B(n)).^2./(2*C(n)^2)); end
noisysignal = y(1,:) + y(2,:) + y(3,:) + 0.2*rand(1,numel(x))
I found this article http://www.engineering.wright.edu/~agoshtas/GMIP94.pdf posted by user355856 answer to thread "Peak decomposition"!
I believe my code generates the correct result for plotting the zero crossings as a function of the gaussian filter resolution sigma, but I have two issues. The first is that it seems yet another fitting routine would be needed to identify the approximate location of the arch intercepts for approximating the initial peak sigma and mu values. The second is that the edges of the scale space plot have substantial arches that definitely do not correspond to any peak. I'm not sure how to screen these out effectively. Last thing is that is used a spacing of 50 when calculating the second derivative central finite difference since too much more destroyed feature, and to much less results in a forest of zero crossings. Would there be a better way to filter that to control random zero crossings in the gaussian peak tails?
function [crossing] = scalespace(x, y, sigmalimit)
figure; hold on; ylim([0 sigmalimit]);
for sigma = 1:sigmalimit %
yconv = convkernel(sigma, y); %convolve with kernel
xconv = linspace(x(1), x(end), length(yconv));
yconvpp = d2centralfinite(xconv, yconv, 50); % 50 was empirically chosen
num = 0;
for i = 1 : length(yconvpp)-1
if sign(yconvpp(i)) ~= sign(yconvpp(i+1))
crossing(sigma, num+1) = xconv(i);
num = num+1;
end
end
plot(crossing(sigma, crossing(sigma, :) ~= 0),...
sigma*ones(1, numel(crossing(sigma, crossing(sigma, :) ~= 0))), '.');
end
function [yconv] = convkernel(sigma, y)
t = sigma^2;
C = 3; % for kernel truncation
M = C*round(sqrt(t))+1;
window = (-M) : (+M);
G = zeros(1, length(window));
G(:) = (1/(2*pi()*t))*exp(-(window.^2)./(2*t));
yconv = conv(G, y);
This is my first post and I apologize in advance for any issues in style. I'm fairly new to programming, so any advice regarding the programming style or information provided in this question would be much appreciated. I also read through Amro's answer about matlab's GMM function! if anyone feels that would be a more efficient approach to modeling multiple gaussians in a digital signal.
Thank you!

Euler's Method In Matlab

I am working on a problem involves my using the Euler Method to approximate the differential equation df/dt= af(t)−b[f(t)]^2, both when b=0 and when b is not zero; and I am to compare the analytic solution to the approximate solution when b=0.
f(1) = 1000;
t(1)= 0;
a = 10;
b = 0 ;
dt = 0.01;
Nsteps = 10/dt;
for i = 2:Nsteps
t(i) = dt + t(i-1);
%f(i) = f(i-1)*(1 + dt*(a - b*f(i-1)));
f(i) = f(i-1)*(1 + a*dt);
end
plot(t,f,'r-')
hold on
fa= a*exp(a*t)
plot(t,fa,'bo')
When b=0, the solution to the differential equation is f(t)=c*exp(at). When I apply the initial condition, that f(0) = 1000, then the differential equation becomes f(t)=1000*exp(at). Now, my professor said that a differential equation has an analytic solution, no matter what time step you use, the graph of analytic solution and the approximation (Euler's Method) will coincide. So, I expected the two graphs to overlap. I attached a picture of what I got.
Why did this occur? In order to get the graphs to overlap, I changed 1000 to 10, which is a=10, just for the heck of it. When I did this, the two overlapped. I don't understand. What am I doing incorrectly?
Why should the numerical solution give the same answer as the analytical one? Looking at pixels overlapping on the screen is not a very precise way to discern anything. You should examine the error between the two (absolute and/or relative). You might also want to examine what happens when you change the step size. And you might want to play with a linear system as well. You don't need to integrate out so far to see these effects – just setting t equal 0.1 or 1 suffices. Here is some better-formatted code to work with:
t0 = 0;
dt = 0.01;
tf = 0.1;
t = t0:dt:tf; % No need to integrate t in for loop for fixed time step
lt = length(t);
f = zeros(1,lt); % Pre-allocate f
f0 = 1000; % Initial condition
f(1) = f0;
a = 10;
for i = 1:lt-1
f(i+1) = f(i) + a*f(i)*dt;
%f(i+1) = f(i) + a*dt; % Alternative linear system to try
end
% Analytic solution
fa = f0*exp(a*t);
%fa = f0+a*t; % Alternative linear system to try
figure;
plot(t,f,'r-',t,fa,'bo')
% Plot absolute error
figure;
plot(t,abs(f-fa))
% Plot relative error
figure;
plot(t,abs(f-fa)./fa)
You're also not preallocating any of your arrays which makes you code very inefficient. My code does. Read about that here.
Much more beyond this is really off-topic for this site, which is focussed on programming rather than mathematics. If you really have questions about the numerical details that aren't answered by reading your text book (or the Wikipedia page for the Euler method) then you should ask them at Math.StackExchange.
Numerical methods are not precise and there is always an error between numerical and analytical solution. As Euler's method is first order method, global truncation error is proportional to step of integration step.

1D gaussian filter over non equidistant data

I have a data distributed in non-equidistant 1D space and I need to convolve this with a Gaussian filter,
gaussFilter = sqrt(6.0/pi*delta**2)*exp(-6.0*x**2 /delta**2);
where delta is a constant and x corresponds to space.
Can anyone hint how to perform a good integration (2nd order) as the data is not equally spaced taking care of the finite end? I intend to write the code in Fortran, but a Matlab example is also welcome.
use this:
function yy = smooth1D(x,y,delta)
n = length(y);
yy = zeros(n,1);
for i=1:n;
ker = sqrt(6.0/pi*delta^2)*exp(-6.0*(x-x(i)).^2 /delta^2);
%the gaussian should be normalized (don't forget dx), but if you don't want to lose (signal) energy, uncomment the next line
%ker = ker/sum(ker);
yy(i) = y'*ker;
end
end
Found something which works.
Though not sure if this is very accurate way as the integration (trapz) is of first order.
function [fbar] = gaussf(f,x,delta )
n = length(f);
fbar = zeros(n,1);
for i=1:n;
kernel = sqrt(6/(pi*delta^2))*exp(-6*((x - x(k))/delta).^2);
kernel = kernel/trapz(x,kernel);
fbar(i) = trapz(x,f.*kernel);
end
end