Determination of the frequency response using a block of a pseudorandom binary sequence signal generator
To build the frequency characteristics of the system, it is necessary to obtain the frequency response of the model: apply a test signal to the input of the system and measure its output. To reduce the time of the experiment, without losing the quality of the results, you can send a pseudorandom binary sequence (PRBS) signal instead of a harmonic signal. A PRBS is a periodic signal that can take only two specific values.
In this example, in the model_analysis_with_prbs.engee model, a PRBS signal is sent using special blocks and the system response is recorded. In this script, the data is processed and the LFCS is built.
neededLibs = ["EngeeDSP", "DSP", "ControlSystems"]
for lib in neededLibs
try
eval(Meta.parse("using $lib"))
catch ex
Pkg.add(lib)
eval(Meta.parse("using $lib"))
end
end
The sampling period of the algorithm
Ts = 0.001 # @param {type:"number"}
;
An array of frequencies at which the frequency response will be collected on a logarithmic scale.
wmin - the minimum frequency at which to build the LFCH
wmax is the maximum frequency at which to build the
LFCH n_ponts is the number of points on the graph.
wmin = 0.01 # @param {type:"number"}
wmax = 100 # @param {type:"number"}
n_points = 20 # @param {type:"number"}
w = collect(logrange(wmin, wmax, length=n_points));
Running the simulation
modelName = "model_analysis_with_prbs" # @param {type:"string"}
;
if modelName ∉ getfield.(engee.get_all_models(), :name)
engee.load("$(@__DIR__)/$(modelName).engee");
end
engee.run(modelName);
Writing simulation data to variables
model_data = collect(PRBSSigGenData);
t = model_data[:,1];
data = model_data[:,2]
nd = size(data, 1)
nw = length(w)
ready = zeros(nd)
perturbation = zeros(nd)
input = zeros(nd)
output = zeros(nd)
for i = 1:nd
ready[i] = data[i][1]
perturbation[i] = data[i][2]
input[i] = data[i][3]
output[i] = data[i][4]
end
We process the signals before calculating the frequency response of the system
ts = t[2] - t[1]
dupidx = findall(diff(t) .< ts/2)
deleteat!(ready, dupidx)
deleteat!(perturbation, dupidx)
deleteat!(input, dupidx)
idx = findall(ready .== 1.)
d = perturbation[idx]
u = input[idx]
y = output[idx]
nfft = sum(idx .> 0.)
if !iszero(rem(nfft, 2))
freq = (2*pi/ts) .* collect(range(0., 1., nfft + 1))
lastel = Int64((nfft + 1) / 2)
freq = freq[1:lastel]
else
freq = (pi/ts) .* collect(range(0., 1., Int64(nfft/2) + 1))
end
pd = 2*pi / (nfft - 1)
filterwindow = [0.5 .* ones(nfft-1) .- 0.5 .* cos.(pd .* collect(0:nfft-2)); 0.]
fd = EngeeDSP.Functions.fft(d .* filterwindow);
fu = EngeeDSP.Functions.fft(u .* filterwindow);
fy = EngeeDSP.Functions.fft(y .* filterwindow);
d2u = fu ./ fd;
d2y = fy ./ fd;
u2y = d2y ./ d2u;
Constructing the frequency response
We get the frequency response of the system
Please note that the folder must contain a file with the function interpfreqresp.jl
# Connecting the file with the service function
include("$(@__DIR__)/interpfreqresp.jl")
plant_response = interpfreqresp(freq, u2y[1:length(freq)], w);
We calculate the frequency response of the system based on the frequency response
magnitude_estimated = 20 * log10.(abs.(plant_response));
phase_estimated = rad2deg.(DSP.unwrap((atan.(imag.(plant_response), real.(plant_response)))));
We are building a low-frequency response system
gr()
p1 = plot(w, magnitude_estimated, linealpha = 0.0, markershape = :circle, markersize = 4, ylabel = "L, dB", legend = :none)
p2 = plot(w, phase_estimated, linealpha = 0.0, markershape = :circle, markersize = 4, label = "Model", xlabel = "ω, рад/с", ylabel = ", hail", legend = :bottomleft)
plot(p1, p2, layout = (2,1), grid = false, framestyle = :box, xscale=:log10)
We calculate the frequency response of the transfer function of the system.
Let's compare the experimental LCF with the characteristic constructed by the transfer function.
# Management object
L = 0.006 # Inductance Gn
k = 0.10 # Counter-EMF coefficient (In⋅s)/rad
R = 0.25 # Ohm Resistance
J = 0.015 # Moment of inertia of the rotor kg⋅m^2
K = 0.10 # Torque constant N⋅m/A
tfnum = [K];
tfden = [L*J, R*J, K*k];
sys = tf(tfnum, tfden)
W = sys
W = c2d(sys, Ts) # We discretize the transfer function with a quantization period equal to the sampling period of the algorithm.
magnitude_ideal, phase_ideal, w_ideal = bode(W);
magnitude_ideal = reshape(magnitude_ideal, size(magnitude_ideal, 3),)
phase_ideal = reshape(phase_ideal, size(phase_ideal, 3),);
Comparison of LFCH
p1 = plot(w, magnitude_estimated, linealpha = 0.0, markershape = :circle, markersize = 4, ylabel = "L, dB", legend = :none)
plot!(w_ideal, 20 * log10.(magnitude_ideal), xlims = (wmin, wmax))
p2 = plot(w, phase_estimated, linealpha = 0.0, markershape = :circle, markersize = 4, label = "Model", xlabel = "ω, рад/с", ylabel = ", hail", legend = :bottomleft)
plot!(w_ideal, phase_ideal, xlims = (wmin, wmax), label = "Transfer function")
plot(p1, p2, layout = (2,1), grid = false, framestyle = :box, xscale=:log10)

