How can i generate gaussian random process using matlab? - matlab

How can i generate Gaussian random process using Matlab with zero mean and unit variance ?
Gaussian random variable can be implemented by
w=(1/sqrt(2*pi))*exp(-(t.^2)/2);
but what about Gaussian random process ?

If the Gaussian process is white (no correlation between samples at different instants), just use
w = randn(1,n);
where n is the desired number of samples.
If you need to introduce correlation between samples (that is, the values at different instants are correlated), the usual approach is to generate a white Gaussian process and then apply a low-pass filter (using conv or filter). The autocorrelation of the process is determined by the filter shape.
For example,
w = randn(1,500);
y = conv(w,ones(1,100)/10,'same'); %// apply a simple low-pass filter
plot(w)
hold on
plot(y,'r')
You can see that the filtered signal (red) has smoother time variations, because of the (auto)correlation introduced by the filter.

A random Gaussian process with specified correlation length(cl) and RMSE -height(hRMSE) can be generated by passing a white noise with mean 0 and standard deviation hRMSE through a Gaussian filter g=exp(-(x.^2)/(cl^2/2)).
Furthermore, you can find the Matlab code under the below link: http://www.mysimlabs.com/matlab/surfgen/rsgeng1D.m
Which has been transcribed below:
function [f,x] = rsgeng1D(N,rL,h,cl)
%
% [f,x] = rsgeng1D(N,rL,h,cl)
%
% generates a 1-dimensional random rough surface f(x) with N surface points.
% The surface has a Gaussian height distribution function and a Gaussian
% autocovariance function, where rL is the length of the surface, h is the
% RMS height and cl is the correlation length.
%
% Input: N - number of surface points
% rL - length of surface
% h - rms height
% cl - correlation length
%
% Output: f - surface heights
% x - surface points
%
% Last updated: 2010-07-26 (David Bergström).
%
format long;
x = linspace(-rL/2,rL/2,N);
Z = h.*randn(1,N); % uncorrelated Gaussian random rough surface distribution
% with mean 0 and standard deviation h
% Gaussian filter
F = exp(-x.^2/(cl^2/2));
% correlation of surface using convolution (faltung), inverse
% Fourier transform and normalizing prefactors
f = sqrt(2/sqrt(pi))*sqrt(rL/N/cl)*ifft(fft(Z).*fft(F));

Related

How to use trapz to calculate a triple integral on a spherical harmonic?

I have a combination of spherical harmonics.
Because spherical harmonics are an orthogonal basis, we can say:
Now, I have a function that gives me a spherical harmonic, which gives a spherical harmonic matrix. (the famous spharm4)
First, I want to check if the Y_6^2 is normalized (the integral should be equal to zero) using trapz. How can a 3D integral be done with trapz function using spherical coordinates?
After that, I want to find the coefficient b using eq(2), but I still can’t understand how to use the trapz function correctly and multiply the matrices.
Any help would be appreciated.
Function that gives me a spherical harmonic:
function varargout=plm2spec(lmcosi,norma,in,ot)
% [sdl,l,bta,lfit,logy,logpm]=PLM2SPEC(lmcosi,norma,in,ot)
%
% Calculates the power spectrum of real spherical harmonic
% sine and cosine coefficients contained in the matrix 'lmcosi' which is
% of the standard form that can be plotted by PLM2XYZ and PLOTPLM.
%
% INPUT:
%
% lmcosi Spherical harmonic coefficients [l m Ccos Csin]
% norma 1 multiplication by (l+1)
% This gives the mean-square value of the
% gradient of a potential in Schmidt-harmonics
% 2 division by (2*l+1) [default]
% This gives the proper power spectral density
% as we've come to know it
% 3 none, i.e. a scaling factor of 1
% in Index to minimum degree to consider for the spectral fit [defaulted]
% ot Index to maximum degree to consider for the spectral fit [defaulted]
%
% OUTPUT:
%
% sdl Spectral density: energy per degree
% l Degree
% bta Spectral slope of loglog(l,sdl)
% lfit,logy Spectral line plot given by loglog(lfit,logy)
% logpm Error on spectral line plot given by
% loglog(lfit,logpm)
%
% SEE ALSO: MTVAR
%
% EXAMPLE:
%
% [sdl,l,bta,lfit,logy,logpm]=plm2spec(fralmanac('EGM96'));
%
% SEE ALSO: ACTSPEC
%
% The normalization by (2l+1) is what's required when the spherical
% harmonics are normalized to 4pi. See DT p. 858. A "delta"-function then
% retains a flat spectrum. See Dahlen and Simons 2008.
% See papers by Hipkin 2001, Kaula 1967, Lowes 1966, 1974, Nagata 1965
% (Lowes, JGR 71(8), 2179 [1966])
% (Nagata, JGeomagGeoel 17, 153-155 [1965])
%
% Last modified by fjsimons-at-alum.mit.edu, 03/18/2020
defval('norma',2)
lmin=lmcosi(1);
lmax=lmcosi(end,1);
pin=0;
for l=lmin:lmax
clm=shcos(lmcosi,l);
slm=shsin(lmcosi,l);
pin=pin+1;
sdl(pin)=clm(:)'*clm(:)+slm(:)'*slm(:);
end
switch norma
case 1
normfac=(lmin:lmax)+1;
case 2
normfac=1./(2*(lmin:lmax)+1);
case 3
normfac=1;
disp('Not further normalized')
otherwise
error('No valid normalization specified')
end
% disp(sprintf('Normalization %i',norma))
sdl=normfac.*sdl;
sdl=sdl(:);
% Figure out the range over which to make the fit
l=lmin:lmax;
l=l(:);
if lmin==0
defval('in',3);
elseif lmin==1
defval('in',2);
else
defval('in',1);
end
defval('ot',lmax)
lfit=l(in:ot);
if nargout>=3
% Calculate spectral slope
[bt,E]=polyfit(log10(lfit),log10(sdl(in:ot)),1);
bta=bt(1);
[logy,loge]=polyval(bt,log10(lfit),E);
logy=10.^logy;
logpm=[logy./(10.^loge) logy.*(10.^loge)];
else
[bta,lfit,logy,logpm]=deal(NaN);
end

Generate a mesh with unequal steps based on a density function, using Matlab

I'm trying to generate a 1D mesh with unequal step length, and with a fixed number of elements [same as the initial mesh].
The length should be proportional to a node density. In the example, this density is inversely proportional to the gradient of a function.
[imagine for example that you have a distribution of the temperature in a 1D mesh, and you want to make the mesh denser in the parts of the mesh where the temperature gradient is higher]
This is what I coded so far:
% % % Initial fixed-step 1D mesh
X=(0:.01:2)';
% % % Values of a function at each mesh node [in this example, f(x)=5*sin(2*pi*x)*x ]
Y=5*sin(2*pi*X).*X;
% % % Calculate density of mesh points based on the Y function gradient
rho=[1e-9; abs(diff(Y))];
% % % Calculate x-steps from the original mesh
h = diff(X);
% % % Rescale the steps based on the inverse of the density
F = cumsum([0; h]./rho);
% % % Make sure F is between 0 and 1
F = F/F(end);
% % % Calculate the new mesh with scaled steps
X2 = X(1) + F * (X(end)-X(1));
% % % Interpolate the function Y at the new positions
Y2 = interp1(X,Y,X2);
% % % Plot
figure
subplot(2,1,1)
hold on
plot(X,Y,'ko-')
plot(X2,Y2,'r.-')
xlabel('x')
ylabel('y')
subplot(2,1,2)
plot(X,rho,'ko-')
xlabel('x')
ylabel('rho')
There are a few problems with this approach:
1. as you see from this example, there are big jumps when the density is very low (gradient almost zero). How could I implement a minimum/maximum time step size?
2. the node density is calculated correctly, but after "integrating" the unequal steps it can happen that the imposed large time step when the gradient is small causes to skip a high-gradient region that should have finer time-steps. [for example, please take a look at the region 1.8-1.9 in the example below, which should have small time step because it has high node density, but the large step size at ~1.75 causes to skip a large section of X]
Any suggestion to improve my code will be appreciated!
Calculate the cumulative sum (CDF) of rho. Take equally spaced samples from the CDF. Map from CDF to X to get new X3. Map from X3 to Y to get Y3:
CDF = cumsum(rho);
eq_smpl = linspace(CDF(1), CDF(end), numel(CDF)+1).';
eq_smpl = eq_smpl(1:end-1) + diff(eq_smpl)/2; %use center points
X3 = interp1(CDF, X, eq_smpl);
Y3 = interp1(X, Y, X3);
plot(X3,Y3,'ro-')
hold on
plot(X,Y,'k.')
The third subplot shows the the result.
rahnema1's answer gave me a huge help, but there were still two remaining issues:
1- the first element of the new mesh is not identical to the first element of the original mesh
2- in case the gradient is zero at some point, the interp1 function will give error ["The grid vectors are not strictly monotonic increasing."]
For the 1st point, I replaced the two lines defining eq_smpl with the following line:
eq_smpl = linspace(CDF(1), CDF(end), numel(CDF))';
[taking as many elements as CDF, and not centering the points]
For the 2nd point, I added a line after the calculation of rho to replace eventual 0 with small non-zero values:
rho(rho==0)=1e-12;
The final code that does what I want is the following:
% % % Initial fixed-step 1D mesh
X=(0:.01:2)';
% % % Values of a function at each mesh node [in this example, f(x)=5*sin(2*pi*x)*x ]
Y=5*sin(2*pi*X).*X;
% % % Calculate density of mesh points based on the Y function gradient
rho=[0; abs(diff(Y)./abs(diff(X)))];
% % % Replace eventual 0 with small non-zero values
rho(rho==0)=1e-12;
CDF = cumsum(rho);
eq_smpl = linspace(CDF(1), CDF(end), numel(CDF))';
% % % Calculate new mesh
X3 = interp1(CDF, X, eq_smpl);
% % % Interpolate the function Y at the new positions
Y3 = interp1(X, Y, X3);
% % % Plot
figure
subplot(2,1,1)
hold on
plot(X,Y,'ko-')
plot(X3,Y3,'r.-')
xlabel('x')
ylabel('y')
subplot(2,1,2)
plot(X,rho,'ko-')
xlabel('x')
ylabel('rho')
Thank you again to rahnema1 for providing 90% of the answer [probably I didn't explain very well the original request]!

MATLAB fft vs Mathematical fourier

I am using the following code to generate a fft and mathematical Fourier transform of a signal. I want to then mathematically recreate the original signal of the fft. This works on the mathematical signal but not on the fft since it is a Discrete Transform. Does anyone know what change I can make to my inverse transform equation that will make it work for fft?
clear all; clc;
N = 1024;
N2 = 1023;
SNR = -10;
fs = 1024;
Ts = 1/fs;
t = (0:(N-1))*Ts;
x = 0.5*sawtooth(2*2*pi*t);
x1 = fft(x);
Magnitude1 = abs(x1);
Phase1 = angle(x1)*360/(2*pi);
for m = 1:1024
f(m) = m; % Sinusoidal frequencies
a = (2/N)*sum(x.*cos(2*pi*f(m)*t)); % Cosine coeff.
b = (2/N)*sum(x.*sin(2*pi*f(m)*t)); % Sine coeff
Magnitude(m) = sqrt(a^2 + b^2); % Magnitude spectrum
Phase(m) = -atan2(b,a); % Phase spectrum
end
subplot(2,1,1);
plot(f,Magnitude1./512); % Plot magnitude spectrum
......Labels and title.......
subplot(2,1,2);
plot(f,Magnitude,'k'); % Plot phase spectrum
ylabel('Phase (deg)','FontSize',14);
pause();
x2 = zeros(1,1024); % Waveform vector
for m = 1:24
f(m) = m; % Sinusoidal frequencies
x2 = (1/m)*(x2 + Magnitude1(m)*cos(2*pi*f(m)*t + Phase1(m)));
end
x3 = zeros(1,1024); % Waveform vector
for m = 1:24
f(m) = m; % Sinusoidal frequencies
x3 = (x3 + Magnitude(m)*cos(2*pi*f(m)*t + Phase(m)));
end
plot(t,x,'--k'); hold on;
plot(t,x2,'k');
plot(t,x3,'b');```
There are a few comments about the Fourier Transform, and I hope I can explain everything for you. Also, I don't know what you mean by "Mathematical Fourier transform", as none of the expressions in your code is resembles the Fourier series of the sawtooth wave.
To understand exactly what the fft function does, we can do things step by step.
First, following your code, we create and plot one period of the sawtooth wave.
n = 1024;
fs = 1024;
dt = 1/fs;
t = (0:(n-1))*dt;
x = 0.5*sawtooth(2*pi*t);
figure; plot(t,x); xlabel('t [s]'); ylabel('x');
We can now calculate a few things.
First, the Nyquist frequency, the maximum detectable frequency from the samples.
f_max = 0.5*fs
f_max =
512
Also, the minimum detectable frequency,
f_min = 1/t(end)
f_min =
1.000977517106549
Calculate now the discrete Fourier transform with MATLAB function:
X = fft(x)/n;
This function obtains the complex coefficients of each term of the discrete Fourier transform. Notice it calculates the coefficients using the exp notation, not in terms of sines and cosines. The division by n is to guarantee that the first coefficient is equal to the arithmetic mean of the samples
If you want to plot the magnitude/phase of the transformed signal, you can type:
f = linspace(f_min,f_max,n/2); % frequency vector
a0 = X(1); % constant amplitude
X(1)=[]; % we don't have to plot the first component, as it is the constant amplitude term
XP = X(1:n/2); % we get only the first half of the array, as the second half is the reflection along the y-axis
figure
subplot(2,1,1)
plot(f,abs(XP)); ylabel('Amplitude');
subplot(2,1,2)
plot(f,angle(XP)); ylabel('Phase');
xlabel('Frequency [Hz]')
What does this plot means? It shows in a figure the amplitude and phase of the complex coefficients of the terms in the Fourier series that represent the original signal (the sawtooth wave). You can use this coefficients to obtain the signal approximation in terms of a (truncated) Fourier series. Of course, to do that, we need the whole transform (not only the first half, as it is usual to plot it).
X = fft(x)/n;
amplitude = abs(X);
phase = angle(X);
f = fs*[(0:(n/2)-1)/n (-n/2:-1)/n]; % frequency vector with all components
% we calculate the value of x for each time step
for j=1:n
x_approx(j) = 0;
for k=1:n % summation done using a for
x_approx(j) = x_approx(j)+X(k)*exp(2*pi*1i/n*(j-1)*(k-1));
end
x_approx(j) = x_approx(j);
end
Notice: The code above is for clarification and does not intend to be well coded. The summation can be done in MATLAB in a much better way than using a for loop, and some warnings will pop up in the code, warning the user to preallocate each variable for speed.
The above code calculates the x(ti) for each time ti, using the terms of the truncated Fourier series. If we plot both the original signal and the approximated one, we get:
figure
plot(t,x,t,x_approx)
legend('original signal','signal from fft','location','best')
The original signal and the approximated one are nearly equal. As a matter of fact,
norm(x-x_approx)
ans =
1.997566360514140e-12
Is almost zero, but not exactly zero.
Also, the plot above will issue a warning, due to the use of complex coefficients when calculating the approximated signal:
Warning: Imaginary parts of complex X and/or Y arguments ignored
But you can check that the imaginary term is very close to zero. It is not exactly zero due to roundoff errors in the computations.
norm(imag(x_approx))
ans =
1.402648396024229e-12
Notice in the codes above how to interpret and use the results from the fft function and how they are represented in the exp form, not on terms of sines and cosines, as you coded.

3D points linear regression Matlab

I have a set of 3D points (x,y,z) and I would like to fit a straight line using Least absolute deviation method to those data.
I found a function from the internet which works pretty well with 2D data, how could I modify this to adapt 3D data points?
function B = L1LinearRegression(X,Y)
% Determine size of predictor data
[n m] = size(X);
% Initialize with least-squares fit
B = [ones(n,1) X] \ Y;
% Least squares regression
BOld = B;
BOld(1) = BOld(1) + 1e-5;
% Force divergence
% Repeat until convergence
while (max(abs(B - BOld)) > 1e-6) % Move old coefficients
BOld = B; % Calculate new observation weights (based on residuals from old coefficients)
W = sqrt(1 ./ max(abs((BOld(1) + (X * BOld(2:end))) - Y),1e-6)); % Floor to avoid division by zero
% Calculate new coefficients
B = (repmat(W,[1 m+1]) .* [ones(n,1) X]) \ (W .* Y);
end
Thank you very much!
I know that this is not answer to the question but rather to different problem leading to the question.
We can use fit function several times.
% XYZ=[x(:),y(:),z(:)]; % suppose we have data in this format
M=size(XYZ,1); % read size of our data
t=((0:M-1)/(M-1))'; % create arbitrary parameter t
% fit all coordinates as function x_i=a_i*t+b_i
fitX=fit(t,XYZ(:,1),'poly1');
fitY=fit(t,XYZ(:,2),'poly1');
fitZ=fit(t,XYZ(:,3),'poly1');
temp=[0;1]; % define the interval where the line shall be plotted
%Evaluate and plot the line coordinates
Line=[feval(fitX(temp)),feval(fitY(temp)),feval(fitZ(temp))];
plot(Line)
The advantage is that this work for any cloud, even if it is parallel to any axis. another advantage is that you are not limitted only to polynomes of 1st order, you can choose any function for different axis and fit any 3D curve.

Matlab Low Pass filter using fft

I implemented a simple low pass filter in matlab using a forward and backward fft.
It works in principle, but the minimum and maximum values differ from the original.
signal = data;
%% fourier spectrum
% number of elements in fft
NFFT = 1024;
% fft of data
Y = fft(signal,NFFT)/L;
% plot(freq_spectrum)
%% apply filter
fullw = zeros(1, numel(Y));
fullw( 1 : 20 ) = 1;
filteredData = Y.*fullw;
%% invers fft
iY = ifft(filteredData,NFFT);
% amplitude is in abs part
fY = abs(iY);
% use only the length of the original data
fY = fY(1:numel(signal));
filteredSignal = fY * NFFT; % correct maximum
clf; hold on;
plot(signal, 'g-')
plot(filteredSignal ,'b-')
hold off;
the resulting image looks like this
What am I doing wrong? If I normalize both data the filtered signal looks correct.
Just to remind ourselves of how MATLAB stores frequency content for Y = fft(y,N):
Y(1) is the constant offset
Y(2:N/2 + 1) is the set of positive frequencies
Y(N/2 + 2:end) is the set of negative frequencies... (normally we would plot this left of the vertical axis)
In order to make a true low pass filter, we must preserve both the low positive frequencies and the low negative frequencies.
Here's an example of doing this with a multiplicative rectangle filter in the frequency domain, as you've done:
% make our noisy function
t = linspace(1,10,1024);
x = -(t-5).^2 + 2;
y = awgn(x,0.5);
Y = fft(y,1024);
r = 20; % range of frequencies we want to preserve
rectangle = zeros(size(Y));
rectangle(1:r+1) = 1; % preserve low +ve frequencies
y_half = ifft(Y.*rectangle,1024); % +ve low-pass filtered signal
rectangle(end-r+1:end) = 1; % preserve low -ve frequencies
y_rect = ifft(Y.*rectangle,1024); % full low-pass filtered signal
hold on;
plot(t,y,'g--'); plot(t,x,'k','LineWidth',2); plot(t,y_half,'b','LineWidth',2); plot(t,y_rect,'r','LineWidth',2);
legend('noisy signal','true signal','+ve low-pass','full low-pass','Location','southwest')
The full low-pass fitler does a better job but you'll notice that the reconstruction is a bit "wavy". This is because multiplication with a rectangle function in the frequency domain is the same as a convolution with a sinc function in the time domain. Convolution with a sinc fucntion replaces every point with a very uneven weighted average of its neighbours, hence the "wave" effect.
A gaussian filter has nicer low-pass filter properties because the fourier transform of a gaussian is a gaussian. A gaussian decays to zero nicely so it doesn't include far-off neighbours in the weighted average during convolution. Here is an example with a gaussian filter preserving the positive and negative frequencies:
gauss = zeros(size(Y));
sigma = 8; % just a guess for a range of ~20
gauss(1:r+1) = exp(-(1:r+1).^ 2 / (2 * sigma ^ 2)); % +ve frequencies
gauss(end-r+1:end) = fliplr(gauss(2:r+1)); % -ve frequencies
y_gauss = ifft(Y.*gauss,1024);
hold on;
plot(t,x,'k','LineWidth',2); plot(t,y_rect,'r','LineWidth',2); plot(t,y_gauss,'c','LineWidth',2);
legend('true signal','full low-pass','gaussian','Location','southwest')
As you can see, the reconstruction is much better this way.