diff --git a/source/getting-started/control-with-amdc/encoder-fb/resources/pll_encoder.slx b/source/getting-started/control-with-amdc/encoder-fb/resources/pll_encoder.slx deleted file mode 100644 index 1503595d..00000000 Binary files a/source/getting-started/control-with-amdc/encoder-fb/resources/pll_encoder.slx and /dev/null differ diff --git a/source/getting-started/control-with-amdc/encoder-fb/resources/pll_test.m b/source/getting-started/control-with-amdc/encoder-fb/resources/pll_test.m deleted file mode 100644 index 35c59524..00000000 --- a/source/getting-started/control-with-amdc/encoder-fb/resources/pll_test.m +++ /dev/null @@ -1,113 +0,0 @@ -clear -close all - -pole_1_Hz = -10; -pole_2_Hz = -100; - -w1 = 2*pi*pole_1_Hz; -w2 = 2*pi*pole_2_Hz; - -Tend = 10; -Tsim = 1e-5; - -finit = 0.1; % initial frequency of chirp [Hz] -ftarget = 1000; % chirp frequency at target time [Hz] - -%% Run simulation -out = sim('pll_test_sim.slx'); - -%% System ID -sim_data = [out.theta_in.Time,out.theta_in.Data,out.theta_out.Data]; - -den = sim_data(:,2); % input signal -num = sim_data(:,3); % output signal - -[freq,mag,phase,coh] = generateFRF(num,den,Tsim,100000,'hann'); - -% Curve Fit Current Command Tracking FRF -% Find where frequency goes positive -idx_f_pos = find(freq >= 0,1); - -G_CL = tf([-w1-w2, w1*w2], [1, -w1-w2, w1*w2]); % CL transfer function -disp('---') -disp('System Poles (Hz):') -my_poles_Hz = pole(G_CL) ./ (2*pi); -disp(my_poles_Hz(1)) -disp(my_poles_Hz(2)) - -mag_pos = mag(idx_f_pos:end); -phase_pos = phase(idx_f_pos:end); -freq_pos = freq(idx_f_pos:end); -[~,index] = min(abs(mag_pos - 1/sqrt(2))); -freq_check = freq_pos(index); -mag_check = mag_pos(index); -phase_check = phase_pos(index); - -%% Plot -markersize = 3; -linewidth = 1; - -% Bode diagram -figure - -f1 = 0.1; -f2 = 1000; - -tiledlayout(3,1); -ax1 = nexttile; -ax2 = nexttile; -ax3 = nexttile; - -% Bode plot by System ID -plot(ax1,freq,20*log10(mag),'oc','markersize',markersize); -plot(ax2,freq,phase,'oc','markersize',markersize); -plot(ax3,freq,coh,'.','markersize',6); -hold (ax1,'on'); -hold (ax2,'on'); - -% Bode plot with ideal Closed-loop transfer function -freq_bode = transpose(linspace(0.1,1/(4*Tsim),10/(4*Tsim))); -[mag_G_CL,phase_G_CL] = bode(G_CL,freq_bode*2*pi); -plot(ax1,freq_bode,squeeze(20*log10(mag_G_CL)),'r','linewidth',linewidth); -plot(ax2,freq_bode,wrapTo180(squeeze(phase_G_CL)),'r','linewidth',linewidth); - -% Set figure limit, label, etc. -xlim(ax1,[f1 f2]); -xlim(ax2,[f1 f2]); -xlim(ax3,[f1 f2]); -ylim(ax3,[0 1]); - -xlabel(ax3,"Frequency (Hz)"); -ylabel(ax1,"Magnitude (dB)"); -ylabel(ax2,"Phase (deg)"); -ylabel(ax3,"Coherence"); - -grid(ax1,'on'); -grid(ax2,'on'); -grid(ax3,'on'); - -set(ax1,'xscale','log'); -set(ax2,'xscale','log'); -set(ax3,'xscale','log'); - -legend(ax1,'System ID','PLL','Location','southwest'); -legend(ax2,'System ID','PLL','Location','southwest'); - -%% -function [freq,mag,phase,coh] = generateFRF(num,den,T,lines,win) - - fs = 1/T; - overlap = lines/2; - averages = floor(length(num)/(lines-overlap)); - windowType = window(win,lines); - - [FRF,freq] = tfestimate(den,num,windowType,overlap,lines,fs); - [coh,freq] = mscohere(den,num,windowType,overlap,lines,fs); - - FRF = fftshift(FRF); - coh = fftshift(coh); - freq = freq - max(freq)/2; - mag = abs(FRF); - phase = angle(FRF) * 180/pi; - -end \ No newline at end of file diff --git a/source/getting-started/control-with-amdc/encoder-fb/resources/pll_test_sim.slx b/source/getting-started/control-with-amdc/encoder-fb/resources/pll_test_sim.slx deleted file mode 100644 index d84461df..00000000 Binary files a/source/getting-started/control-with-amdc/encoder-fb/resources/pll_test_sim.slx and /dev/null differ diff --git a/source/getting-started/control-with-amdc/encoder-fb/simulink/.gitignore b/source/getting-started/control-with-amdc/encoder-fb/simulink/.gitignore new file mode 100644 index 00000000..1f886b6c --- /dev/null +++ b/source/getting-started/control-with-amdc/encoder-fb/simulink/.gitignore @@ -0,0 +1,32 @@ +########## +# MATLAB # +########## + +# Windows default autosave extension +*.asv + +# OSX / *nix default autosave extension +*.m~ + +# Compiled MEX binaries (all platforms) +*.mex* + +# Packaged app and toolbox files +*.mlappinstall +*.mltbx + +# Generated helpsearch folders +helpsearch*/ + +# Simulink code generation folders +slprj/ +sccprj/ + +# Matlab code generation folders +codegen/ + +# Simulink autosave extension +*.autosave + +# Simulink cache files +*.slxc diff --git a/source/getting-started/control-with-amdc/encoder-fb/simulink/lowPassFilter.slx b/source/getting-started/control-with-amdc/encoder-fb/simulink/lowPassFilter.slx new file mode 100644 index 00000000..6f25f2ab Binary files /dev/null and b/source/getting-started/control-with-amdc/encoder-fb/simulink/lowPassFilter.slx differ diff --git a/source/getting-started/control-with-amdc/encoder-fb/simulink/observer.slx b/source/getting-started/control-with-amdc/encoder-fb/simulink/observer.slx new file mode 100644 index 00000000..9fb5cf97 Binary files /dev/null and b/source/getting-started/control-with-amdc/encoder-fb/simulink/observer.slx differ diff --git a/source/getting-started/control-with-amdc/encoder-fb/simulink/pllEncoder.slx b/source/getting-started/control-with-amdc/encoder-fb/simulink/pllEncoder.slx new file mode 100644 index 00000000..bc44e61a Binary files /dev/null and b/source/getting-started/control-with-amdc/encoder-fb/simulink/pllEncoder.slx differ diff --git a/source/getting-started/control-with-amdc/encoder-fb/simulink/setup.m b/source/getting-started/control-with-amdc/encoder-fb/simulink/setup.m new file mode 100644 index 00000000..8634526b --- /dev/null +++ b/source/getting-started/control-with-amdc/encoder-fb/simulink/setup.m @@ -0,0 +1,131 @@ +clear +close all + +Ts = 1e-4; +Tsim = 1e-5; + + +%% Switch winding that you develop +load_system('speedControlSimulation') % load Simulink model +% The input of this function should be 'lowPassFilter', 'pllEncoder', 'observer' +switch_speed_calculation('observer') + +Tend = 0.2; + +p = 1; % number of pole +speed_cmd = 3000; % rotational speed (r/min) + +% Parameters for plant +J_z = 29.54e-6; +b = 4.28e-6; + +% Parameters for low pass filter +f_lpf = 100; % low pass fileter cut-off frequency (Hz) +omega_lpf = 2*pi*f_lpf; % low pass fileter cut-off frequency (rad/s) + +% Parameters for PLL +pole_1_Hz = -10; +pole_2_Hz = -100; +w1 = 2*pi*pole_1_Hz; +w2 = 2*pi*pole_2_Hz; + +f_sf = 10; % motion state fileter cut-off frequency (Hz) +wb_sf = 2*pi*f_sf; +b_o_sf = wb_sf*J_z; +K_io_sf = wb_sf*b; + +% Parameters for chirp signal +f_init = 0.1; % initial frequency of chirp [Hz] +f_target = 1000; % chirp frequency at target time [Hz] + +% Parameters for speed control +fb_speed = 100; +omega_b_speed = 2*pi*fb_speed; +Kp_speed = omega_b_speed*J_z; +Ki_speed = omega_b_speed*b; + +%% Run simulation +% set_param('compute_speed/Speed Controller LPF', 'Commented', 'off'); +% set_param('compute_speed/Speed Controller PLL', 'Commented', 'on'); +% set_param('compute_speed/Speed Control Observer', 'Commented', 'on'); +sim('speedControlSimulation.slx'); +run1 = Simulink.sdi.Run.getLatest; + +% set_param('compute_speed/Speed Controller LPF', 'Commented', 'on'); +% set_param('compute_speed/Speed Controller PLL', 'Commented', 'off'); +% set_param('compute_speed/Speed Control Observer', 'Commented', 'on'); +% sim('compute_speed.slx'); +% run2 = Simulink.sdi.Run.getLatest; +% +% set_param('compute_speed/Speed Controller LPF', 'Commented', 'on'); +% set_param('compute_speed/Speed Controller PLL', 'Commented', 'on'); +% set_param('compute_speed/Speed Control Observer', 'Commented', 'off'); +% sim('compute_speed.slx'); +% run3 = Simulink.sdi.Run.getLatest; + +%% Post processing +% List of variables to extract +% obj2ext = {'time', 'omega_raw', 'omega_lpf', 'omega_pll', 'omega_sf'}; +obj2ext = {'time', 'omega'}; +% runs = {run1, run2, run3}; +runs = {run1}; + +for r = 1:1 + runObj = runs{r}; + for i = 1:length(obj2ext) + sigID = getSignalIDsByName(runObj, obj2ext{i}); + if ~isempty(sigID) + sig_obj{r}.(obj2ext{i}) = Simulink.sdi.getSignal(sigID); + sig_val{r}.(obj2ext{i}) = sig_obj{r}.(obj2ext{i}).Values.Data; + time{r} = sig_obj{r}.(obj2ext{i}).Values.Time; + end + end +end + +%% Plot figure +width = 2*5.43; +height = 1.2*3*4.38/3/2; +set(0,'units','inches'); +Inch_SS = get(0,'screensize'); +lw = 1; % line width + +figure1 = figure; +% Plot omega +hold on; +% plot(time{3}, squeeze(sig_val{3}.omega_raw), 'Color', 'k', 'LineWidth', lw); +plot(time{1}, squeeze(sig_val{1}.omega), 'Color', 'r', 'LineWidth', lw); +% plot(time{2}, squeeze(sig_val{2}.omega_pll), 'Color', 'b', 'LineWidth', lw); +% plot(time{3}, squeeze(sig_val{3}.omega_sf), '--', 'Color', 'g', 'LineWidth', lw); +xlabel('Time [s]','Interpreter','latex'); +ylabel('$\Omega$ (rad/s)','Interpreter','latex'); +xlim([0 Tend]); +% ylim([0 400]); +% legend('$\Omega_{\mathrm{raw}}$','$\Omega_{\mathrm{lpf}}$', '$\Omega_{\mathrm{pll}}$', '$\Omega_{\mathrm{sf}}$', 'Interpreter','latex','Location','east'); + +set(findall(gcf, '-property', 'FontName'), 'FontName', 'Times New Roman'); + +set(figure1,'Units','inches','Position',[(Inch_SS(3)-width)/2 (Inch_SS(4)-height)/2 width height]); +print(figure1, '-dsvg','-noui','plot_results'); +print(figure1, '-dpng','-r300','plot_results'); + +function switch_speed_calculation(speed_calculation_type) + % Define maps for speed calculation models + speed_calculation_models = containers.Map( ... + {'lowPassFilter', 'pllEncoder', 'observer'}, ... + {'lowPassFilter', 'pllEncoder', 'observer'} ... + ); + + if ~isKey(speed_calculation_models, speed_calculation_type) + error('Unknown speed calculation type: %s. Choose from: %s', speed_calculation_type, strjoin(keys(speed_calculation_models), ', ')); + end + + speed_calculation_name = speed_calculation_models(speed_calculation_type); + + % Load the referenced models + load_system(speed_calculation_name); + + % Update the reference blocks + set_param('speedControlSimulation', 'ModelName', speed_calculation_name); + + fprintf('Speed calculation block has been switched to referenced model of %s and %s\n', controller_name); +end \ No newline at end of file diff --git a/source/getting-started/control-with-amdc/encoder-fb/simulink/speedControlSimulation.slx b/source/getting-started/control-with-amdc/encoder-fb/simulink/speedControlSimulation.slx new file mode 100644 index 00000000..42238ba6 Binary files /dev/null and b/source/getting-started/control-with-amdc/encoder-fb/simulink/speedControlSimulation.slx differ