前回はルンゲ=クッタ法で2自由度の2階の微分方程式(連成振動)の数値計算が行えるところまで確かめた。
今回は、周波数特性のグラフ化まで行う。
主系に対する従系の質量比、ダンパ減衰比、バネ剛性比を変えた状態で周波数特性を比較することで、目的に応じた動吸振器の設計が可能になるだろう。
#ループの打ち切り
%% Store extreme values
if i>2 && ym(i,j,iRk)<ym(i-1,j,iRk) && ym(i-1,j,iRk)>ym(i-2,j,iRk)
yex(s,j,iRk)=ym(i-1,j,iRk);
s=s+1;
end
%% Check the decrese of extreme values
if s>10 && yex(s-1,j,iRk)<(yex(s-2,j,iRk)+yex(s-3,j,iRk)+yex(s-4,j,iRk)+yex(s-5,j,iRk))/4.8
fin(j,iRk)=s;
break
else
[ym(i+1,j,iRm,iRc,iRk),ya(i+1,j,iRm,iRc,iRk),vm(i+1,j,iRm,iRc,iRk),va(i+1,j,iRm,iRc,iRk)] ...
= RungeKutta(ym(i,j,iRm,iRc,iRk),ya(i,j,iRm,iRc,iRk),vm(i,j,iRm,iRc,iRk),va(i,j,iRm,iRc,iRk),Rm(iRm),Rc(iRc),Rk(iRk),Rs(j),zm,dtau*i,dtau);
end
一番下のサンプルコードの、この部分でループの打ち切り判定を行う
おおまかな意味は
①極大値格納
②if 極大値が(手前4つの極大値の和/4.8)より小さい
→減衰しているのでループ打ち切り(打ち切り点を記録)
else 計算続行
である。
この部分を時間ループ、周波数ループ、パラメータ比のループ(Rm,Rc,Rk)の5つの入れ子でループさせる。
打ち切りなし
これでかなり計算量が減るので計算時間が格段に減った。
#パラメータ比ごとの計算
パラメータ比の宣言がこちらである。
Rm = 1;
Rc = 1;
Rk = [0.1,1,10];
ベクトルになっているので、好きに値を変更・追加できる。
パラメータ比ごとに計算させるために、変位、速度の変数が
ym = zeros(Tn+1,Fn,RmN,RcN,RkN);
ya = zeros(Tn+1,Fn,RmN,RcN,RkN);
vm = zeros(Tn+1,Fn,RmN,RcN,RkN);
va = zeros(Tn+1,Fn,RmN,RcN,RkN);
このような形の5次元配列になっている。
各要素ごとにforループを増やせば良いというわけだ。
計算数はTn,Fnで宣言している。ここを増やすことで時間、および周波数の計算数が増加し、精度の高い結果が得られる。
#周波数特性
各周波数ごとに変位の最大値を格納していき、周波数に対応させてプロットさせる。
ここの計算で、無次元化した変位をもとの変位に戻している。($y = x/(F/k_m)$より)
xm(j,iRm,iRc,iRk) = F/km*max(ym(:,j,iRm,iRc,iRk));
xa(j,iRm,iRc,iRk) = F/km*max(ya(:,j,iRm,iRc,iRk));
周波数は$f = R_s/T_m$ なので、それに対応させたプロットをすれば、無次元化ではなくもとの微分方程式の値が算出される。
#サンプルコード
clear
close
hold off
%% Input
RsLow =0; %"1" is Out of Phase , "0" show both
RsHigh =5; % Freq end
Tn = 5000;
Fn = 500;
Rm = [1];
Rc = [1.2];
Rk = [0.1,1,10];
mm = 10;
cm = 0.001;
km = 30;
F = 1; % Force
zm = cm / (2*sqrt(mm*km));
sm = sqrt(km/mm);
Tm = 2*pi/ sm; % Period
%% Loop preparation
% Declaration
ym = zeros(Tn+1,Fn,RmN,RcN,RkN);
ya = zeros(Tn+1,Fn,RmN,RcN,RkN);
vm = zeros(Tn+1,Fn,RmN,RcN,RkN);
va = zeros(Tn+1,Fn,RmN,RcN,RkN);
% Loop variable
RmN = length(Rm);
RcN = length(Rc);
RkN = length(Rk);
dtau = 0.1 *sm;
Rs = RsLow:(RsHigh-RsLow)/Fn:RsHigh;
% For plot
freq = Rs/Tm;
N_freq = sm/(2*pi);
% max variable
xm=zeros(Fn+1,RmN,RcN,RkN);
xa=zeros(Fn+1,RmN,RcN,RkN);
% Loop cutoff variable
yex= zeros(Tn,Fn,RmN,RcN,RkN);
maxI = 0;
fin=zeros(Fn,RmN,RcN,RkN);
%% Calculation
for iRm = 1:RmN
for iRc = 1:RcN
for iRk = 1:RkN
for j=1:Fn % frequency loop
s=1;
for i=1:Tn % time loop
%% Store extreme values
if i>2 && ym(i,j,iRk)<ym(i-1,j,iRk) && ym(i-1,j,iRk)>ym(i-2,j,iRk)
yex(s,j,iRk)=ym(i-1,j,iRk);
s=s+1;
end
%% Check the decrese of extreme values
if s>10 && yex(s-1,j,iRk)<(yex(s-2,j,iRk)+yex(s-3,j,iRk)+yex(s-4,j,iRk)+yex(s-5,j,iRk))/4.8
fin(j,iRk)=s;
break
else
[ym(i+1,j,iRm,iRc,iRk),ya(i+1,j,iRm,iRc,iRk),vm(i+1,j,iRm,iRc,iRk),va(i+1,j,iRm,iRc,iRk)] ...
= RungeKutta(ym(i,j,iRm,iRc,iRk),ya(i,j,iRm,iRc,iRk),vm(i,j,iRm,iRc,iRk),va(i,j,iRm,iRc,iRk),Rm(iRm),Rc(iRc),Rk(iRk),Rs(j),zm,dtau*i,dtau);
end
end
xm(j,iRm,iRc,iRk) = F/km*max(ym(:,j,iRm,iRc,iRk));
xa(j,iRm,iRc,iRk) = F/km*max(ya(:,j,iRm,iRc,iRk));
end
end
end
end
%% Plot
%%%%% Separate type %%%%%
for iRk = 1:RkN
subplot(RkN,1,iRk)
plot(freq,xm(:,1,1,iRk))
xline(N_freq,'--','DisplayName','Natural Frequency')
title(['Rk=',num2str(Rk(iRk))])
end
%%%%% Same area %%%%%
% hold on
% for iRk = 1:RkN
% plot(freq,xm(:,1,1,iRk),'DisplayName',strcat('Rk =',num2str(Rk(iRk))))
% end
% xline(N_freq,'--','DisplayName','Natural Frequency')
% legend()
% hold off
%% Functions
function [x1,x2,u1,u2]=RungeKutta(x1,x2,u1,u2,Rm,Rc,Rk,Rs,zm,tau,dtau)
[Cx1_1,Cx2_1,Cu1_1,Cu2_1] = DifEqu(x1,x2,u1,u2,Rm,Rc,Rk,Rs,zm,tau);
[Cx1_2,Cx2_2,Cu1_2,Cu2_2] = DifEqu(x1+Cx1_1*0.5*dtau,x2+Cx2_1*0.5*dtau,u1+Cu1_1*0.5*dtau,u2+Cu2_1*0.5*dtau,Rm,Rc,Rk,Rs,zm,tau+0.5*dtau);
[Cx1_3,Cx2_3,Cu1_3,Cu2_3] = DifEqu(x1+Cx1_2*0.5*dtau,x2+Cx2_2*0.5*dtau,u1+Cu1_2*0.5*dtau,u2+Cu2_2*0.5*dtau,Rm,Rc,Rk,Rs,zm,tau+0.5*dtau);
[Cx1_4,Cx2_4,Cu1_4,Cu2_4] = DifEqu(x1+Cx1_3*dtau,x2+Cx2_3*dtau,u1+Cu1_3*dtau,u2+Cu2_3*dtau,Rm,Rc,Rk,Rs,zm,tau+dtau);
x1 = x1+dtau*(Cx1_1 + 2*Cx1_2 + 2*Cx1_3 + Cx1_4)/6;
x2 = x2+dtau*(Cx2_1 + 2*Cx2_2 + 2*Cx2_3 + Cx2_4)/6;
u1 = u1+dtau*(Cu1_1 + 2*Cu1_2 + 2*Cu1_3 + Cu1_4)/6;
u2 = u2+dtau*(Cu2_1 + 2*Cu2_2 + 2*Cu2_3 + Cu2_4)/6;
end
function [dym,dya,dvm,dva] = DifEqu(ym,ya,vm,va,Rm,Rc,Rk,Rs,zm,tau)
dym = vm;
dya = va;
dvm = sin(Rs*tau)- 2*zm*vm-ym-Rc*2*zm*(vm-va)-Rk*(ym-ya);
dva = -1/Rm*(Rc*2*zm*(va-vm)+Rk*(ya-ym));
end
#結果
前述の通り2通りのプロットを用意したので順番に見てみよう。
今回はRkだけを3通りの値で変化させて周波数特性を出力した。
Rk = [ 0.1 , 1 , 10 ]
Rk = 0.1およびRk = 10にはピークが1つしか無いように見える。
しかし、よく見ると極小のピークが立っている。
また、破線が主系のみの固有振動数である。つまり、従系(動吸振器)を追加することで共振周波数がシフトすることが確認できた。
どちらのグラフも縦軸が変位、横軸が周波数でプロットしている。
このときの値は無次元化したものではなく、もとの微分方程式の値である。
すなわち、実際に設計に反映できる値である。
#まとめ
今回の記事では動吸振器をモデルにした2自由度振動系の数値計算をmatlabで行った。
個人的にはmatlabはpythonよりも使いやすいと思う。
pythonと比べたとき、
・標準ライブラリが非常に豊富なので、追加インストールなしで使える。
・計算が速い(特に配列の計算)
・変数の値を表示してくれる。(↓画像)
・複数のタスクを開いておける(計算とplotを分割出来る)
この4点が非常に優秀だと感じる。
matlabの計算性能は非常に高いので、膨大なデータの計算をゴリゴリ回したい方は是非挑戦してみてほしい。
(完)