Generate white noise with amplitude between [-1 1] with Matlab - matlab

I'm using the Matlab function Y = WGN(M,N,P) to generate white noise with Gaussian distribution. This function uses a power value (dB Watts) to calculate the amplitude of the output signal. Since I want to get an output amplitude range of -1 V to 1 V there is a function mode 'linear'.
I'm trying to use the 'linear' mode to produce the output but the result is an output amplitude range of [-4 4]
RandomSignal = wgn(10000,1,1,1,'linear');
Time = linspace(0,10,10000);
figure()
plot(Time,RandomSignal)
figure()
hist(RandomSignal,100)
Is there another function to produce this result, or am I just doing something wrong?

As others have said, you can't limit a Gaussian distribution.
What you can do is define your range to be 6 standard deviations, and then use randn(m,sigma) to generate your signal.
For example if you want a range of [-1 1] you will choose sigma=2/6=0.333 and Mu=0. This will create a chance of 99.7% to be inside the range. You can then round up and down those numbers that are out of the range.
This will not be a pure Gaussian distribution, but this is the closest you can get.

why you just take randn function of whatever bound and then just normalize it like this ex.
noise=randn(400); noise=noise./max(max(noise));
so whatever is the output of randn finally you will have a w.n. inside [-1 1].

Gaussian noise has an unbounded range. (The support of the Gaussian pdf is infinite.)

You can use rand rather than Gaussian generator. The output range of rand is 0-1, so to make it in the range -1 1 you use rand(args)*2 -1.
It should be noted that this generator is sampling a uniform density.

Don't want to say something very wrong, but when I copied your code and changed
RandomSignal = .25*wgn(10000,1,1,1,'linear');
it was then ok. Hope it works for you.(Assuming random data/4 is still random data)

hello I think it is so late to answer this question but I think it can be useful for other research.
the function which is shown below is worked for producing gaussian random noise between [-1,1].
function nois=randn_fun_Q(S_Q)
% S_Q a represents the number of rows of the noise vector. For example, in
% system identification, it shows the number of rows of the covariance matrix.
i=0;
nois=[];
for j=1:S_Q
while i~=1
nois_n=randn;
if nois_n<1 && nois_n>-1
nois_=nois_n;
i=1;
else
continue
end
end
nois=[nois;nois_];
i=0;
end
end
you should use this function in "for" loop in main cod to produce n number of noisy point in range of [-1,1].

Related

Generate random samples from arbitrary discrete probability density function in Matlab

I've got an arbitrary probability density function discretized as a matrix in Matlab, that means that for every pair x,y the probability is stored in the matrix:
A(x,y) = probability
This is a 100x100 matrix, and I would like to be able to generate random samples of two dimensions (x,y) out of this matrix and also, if possible, to be able to calculate the mean and other moments of the PDF. I want to do this because after resampling, I want to fit the samples to an approximated Gaussian Mixture Model.
I've been looking everywhere but I haven't found anything as specific as this. I hope you may be able to help me.
Thank you.
If you really have a discrete probably density function defined by A (as opposed to a continuous probability density function that is merely described by A), you can "cheat" by turning your 2D problem into a 1D problem.
%define the possible values for the (x,y) pair
row_vals = [1:size(A,1)]'*ones(1,size(A,2)); %all x values
col_vals = ones(size(A,1),1)*[1:size(A,2)]; %all y values
%convert your 2D problem into a 1D problem
A = A(:);
row_vals = row_vals(:);
col_vals = col_vals(:);
%calculate your fake 1D CDF, assumes sum(A(:))==1
CDF = cumsum(A); %remember, first term out of of cumsum is not zero
%because of the operation we're doing below (interp1 followed by ceil)
%we need the CDF to start at zero
CDF = [0; CDF(:)];
%generate random values
N_vals = 1000; %give me 1000 values
rand_vals = rand(N_vals,1); %spans zero to one
%look into CDF to see which index the rand val corresponds to
out_val = interp1(CDF,[0:1/(length(CDF)-1):1],rand_vals); %spans zero to one
ind = ceil(out_val*length(A));
%using the inds, you can lookup each pair of values
xy_values = [row_vals(ind) col_vals(ind)];
I hope that this helps!
Chip
I don't believe matlab has built-in functionality for generating multivariate random variables with arbitrary distribution. As a matter of fact, the same is true for univariate random numbers. But while the latter can be easily generated based on the cumulative distribution function, the CDF does not exist for multivariate distributions, so generating such numbers is much more messy (the main problem is the fact that 2 or more variables have correlation). So this part of your question is far beyond the scope of this site.
Since half an answer is better than no answer, here's how you can compute the mean and higher moments numerically using matlab:
%generate some dummy input
xv=linspace(-50,50,101);
yv=linspace(-30,30,100);
[x y]=meshgrid(xv,yv);
%define a discretized two-hump Gaussian distribution
A=floor(15*exp(-((x-10).^2+y.^2)/100)+15*exp(-((x+25).^2+y.^2)/100));
A=A/sum(A(:)); %normalized to sum to 1
%plot it if you like
%figure;
%surf(x,y,A)
%actual half-answer starts here
%get normalized pdf
weight=trapz(xv,trapz(yv,A));
A=A/weight; %A normalized to 1 according to trapz^2
%mean
mean_x=trapz(xv,trapz(yv,A.*x));
mean_y=trapz(xv,trapz(yv,A.*y));
So, the point is that you can perform a double integral on a rectangular mesh using two consecutive calls to trapz. This allows you to compute the integral of any quantity that has the same shape as your mesh, but a drawback is that vector components have to be computed independently. If you only wish to compute things which can be parametrized with x and y (which are naturally the same size as you mesh), then you can get along without having to do any additional thinking.
You could also define a function for the integration:
function res=trapz2(xv,yv,A,arg)
if ~isscalar(arg) && any(size(arg)~=size(A))
error('Size of A and var must be the same!')
end
res=trapz(xv,trapz(yv,A.*arg));
end
This way you can compute stuff like
weight=trapz2(xv,yv,A,1);
mean_x=trapz2(xv,yv,A,x);
NOTE: the reason I used a 101x100 mesh in the example is that the double call to trapz should be performed in the proper order. If you interchange xv and yv in the calls, you get the wrong answer due to inconsistency with the definition of A, but this will not be evident if A is square. I suggest avoiding symmetric quantities during the development stage.

How to generate normally distributed random number

can someone explain or point me to a page that explain how to create normally distributed random number in matlab using just error function, the inverse of the error function, and rand()(uniform random number generator between 0 and 1)? the random number doesn't have to be bounded to a certain interval. I'm having problem understand the concept of the error function and the inverse of it, and how it relates to creating random number that is normally distribute
You need to apply the method called inverse transform sampling, which consists in the following. Assume you want to generate a random variable with a given distribution function F. If you can compute the inverse function F-1, then you can obtain the desired random variable by applying F-1 to random samples with uniform distribution on the interval [0,1].
The error function (erf in Matlab) almost gives the distribution function of a normal random variable. Its inverse function is called erfinv in Matlab. Uniformly distributed random numbers are generated with rand.
With these ingredients you should be able to do the task. Please give it a try, and then see the code hovering the mouse over the rectangle:
N = 1e6; % number of samples
x = erfinv(2*rand(1,N)-1); % note factor 2, because of definition of erf
hist(x,31) % plot histogram to check it is (approximately) normal
This link from Mathworks seems to give the answer.
Here's the example from the link:
% First, initialize the random number generator to make the results in this
% example repeatable.
rng(0,'twister');
% Create a vector of 1000 random values drawn from a normal distribution
% with a mean of 500 and a standard deviation of 5.
a = 5;
b = 500;
y = a.*randn(1000,1) + b;
% Calculate the sample mean, standard deviation, and variance.
stats = [mean(y) std(y) var(y)]
% stats =
%
% 499.8368 4.9948 24.9483
%
% The mean and variance are not 500 and 25 exactly because they are
% calculated from a sampling of the distribution.

What's the range of random variable with randn in matlab?

I am using matlab to plot the random variables satisfying the normal distribution. I plot the histogram as
w = 0.2;
y = randn(1, 1000)*w;
hist(y);
this shows the variables in the histogram ranges from -40 to 40, but what's that? I think since the width of the normal distribution is 0.2, I think the range of the variable should be within -1 to 1, right? So why the hist shows from -40 to 40? How do I know the actual range of the random variable? Thanks.
In the normal random variable, sometimes called Gaussian distribution, the range could be from -infinity to +infinity in theory. However, the distribution has a bell shape, this means the larger values have lower probability of occurring, but there is a chance that they happen. So if instead of randn(1, 1000) you use randn(1,1000000) with a high probability you will see a larger range. The value 0.2 that you multiply the randn() with just changes the energy of this random signal.
Can you give a bit more information?
When I run your snippet, I get a Gaussian histogram with min and max:
>> [min(y) max(y)]
ans =
-0.6464 0.7157

Generating random noise in matlab

When I add Gaussian noise to an array shouldnt the histogram be Gaussian? Although the noise is random, the distribution should be gaussian right? That is not what I get.
A=zeros(10);
A=imnoise(A,'gaussian');
imhist(A)
Two things could be going on:
You don't have enough of a sample size, or
The default mean of imnoise with gaussian distribution is 0, meaning you're only seeing the right half of the bell curve.
Try
imhist(imnoise(zeros(1000), 'gaussian', 0.5));
This is what your code is doing:
A = zeros(10);
mu = 0; sd = 0.1; %# mean, std dev
B = A + randn(size(A))*sd + mu; %# add gaussian noise
B = max(0,min(B,1)); %# make sure that 0 <= B <= 1
imhist(B) %# intensities histogram
can you see where the problem is? (Hint: RANDN returns number ~N(0,1), thus the resulting added noise is ~N(mu,sd))
Perhaps what you are trying to do is:
hist( randn(1000,1) )
imnoise() is a function that can be applied to images, not plain arrays.
Maybe you can look into the randn() function, instead.
You might not see a bell-curve with a sampling frame of only 10.
See the central limit theorem.
http://en.wikipedia.org/wiki/Central_limit_theorem
I would try increasing the sampling frame to something much larger.
Reference:
Law of Large Numbers
http://en.wikipedia.org/wiki/Law_of_large_numbers

Extending a sequence statistically in MATLAB

Is there any built-in functions in MATLAB that would statistically extend a sequence of real numbers so that the resulting sequence is extended to any size I want. I have a sequence of 499 elements and I want to extend it to 4096 elements. Thanks in advance.
If you're wanting to interpolate a vector of 499 elements to a higher resolution of 4096 elements, you can use the INTERP1 function in the following way (where x is your 499-element vector):
y = interp1(x,linspace(1,499,4096));
The above uses the function LINSPACE to generate a 4096-element vector of values spaced linearly between 1 and 499, which is then used as the interpolation points. By default, the INTERP1 function uses linear interpolation to compute new values between the old points. You can use other interpolation methods in the following way:
y = interp1(x,linspace(1,499,4096),'spline'); %# Cubic spline method
y = interp1(x,linspace(1,499,4096),'pchip'); %# Piecewise cubic Hermite method
I don't really understand the word "statistically" in the question, but from your comments it seems that you just need linear (or smooth) interpolation.
Try with interp1q or interp1.
If you know the distribution of the data to be in a Pearson or Johnson system of parametric family of distributions, then you can generate more data using the sampling functions pearsrnd and johnsrnd (useful in generating random values without specifying which parametric distribution)
Example:
%# load data, lets say this is vector of 499 elements
data = load('data.dat');
%# generate more data using pearsrnd
moments = {mean(data),std(data),skewness(data),kurtosis(data)};
newData = pearsrnd(moments{:}, [4096-499 1]);
%# concat sequences
extendedData = [data; newData];
%# plot histograms (you may need to adjust the num of bins to see the similarity)
subplot(121), hist(data), xlabel('x'), ylabel('Frequency')
subplot(122), hist(extendedData), xlabel('x'), ylabel('Frequency')
or using johnsrnd:
%# generate more data using johnsrnd
quantiles = quantile(data, normcdf([-1.5 -0.5 0.5 1.5]));
newData = johnsrnd(quantiles, [4096-499 1]);
On the other hand, if you want to assume a non-paramteric distribution, you can use the ecdf function or the ksdensity function.
Please refer to the demo Nonparametric Estimates of Cumulative Distribution Functions and Their Inverses for a complete example (highly suggested!).