マシンガンで音を撃ち、弾丸を回収しにいく話

##１．はじめに
この記事はMATLABで音響シミュレーションを行なう例として書いてみました。物理読み物のような感じで見ていただければと思います。

##２．シミュレーションの手法
例題として次のようなものをあげてみます。
![fig1.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/434947/d14341e5-c873-e5a9-3727-9b681d3104c2.png)
この図の下のように振動板があって、図のような波形で一様に振動するとします。このとき、観測点Pにおいて観測される波形はどのようになりますか？　という問題です。

解き方は大きく分けて２通りあり、１つは有限要素法のようにメッシュを切って（伝搬領域を細かく分割するの意味）、解析するものです。演算量は多くなりますが、例えば回折の影響なども加味した結果が得られるのが特徴です。
もう１つの方法は光線法です。今回は光線法による解き方について述べてみます。
（ジュジュツ光線？　ちゃう。ちゃうで）

##３．光線法の手法とMATLABでの記述
まず、振動板がこのままだと解析できないので、細かく分割します。分割のピッチは波形の波長を考慮して決めます。ｎ個に分割したとしましょう。
![fig2.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/434947/776d5363-5404-5140-167e-f195a008ac1d.png)

細かくした微量振動板の座標を(x1,y1),・・・,(xn,yn）とし、微小振動板の間隔をｗとしますと、各振動板のｘ座標は、

```matlab
x = (1:n)*w;
x = x-mean(x);%原点中心に持ってくる
```
こんな感じで表せて（各振動板のy座標はゼロ）、各振動板と観測点（Px,Py）の距離Lは、

```matlab
L = abs(x-Px + 1i*Py); %上下方向は虚軸としてabsでユークリッド距離を求める
```
となり、各振動板から観測点Pまでの伝搬時間tpは、媒質の音速がVcなので、

```matlab
tp = L/Vc;
```

波形も伝搬時間も離散時間系を用いる（サンプリング周期tsとする）と、

```matlab
tc = tp/ts;
```
で、到達時間が下の図のようになったとすると、
![fig3.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/434947/5fdbbb9e-6e81-a966-fd35-0f9b3316689b.png)
この到達時間hv（hv=[6 2 2 0 2 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1]のようになる）と波形Aの畳み込みを行ない、

```matlab
Ap = conv(A,hv);
```
到達波形Apを得ます。
![Fig4.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/434947/0131b409-0541-dfeb-ca1e-e958d82c375c.png)
※到達時間のヒストグラムについては、昨年のアドベントカレンダーで書いた[MATLABで「たたみこみ」を語る](https://qiita.com/Monzo_N/items/8ca510022648fd72adb5)を参照ください。

##４．２層の媒質による伝搬経路
ということで、ここまでは比較的順調に来ました。
ところで、伝搬媒質が１種類でなく２種類になった場合、例えば下の図のようになったとしたらどのようにして各振動板から観測点までの経路を求めるのでしょうか。
![fig5.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/434947/8c0fea96-a3e8-0762-973c-c0aa82a4e71c.png)
媒質１と媒質２の境界で屈折するわけですが、２つの媒質の音速が定まっているので（Vc1,Vc2)、スネルの法則により屈折角を求めることができます。
![fig6.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/434947/cfcc7a40-a8aa-e466-7246-b25afcdc63f5.png)

しかしながら、スネルの法則で簡単に求められるのは、振動板から出て、媒質境界のどの部分を通過したら屈折角がいくつで（結果として壁のどの部分に到達するか）ということであり、振動板と観測点の位置が定められているときに、媒質境界のどこを通るかというのはなかなか計算が難しいものです。いわんや境界面が下図のように曲面においておや、ということになります。
![fig7.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/434947/202535eb-db28-ab26-49e7-4eec4c23e0c3.png)

筆者は（いきなり論文口調）、当初、はさみうち法において境界の通過点を求めようとしたのですが、残念ながらあまり能率の良い手法とはなりませんでした。

##５．そこでマシンガン
すみません、マシンガンじゃなくて重機関銃だったみたいです。これです。
![重機関銃.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/434947/785e5e5c-97a1-ff29-d3b6-1d3c3a83f102.jpeg)
台座があって、銃が固定されてて、回転することで向きが変えられるやつです。これをそれぞれの微小振動板のところに置き、角度を変えながら撃ちます。
どの銃も同時に発砲するものとします。
![fig9.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/434947/e52d24bf-fff2-8aea-70e8-95b8d589a721.png)
こんな感じに角度を変えて撃ち、また変えて撃つ、というのを繰り返していきます。
結果として、壁面にこんな感じに弾痕が残ります。
（実際にはもっと密度が濃くならないと誤差が大きいです）。
![fig10.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/434947/c5c9344a-f525-3549-80dc-926cdc6151fa.png)
これらの弾痕には、「どの銃（振動板）から撃たれたか」「境界面のどこを通ってきたか」の情報が含まれています。
と、いうことは、その弾痕をあけた弾が、銃から壁までにかかったフライトタイムがわかります。
次に壁を微小間隔で区切ります。
![fig11.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/434947/1ccee2f4-5d46-19e9-d082-a68e05da757c.png)

今、観測点Ｐがここにあるとすると、Ｐを含む区切りの中の弾痕に関する弾のフライトタイムを計算し、まとめます。結果は、こうなります。
![fig3.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/434947/bd518ded-37c2-510e-6a9a-bbac2b406215.png)

なので、あとは波形と畳み込みすれば、Ｐ点（正確にはＰ点付近）で観測される音の波形が分かる、というわけです。
![Fig4.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/434947/f3125217-1bae-fd56-8aa4-3e4b74bfa729.png)

##６．MATLAB的な見せ場は？

すみません、意外にありませんでした。

直線と円弧の交点座標の計算は２次方程式の解の公式で解いていますし。

```matlab
%直線 y=Ax+B と　x軸上の円の弧（直径:R,弧とx軸の交点のx座標:L,
%T:弧が左（下）に凸が-1、右（上）に凸が+1
%媒質１，２の音速:Vc1,Vc2
%直線と弧の交点の座標:x2,y2
%媒質２における直線の方程式　y-A2 x +B2

C=L-R*T;

aa=A.^2+1;
bb=2*(A.*B-C);
cc=C^2+B.^2-R^2;

x2dum(1,:)=(-bb+sqrt(bb.^2-4*aa.*cc))./(2*aa);
x2dum(2,:)=(-bb-sqrt(bb.^2-4*aa.*cc))./(2*aa);

x2dum1=x2dum(1,:);
Ix1=find(imag(x2dum1)~=0);
if(isempty(Ix1)~=1)
	x2dum(1,Ix1)=NaN;
	x2dum(2,Ix1)=NaN;
end
y2dum(1,:)=A.*x2dum(1,:)+B;
y2dum(2,:)=A.*x2dum(2,:)+B;
if(T>0)
    [x2 x2num]=max(x2dum);
else
    [x2 x2num]=min(x2dum);
end

Ix2=find(x2num==1);
x2=x2dum(2,:);
y2=y2dum(2,:);
x2(Ix2)=x2dum(1,Ix2);
y2(Ix2)=y2dum(1,Ix2);
```
あとは、壁全体のデータからＰ点付近のデータを取り出して計算するあたり。

```matlab
% ANGall:全弾丸の弾痕の位置（角度表示）
% Pang:観測点Pの位置（角度表示）
% ptcang:壁の分割ピッチ（角度表示）
% CNTall:全弾丸のフライト時間（サンプリング時間でカウント）
% A:振動波形

% 観測点Ｐ付近のデータを抜き出しCjに入力
Cj= ANGall(:)>=(Pang-ptcang/2) & ANGall(:)<(Pang+ptcang/2);

% 該当する弾丸のフライト時間をCNTdumに入力
CNTsub=CNTall(Cj);

%インパルス応答（フライトタイムの集計）を計算
h=histogram(CNTsub,min(CNTsub):max(CNTsub));
HISTcnt=h.Value;

%振動波形との畳み込み
AA=conv(A,HISTcnt);
```

ということで。
おつかれさまでした。