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);
Related
I am trying to use MATLAB to solve the ODE involving step function
Here is my code to solve the above ODE:
syms t s Y y(t) Dy(t) u(t) f(t) k
Dy = diff(y,t)
D2y = diff(Dy,t)
f = heaviside(t) + 2*symsum((-1)^k*heaviside(t-k*pi()),k,1,Inf)
eqn = D2y +0.1*Dy + y == f
leqn = laplace(eqn,t,s)
LT_Y=subs (leqn, laplace (y,t,s),Y);
LT_Y=subs (LT_Y, y(0), 0);
LT_Y=subs(LT_Y, subs(diff(y(t), t), t, 0), 0);
Y=solve(LT_Y,Y);
y=ilaplace(Y,s,t)
However, the result seems strange and I cannot plot the graph of the solution. Could anyone tell me what should I do to my code so that I can plot the solution? Thank you so much
The decay rate of the friction term is 0.1/2=0.05, so you need about t=40 for a decay of 0.1. In a standard plot features down to 1% of the plot size are visible, which would require a time span of t=80, or longer for some visual confirmation of the stabilization of the amplitude at that level.
The right side is about in resonance with the left one, so the steady-state solution will roughly look like -10*cos(t) plus higher frequency components.
Just for plotting a numerical solution is sufficient
opts=odeset("AbsTol",1e-6,"RelTol",1e-9);
[T,Y] = ode45(#(t,y)[y(2); f(t)-0.1*y(2)-y(1)], [0, 100], [0;0], opts);
plot(T,Y(:,1),T,-13*cos(T));
function z=f(t)
z = sign(sin(t));
end
This gives the plot below, blue for the solution and green for the reference (guessed amplitude)
Computing the Fourier series for the right side, the amplitude of the cosine component of the solution is 40/pi=12.732.
Theoretical result for convolution of an exponential function with a sinusoidal function is shown below.
When I plot the function directly using matlab, I get this,
However Matlab conv command yields this,
The two plots look similar but they are not the same, see the scales. The matlab yield is ten times of the theoretical result. Why?
The matlab code is here.
clc;
clear all;
close all;
t = 0:0.1:50;
x1 = exp(-t);
x2 = sin(t);
x = conv(x1,x2);
x_theory = 0.5.*(exp(-t) + sin(t) - cos(t));
figure(1)
subplot(313), plot(t, x(1:length(t))); subplot(311), plot(t, x1(1:length(t))); subplot(312), plot(t, x2(1:length(t)))
figure(2)
subplot(313), plot(t, x_theory); subplot(311), plot(t, x1(1:length(t))); subplot(312), plot(t, x2(1:length(t)))
conv does discrete-time convolution, it does not do the mathematical integral function. Numerically, this basically means multiplying and adding the result of the two signals many times, once for each point, with a small shift of one of the signals.
If you think about this, you will realize that the sampling of the signals will have an effect. i.e. if you have a point every 0.1 values, or 0.001 values, the amount of points you multiply is different, and thus the result is different in value (not in shape).
Therefore, every time you do numerical convolution, you always need to multiply with the sampling rate, to "normalize" the operation.
Just change your code to do
sampling_rate= 0.1;
t = 0:sampling_rate:50;
x = conv(x1,x2)*sampling_rate;
I have an instrument which produces roughly sinusoidal data, but with frequency varying slightly in time. I am using MATLAB to prototype some code to characterize the time dependence, but I'm running into some issues.
I am generating an idealized approximation of my data, I(t) = sin(2 pi f(t) t), with f(t) variable but currently tested as linear or quadratic. I then implement a sliding Hamming window (of width w) to generate a set of Fourier transforms F[I(t), t'] corresponding to the data points in I(t), and each F[I(t), t'] is fit with a Gaussian to more precisely determine the peak location.
My current MATLAB code is:
fs = 1000; %Sample frequency (Hz)
tlim = [0,1];
t = (tlim(1)/fs:1/fs:tlim(2)-1/fs)'; %Sample domain (t)
N = numel(t);
f = #(t) 100-30*(t-0.5).^2; %Frequency function (Hz)
I = sin(2*pi*f(t).*t); %Sample function
w = 201; %window width
ww=floor(w/2); %window half-width
for i=0:2:N-w
%Take the FFT of a portion of I, convolved with a Hamming window
II = 1/(fs*N)*abs(fft(I((1:w)+i).*hamming(w))).^2;
II = II(1:floor(numel(II)/2));
p = (0:fs/w:(fs/2-fs/w))';
%Find approximate FFT maximum
[~,maxIx] = max(II);
maxLoc = p(maxIx);
%Fit the resulting FFT with a Gaussian function
gauss = #(c,x) c(1)*exp(-(x-c(2)).^2/(2*c(3)^2));
op = optimset('Display','off');
mdl = lsqcurvefit(gauss,[max(II),maxLoc,10],p,II,[],[],op);
%Generate diagnostic plots
subplot(3,1,1);plot(p,II,p,gauss(mdl,p))
line(f(t(i+ww))*[1,1],ylim,'color','r');
subplot(3,1,2);plot(t,I);
line(t(1+i)*[1,1],ylim,'color','r');line(t(w+i)*[1,1],ylim,'color','r')
subplot(3,1,3);plot(t(i+ww),f(t(i+ww)),'b.',t(i+ww),mdl(2),'r.');
hold on
xlim([0,max(t)])
drawnow
end
hold off
My thought process is that the peak location in each F[I(t), t'] should be a close approximation of the frequency at the center of the window which was used to produce it. However, this does not seem to be the case, experimentally.
I have had some success using discrete Fourier analysis for engineering problems in the past, but I've only done coursework on continuous Fourier transforms--so there may be something obvious that I'm missing. Also, this is my first question on StackExchange, so constructive criticism is welcome.
So it turns out that my problem was a poor understanding of the mathematics of the sine function. I had assumed that the frequency of the wave was equal to whatever was multiplied by the time variable (e.g. the f in sin(ft)). However, it turns out that the frequency is actually defined by the derivative of the entire argument of the sine function--the rate of change of the phase.
For constant f the two definitions are equal, since d(ft)/dt = f. But for, say, f(t) = sin(t):
d(f(t)t)/dt = d(sin(t) t)/dt = t cos(t) + sin(t)
The frequency varies as a function very different from f(t). Changing the function definition to the following fixed my problem:
f = #(t) 100-30*(t-0.5).^2; %Frequency function (Hz)
G = cumsum(f(t))/fs; %Phase function (Hz)
I = sin(2*pi*G); %Sampling function
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.
I've read some explanations of how autocorrelation can be more efficiently calculated using the fft of a signal, multiplying the real part by the complex conjugate (Fourier domain), then using the inverse fft, but I'm having trouble realizing this in Matlab because at a detailed level.
Just like you stated, take the fft and multiply pointwise by its complex conjugate, then use the inverse fft (or in the case of cross-correlation of two signals: Corr(x,y) <=> FFT(x)FFT(y)*)
x = rand(100,1);
len = length(x);
%# autocorrelation
nfft = 2^nextpow2(2*len-1);
r = ifft( fft(x,nfft) .* conj(fft(x,nfft)) );
%# rearrange and keep values corresponding to lags: -(len-1):+(len-1)
r = [r(end-len+2:end) ; r(1:len)];
%# compare with MATLAB's XCORR output
all( (xcorr(x)-r) < 1e-10 )
In fact, if you look at the code of xcorr.m, that's exactly what it's doing (only it has to deal with all the cases of padding, normalizing, vector/matrix input, etc...)
By the Wiener–Khinchin theorem, the power-spectral density (PSD) of a function is the Fourier transform of the autocorrelation. For deterministic signals, the PSD is simply the magnitude-squared of the Fourier transform. See also the convolution theorem.
When it comes to discrete Fourier transforms (i.e. using FFTs), you actually get the cyclic autocorrelation. In order to get proper (linear) autocorrelation, you must zero-pad the original data to twice its original length before taking the Fourier transform. So something like:
x = [ ... ];
x_pad = [x zeros(size(x))];
X = fft(x_pad);
X_psd = abs(X).^2;
r_xx = ifft(X_psd);