tp@8
|
1 function simulateBinauralSignals(inputstruct)
|
tp@8
|
2 %Creates .wav file of 2sec long binaural signals for specific board dimensions and gaussian white noise stimulus
|
tp@8
|
3 %
|
tp@8
|
4 % INPUTS:
|
tp@8
|
5 % The input must be a structure with fields:
|
tp@8
|
6 % .dist (1st input argument) is the distance in meters
|
tp@8
|
7 % .azim (2nd input argument) is the azimuth in degrees (0 means straight ahead, positive angles are left and negative
|
tp@8
|
8 % are right)
|
tp@8
|
9 % .orient (3rd input argument) must be either 'horz' or 'angled' corresponding to flat and angled descriptions in
|
tp@8
|
10 % Papadopoulos et al. BSPC 2011.
|
Chris@10
|
11 % .dirweight (4th input argument) must be a nonnegative real scalar determining what is the relative weight of the
|
tp@8
|
12 % emission path to the echo path (i.e. due to directivity focus in the frontal direction of the source, the emission
|
tp@8
|
13 % which is directed upwards and backwards in our specific geometry is significantly attenuated, typically by factor in
|
tp@8
|
14 % the vicinity of 0.2)
|
Chris@12
|
15 % .outdir (5th input argument) must be the directory in which the wave file
|
Chris@10
|
16 % is to be written. It may be an absolute path, or relative to the current
|
Chris@12
|
17 % directory. Temporary files will be written in the same directory.
|
Chris@12
|
18 % .outname (6th input argument) must be the name of the wave file to write, within the outdir, without the .wav suffix (which will be added).
|
tp@8
|
19 %
|
tp@8
|
20
|
tp@8
|
21 %% Internal workings description
|
tp@8
|
22 %
|
tp@8
|
23 % Center of spherical coordinates system is taken to be the center of head. The azimuth, elevation and distance
|
tp@8
|
24 % coordinates are as in matlabs sph2cart function (azimuth and elevation are angular displacements from the positive
|
tp@8
|
25 % x-axis and from the x-y plane, respectively) with positive x axis taken to be extending to the right of the head from
|
tp@8
|
26 % top view, positive y axis to be extending forward of the head in top view and positive z axis to be extending upwards
|
tp@8
|
27 % in top view.
|
tp@8
|
28 %
|
tp@8
|
29 % Board dimensions are defined as
|
tp@8
|
30 % params.board_size_x (width in meters for the 'center' orientation of Papadopoulos et al. BSPC 2011)
|
tp@8
|
31 % params.board_size_y (depth in meters for the 'center' orientation of Papadopoulos et al. BSPC 2011)
|
tp@8
|
32 % params.board_size_z (height in meters for the 'center' orientation of Papadopoulos et al. BSPC 2011)
|
tp@8
|
33 %
|
tp@8
|
34 % Board center position is defined as
|
tp@8
|
35 % params.board_distance (distance in meters from coords origin to center of board following coordinate system described
|
tp@8
|
36 % above), can be row vector.
|
tp@8
|
37 % params.board_azim (azimuth in radians of the center of the board following coordinate system described above),
|
tp@8
|
38 % can be row vector.
|
tp@8
|
39 % params.board_elev (elevation in radians of the center of the board following coordinate system described above),
|
tp@8
|
40 % must be scalar
|
tp@8
|
41 %
|
tp@8
|
42 % params.board_orientation scalar or 1x2 cell with elements 'horz' or/and 'angled'
|
tp@8
|
43 % Board is taken to always be vertically positioned (i.e. with its width-height plane vertical to the y coordinate) and
|
tp@8
|
44 % two cases of orientation are considered: horizontal and angled corresponding to flat and angled descriptions in
|
tp@8
|
45 % Papadopoulos et al. BSPC 2011.
|
tp@8
|
46 %
|
tp@8
|
47 % params.source_down non-negative scalar in meters
|
tp@8
|
48 % params.source_front non-negative scalar in meters
|
tp@8
|
49 % The source is assumed to always be in front of the chest and below the head. (params.source_down and
|
tp@8
|
50 % params.source_front cannot both be 0)
|
tp@8
|
51 %
|
tp@8
|
52 %
|
tp@8
|
53 % params.horz_disamb string which can be either 'BSPC2011' or 'collocated'. If equal to 'BSPC2011' then board distance
|
tp@8
|
54 % for the horizontal (flat) case is as described in Papadopoulos et al. BSPC 2011, i.e. the board
|
tp@8
|
55 % distance is the distance between the centre of the head and the PLANE OF THE BOARD.
|
tp@8
|
56 % Alternatively, in the 'collocated' case, the board distance in the horizontal (flat) case is taken
|
tp@8
|
57 % as the distance between the centre of the head and the centre of the board
|
tp@8
|
58 %
|
tp@8
|
59 % NOTE: in the 'BSPC2011' case of params.horz_disamb, it is easy to see that the geometry is ill-specified for board
|
tp@8
|
60 % positions far away from the median plane.
|
tp@8
|
61 %
|
tp@8
|
62 % OUTPUTS:
|
tp@8
|
63 %
|
tp@8
|
64 % --- simulation_data is a structure with the following fields:
|
tp@8
|
65 % - simulation_data.echo is a cell of dimensions
|
tp@8
|
66 % length(params.board_dist) x length(params.board_azim) x length(params.board_orientation)
|
tp@8
|
67 % each element of which is a 2-row matrix with the left (top row) and right (bottom row) ear responses corresponding the
|
tp@8
|
68 % echo only.
|
tp@8
|
69 %
|
tp@8
|
70 % - simulation_data.emission is a cell of dimensions
|
tp@8
|
71 % length(params.board_dist) x length(params.board_azim) x length(params.board_orientation)
|
tp@8
|
72 % each element of which is a 2-row matrix with the left (top row) and right (bottom row) ear responses corresponding the
|
tp@8
|
73 % direct source-to-receiver path only. (NOTE: source term (binaural_irs_emission) does not need to be computed for each
|
tp@8
|
74 % different board distance/azimuth/orientation as it is the same irs but containing a different number of trailing zero
|
tp@8
|
75 % samples. I include this redundancy because it simplified the computation a bit and also because this way the emission
|
tp@8
|
76 % part is always equal in length with the corresponding echo part and can be added easier)
|
tp@8
|
77 %
|
tp@8
|
78 % Adding any given
|
tp@8
|
79 % directivity_weighting * simulation_data.emission{ii,jj,kk}(1,:) + simulation_data.echo{ii,jj,kk}(1,:)
|
tp@8
|
80 % for any given ii, jj, kk will give the total left ear IR and the same for right ear by
|
tp@8
|
81 % directivity_weighting * simulation_data.emission{ii,jj,kk}(2,:) + simulation_data.echo{ii,jj,kk}(2,:)
|
tp@8
|
82 %
|
tp@8
|
83 % - simulation_data.params is the stucture params described above
|
tp@8
|
84 % - simulation_data.board_coords is an array of dimensions
|
tp@8
|
85 % 8 x 3 x length(params.board_dist) x length(params.board_azim) x length(params.board_orientation)
|
tp@8
|
86 % containing the x y z coordinates (2nd dimension) of the 8 edges (1st dimension) of the board geometries for different
|
tp@8
|
87 % board distances, azimuths and orientations.
|
tp@8
|
88 % - simulation_data.azerr and simulation_data.elerr are arrays of dimensions
|
tp@8
|
89 % 2 x 1+length(params.board_azim))
|
tp@8
|
90 % which contain the error (in degrees) between the azimuth and elevation respectively of the HRTFs that are used (as
|
tp@8
|
91 % existing in the CIPIC spherical grid) and the actual board center azimuth and elevation.
|
tp@8
|
92 %
|
tp@8
|
93 %
|
tp@8
|
94 %
|
tp@8
|
95 % DEVELOPMENT NOTES
|
tp@8
|
96 %
|
tp@8
|
97 % TODO: include case of multiple boards and of non-vertically oriented boards (i.e. all cases of pitch, roll, yaw for
|
tp@8
|
98 % board orientation)
|
tp@8
|
99 %
|
tp@8
|
100 % TODO: include geometrical description for all possible positions of the source
|
tp@8
|
101 %
|
tp@8
|
102 % TODO: include validateattributes for all parameters
|
tp@8
|
103 %
|
tp@8
|
104 % TODO: include parameter controls for specorder (now set to 1), difforder (now set to 1), elemsize (now set to [1]) and
|
tp@8
|
105 % nedgesubs (now set to 2)
|
tp@8
|
106 %
|
tp@8
|
107 %
|
tp@8
|
108
|
tp@8
|
109 %% Take inputs args from input structure
|
tp@8
|
110 dist = inputstruct.dist;
|
tp@8
|
111 azim = inputstruct.azim;
|
tp@8
|
112 orient = inputstruct.orient;
|
tp@8
|
113 dirweight = inputstruct.dirweight;
|
Chris@12
|
114 outdir = inputstruct.outdir;
|
Chris@12
|
115 outname = inputstruct.outname;
|
tp@8
|
116
|
tp@8
|
117 %% Validate attributes
|
tp@8
|
118 validateattributes(dist,{'double'},{'scalar','>',0})
|
tp@8
|
119 validateattributes(azim,{'double'},{'scalar','<=',90,'>=',-90})
|
tp@8
|
120 validateattributes(orient,{'char'},{'nonempty'})
|
tp@8
|
121 validateattributes(dirweight,{'double'},{'scalar','>',0})
|
Chris@12
|
122 validateattributes(outdir,{'char'},{'nonempty'})
|
Chris@12
|
123 validateattributes(outname,{'char'},{'nonempty'})
|
tp@8
|
124
|
tp@8
|
125 %% Computation parameters (Some fixed, some taken from input arguments)
|
tp@8
|
126 params.board_size_x = .55;
|
tp@8
|
127 params.board_size_y = .02;
|
tp@8
|
128 params.board_size_z = .55;
|
tp@8
|
129
|
tp@8
|
130 params.board_azim = mod(90+azim,360)*pi/180;
|
tp@8
|
131 params.board_elev = 0*pi/180;
|
tp@8
|
132 params.board_dist = dist;
|
tp@8
|
133 %
|
tp@8
|
134 % params.board_azim = mod(90+[-17 17],360)*pi/180; % corresponds to a board 17degress to the right and a board 17
|
tp@8
|
135 % degrees to the left. The elements of the vector ([-17 17] in this example) must be in the range (-180,180] and are
|
tp@8
|
136 % converted by the line in this example to the coordinate system described in the help preample.
|
tp@8
|
137 %
|
tp@8
|
138 % params.board_elev = 10*pi/180; % corresponds to a board 10 degrees above the azimuthal plane. The value (0 in this
|
tp@8
|
139 % example) must be in the range [-90,90] and is converted by the line in this example to the coordinate system described
|
tp@8
|
140 % in the help preample.
|
tp@8
|
141 %
|
tp@8
|
142 % params.board_dist is in meters and it can be a vector of (strictly positive) distances as needed
|
tp@8
|
143
|
tp@8
|
144 params.board_orientation = {validatestring(orient,{'horz','angled'})};
|
tp@8
|
145
|
tp@8
|
146 params.source_down = 0.25; % Take the source to always be directly below the chin.
|
tp@8
|
147 params.source_front = 0.05; % Take the source to always be directly in front of chest.
|
tp@8
|
148
|
tp@8
|
149 params.Fs = 44100;
|
tp@8
|
150 params.Cair = 344;
|
tp@8
|
151 params.Rhoair = 1.21;
|
tp@8
|
152 params.WavDurationSec = 2;
|
tp@8
|
153 params.WavScaling = 0.1;
|
tp@8
|
154 params.dirweight = dirweight;
|
tp@8
|
155
|
tp@8
|
156 params.horz_disamb = 'BSPC2011';
|
Chris@12
|
157 params.wavfilename = [outdir filesep outname '.wav']
|
tp@8
|
158
|
tp@8
|
159 %% Compute free field (no head) IRs
|
tp@8
|
160
|
tp@8
|
161 temp_edges = [
|
tp@8
|
162 +params.board_size_x/2 +params.board_size_y/2 +params.board_size_z/2
|
tp@8
|
163 -params.board_size_x/2 +params.board_size_y/2 +params.board_size_z/2
|
tp@8
|
164 -params.board_size_x/2 -params.board_size_y/2 +params.board_size_z/2
|
tp@8
|
165 +params.board_size_x/2 -params.board_size_y/2 +params.board_size_z/2
|
tp@8
|
166 +params.board_size_x/2 +params.board_size_y/2 -params.board_size_z/2
|
tp@8
|
167 -params.board_size_x/2 +params.board_size_y/2 -params.board_size_z/2
|
tp@8
|
168 -params.board_size_x/2 -params.board_size_y/2 -params.board_size_z/2
|
tp@8
|
169 +params.board_size_x/2 -params.board_size_y/2 -params.board_size_z/2
|
tp@8
|
170 ];
|
tp@8
|
171
|
tp@8
|
172 FFresp{length(params.board_dist),length(params.board_azim),length(params.board_orientation)} = [];
|
tp@8
|
173 binaural_irs_echo{length(params.board_dist),length(params.board_azim),length(params.board_orientation)} = [];
|
tp@8
|
174 binaural_irs_emission{length(params.board_dist),length(params.board_azim),length(params.board_orientation)} = [];
|
tp@8
|
175 % NOTE: in the above initialisation the source term (binaural_irs_emission) does not need to be computed for each
|
tp@8
|
176 % different board distance/azimuth/orientation as it is the same. I include this redundancy so that the emission
|
tp@8
|
177 % binaural irs that I compute each time in in a few lines are correct, i.e. I can check that all the binaural responses
|
tp@8
|
178 % in the binaural_irs_emission cell are equal.
|
tp@8
|
179 board_coords(8,3,length(params.board_dist),length(params.board_azim),length(params.board_orientation)) = 0;
|
tp@8
|
180
|
tp@8
|
181
|
tp@8
|
182 geom.Fs = params.Fs;
|
tp@8
|
183 geom.Cair = params.Cair;
|
tp@8
|
184 geom.Rhoair = params.Rhoair;
|
tp@8
|
185
|
tp@8
|
186 geom.source_position = [0 params.source_front -params.source_down];
|
tp@8
|
187
|
tp@8
|
188 for ii = 1:length(params.board_dist)
|
tp@8
|
189 for jj = 1:length(params.board_azim)
|
tp@8
|
190 for kk = 1:length(params.board_orientation)
|
tp@8
|
191
|
tp@8
|
192 if strcmp(params.board_orientation{kk},'angled')
|
tp@8
|
193 theta_angled = params.board_azim(jj) - pi/2;
|
tp@8
|
194 Rot_mat = [
|
tp@8
|
195 cos(theta_angled) -sin(theta_angled) 0
|
tp@8
|
196 sin(theta_angled) cos(theta_angled) 0
|
tp@8
|
197 0 0 1
|
tp@8
|
198 ];
|
tp@8
|
199 temp2_edges = ( Rot_mat * temp_edges.' ) .' ;
|
tp@8
|
200 % for the rotation matrix see http://en.wikipedia.org/wiki/Rotation_matrix
|
tp@8
|
201 [trans_x, trans_y, trans_z] = sph2cart(params.board_azim(jj),params.board_elev,params.board_dist(ii));
|
tp@8
|
202 geom.scatterer_edges = ...
|
tp@8
|
203 temp2_edges + repmat([trans_x, trans_y, trans_z],8,1);
|
tp@8
|
204 board_coords(:,:,ii,jj,kk) = geom.scatterer_edges;
|
tp@8
|
205 elseif strcmp(params.board_orientation{kk},'horz')
|
tp@8
|
206 temp2_edges = temp_edges;
|
tp@8
|
207 if strcmp(params.horz_disamb,'collocated')
|
tp@8
|
208 [trans_x, trans_y, trans_z] = sph2cart(params.board_azim(jj),params.board_elev,params.board_dist(ii));
|
tp@8
|
209 elseif strcmp(params.horz_disamb,'BSPC2011')
|
tp@8
|
210 [trans_x, trans_y, trans_z] = sph2cart(...
|
tp@8
|
211 params.board_azim(jj),...
|
tp@8
|
212 params.board_elev,...
|
tp@8
|
213 params.board_dist(ii)/abs(cos(params.board_azim(jj)-pi/2)));
|
tp@8
|
214 else
|
tp@8
|
215 error('params.horz_disamb must be set to either ''BSPC2011'' or ''collocated''')
|
tp@8
|
216 end
|
tp@8
|
217 geom.scatterer_edges = ...
|
tp@8
|
218 temp2_edges + repmat([trans_x, trans_y, trans_z],8,1);
|
tp@8
|
219 board_coords(:,:,ii,jj,kk) = geom.scatterer_edges;
|
tp@8
|
220 end
|
tp@8
|
221
|
tp@8
|
222 FFresp(ii,jj,kk) = edhrir_single_cuboid(geom);
|
tp@8
|
223
|
tp@8
|
224 end
|
tp@8
|
225 end
|
tp@8
|
226 end
|
tp@8
|
227
|
tp@8
|
228 %% Compute binaural IRs
|
tp@8
|
229
|
tp@8
|
230 temp = load('hrir_final.mat'); %This is subject_165 CIPIC data
|
tp@8
|
231 h3D_lear = temp.hrir_l;
|
tp@8
|
232 h3D_rear = temp.hrir_r;
|
tp@8
|
233 clear temp
|
tp@8
|
234
|
tp@8
|
235 cipic_source_az = 0*180/pi;
|
tp@8
|
236 cipic_source_el = atan(-params.source_down/params.source_front)*180/pi;
|
tp@8
|
237 [source_lear_ir, azerr(1,1+length(params.board_azim)), elerr(1,1+length(params.board_azim))] = ...
|
tp@8
|
238 getNearestUCDpulse(cipic_source_az,cipic_source_el,h3D_lear);
|
tp@8
|
239 [source_rear_ir, azerr(2,1+length(params.board_azim)), elerr(2,1+length(params.board_azim))] = ...
|
tp@8
|
240 getNearestUCDpulse(cipic_source_az,cipic_source_el,h3D_rear);
|
tp@8
|
241
|
tp@8
|
242 % NOTE: in the following computation the source term (binaural_irs_emission) does not need to be computed for each
|
tp@8
|
243 % different board distance/azimuth/orientation as it is the same. I include the redundancy as a check that the geometry
|
tp@8
|
244 % modelling and computations are correct, i.e. I can check that all the binaural responses in the binaural_irs_emission
|
tp@8
|
245 % cell are equal.
|
tp@8
|
246
|
tp@8
|
247 for ii = 1:length(params.board_azim)
|
tp@8
|
248
|
tp@8
|
249 cipic_board_az = 90-params.board_azim(ii)*180/pi;
|
tp@8
|
250 cipic_board_el = params.board_elev*180/pi;
|
tp@8
|
251 [lear_ir, azerr(1,ii), elerr(1,ii)] = getNearestUCDpulse(cipic_board_az,cipic_board_el,h3D_lear);
|
tp@8
|
252 [rear_ir, azerr(2,ii), elerr(2,ii)] = getNearestUCDpulse(cipic_board_az,cipic_board_el,h3D_rear);
|
tp@8
|
253
|
tp@8
|
254 for jj = 1:length(params.board_dist)
|
tp@8
|
255 for kk = 1:length(params.board_orientation)
|
tp@8
|
256
|
tp@8
|
257 binaural_irs_emission{jj,ii,kk}(1,:) = fftconv(source_lear_ir,FFresp{jj,ii,kk}(2,:)); %source term
|
tp@8
|
258 binaural_irs_emission{jj,ii,kk}(2,:) = fftconv(source_rear_ir,FFresp{jj,ii,kk}(2,:)); %source term
|
tp@8
|
259
|
tp@8
|
260 binaural_irs_echo{jj,ii,kk}(1,:) = fftconv(lear_ir,FFresp{jj,ii,kk}(1,:)+FFresp{jj,ii,kk}(3,:));
|
tp@8
|
261 %board echo term
|
tp@8
|
262 binaural_irs_echo{jj,ii,kk}(2,:) = fftconv(rear_ir,FFresp{jj,ii,kk}(1,:)+FFresp{jj,ii,kk}(3,:));
|
tp@8
|
263 %board echo term
|
tp@8
|
264
|
tp@8
|
265 end
|
tp@8
|
266 end
|
tp@8
|
267 end
|
tp@8
|
268
|
tp@8
|
269 simulation_data.echo = binaural_irs_echo;
|
tp@8
|
270 simulation_data.emission =binaural_irs_emission;
|
tp@8
|
271 simulation_data.params = params;
|
tp@8
|
272 simulation_data.board_coords = board_coords;
|
tp@8
|
273 simulation_data.azerr = azerr;
|
tp@8
|
274 simulation_data.elerr = elerr;
|
tp@8
|
275
|
tp@8
|
276 %% Compute binaural signals and save binaural wav file
|
tp@8
|
277
|
tp@8
|
278 binaural_ir = params.dirweight*simulation_data.emission{1,1,1} + simulation_data.echo{1,1,1};
|
tp@8
|
279 stim = params.WavScaling*randn(1,params.WavDurationSec*params.Fs);
|
tp@8
|
280 temp = [fftfilt(binaural_ir(1,:),stim);fftfilt(binaural_ir(2,:),stim)].';
|
tp@8
|
281 if max(max(abs(temp))) > 1
|
tp@8
|
282 warning('wavfile clipped')
|
tp@8
|
283 end
|
tp@8
|
284 audiowrite(params.wavfilename,temp,params.Fs);
|
tp@8
|
285
|
tp@8
|
286 %% Subfunctions
|
tp@8
|
287
|
tp@8
|
288 function [pulse, azerr, elerr] = getNearestUCDpulse(azimuth,elevation,h3D)
|
tp@8
|
289 azimuth = pvaldeg(azimuth);
|
tp@8
|
290 elevation = pvaldeg(elevation);
|
tp@8
|
291
|
tp@8
|
292 elmax = 50;
|
tp@8
|
293 elindices = 1:elmax;
|
tp@8
|
294 elevations = -45 + 5.625*(elindices - 1);
|
tp@8
|
295 el = round((elevation + 45)/5.625 + 1);
|
tp@8
|
296 el = max(el,1);
|
tp@8
|
297 el = min(el,elmax);
|
tp@8
|
298 elerr = pvaldeg(elevation - elevations(el));
|
tp@8
|
299
|
tp@8
|
300 azimuths = [-80 -65 -55 -45:5:45 55 65 80];
|
tp@8
|
301 [azerr, az] = min(abs(pvaldeg(abs(azimuths - azimuth))));
|
tp@8
|
302
|
tp@8
|
303 pulse = squeeze(h3D(az,el,:));
|
tp@8
|
304
|
tp@8
|
305 function angle = pvaldeg(angle)
|
tp@8
|
306 dtr = pi/180;
|
tp@8
|
307 angle = atan2(sin(angle*dtr),cos(angle*dtr))/dtr;
|
tp@8
|
308 if angle < - 90
|
tp@8
|
309 angle = angle + 360;
|
tp@8
|
310 end
|
tp@8
|
311
|
tp@8
|
312 function out=fftconv(in1,in2)
|
tp@8
|
313 %
|
tp@8
|
314 % Computes the convolution output out of the input vectors in1 and in2
|
tp@8
|
315 % either with time-domain convolution (as implemented by conv) or by
|
tp@8
|
316 % frequency-domain filtering (as implemented by zero-padded fftfilt).
|
tp@8
|
317 %
|
tp@8
|
318 % out=fftconv(in1,in2)
|
tp@8
|
319 %
|
tp@8
|
320 in1=in1(:).';in2=in2(:).';
|
tp@8
|
321
|
tp@8
|
322 if (length(in1)>100 && length(in2)>100)
|
tp@8
|
323 if length(in1)>=length(in2)
|
tp@8
|
324 out=fftfilt(in2,[in1 zeros(1,length(in2)-1)]);
|
tp@8
|
325 else
|
tp@8
|
326 out=fftfilt(in1,[in2 zeros(1,length(in1)-1)]);
|
tp@8
|
327 end
|
tp@8
|
328 else
|
tp@8
|
329 out=conv(in1,in2);
|
tp@8
|
330 end
|
tp@8
|
331
|
tp@8
|
332 function ir_matrix=edhrir_single_cuboid(geom)
|
tp@8
|
333 %
|
tp@8
|
334 % Matrix of irs for a single cuboid scatterer using EDTB
|
tp@8
|
335 %
|
tp@8
|
336 % Works for external geometry. Definition of corners and planes in the created CAD file should be pointing outwards (in
|
tp@8
|
337 % cartesian coordinates as defined below).
|
tp@8
|
338 %
|
tp@8
|
339 % x coordinate (increasing to right in top view, right hand thumb)
|
tp@8
|
340 % y coordinate (increasing in front in top view, right hand index)
|
tp@8
|
341 % z coordinate (increasing upwards in top view, right hand middle)
|
tp@8
|
342 %
|
tp@8
|
343 % For more details about geometry description see the main help preample.
|
tp@8
|
344 %
|
tp@8
|
345 % geom input parameter should be a structure with the following fields:
|
tp@8
|
346 %
|
tp@8
|
347 % geom.scatterer_edges is a 8x3 matrix with elements:
|
tp@8
|
348 % x y z coordinates of back right top edge (point 1)
|
tp@8
|
349 % x y z coordinates of back left top edge (point 2)
|
tp@8
|
350 % x y z coordinates of front left top edge (point 3)
|
tp@8
|
351 % x y z coordinates of front right top edge (point 4)
|
tp@8
|
352 % x y z coordinates of back right bottom edge (point 1)
|
tp@8
|
353 % x y z coordinates of back left bottom edge (point 2)
|
tp@8
|
354 % x y z coordinates of front left bottom edge (point 3)
|
tp@8
|
355 % x y z coordinates of front right bottom edge (point 4)
|
tp@8
|
356 %
|
tp@8
|
357 % (or any sequence of rotations of a cuboid with edges as above)
|
tp@8
|
358 %
|
tp@8
|
359 % geom.source_position (Single) source coordinates in cartesian system defined 1x3 positive real vector. (Single)
|
tp@8
|
360 % receiver always taken to be at coordinates origin (0,0,0)
|
tp@8
|
361 %
|
tp@8
|
362 % geom.Fs
|
tp@8
|
363 % geom.Cair
|
tp@8
|
364 % geom.Rhoair
|
tp@8
|
365 %
|
tp@8
|
366
|
tp@8
|
367 %% 1
|
Chris@13
|
368 temp_filename=['a' num2str(now*1e12,'%-24.0f')];
|
Chris@12
|
369 cad_filename=[temp_filename '.cad']
|
tp@8
|
370
|
Chris@13
|
371 fid=fopen([outdir filesep cad_filename],'w');
|
tp@8
|
372 % TODO add onCleanup to fclose this file
|
tp@8
|
373 fprintf(fid,'%%CORNERS\n\n');
|
tp@8
|
374 fprintf(fid,'%.0f %9.6f %9.6f %9.6f\n',...
|
tp@8
|
375 1, geom.scatterer_edges(1,1), geom.scatterer_edges(1,2), geom.scatterer_edges(1,3),...
|
tp@8
|
376 2, geom.scatterer_edges(2,1), geom.scatterer_edges(2,2), geom.scatterer_edges(2,3),...
|
tp@8
|
377 3, geom.scatterer_edges(3,1), geom.scatterer_edges(3,2), geom.scatterer_edges(3,3),...
|
tp@8
|
378 4, geom.scatterer_edges(4,1), geom.scatterer_edges(4,2), geom.scatterer_edges(4,3),...
|
tp@8
|
379 5, geom.scatterer_edges(5,1), geom.scatterer_edges(5,2), geom.scatterer_edges(5,3),...
|
tp@8
|
380 6, geom.scatterer_edges(6,1), geom.scatterer_edges(6,2), geom.scatterer_edges(6,3),...
|
tp@8
|
381 7, geom.scatterer_edges(7,1), geom.scatterer_edges(7,2), geom.scatterer_edges(7,3),...
|
tp@8
|
382 8, geom.scatterer_edges(8,1), geom.scatterer_edges(8,2), geom.scatterer_edges(8,3));
|
tp@8
|
383 fprintf(fid,'\n%%PLANES\n');
|
tp@8
|
384 fprintf(fid,'\n1 / /RIGID\n1 2 3 4\n');
|
tp@8
|
385 fprintf(fid,'\n2 / /RIGID\n5 8 7 6\n');
|
tp@8
|
386 fprintf(fid,'\n3 / /RIGID\n1 4 8 5\n');
|
tp@8
|
387 fprintf(fid,'\n4 / /RIGID\n1 5 6 2\n');
|
tp@8
|
388 fprintf(fid,'\n5 / /RIGID\n2 6 7 3\n');
|
tp@8
|
389 fprintf(fid,'\n6 / /RIGID\n7 8 4 3\n');
|
tp@8
|
390 fprintf(fid,'\n%%EOF');
|
tp@8
|
391 fclose(fid);
|
tp@8
|
392
|
Chris@12
|
393 setup_filename = [temp_filename '_setup.m']
|
luis@9
|
394
|
Chris@13
|
395 fid=fopen([outdir filesep setup_filename],'wt');
|
tp@8
|
396 % TODO add onCleanup to fclose this file
|
tp@8
|
397 fprintf(fid,'\n global FSAMP CAIR RHOAIR SHOWTEXT');
|
tp@8
|
398 fprintf(fid,['\n FSAMP = ' num2str(geom.Fs) ';']);
|
tp@8
|
399 fprintf(fid,['\n CAIR = ' num2str(geom.Cair) ';']);
|
tp@8
|
400 fprintf(fid,['\n RHOAIR = ' num2str(geom.Rhoair) ';']);
|
tp@8
|
401 fprintf(fid,'\n SHOWTEXT = 0;');
|
tp@8
|
402 fprintf(fid,'\n SUPPRESSFILES = 0;');
|
Chris@13
|
403 temp = strrep(outdir,'\','\\');
|
tp@8
|
404 fprintf(fid,['\n Filepath=''''''' temp ''''''';']);
|
tp@8
|
405 fprintf(fid,['\n Filestem=''' temp_filename ''';']);
|
Chris@13
|
406 fprintf(fid,['\n CADfile=''' cad_filename ''';']);
|
tp@8
|
407 fprintf(fid,'\n open_or_closed_model = ''open'';');
|
tp@8
|
408 fprintf(fid,'\n int_or_ext_model = ''ext'';');
|
tp@8
|
409 fprintf(fid,'\n EDcalcmethod = ''n'';');
|
tp@8
|
410 fprintf(fid,'\n directsound = 1;');
|
tp@8
|
411 fprintf(fid,'\n specorder = 1;');
|
tp@8
|
412 fprintf(fid,'\n difforder = 1;');
|
tp@8
|
413 fprintf(fid,'\n elemsize = [1];');
|
tp@8
|
414 fprintf(fid,'\n nedgesubs = 2;');
|
tp@8
|
415 fprintf(fid,'\n calcpaths = 1;');
|
tp@8
|
416 fprintf(fid,'\n calcirs = 1;');
|
tp@8
|
417 fprintf(fid,'\n sources=[');
|
tp@8
|
418 for n=1:1
|
tp@8
|
419 fprintf(fid,['\n' num2str(geom.source_position(1)) ' ' ...
|
tp@8
|
420 num2str(geom.source_position(2)) ' ' ...
|
tp@8
|
421 num2str(geom.source_position(3))]);
|
tp@8
|
422 end
|
tp@8
|
423 fprintf(fid,'\n ];');
|
tp@8
|
424 fprintf(fid,'\n receivers=[');
|
tp@8
|
425 for n=1:1
|
tp@8
|
426 fprintf(fid,'\n 0 0 0');
|
tp@8
|
427 end
|
tp@8
|
428 fprintf(fid,'\n ];');
|
tp@8
|
429 fprintf(fid,'\n skipcorners = 1000000;');
|
tp@8
|
430 fprintf(fid,'\n Rstart = 0;');
|
tp@8
|
431
|
tp@8
|
432 fclose(fid);
|
tp@8
|
433
|
tp@8
|
434 pause(1);
|
tp@8
|
435
|
luis@9
|
436 [~, ir_matrix]=myver_edtb(setup_filename);
|
tp@8
|
437
|
Chris@13
|
438 delete([outdir filesep cad_filename]);
|
Chris@13
|
439 delete([outdir filesep setup_filename]);
|
tp@8
|
440
|
tp@8
|
441 function [ir,varargout]=myver_edtb(EDsetupfile)
|
tp@8
|
442 % implements the computation of EDToolbox (by Peter Svensson) with a front-end
|
tp@8
|
443 % designed for my needs.
|
tp@8
|
444 %
|
tp@8
|
445 % Takes one input which a setup file as specified by Svensson and gives
|
tp@8
|
446 % either one vector output (which is the irtot output of Svensson's implementation for
|
tp@8
|
447 % the first source and first receiver in the input "EDsetupfile" setup file) or
|
tp@8
|
448 % two outputs, the first as above and the second being a {NxM} cell (N the number
|
tp@8
|
449 % of sources and M the number of receivers) each element of which is a 4xL matrix
|
tp@8
|
450 % with its 4 rows being the irdiff, irdirect, irgeom and irtot outputs of Svensson's
|
tp@8
|
451 % computation for the corresponding source and receiver.
|
tp@8
|
452 %
|
tp@8
|
453 % The code deletes all other .mat files created by Svensson's
|
tp@8
|
454 % implementation.
|
tp@8
|
455 %
|
tp@8
|
456 % [ir ir_all_data]=myver_edtb(EDsetupfile);
|
tp@8
|
457
|
tp@8
|
458 %keep record of files in the current directory before computation
|
tp@8
|
459 dir_bef=dir;
|
tp@8
|
460 ir=1;
|
tp@8
|
461
|
luis@9
|
462 disp(['Will call' EDsetupfile])
|
luis@9
|
463
|
tp@8
|
464 %run computation
|
tp@8
|
465 EDB1main(EDsetupfile);
|
tp@8
|
466
|
tp@8
|
467 %get files list in the current directory after computation
|
tp@8
|
468 dir_aft=dir;
|
tp@8
|
469
|
tp@8
|
470 %get all genuine files (excluding other directories) in current directory
|
tp@8
|
471 %after computation
|
tp@8
|
472 k=1;
|
tp@8
|
473 for n=1:size(dir_aft,1)
|
tp@8
|
474 if(~dir_aft(n).isdir)
|
tp@8
|
475 names_aft{k}=dir_aft(n).name;k=k+1; %#ok<AGROW>
|
tp@8
|
476 end
|
tp@8
|
477 end
|
tp@8
|
478
|
tp@8
|
479 %get all genuine files (excluding other directories) in current directory
|
tp@8
|
480 %before computation
|
tp@8
|
481 k=1;
|
tp@8
|
482 for n=1:size(dir_bef,1)
|
tp@8
|
483 if(~dir_bef(n).isdir)
|
tp@8
|
484 names_bef{k}=dir_bef(n).name;k=k+1; %#ok<AGROW>
|
tp@8
|
485 end
|
tp@8
|
486 end
|
tp@8
|
487
|
tp@8
|
488 %get irtot for 1st source 1st receiver and delete files created by
|
tp@8
|
489 %computation.
|
tp@8
|
490 % for n=1:length(names_aft)
|
tp@8
|
491 % if ~strcmp(names_aft(n),names_bef)
|
tp@8
|
492 % if ~isempty(strfind(names_aft{n},'_1_1_ir.mat'))
|
tp@8
|
493 % temp=load(names_aft{n});
|
tp@8
|
494 % ir=full(temp.irtot);
|
tp@8
|
495 % clear temp
|
tp@8
|
496 % end
|
tp@8
|
497 % delete(names_aft{n})
|
tp@8
|
498 % end
|
tp@8
|
499 % end
|
tp@8
|
500 for n=1:length(names_aft)
|
tp@8
|
501 if ~strcmp(names_aft(n),names_bef)
|
tp@8
|
502 if ~isempty(strfind(names_aft{n},'_1_1_ir.mat'))
|
tp@8
|
503 temp=load(names_aft{n});
|
tp@8
|
504 ir=full(temp.irtot);
|
tp@8
|
505 clear temp
|
tp@8
|
506 end
|
tp@8
|
507 if nargout>1
|
tp@8
|
508 if ~isempty(strfind(names_aft{n},'_ir.mat'))
|
tp@8
|
509 temp=load(names_aft{n});
|
tp@8
|
510 temp2=regexp(regexp(names_aft{n},'_\d*_\d*_','match'),'\d*','match');
|
tp@8
|
511 temp3{str2double(temp2{1}(1)),str2double(temp2{1}(2))}(4,:)=full(temp.irtot); %#ok<AGROW>
|
tp@8
|
512 temp3{str2double(temp2{1}(1)),str2double(temp2{1}(2))}(1,:)=full(temp.irdiff); %#ok<AGROW>
|
tp@8
|
513 temp3{str2double(temp2{1}(1)),str2double(temp2{1}(2))}(2,:)=full(temp.irdirect); %#ok<AGROW>
|
tp@8
|
514 temp3{str2double(temp2{1}(1)),str2double(temp2{1}(2))}(3,:)=full(temp.irgeom); %#ok<AGROW>
|
tp@8
|
515 clear temp temp2
|
tp@8
|
516 end
|
tp@8
|
517 end
|
tp@8
|
518 delete(names_aft{n})
|
tp@8
|
519 end
|
tp@8
|
520 end
|
tp@8
|
521 if nargout>1
|
tp@8
|
522 varargout(1)={temp3};
|
tp@8
|
523 end
|
tp@8
|
524
|