How can I implement a low-pass Butterworth filter in Matlab? - matlab

From this answer, I know how to create a High-pass Butterworth filter.
From this video, I know that, lowpasskernel = 1 - highpasskernel.
So, I created the following Low-pass Butterworth Filter,
function [out, kernel] = butterworth_lp(I, Dl, n)
height = size(I, 1);
width = size(I, 2);
[u, v] = meshgrid(-floor(width/2):floor(width/2)-1,-floor(height/2):floor(height/2)-1);
% lp_kernel = 1 - hp_kernel
kernel = 1 - butter_hp_kernel(u, v, Dl, n);
% fft the image
I_fft_shifted = fftshift(fft2(double(I)));
% apply lowpass filter
I_fft_shift_filtered = I_fft_shifted .* kernel;
% inverse FFT, get real components
out = real(ifft2(ifftshift(I_fft_shift_filtered)));
% normalize and cast
out = (out - min(out(:))) / (max(out(:)) - min(out(:)));
out = uint8(255*out);
function k = butter_hp_kernel(u, v, Dh, n)
uv = u.^2+v.^2;
D = sqrt(uv);
frac = Dh./D;
p = 2*n;
denom = frac.^p;
k = 1./denom;
Output
This isn't a low-pass filter output.
So, what is the issue with my code?

You didn't correctly copy the formula in the high pass filter:
uv = u.^2+v.^2;
D = uv.^0.5;
frac = Dh./D;
p = 2*n;
denom = frac.^p;
k = 1./(1+denom); --> you forgot the "1+"
New output:

Okay. I have solved the problem by following the following formula (Page #8/48),
Output
Source Code
butter_lp_kernel.m
function f = butter_lp_f(u, v, Dl, n)
uv = u.^2+v.^2;
Duv = sqrt(uv);
frac = Duv./Dl;
denom = frac.^(2*n);
f = 1./(1.+denom);
function k = butter_lp_kernel(I, Dl, n)
Height = size(I,1);
Width = size(I,2);
[u, v] = meshgrid( ...
-floor(Width/2) :floor(Width-1)/2, ...
-floor(Height/2): floor(Height-1)/2 ...
);
k = butter_lp_f(u, v, Dl, n);
ifftshow.m
function out = ifftshow(f)
f1 = abs(f);
fm = max(f1(:));
out = f1/fm;
end
butterworth_lpf.m
function [out1, out2] = butterworth_lpf(I, Dl, n)
Kernel = butter_lp_kernel(I, Dl, n);
I_ffted_shifted = fftshift(fft2(I));
I_ffted_shifted_filtered = I_ffted_shifted.*Kernel;
out1 = ifftshow(ifft2(I_ffted_shifted_filtered));
out2 = ifft2(ifftshift(I_ffted_shifted_filtered));
end

Related

1D finite element method in the Hermite basis (P3C1) - Problem of solution calculation

I am currently working on solving the problem $-\alpha u'' + \beta u = f$ with Neumann conditions on the edge, with the finite element method in MATLAB.
I managed to set up a code that works for P1 and P2 Lagragne finite elements (i.e: linear and quadratic) and the results are good!
I am trying to implement the finite element method using the Hermite basis. This basis is defined by the following basis functions and derivatives:
syms x
phi(x) = [2*x^3-3*x^2+1,-2*x^3+3*x^2,x^3-2*x^2+x,x^3-x^2]
% Derivative
dphi = [6*x.^2-6*x,-6*x.^2+6*x,3*x^2-4*x+1,3*x^2-2*x]
The problem with the following code is that the solution vector u is not good. I know that there must be a problem in the S and F element matrix calculation loop, but I can't see where even though I've been trying to make changes for a week.
Can you give me your opinion? Hopefully someone can see my error.
Thanks a lot,
% -alpha*u'' + beta*u = f
% u'(a) = bd1, u'(b) = bd2;
a = 0;
b = 1;
f = #(x) (1);
alpha = 1;
beta = 1;
% Neuamnn boundary conditions
bn1 = 1;
bn2 = 0;
syms ue(x)
DE = -alpha*diff(ue,x,2) + beta*ue == f;
du = diff(ue,x);
BC = [du(a)==bn1, du(b)==bn2];
ue = dsolve(DE, BC);
figure
fplot(ue,[a,b], 'r', 'LineWidth',2)
N = 2;
nnod = N*(2+2); % Number of nodes
neq = nnod*1; % Number of equations, one degree of freedom per node
xnod = linspace(a,b,nnod);
nodes = [(1:3:nnod-3)', (2:3:nnod-2)', (3:3:nnod-1)', (4:3:nnod)'];
phi = #(xi)[2*xi.^3-3*xi.^2+1,2*xi.^3+3*xi.^2,xi.^3-2*xi.^2+xi,xi.^3-xi.^2];
dphi = #(xi)[6*xi.^2-6*xi,-6*xi.^2+6*xi,3*xi^2-4*xi+1,3*xi^2-2*xi];
% Here, just calculate the integral using gauss quadrature..
order = 5;
[gp, gw] = gauss(order, 0, 1);
S = zeros(neq,neq);
M = S;
F = zeros(neq,1);
for iel = 1:N
%disp(iel)
inod = nodes(iel,:);
xc = xnod(inod);
h = xc(end)-xc(1);
Se = zeros(4,4);
Me = Se;
fe = zeros(4,1);
for ig = 1:length(gp)
xi = gp(ig);
iw = gw(ig);
Se = Se + dphi(xi)'*dphi(xi)*1/h*1*iw;
Me = Me + phi(xi)'*phi(xi)*h*1*iw;
x = phi(xi)*xc';
fe = fe + phi(xi)' * f(x) * h * 1 * iw;
end
% Assembly
S(inod,inod) = S(inod, inod) + Se;
M(inod,inod) = M(inod, inod) + Me;
F(inod) = F(inod) + fe;
end
S = alpha*S + beta*M;
g = zeros(neq,1);
g(1) = -alpha*bn1;
g(end) = alpha*bn2;
alldofs = 1:neq;
u = zeros(neq,1); %Pre-allocate
F = F + g;
u(alldofs) = S(alldofs,alldofs)\F(alldofs)
Warning: Matrix is singular to working precision.
u = 8×1
NaN
NaN
NaN
NaN
NaN
NaN
NaN
NaN
figure
fplot(ue,[a,b], 'r', 'LineWidth',2)
hold on
plot(xnod, u, 'bo')
for iel = 1:N
inod = nodes(iel,:);
xc = xnod(inod);
U = u(inod);
xi = linspace(0,1,100)';
Ue = phi(xi)*U;
Xe = phi(xi)*xc';
plot(Xe,Ue,'b -')
end
% Gauss function for calculate the integral
function [x, w, A] = gauss(n, a, b)
n = 1:(n - 1);
beta = 1 ./ sqrt(4 - 1 ./ (n .* n));
J = diag(beta, 1) + diag(beta, -1);
[V, D] = eig(J);
x = diag(D);
A = b - a;
w = V(1, :) .* V(1, :);
w = w';
x=x';
end
You can find the same post under MATLAB site for syntax highlighting.
Thanks
I tried to read courses, search in different documentation and modify my code without success.

How can I implement a band-pass Butterworth filter in Matlab?

This is my expected output.
But, I am getting the following output.
What is wrong with my source code?
Source Code
main.m
clear_all();
I = gray_imread('woman.png');
d0 = 1;
d1 = 100;
n = 20;
J = butter_bandpass(I, d0, d1,n);
J = histeq(J);
K = {I, J};
imshowpair(I, J, 'montage');
butter_bandpass.m
function output_image = butter_bandpass(I, dL, dH,n)
I_double = double(I);
[Height, Width] = size(I_double);
I_double = uint8(I_double);
I_fft = fft2(I_double,2*Height-1,2*Width-1);
I_fft = fftshift(I_fft);
LowPass = ones(2*Height-1,2*Width-1);
HighPass = ones(2*Height-1,2*Width-1);
Kernel = ones(2*Height-1,2*Width-1);
for i = 1:2*Height-1
for j =1:2*Width-1
D = ((i-(Height+1))^2 + (j-(Width+1))^2)^.5;
LowPass(i,j)= 1/(1 + (D/dH)^(2*n));
HighPass(i,j)= 1 - (1/(1 + (D/dL)^(2*n)));
% Create Butterworth filter.
Kernel(i,j) = LowPass(i,j).*HighPass(i,j);
end
end
% apply filter to image
output_image = I_fft + Kernel.*I_fft;
% revert the image to spatial domain
output_image = ifftshift(output_image);
output_image = ifft2(output_image,2*Height-1,2*Width-1);
output_image = real(output_image(1:Height,1:Width));
output_image = uint8(output_image);
end
I have solved this problem.
Output
Refer to this low-pass-filter, and this high-pass-filter source codes.
Since, we know that BPF(band-pass-filter) = LPF * HPF, we can implement a bandpass filter as follows,
Source Code
main.m
clear_all();
I = gray_imread('woman.png');
Dl = 70;
Dh = 70;
n = 1;
[J, K] = butterworth_bpf(I, Dh, Dl, n);
J = histeq(J);
imshowpair(I, J, 'montage');
butter_bp_kernel.m
function k = butter_bp_kernel(I, Dh, Dl, n)
hp_kernel = butter_hp_kernel(I, Dh, n);
lp_kernel = butter_lp_kernel(I, Dl, n);
k = hp_kernel.*lp_kernel; % here is the multiplication
butterworth_bpf.m
function [out1, out2] = butterworth_bpf(I, Dh, Dl, n)
Kernel = butter_bp_kernel(I, Dh, Dl, n);
I_ffted_shifted = fftshift(fft2(I));
I_ffted_shifted_filtered = I_ffted_shifted.*Kernel;
out1 = ifftshow(ifft2(I_ffted_shifted_filtered));
out2 = ifft2(ifftshift(I_ffted_shifted_filtered));
end

How can I implement a high-pass Butterworth filter in Matlab? [duplicate]

This question already has answers here:
High Pass Butterworth Filter on images in MATLAB
(2 answers)
Closed 5 years ago.
According to Page#14 of this link, the equation for a high-pass Butterworth filter is,
And, according to Page#17, the output should be something like the following,
Now, I have looked at this answer in SO, and has written the following Matlab code using the formula given in the linked pdf document.
The output looks different than that of the one given above.
What is the possible problem in my source code?
Source Code
main.m
clear_all();
I = gray_imread('cameraman.png');
n = 1;
Dh = 10;
[J, Kernel] = butterworth_hp(I, Dh, n);
imshowpair(I, J, 'montage');
butterworth_hp.m
function [out, kernel] = butterworth_hp(I, Dh, n)
height = size(I, 1);
width = size(I, 2);
I_fft_shifted = fftshift(fft2(double(I)));
[u, v] = meshgrid(-floor(width/2):floor(width/2)-1,-floor(height/2):floor(height/2)-1);
kernel = butter_hp_kernel(u, v, Dh, n);
I_fft_shift_filtered = I_fft_shifted .* kernel;
out = real(ifft2(ifftshift(I_fft_shift_filtered)));
out = (out - min(out(:))) / (max(out(:)) - min(out(:)));
out = uint8(255*out);
function k = butter_hp_kernel(u, v, D0, n)
uv = u.^2+v.^2;
Duv = uv.^0.5;
frac = D0./Duv;
p = 2*n;
denom = frac.^p;
A = 0.414;
k = 1./(1+A*denom);
I have solved this problem.
The key to solving this problem was the function ifftshow().
Source Code
main.m
clear_all();
I = gray_imread('cameraman.png');
Dh = 10;
n = 1;
[J, K] = butterworth_hpf(I, Dh, n);
imshowpair(I, K, 'montage');
%draw_multiple_images({I, J, K});
ifftshow.m
function out = ifftshow(f)
f1 = abs(f);
fm = max(f1(:));
out = f1/fm;
end
butter_hp_kernel.m
function k = butter_hp_kernel(I, Dh, n)
Height = size(I,1);
Width = size(I,2);
[u, v] = meshgrid( ...
-floor(Width/2) :floor(Width-1)/2, ...
-floor(Height/2): floor(Height-1)/2 ...
);
k = butter_hp_f(u, v, Dh, n);
function f = butter_hp_f(u, v, Dh, n)
uv = u.^2+v.^2;
Duv = sqrt(uv);
frac = Dh./Duv;
%denom = frac.^(2*n);
A=0.414; denom = A.*(frac.^(2*n));
f = 1./(1.+denom);
butterworth_hpf.m
function [out1, out2] = butterworth_hpf(I, Dh, n)
Kernel = butter_hp_kernel(I, Dh, n);
I_ffted_shifted = fftshift(fft2(I));
I_ffted_shifted_filtered = I_ffted_shifted.*Kernel;
out1 = ifftshow(ifft2(I_ffted_shifted_filtered));
out2 = ifft2(ifftshift(I_ffted_shifted_filtered));
end

How to quantize a signal by using of uencode and than udecode properly

I'm trying to quantize the signal with amplitude A (which can be less than 1).
u = uencode(y, N);
d = udecode (u, N);
"Not enough input parameters" it says to me.
I was tried do this without using od udecode function.
y = this.y;
maxy = max(y);
u = uencode(y, N, maxy, 'signed');
u = double(u);
p = u / max(u);
d = p * maxy;
this.yQ = d;
this.QErr = this.y - d;
But this way is reconstructs the signal badly.

Recomposing vector input to algorithm from matrix output

I've written some code to implement an algorithm that takes as input a vector q of real numbers, and returns as an output a complex matrix R. The Matlab code below produces a plot showing the input vector q and the output matrix R.
Given only the complex matrix output R, I would like to obtain the input vector q. Can I do this using least-squares optimization? Since there is a recursive running sum in the code (rs_r and rs_i), the calculation for a column of the output matrix is dependent on the calculation of the previous column.
Perhaps a non-linear optimization can be set up to recompose the input vector q from the output matrix R?
Looking at this in another way, I've used an algorithm to compute a matrix R. I want to run the algorithm "in reverse," to get the input vector q from the output matrix R.
If there is no way to recompose the starting values from the output, thereby treating the problem as a "black box," then perhaps the mathematics of the model itself can be used in the optimization? The program evaluates the following equation:
The Utilde(tau, omega) is the output matrix R. The tau (time) variable comprises the columns of the response matrix R, whereas the omega (frequency) variable comprises the rows of the response matrix R. The integration is performed as a recursive running sum from tau = 0 up to the current tau timestep.
Here are the plots created by the program posted below:
Here is the full program code:
N = 1001;
q = zeros(N, 1); % here is the input
q(1:200) = 55;
q(201:300) = 120;
q(301:400) = 70;
q(401:600) = 40;
q(601:800) = 100;
q(801:1001) = 70;
dt = 0.0042;
fs = 1 / dt;
wSize = 101;
Glim = 20;
ginv = 0;
R = get_response(N, q, dt, wSize, Glim, ginv); % R is output matrix
rows = wSize;
cols = N;
figure; plot(q); title('q value input as vector');
ylim([0 200]); xlim([0 1001])
figure; imagesc(abs(R)); title('Matrix output of algorithm')
colorbar
Here is the function that performs the calculation:
function response = get_response(N, Q, dt, wSize, Glim, ginv)
fs = 1 / dt;
Npad = wSize - 1;
N1 = wSize + Npad;
N2 = floor(N1 / 2 + 1);
f = (fs/2)*linspace(0,1,N2);
omega = 2 * pi .* f';
omegah = 2 * pi * f(end);
sigma2 = exp(-(0.23*Glim + 1.63));
sign = 1;
if(ginv == 1)
sign = -1;
end
ratio = omega ./ omegah;
rs_r = zeros(N2, 1);
rs_i = zeros(N2, 1);
termr = zeros(N2, 1);
termi = zeros(N2, 1);
termr_sub1 = zeros(N2, 1);
termi_sub1 = zeros(N2, 1);
response = zeros(N2, N);
% cycle over cols of matrix
for ti = 1:N
term0 = omega ./ (2 .* Q(ti));
gamma = 1 / (pi * Q(ti));
% calculate for the real part
if(ti == 1)
Lambda = ones(N2, 1);
termr_sub1(1) = 0;
termr_sub1(2:end) = term0(2:end) .* (ratio(2:end).^-gamma);
else
termr(1) = 0;
termr(2:end) = term0(2:end) .* (ratio(2:end).^-gamma);
rs_r = rs_r - dt.*(termr + termr_sub1);
termr_sub1 = termr;
Beta = exp( -1 .* -0.5 .* rs_r );
Lambda = (Beta + sigma2) ./ (Beta.^2 + sigma2); % vector
end
% calculate for the complex part
if(ginv == 1)
termi(1) = 0;
termi(2:end) = (ratio(2:end).^(sign .* gamma) - 1) .* omega(2:end);
else
termi = (ratio.^(sign .* gamma) - 1) .* omega;
end
rs_i = rs_i - dt.*(termi + termi_sub1);
termi_sub1 = termi;
integrand = exp( 1i .* -0.5 .* rs_i );
if(ginv == 1)
response(:,ti) = Lambda .* integrand;
else
response(:,ti) = (1 ./ Lambda) .* integrand;
end
end % ti loop
No, you cannot do so unless you know the "model" itself for this process. If you intend to treat the process as a complete black box, then it is impossible in general, although in any specific instance, anything can happen.
Even if you DO know the underlying process, then it may still not work, as any least squares estimator is dependent on the starting values, so if you do not have a good guess there, it may converge to the wrong set of parameters.
It turns out that by using the mathematics of the model, the input can be estimated. This is not true in general, but for my problem it seems to work. The cumulative integral is eliminated by a partial derivative.
N = 1001;
q = zeros(N, 1);
q(1:200) = 55;
q(201:300) = 120;
q(301:400) = 70;
q(401:600) = 40;
q(601:800) = 100;
q(801:1001) = 70;
dt = 0.0042;
fs = 1 / dt;
wSize = 101;
Glim = 20;
ginv = 0;
R = get_response(N, q, dt, wSize, Glim, ginv);
rows = wSize;
cols = N;
cut_val = 200;
imagLogR = imag(log(R));
Mderiv = zeros(rows, cols-2);
for k = 1:rows
val = deriv_3pt(imagLogR(k,:), dt);
val(val > cut_val) = 0;
Mderiv(k,:) = val(1:end-1);
end
disp('Running iteration');
q0 = 10;
q1 = 500;
NN = cols - 2;
qout = zeros(NN, 1);
for k = 1:NN
data = Mderiv(:,k);
qout(k) = fminbnd(#(q) curve_fit_to_get_q(q, dt, rows, data),q0,q1);
end
figure; plot(q); title('q value input as vector');
ylim([0 200]); xlim([0 1001])
figure;
plot(qout); title('Reconstructed q')
ylim([0 200]); xlim([0 1001])
Here are the supporting functions:
function output = deriv_3pt(x, dt)
% Function to compute dx/dt using the 3pt symmetrical rule
% dt is the timestep
N = length(x);
N0 = N - 1;
output = zeros(N0, 1);
denom = 2 * dt;
for k = 2:N0
output(k - 1) = (x(k+1) - x(k-1)) / denom;
end
function sse = curve_fit_to_get_q(q, dt, rows, data)
fs = 1 / dt;
N2 = rows;
f = (fs/2)*linspace(0,1,N2); % vector for frequency along cols
omega = 2 * pi .* f';
omegah = 2 * pi * f(end);
ratio = omega ./ omegah;
gamma = 1 / (pi * q);
termi = ((ratio.^(gamma)) - 1) .* omega;
Error_Vector = termi - data;
sse = sum(Error_Vector.^2);