Loading [MathJax]/extensions/MathEvents.js

MATLABで学ぶ音響工学 閉空間(直方体)1


記事の書き方にもだんだん慣れてきました。これからはもう少し見やすさも意識して書きたいと思います!

さて、今回は閉空間(直方体)の共振周波数と音響モードを求めたいと思います。基本的に理論式などは教科書などの文献を参考にしているので、諸元を記載したいと思います。本記事で参考にしているのは下記文献なので、詳しい導出過程は下記文献でご確認お願いします。

直方体の音響空間

 

{k_n}^2 = \frac{{ω_n}^2}{{c_o}^2}=[\frac{n_1\pi}{L_1}]^2+[\frac{n_2\pi}{L_2}]^2+[\frac{n_3\pi}{L_3}]^2
参考文献ではkn^2が固有値と述べられています(これが固有値なのかの議論はここではしません。)
wnは固有角振動数、nはモード次数です。(モード次数というより、「節の数」だと思ってください。)

この直方体の壁が剛体(反射率が1)のときモードベクトルψnは下記のように表すことができます。
{\psi_n}=\sqrt{\epsilon_1 \epsilon_2 \epsilon_3} \ cos{\frac{n_1\pi x_1}{L_1}} \ cos{\frac{n_2\pi x_2}{L_2}} \ cos{\frac{n_3\pi x_3}{L_3}}
ここでεは正規化係数であり、上記式では下記関係が成立します。
L_1 > L_2 > L_3
if n_{axis} = 0 \epsilon_{axis} = 1
elseif n_1=n_2=n_3 = 0 \epsilon_{axis} = 0
else n_{axis} \neq 0 \epsilon_{axis} = 2

一連の式展開のプログラムを下に添付しましたので、ご確認ください。

振動のモード法で説明したのと同様に、音響についてもモードベクトルの重ね合わせで音場を表現できます。そのため上記ψが計算できれば、音場を表現することができます。また、入力点から応答点(受音点)までの周波数応答関数(Frequency Response Function:FRF)を計算することができるようになります。
ここらへんの説明は次回したいと思います。
今回はこのへんでGood luck

 

メインコード(実行コード)


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
clear all
% % % % size of rectangular parallelopiped
L1=3;
L2=2;
L3=1;
V=L1*L2*L3;
% % % % Constant value
co=344;
rho=1.205;
% % % % modal numbers
n_max=100;
Combi=combinator(n_max,3,'p','r')-1;
% % % % setting max frequency
f_max=10*10^3;
% % % % xi
xi=[0.5 0.5 0.5];
% % % % function wn
[wn]=angular_frequency(Combi,L1,L2,L3,co);
% % % % function psi psi(modal number , x_number)
[psi]=Psi(xi_front,Combi,L1,L2,L3);
[wn,I] =sortrows(wn);

1
2
3
4
5
6
7
8
9
10
11
12
function [wn]=angular_frequency(Combi,L1,L2,L3,co)
wn=zeros(size(Combi,1),1);
for n=1:size(Combi,1)
    wn(n,1)=.....
        co*sqrt(....
        (Combi(n,1)*pi/L1)^2.....
        + (Combi(n,2)*pi/L2)^2.....
        + (Combi(n,3)*pi/L3)^2.....
        );
end
 
end

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
function [psix]=Psi(xi,Combi,L1,L2,L3)
psix=zeros(size(Combi,1),size(xi,1));
for nx=1:size(xi,1)
    for n=1:size(Combi,1)
                if Combi(n,1)==0               
                    e1=1;           
                else
                    e1=2;           
                end
                if Combi(n,2)==0               
                    e2=1;
                else
                    e2=2;
                end
                if Combi(n,3)==0
                    e3=1;
                else
                    e3=2;
                end
                psix( n , nx  )=.....               
            sqrt(e1*e2*e3)*....
            cos(Combi(n,1)*pi* xi(nx,1)/L1)*....
            cos(Combi(n,2)*pi* xi(nx,2)/L2)*....
            cos(Combi(n,3)*pi* xi(nx,3)/L3);
             
    end
end
 
end

MATLAB centralより

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
function [A] = combinator(N,K,s1,s2)
%COMBINATOR  Perform basic permutation and combination samplings.
% COMBINATOR will return one of 4 different samplings on the set 1:N, 
% taken K at a time.  These samplings are given as follows:
%   
% PERMUTATIONS WITH REPETITION/REPLACEMENT
%   COMBINATOR(N,K,'p','r')  --  N >= 1, K >= 0
% PERMUTATIONS WITHOUT REPETITION/REPLACEMENT
%   COMBINATOR(N,K,'p')  --  N >= 1, N >= K >= 0
% COMBINATIONS WITH REPETITION/REPLACEMENT
%   COMBINATOR(N,K,'c','r')  --  N >= 1, K >= 0
% COMBINATIONS WITHOUT REPETITION/REPLACEMENT
%   COMBINATOR(N,K,'c')  --  N >= 1, N >= K >= 0
%
% Example:
%
% To see the subset relationships, do this: 
%     combinator(4,2,'p','r')  % Permutations with repetition
%     combinator(4,2,'p')      % Permutations without repetition
%     combinator(4,2,'c','r')  % Combinations with repetition
%     combinator(4,2,'c')      % Combinations without repetition
%
%
% If it is desired to use a set other than 1:N, simply use the output from
% COMBINATOR as an index into the set of interest.  For example:
%
%    MySet = ['a' 'b' 'c' 'd'];
%    MySetperms = combinator(length(MySet),3,'p','r'); % Take 3 at a time.
%    MySetperms = MySet(MySetperms)
%   
%  
%    Class support for input N:
%       float: double, single
%       integers: int8,int16,int32
%
%
% Notes:
% All of these algorithms have the potential to create VERY large outputs.
% In each subfunction there is an anonymous function which can be used to
% calculate the number of row which will appear in the output.  If a rather
% large output is expected, consider using an integer class to conserve
% memory.  For example:
%
%          M = combinator(int8(30),3,'p','r');  % NOT uint8(30)
%
% will take up 1/8 the memory as passing the 30 as a double.  See the note
% below on using the MEX-File.
%
% To make your own code easier to read, the fourth argument can be any
% string.  If the string begins with an 'r' (or 'R'), the function
% will be called with the replacement/repetition algorithm.  If not, the
% string will be ignored. 
% For instance, you could use:  'No replacement', or 'Repetition allowed'
% If only two inputs are used, the function will assume 'p','r'.
% The third argument must begin with either a 'p' or a 'c' but can be any
% string beyond that.
%
% The permutations with repetitions algorithm uses cumsum.  So does the
% combinations without repetition algorithm for the special case of K=2.
% Unfortunately, MATLAB does not allow cumsum to work with integer classes.
% Thus a subfunction has been placed at the end for the case when these
% classes are passed.  The subfunction will automatically pass the
% necessary matrix to the built-in cumsum when a single or double is used.
% When an integer class is used, the subfunction first looks to see if the
% accompanying MEX-File (cumsumall.cpp) has been compiled.  If not,
% then a MATLAB For loop is used to perform the cumsumming.  This is
% VERY slow!  Therefore it is recommended to compile the MEX-File when
% using integer classes.
% The MEX-File was tested by the author using the Borland 5.5 C++ compiler.
%
% See also, perms, nchoosek, npermutek (on the FEX)
%            
% Author:   Matt Fig
% Contact:  popkenai@yahoo.com
% Date:     5/30/2009
%
 
ng = nargin;
 
if ng == 2
    s1 = 'p';
    s2 = 'r';
elseif ng == 3
    s2 = 'n';
elseif ng ~= 4
    error('Only 2, 3 or 4 inputs are allowed.  See help.')
end
 
if isempty(N) || K == 0
   A = []; 
   return
elseif numel(N)~=1 || N<=0 || ~isreal(N) || floor(N) ~= N
    error('N should be one real, positive integer. See help.')
elseif numel(K)~=1 || K<0 || ~isreal(K) || floor(K) ~= K
    error('K should be one real non-negative integer. See help.')
end
 
STR = lower(s1(1)); % We are only interested in the first letter.
 
if ~strcmpi(s2(1),'r')
    STR = [STR,'n'];
else
   STR = [STR,'r'];
end
 
try
    switch STR
        case 'pr'
            A = perms_rep(N,K);     % strings
        case 'pn'
            A = perms_no_rep(N,K);  % permutations
        case 'cr'
            A = combs_rep(N,K);     % multichoose
        case 'cn'
            A = combs_no_rep(N,K);  % choose
        otherwise
            error('Unknown option passed.  See help')
    end
catch
    rethrow(lasterror) % Throw error from here, not subfunction.
    % The only error thrown should be K>N for non-replacement calls.
end
 
 
 
 
function PR = perms_rep(N,K)
% This is (basically) the same as npermutek found on the FEX.  It is the 
% fastest way to calculate these (in MATLAB) that I know. 
% pr = @(N,K) N^K;  Number of rows.
% A speed comparison could be made with COMBN.m, found on the FEX.  This
% is an excellent code which uses ndgrid.  COMBN is written by Jos.
%
%      % All timings represent the best of 4 consecutive runs.
%      % All timings shown in subfunction notes used this configuration:
%      % 2007a 64-bit, Intel Xeon, win xp 64, 16 GB RAM 
%      tic,Tc = combinator(single(9),7,'p','r');toc 
%      %Elapsed time is 0.199397 seconds.  Allow Ctrl+T+C+R on block
%      tic,Tj = combn(single(1:9),7);toc 
%      %Elapsed time is 0.934780 seconds.
%      isequal(Tc,Tj)  % Yes
 
if N==1
   PR = ones(1,K,class(N));
   return
elseif K==1
    PR = (1:N).';
    return
end
 
CN = class(N);
M = double(N);  % Single will give us trouble on indexing.
L = M^K;  % This is the number of rows the outputs will have.
PR = zeros(L,K,CN);  % Preallocation.
D = ones(1,N-1,CN);  % Use this for cumsumming later.
LD = M-1;  % See comment on N.
VL = [-(N-1) D].';  % These values will be put into PR.
% Now start building the matrix.
TMP = VL(:,ones(L/M,1,CN));  % Instead of repmatting.
PR(:,K) = TMP(:);  % We don't need to do two these in loop.
PR(1:M^(K-1):L,1) = VL;  % The first column is the simplest.
% Here we have to build the cols of PR the rest of the way.
for ii = K-1:-1:2
    ROWS = 1:M^(ii-1):L;  % Indices into the rows for this col.
    TMP = VL(:,ones(length(ROWS)/(LD+1),1,CN));  % Match dimension.
    PR(ROWS,K-ii+1) = TMP(:);  % Build it up, insert values.
end
 
PR(1,:) = 1;  % For proper cumsumming.
PR = cumsum2(PR);  % This is the time hog.
 
 
 
 
function PN = perms_no_rep(N,K)
% Subfunction: permutations without replacement.
% Uses the algorithm in combs_no_rep as a basis, then permutes each row.
% pn = @(N,K) prod(1:N)/(prod(1:(N-K)));  Number of rows.
 
if N==K
    PN = perms_loop(N);  % Call helper function.
%     [id,id] = sort(PN(:,1));  %#ok  Not nec., uncomment for nice order.
%     PN = PN(id,:);  % Return values.
    return
elseif K==1
    PN = (1:N).';  % Easy case.
    return
end
 
if K>N  % Since there is no replacement, this cannot happen.
    error(['When no repetitions are allowed, '...
           'K must be less than or equal to N'])
end
 
M = double(N);  % Single will give us trouble on indexing.
WV = 1:K;  % Working vector.
lim = K;   % Sets the limit for working index.
inc = 1;   % Controls which element of WV is being worked on.
BC = prod(M-K+1:M);  % Pre-allocation of return arg.
BC1 = BC / ( prod(1:K)); % Number of comb blocks.
PN = zeros(round(BC),K,class(N));
L = prod(1:K) ;  % To get the size of the blocks.
cnt = 1+L;
P = perms_loop(K);  % Only need to use this once.
PN(1:(1+L-1),:) = WV(P);  % The first row.
 
for ii = 2:(BC1 - 1);
    if logical((inc+lim)-N)  % The logical is nec. for class single(?)
        stp = inc;  % This is where the for loop below stops.
        flg = 0;  % Used for resetting inc.
    else
        stp = 1;
        flg = 1;
    end
     
    for jj = 1:stp
        WV(K  + jj - inc) = lim + jj;  % Faster than a vector assignment!
    end
                                                                              
    PN(cnt:(cnt+L-1),:) = WV(P);  % Assign block.
    cnt = cnt + L;  % Increment base index.   
    inc = inc*flg + 1;  % Increment the counter.
    lim = WV(K - inc + 1 );  % lim for next run.
end
 
V = (N-K+1):N;  % Final vector.
PN(cnt:(cnt+L-1),:) = V(P);  % Fill final block.
% The sorting below is NOT necessary.  If you prefer this nice
% order, the next two lines can be un-commented.
% [id,id] = sort(PN(:,1));  %#ok  This is not necessary!
% PN = PN(id,:);  % Return values.
 
 
 
 
function P = perms_loop(N)
% Helper function to perms_no_rep.  This is basically the same as the
% MATLAB function perms.  It has been un-recursed for a runtime of around 
% half the recursive version found in perms.m  For example:
%
%      tic,Tp = perms(1:9);toc
%      %Elapsed time is 0.222111 seconds.  Allow Ctrl+T+C+R on block
%      tic,Tc = combinator(9,9,'p');toc 
%      %Elapsed time is 0.143219 seconds.
%      isequal(Tc,Tp)  % Yes
 
M = double(N); % Single will give us trouble on indexing.
P = 1;  % Initializer.
G = cumprod(1:(M-1));  % Holds the sizes of P.
CN = class(N);
 
for n = 2:M
    q = P;
    m = G(n-1);
    P = zeros(n*m,n,CN);
    P(1:m, 1) = n;
    P(1:m, 2:n) = q;
    a = m + 1;
     
    for ii = n-1:-1:1,
        t = q;
        t(t == ii) = n;
        b = a + m - 1;
        P(a:b, 1) = ii;
        P(a:b, 2:n) = t;
        a = b + 1;
    end
end
 
 
 
 
function CR = combs_rep(N,K)
% Subfunction multichoose:  combinations with replacement.
% cr = @(N,K) prod((N):(N+K-1))/(prod(1:K)); Number of rows.
 
M = double(N);  % Single will give us trouble on indexing.
WV = ones(1,K,class(N));  % This is the working vector.
mch = prod((M:(M+K-1)) ./ (1:K));  % Pre-allocation.
CR = ones(round(mch),K,class(N));
 
for ii = 2:mch
    if WV(K) == N
        cnt = K-1;  % Work backwards in WV.
         
        while WV(cnt) == N
            cnt = cnt-1;  % Work backwards in WV.
        end
 
        WV(cnt:K) = WV(cnt) + 1;  % Fill forward.
    else
        WV(K) = WV(K)+1;   % Keep working in this group.
    end
 
    CR(ii,:) = WV;
end
 
 
 
 
function CN = combs_no_rep(N,K)
% Subfunction choose:  combinations w/o replacement.
% cn = @(N,K) prod(N-K+1:N)/(prod(1:K));  Number of rows.
% Same output as the MATLAB function nchoosek(1:N,K), but often faster for
% larger N.
% For example:
%
%      tic,Tn = nchoosek(1:17,8);toc
%      %Elapsed time is 0.430216 seconds.  Allow Ctrl+T+C+R on block
%      tic,Tc = combinator(17,8,'c');toc 
%      %Elapsed time is 0.024438 seconds.
%      isequal(Tc,Tn)  % Yes
 
if K>N
    error(['When no repetitions are allowed, '...
           'K must be less than or equal to N'])
end
 
M = double(N);  % Single will give us trouble on indexing.
 
if K == 1
   CN =(1:N).';  % These are simple cases.
   return
elseif K == N
    CN = (1:N);
    return
elseif K==2 && N>2  % This is an easy case to do quickly.
    BC = (M-1)*M / 2;
    id1 = cumsum2((M-1):-1:2)+1;
    CN = zeros(BC,2,class(N));
    CN(:,2) = 1;
    CN(1,:) = [1 2];
    CN(id1,1) = 1;
    CN(id1,2) = -((N-3):-1:0);
    CN = cumsum2(CN);
    return
end
 
WV = 1:K;  % Working vector.
lim = K;   % Sets the limit for working index.
inc = 1;   % Controls which element of WV is being worked on.
BC = prod(M-K+1:M) / (prod(1:K));  % Pre-allocation.
CN = zeros(round(BC),K,class(N));
CN(1,:) = WV;  % The first row.
 
for ii = 2:(BC - 1);  
    if logical((inc+lim)-N) % The logical is nec. for class single(?)
        stp = inc;  % This is where the for loop below stops.
        flg = 0;  % Used for resetting inc.
    else
        stp = 1;
        flg = 1;
    end
     
    for jj = 1:stp
        WV(K  + jj - inc) = lim + jj;  % Faster than a vector assignment.
    end
     
    CN(ii,:) = WV;  % Make assignment.
    inc = inc*flg + 1;  % Increment the counter.
    lim = WV(K - inc + 1 );  % lim for next run.
end
   
CN(ii+1,:) = (N-K+1):N;
 
 
 
 
function A = cumsum2(A)
%CUMSUM2, works with integer classes.
% Duplicates the action of cumsum, but for integer classes.
% If Matlab ever allows cumsum to work for integer classes, we can remove
% this.
 
if isfloat(A)
    A = cumsum(A);  % For single and double, use built-in.
    return
else
    try
        A = cumsumall(A);  % User has the MEX-File ready?
    catch
        warning('Cumsumming by loop.  MEX cumsumall.cpp for speed.') %#ok
        for ii = 2:size(A,1)
            A(ii,:) = A(ii,:) + A(ii-1,:); % User likes it slow.
        end
    end
end

コメント