I'm trying to understand the difference between linear and circular convolution by adapting the Matlab methodologies here. I'm comparing the results of linear convolution with use of the inbuilt conv and cconv function, Bruno Luong's convnfft, and NAG's c06pk.
This is related to the math.stackexchange post.
My code is
% complex vectors
x = rand(2^5,1) + 1j*rand(2^5,1);
y = rand(2^5,1) - 1j*rand(2^5,1);
clin = conv(x,y); % Matlab convolution function
cfun = convnfft(x,y); % Bruno Luong function
N = length(x)+length(y)-1;
xpad = [x' zeros(1,N-length(x))]; % pad vectors
ypad = [y' zeros(1,N-length(y))];
ccirc = cconv(xpad,ypad); % do linear convolution with circular convolution function
cnag = c06pk(int64(1),xpad,ypad); % do linear convolution with NAG function
figure()
plot(clin,'o'); hold on; plot(cfun,'+')
figure()
plot(ccirc,'.'); hold on; plot(cnag,'x')
When I plot the results of linear convolution using the various methods outlined in the code, not all of them agree with the clin result. The cfun agrees, but ccirc and cnag don't because they are designed for finding circular convolutions.
Have I done something wrong with the zero-padding?
Edit: If I plot the results of these linear convolutions I get:
Is there some scaling issue in cconv and c06pk?
You wrote:
xpad = [x' zeros(1,N-length(x))];
ypad = [y' zeros(1,N-length(x))];
However, the ' operator, does not only transpose but also conjugate. Replace it by
xpad = [x.' zeros(1,N-length(x))];
ypad = [y.' zeros(1,N-length(x))];
This should fix the problem. I could only test conv and cconv which after this fix agreed perfectly.
Related
I am trying to get the filter coefficients for a digital IIR filter of a simple 180° phase shift allpass filter with the transfer function: (1+s)/(1-s)
This is what Wolfram gives me:
Bode Plot in Wolfram
and this is what I get from MATLAB:
Bode Plot in MATLAB
My code is:
clc; clear; close all;
z = [-1]; %zeros
p = [1]; %poles
k = 1; %gain
[num,den] = zp2tf(z,p,k); %convert zero-pole into numerator denominator
freqz(num,den); %bode plot
I would like to get the same plot in MATLAB as I do in Wolfram Alpha, to obtain the filter coefficients with fvtool so I can write a filter in C. Therefore my question is how do manage to convert the poles and zeros of the transfer function into the right format so that MATLAB does the same plot like Wolfram Alpha? What am I doing wrong?
Your issue is that you are mixing concepts
freqz is for z-based discrete frequency transforms, while you are working with s-based continuous Laplace transforms. These are unequivocally not the same thing.
Just use the functions for continuous transforms.
z = [-1]; %zeros
p = [1]; %poles
k = 1; %gain
[num,den] = zp2tf(z,p,k); %convert zero-pole into numerator denominator
my_filter=tf(num,den);
bode(my_filter);
I am trying to create a program on Matlab to show the convolution of 2 signals but without using the 'conv' function.
The input is 𝑣(𝑡)=𝑒xp(-4t+4)*𝑢(𝑡−1)+0.5𝑢(𝑡−5)+2𝛿(𝑡−10)
I have worked out that h(t) = 4*exp(-4t)*u(t). I am trying to make a program on MATLAB to compute and display the convolution of two arrays representing two signals but without using the built-in 'conv' function.
I have a working code but it includes 'conv' and so I am trying to do it without using this.
t=linspace(0,11,1101);
%create more than 500 time-series values
vs=exp(-4*(t-1)).*heaviside(t-1)+0.5*heaviside(t-5)+2*dirac(t-10);
%Input signal array
h=4*exp(-4*t).*heaviside(t);
%Input signal array
vc=conv(vs,h);
t1=linspace(0,22,2201);
%Convolution of two arrays
subplot(3,1,1)
plot(t,vs)
xlabel('t')
ylabel('v_s(t)')
title('Input signal')
subplot(3,1,2)
plot(t,h)
xlabel('t')
ylabel('h(t)')
title('System impulse response')
subplot(3,1,3)
plot(t1,vc)
xlabel('t')
ylabel('v_c(t)')
title('Output signal')
Try replacing the conv line with this:
N = length(vs);
M = length(h);
lout=N+M-1;
vc=zeros(1,lout);
for i = 1:N
for k = 1:M
vc(i+k-1) = vc(i+k-1) + h(k)*vs(i);
end
end
It is a basic matlab implementation of the convolution formula
I have a set of frequency data with peaks to which I need to fit a Gaussian curve and then get the full width half maximum from. The FWHM part I can do, I already have a code for that but I'm having trouble writing code to fit the Gaussian.
Does anyone know of any functions that'll do this for me or would be able to point me in the right direction? (I can do least squares fitting for lines and polynomials but I can't get it to work for gaussians)
Also it would be helpful if it was compatible with both Octave and Matlab as I have Octave at the moment but don't get access to Matlab until next week.
Any help would be greatly appreciated!
Fitting a single 1D Gaussian directly is a non-linear fitting problem. You'll find ready-made implementations here, or here, or here for 2D, or here (if you have the statistics toolbox) (have you heard of Google? :)
Anyway, there might be a simpler solution. If you know for sure your data y will be well-described by a Gaussian, and is reasonably well-distributed over your entire x-range, you can linearize the problem (these are equations, not statements):
y = 1/(σ·√(2π)) · exp( -½ ( (x-μ)/σ )² )
ln y = ln( 1/(σ·√(2π)) ) - ½ ( (x-μ)/σ )²
= Px² + Qx + R
where the substitutions
P = -1/(2σ²)
Q = +2μ/(2σ²)
R = ln( 1/(σ·√(2π)) ) - ½(μ/σ)²
have been made. Now, solve for the linear system Ax=b with (these are Matlab statements):
% design matrix for least squares fit
xdata = xdata(:);
A = [xdata.^2, xdata, ones(size(xdata))];
% log of your data
b = log(y(:));
% least-squares solution for x
x = A\b;
The vector x you found this way will equal
x == [P Q R]
which you then have to reverse-engineer to find the mean μ and the standard-deviation σ:
mu = -x(2)/x(1)/2;
sigma = sqrt( -1/2/x(1) );
Which you can cross-check with x(3) == R (there should only be small differences).
Perhaps this has the thing you are looking for? Not sure about compatability:
http://www.mathworks.com/matlabcentral/fileexchange/11733-gaussian-curve-fit
From its documentation:
[sigma,mu,A]=mygaussfit(x,y)
[sigma,mu,A]=mygaussfit(x,y,h)
this function is doing fit to the function
y=A * exp( -(x-mu)^2 / (2*sigma^2) )
the fitting is been done by a polyfit
the lan of the data.
h is the threshold which is the fraction
from the maximum y height that the data
is been taken from.
h should be a number between 0-1.
if h have not been taken it is set to be 0.2
as default.
i had similar problem.
this was the first result on google, and some of the scripts linked here made my matlab crash.
finally i found here that matlab has built in fit function, that can fit Gaussians too.
it look like that:
>> v=-30:30;
>> fit(v', exp(-v.^2)', 'gauss1')
ans =
General model Gauss1:
ans(x) = a1*exp(-((x-b1)/c1)^2)
Coefficients (with 95% confidence bounds):
a1 = 1 (1, 1)
b1 = -8.489e-17 (-3.638e-12, 3.638e-12)
c1 = 1 (1, 1)
I found that the MATLAB "fit" function was slow, and used "lsqcurvefit" with an inline Gaussian function. This is for fitting a Gaussian FUNCTION, if you just want to fit data to a Normal distribution, use "normfit."
Check it
% % Generate synthetic data (for example) % % %
nPoints = 200; binSize = 1/nPoints ;
fauxMean = 47 ;fauxStd = 8;
faux = fauxStd.*randn(1,nPoints) + fauxMean; % REPLACE WITH YOUR ACTUAL DATA
xaxis = 1:length(faux) ;fauxData = histc(faux,xaxis);
yourData = fauxData; % replace with your actual distribution
xAxis = 1:length(yourData) ;
gausFun = #(hms,x) hms(1) .* exp (-(x-hms(2)).^2 ./ (2*hms(3)^2)) ; % Gaussian FUNCTION
% % Provide estimates for initial conditions (for lsqcurvefit) % %
height_est = max(fauxData)*rand ; mean_est = fauxMean*rand; std_est=fauxStd*rand;
x0 = [height_est;mean_est; std_est]; % parameters need to be in a single variable
options=optimset('Display','off'); % avoid pesky messages from lsqcurvefit (optional)
[params]=lsqcurvefit(gausFun,x0,xAxis,yourData,[],[],options); % meat and potatoes
lsq_mean = params(2); lsq_std = params(3) ; % what you want
% % % Plot data with fit % % %
myFit = gausFun(params,xAxis);
figure;hold on;plot(xAxis,yourData./sum(yourData),'k');
plot(xAxis,myFit./sum(myFit),'r','linewidth',3) % normalization optional
xlabel('Value');ylabel('Probability');legend('Data','Fit')
Does MatLab have any built in function to evaluate the density of a random variable from a custom histogram? (I suspect there are probably lots of ways to do this, I am just looking to see if there is already any builtin MatLab functionality).
Thanks.
The function hist gives you an approximation of the probability density you are evaluating.
If you want a continuous representation of it, this article from the Matlab documentation explains how to get one using the spline command from the Curve Fitting Toolbox. Basically the article explains how to make a cubic interpolation of your histogram.
The resulting code is :
y = randn(1,5001); % Replace y by your own dataset
[heights,centers] = hist(y);
hold on
n = length(centers);
w = centers(2)-centers(1);
t = linspace(centers(1)-w/2,centers(end)+w/2,n+1);
dt = diff(t);
Fvals = cumsum([0,heights.*dt]);
F = spline(t, [0, Fvals, 0]);
DF = fnder(F);
hold on
fnplt(DF, 'r', 2)
hold off
ylims = ylim;
ylim([0,ylims(2)]);
A popular way is to use kernel density estimation. The simplest way to do this in Matlab is using ksdensity.
I have an assignment to implement a Ram-Lak filter, but nearly no information given on it (except look at fft, ifft, fftshift, ifftshift).
I have a sinogram that I have to filter via Ram-Lak. Also the number of projections is given.
I try to use the filter
1/4 if I == 0
(b^2)/(2*pi^2) * 0 if I even
-1/(pi^2 * I^2) if I odd
b seems to be the cut-off frequency, I has something to do with the sampling rate?
Also it is said that the convolution of two functions is a simple multiplication in Fourier space.
I do not understand how to implement the filter at all, especially with no b given, not told what I is and no idea how to apply this to the sinogram, I hope someone can help me here. I spent 2hrs googling and trying to understand what is needed to do here, but I could not understand how to implement it.
The formula you listed is an intermediate result if you wanted to do an inverse Radon transform without filtering in the Fourier domain. An alternative is to do the entire filtered back projection algorithm using convolution in the spatial domain, which might have been faster 40 years ago; you would eventually rederive the formula you posted. However, I wouldn't recommended it now, especially not for your first reconstruction; you should really understand the Hilbert transform first.
Anyway, here's some Matlab code which does the obligatory Shepp-Logan phantom filtered back projection reconstruction. I show how you can do your own filtering with the Ram-Lak filter. If I was really motivated, I would replace radon/iradon with some interp2 commands and summations.
phantomData=phantom();
N=size(phantomData,1);
theta = 0:179;
N_theta = length(theta);
[R,xp] = radon(phantomData,theta);
% make a Ram-Lak filter. it's just abs(f).
N1 = length(xp);
freqs=linspace(-1, 1, N1).';
myFilter = abs( freqs );
myFilter = repmat(myFilter, [1 N_theta]);
% do my own FT domain filtering
ft_R = fftshift(fft(R,[],1),1);
filteredProj = ft_R .* myFilter;
filteredProj = ifftshift(filteredProj,1);
ift_R = real(ifft(filteredProj,[],1));
% tell matlab to do inverse FBP without a filter
I1 = iradon(ift_R, theta, 'linear', 'none', 1.0, N);
subplot(1,3,1);imagesc( real(I1) ); title('Manual filtering')
colormap(gray(256)); axis image; axis off
% for comparison, ask matlab to use their Ram-Lak filter implementation
I2 = iradon(R, theta, 'linear', 'Ram-Lak', 1.0, N);
subplot(1,3,2);imagesc( real(I2) ); title('Matlab filtering')
colormap(gray(256)); axis image; axis off
% for fun, redo the filtering wrong on purpose
% exclude high frequencies to create a low-resolution reconstruction
myFilter( myFilter > 0.1 ) = 0;
ift_R = real(ifft(ifftshift(ft_R .* myFilter,1),[],1));
I3 = iradon(ift_R, theta, 'linear', 'none', 1.0, N);
subplot(1,3,3);imagesc( real(I3) ); title('Low resolution filtering')
colormap(gray(256)); axis image; axis off