I am new to MATLAB and I am trying to built a voice morphing system using MATLAB.
So I would like to know how to normalize a signal to zero mean and unit variance using MATLAB?
if your signal is in the matrix X, you make it zero-mean by removing the average:
X=X-mean(X(:));
and unit variance by dividing by the standard deviation:
X=X/std(X(:));
If you have the stats toolbox, then you can compute
Z = zscore(S);
You can determine the mean of the signal, and just subtract that value from all the entries. That will give you a zero mean result.
To get unit variance, determine the standard deviation of the signal, and divide all entries by that value.
It seems like you are essentially looking into computing the z-score or standard score of your data, which is calculated through the formula: z = (x-mean(x))/std(x)
This should work:
%% Original data (Normal with mean 1 and standard deviation 2)
x = 1 + 2*randn(100,1);
mean(x)
var(x)
std(x)
%% Normalized data with mean 0 and variance 1
z = (x-mean(x))/std(x);
mean(z)
var(z)
std(z)
To avoid division by zero!
function x = normalize(x, eps)
% Normalize vector `x` (zero mean, unit variance)
% default values
if (~exist('eps', 'var'))
eps = 1e-6;
end
mu = mean(x(:));
sigma = std(x(:));
if sigma < eps
sigma = 1;
end
x = (x - mu) / sigma;
end
Related
I'm having problems in curve fitting my randomized data for the function
Here is my code
N = 100;
mu = 5; stdev = 2;
x = mu+stdev*randn(N,1);
bin=mu-6*stdev:0.5:mu+6*stdev;
f=hist(x,bin);
plot(bin,f,'bo'); hold on;
x_ = x(1):0.1:x(end);
y_ = (1./sqrt(8.*pi)).*exp(-((x_-mu).^2)./8);
plot(x_,y_,'b-'); hold on;
It seems like I'm having vector size problems since it is giving me the error
Error using plot
Vectors must be the same length.
Note that I simplified y_ since mu and the standard deviation is known.
Plot:
Well first of all some adjustments to your question:
You are not trying to do curve fitting. What you are trying to do (in my opinion) is to overlay a probability density function on an histogram obtained by taking random points from the same distribution (A normal distribution with parameters (mu,sigma)). These two curve should indeed overlay, as they represent the same thing, only one is analytical and the other one is obtained numerically.
As seen in the hist documentation, hist is not recommended and you should use histogram instead
First step: Generating your random data
Knowing the distribution is the Normal distribution, we can use MATLAB's random function to do that :
N = 150;
rng('default') % For reproducibility
mu = 5;
sigma = 2;
r = random('Normal',mu,sigma,N,1);
Second step: Plot the histogram
Because we don't just want a count of the elements in each bin, but a feel of the probability density function, we can use the 'Normalization' 'pdf' arguments
Nbins = 25;
f=histogram(r,Nbins,'Normalization','pdf');
hold on
Here I'd rather specify a number of bins than specifying the bins themselves, because you never know in advance how far from the mean your data is going to be.
Last step: overlay the probability density function over the histogram
The histogram being already consistent with a probability density function, it is sufficient to just overlay the density function:
x_ = linspace(min(r),max(r),100);
y_ = (1./sqrt(2*sigma^2*pi)).*exp(-((x_-mu).^2)./(2*sigma^2));
plot(x_,y_,'b-');
With N = 150
With N = 1500
With N = 150.000 and Nbins = 50
If for some obscure reason you want to use old hist() function
The old hist() function can't handle normalization, so you'll have to do it by hand, by normalizing your density function to fit your histogram:
N = 1500;
% rng('default') % For reproducibility
mu = 5;
sigma = 2;
r = random('Normal',mu,sigma,1,N);
Nbins = 50;
[~,centers]=hist(r,Nbins);
hist(r,Nbins); hold on
% Width of bins
Widths = diff(centers);
x_ = linspace(min(r),max(r),100);
y_ = N*mean(Widths)*(1./sqrt(2*sigma^2*pi)).*exp(-((x_-mu).^2)./(2*sigma^2));
plot(x_,y_,'r-');
I was given the original sine wave(Image 1) and a noisy version of it too(Image 2).
Image 1
Image 2
Now to find the original signal, I am looking at the frequency in the first half of the graph which has the greatest value. This would be 21. When I try to create a sine wave with 21 as a frequency using the code below, I get the result of Image 3.
% Creating the Sine Wave
t = (1:1:256);
A = 1;
y = A*sin(2*pi*max_index*t);
plot(t,y);
Image 3
Why is this the case. What am I doing wrong?
RUNNABLE CODE
Here is my Function:
function [ ] = function1b( Sig_noise )
% Max Index is the frequency of the pure tone
noise_f = fft(Sig_noise);
s_nf = size(noise_f);
size_f = s_nf(2);
max = 0;
max_index = 1;
for n = 1:(size_f/2)
if abs(noise_f(n)) > max
max = abs(noise_f(n));
max_index = n;
end
end
% Creating the Sine Wave
t = (1:1:256);
A = 1;
y = A*sin(2*pi*max_index*t);
plot(t,y);
end
And I am calling it from this part of the script:
load('Sig'); % Original Signal
Sig_noise2=awgn(Sig,10);
function1b(Sig_noise2);
Andras' Solution
This is the result I seem to be getting:
Using linspace(0,2,100); gives me this result:
Your code says
t = (1:1:256);
A = 1;
y = A*sin(2*pi*max_index*t);
While your amplitude is nice and big and 1, if max_index is integer then your phase inside the sin is an integer multiple of 2*pi for every t, which is exactly zero. This is why your function is numerically zero. You need the frequency of the max index:
y = A*sin(2*pi*freq(max_index)*t);
if the frequencies are stored in freq, or if max_index already stands for a frequency, then use a denser t mesh, like
t = linspace(1,256,1000);
You might be misinterpreting the output of fft. From help fft:
For length N input vector x, the DFT is a length N vector X,
with elements
N
X(k) = sum x(n)*exp(-j*2*pi*(k-1)*(n-1)/N), 1 <= k <= N.
n=1
The inverse DFT (computed by IFFT) is given by
N
x(n) = (1/N) sum X(k)*exp( j*2*pi*(k-1)*(n-1)/N), 1 <= n <= N.
k=1
That means that the frequencies are not max_index, but (max_index-1)/N if your original sample has N points. This turns your flawed large frequency into the actual small frequency, solving your issues.
To break it down to you: try
t = 1:256;
y = A*sin(2*pi*(max_index-1)/length(Sig_noise)*t);
I guess there is some problem in sampling rate.
replace
t=(1:1:256)
with
t = (1:1/(f*3):3)
Here f=max_index =21
I need to define several windows for an experimental plot for which slopes can be found. For example, x runs from 0 to 400. I want to find the derivative of each 50x (i.e. 0 to 50, 50 to 100 & so on), and then average all derivatives (8 derivatives in this example). Thanks for any helps!
Assuming you have a vector y of measurements and want to compute the derivative by taking the difference between entry 1 and 50, 51 and 100, and so on, you could do the following:
% generate a signal
x=1:400;
y = x.^2;
nSamples = length(y);
% define number of segments and window size
N = 8;
Winsize = ceil(nSamples/N);
% preallocate the vector of slopes and compute the slopes
slopes = zeros(1,N);
for ii=1:N
slopes(ii) = (y(min(nSamples,Winsize*ii))-y(1+Winsize*(ii-1)))/(x(min(nSamples,Winsize*ii))-x(1+Winsize*(ii-1)));
end
% take the average slope value
Averageslope = mean(slopes);
However, since you are using matlab anyway you could also just take the average derivative of the vector, which should yield a much more accurate average when dealing with noisy data:
% generate a signal
x=1:400;
y = x.^2;
slope = mean(diff(y)/diff(x));
function Y=normpdf(X)
syms X
Y = normpdf(X);
int(Y,X,1,inf)
end
I need to integrate normal pdf function from 1 to infinity for the case of N=100 where N is the total numbers generated.I know i need to use randn() for generating random numbers but i dont know how to use it in this situation.
You could have N = 100 random numbers from t = randn(N, 1);. First, we sort with t = sort(t), then the integrated PDF, i.e. cumulative density function is approximated by your samples with p = (1 : N) / N for t as you can see with plot(t, p). It will overlap well with hold on, plot(t, normcdf(t), 'r').
A perhaps more intuitive approach is to partition the x axis into bins in order to estimate the CDF:
N = 100; % number of samples
t = randn(N, 1); % random data
x = linspace(-10,10,200); % define bins
estim_cdf = mean(bsxfun(#le, t, x)); % estimate CDF
plot(x, estim_cdf);
hold on
plot(x, normcdf(x), 'r')
Note that #s.bandara's solution can be interpreted as the limiting case of this as the number of bins tends to infinity, and therefore it probably gives more accurate results.
By using randn function I want to create a Gaussian random variable X such that X ~ N(2,4) and plot this simulated PDF together with theoretic curve.
Matlab randn generates realisations from a normal distribution with zero mean and a standard deviation of 1.
Samples from any other normal distribution can simply be generated via:
numSamples = 1000;
mu = 2;
sigma = 4;
samples = mu + sigma.*randn(numSamples, 1);
You can verify this by plotting the histogram:
figure;hist(samples(:));
See the matlab help.
N = 1000;
x = [-20:20];
samples = 2 + 4*randn(N, 1);
ySamples = histc(samples,x) / N;
yTheoretical = pdf('norm', x, 2, 4);
plot(x, yTheoretical, x, ySamples)
randn(N, 1) creates an N-by-1 vector.
histc is histogram count by bins given in x - you can use hist to plot the result immediately, but here we want to divide it by N.
pdf contains many useful PDFs, normal is just one example.
remember this: X ~ N(mean, variance)
randn in matlab produces normal distributed random variables W with zero mean and unit variance.
To change the mean and variance to be the random variable X (with custom mean and variance), follow this equation:
X = mean + standard_deviation*W
Please be aware of that standard_deviation is square root of variance.
N = 1000;
x = [-20:20];
samples = 2 + sqrt(4)*randn(N, 1);
ySamples = histc(samples,x) / N;
yTheoretical = pdf('norm', x, 2, sqrt(4)); %put std_deviation not variance
plot(x, yTheoretical, x, ySamples)
A quick and easy way to achieve this using one line of code is to use :
mu = 2;
sigma = 2;
samples = normrnd(mu,sigma,M,N);
This will generate an MxN matrix, sampled from N(μ,𝜎), (= N(2,2) in this particular case).
For additional information, see normrnd.