動吸振器の問題を解く（後編）

[動吸振器の問題を解く(1)](https://qiita.com/NagayamaT/items/54325be5c063f9b38d56)の続き

前回はルンゲ＝クッタ法で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.8）より小さい
　→減衰しているのでループ打ち切り（打ち切り点を記録）
　else 計算続行

である。
この部分を時間ループ、周波数ループ、パラメータ比のループ（Rm,Rc,Rk）の5つの入れ子でループさせる。
打ち切りなし
![3.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/923577/7e703452-fc02-4c54-5b1a-e476263897bb.jpeg)

打ち切りあり
![4.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/923577/78700c75-d9ac-95da-013c-c4cf8849facb.jpeg)

これでかなり計算量が減るので計算時間が格段に減った。




#パラメータ比ごとの計算
パラメータ比の宣言がこちらである。

```
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つしか無いように見える。
しかし、よく見ると極小のピークが立っている。
また、破線が主系のみの固有振動数である。つまり、従系（動吸振器）を追加することで共振周波数がシフトすることが確認できた。

![1.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/923577/5d5e9332-70c7-ee4e-2de7-834af48386ed.jpeg)
![2.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/923577/c015fa38-9171-2ab9-fa81-b8d8afe54153.jpeg)

どちらのグラフも縦軸が変位、横軸が周波数でプロットしている。
このときの値は**無次元化したものではなく、もとの微分方程式の値**である。
すなわち、実際に設計に反映できる値である。


#まとめ

今回の記事では動吸振器をモデルにした2自由度振動系の数値計算をmatlabで行った。
個人的にはmatlabはpythonよりも使いやすいと思う。
pythonと比べたとき、
・標準ライブラリが非常に豊富なので、追加インストールなしで使える。
・計算が速い（特に配列の計算）
・**変数の値を表示してくれる。(↓画像)**
・複数のタスクを開いておける（計算とplotを分割出来る）
この4点が非常に優秀だと感じる。

![キャプ.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/923577/758b22f4-22b7-d718-201a-3c25755cde21.png)

matlabの計算性能は非常に高いので、膨大なデータの計算をゴリゴリ回したい方は是非挑戦してみてほしい。

（完）