That’s true if you specify it as a differential equation as in the original post, but if it is specified as a rational transfer function H(z) as in the later post then the discrete-time function is specified uniquely. It depends on what @ufechner7 is comparing to.
The point is, that the Simulink component I try to port to Julia is a hybrid that is working both in continues and discrete time… Which is a pain, you cannot easily know what it is really doing, and the documentation mixes both implementations…
Sorry for posting a continues time problem in the first place, this is not what I am looking for…
Yes the discrete time version posted later will be unique. I was comparing to the continuous time one.
If you have access to MATLAB you can select the block and press Ctrl+U
to look under the mask. Most probably it would be using Variant subsystem somewhere and in that will implement the continuous and discrete versions.
Just for completeness my current, verified implementation:
using PyPlot
# this implements the function (1/T)(z - 1)/(z + Ts/T -1)
function filtered_derivative(Ω; Ts=0.01, T=0.1)
dΩ = zeros(length(Ω))
a = [Ts/T - 1]
b = [1, -1] / T
for n in eachindex(Ω)
if n > 1
dΩ[n] = b[1] * Ω[n] + b[2] * Ω[n-1] - a[1] * dΩ[n-1]
end
end
dΩ
end
N = 200
Ts = 0.01
Ω = zeros(N)
for i in 101:200
Ω[i] = 1
end
dΩ = filtered_derivative(Ω; Ts)
P = zeros(N)
PyPlot.step((1:N)*Ts, dΩ)
grid(true)
Looks like you’ve got it working, but here’s some context. First, the original continuous-time equations @ufechner7 provided are not a filtered derivative. They are equivalent to transfer function
\frac{K_d}{T_d} \frac{1}{(T_d s+1)}
which is a first-order low-pass filter. Almost certainly you want
\frac{K_d s}{(T_d s+1)}
which is what your reference shows in block diagram (a), but their implementation (b) forgets the s in numerator, which means derivative. (T_d s+1) in denominator is a low-pass filter, so you need both to get a filtered derivative. The frequency response asymptotes to K_d/T_d at high frequencies, which you can understand by taking s \to\infty. Here s is the Laplace transform operator, or kind of a derivative operator, or a complex frequency for a one-sided Fourier transform.
How did they get the discrete-time implementation? Any sampling of a continuous-time system will be an approximation, and it’s a matter of what you prioritize. Here they discretize a derivative as backward rectangular rule. So each s \gets (1 - z^{-1})/T_s, i.e. current sample minus previous sample and divide by sample period. Then multiply by whatever you need get the high-frequency gain above.
All this is from discrete-time control systems. @stevengj was able to figure it out because it’s math, but you can look up some textbooks if you want background for designing filters. (Personally I think this IIR implementation is standard and am skeptical there’s much to gain from FIR.)
BTW @ufechner7 I believe your implementation is still missing something, because your reference also shows a signal limiter, so you won’t truly reproduce their system until you put it in.
The implementation in block diagram (b) seems correct to me. The transfer function can be written as:
y(s)=\frac{K_{d}s}{1+sT_{d}}u(s)=\left(\frac{K_{d}}{T_{d}}\right)\left(\frac{1}{1+\frac{1}{sT_{d}}}\right)u(s),
which is what the block diagram (b) implements. The code that I have posted above actually implements the backward euler discretization of the block diagram along with saturation.
Thanks for your comments!
I am only porting a model to Julia that does not make use of the limiters, so I don’t need them. Another question is if this filter should be part of a package, DSP.jl or another package… I considered to create a Filters.jl package, but for now the code is so simple that it is not really worth creating a package for it…
I learned this all at university, but that is long time ago… From an engineering point of view it would be nice to have a set of often used filters available in a package that you can use without understanding the math…
Might be nice to have some convenience filters within DSP.jl, as non-exported but public functions. It’s already pretty close, because you can do digitalfilter(Highpass(1/T, 1/Ts), Butterworth(1))
. The “filtered derivative” is not exactly a Butterworth, which I believe is usually digitized with bilinear (trapezoidal) transform rather than backward difference.
But all first-order filters are pretty similar, perhaps differing slightly in cut-off and pass-band gain. The filter could even be designed in analog but implemented digitally with analogfilter
. (I’ve not verified any of the above.)