% FUNCTION [R,X] = CONSTANT_STEP( P ) % % To see parameters: use "dbtype constant_step" to see code. % % Important note: planar array % % For a non-planar array, it would be important to use a more % generic way of picking points out of each sphere. % % For arrays that are quite stretched in space (e.g. like a strline), % it would be important to use a more adequate shape than sphere % (e.g. ellipsoid). Or find a generic way to create the shape. function [r,X] = constant_step( p ) if nargin < 1 error( 'constant_step needs one parameter' ); end required_param = 'geometry'; check_param( required_param, fieldnames( p ) ); p_default.up_factor = 5; p_default.r_min = []; p_default.el_max = 70 / 180 * pi; % in radians pairs = []; n_channels = size( p.geometry, 2 ) for a = 1:n_channels for b = a+1:n_channels pairs = [pairs; a b]; end end p_default.pairs = pairs; pairs = []; p = fill_default( p, p_default ); if isempty( p.r_min ) r_geometry = sqrt( sum( p.geometry( 1,:).^2 + p.geometry(2,:).^2,1)); p.r_min = max( r_geometry ) * 2; end % Verbosity p %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% % Initial radius % We don't expect to locate anything beyond that distance % (meters) r = 5; % Step -> our average precision in time-delay space t_step_square = ( 1 / p.up_factor ) ^ 2; n_pairs = size( p.pairs, 1 ); % We will now go along the x axis, decreasing radius, % picking locations so that the distance in time-delay space % between two consecutive locations is constant. % The chosen distance in time-delay space is euclidian, % normalized by the number of pairs (P): % % d( tau_1, tau_2 ) = ( 1/P * sum for j from 1 to P of % (( tau_1_j - tau_2_j ) ^ 2) ) ^ 1/2 % So constant distance in time-delay space between two positions % x_k and x_k+1 means the following sum is constant against k: % % sum for j = 1..P of (( ||x_k - m_a_j|| - ||x_k - m_b_j|| % -||x_k+1 - m_a_j|| + ||x_k+1 - m_b_j|| )^2 ) % % where m_a_j and m_b_j are the spatial positions of microphones % defining pair j. % Circle of points used for selecting radiuses a = (0:15) / 16 * 2 * pi; the_circle = [cos(a); sin(a); 0*a]; t = location_to_timedelay( p.geometry, p.pairs, r * the_circle ); % Abortion constants the_precision = 1e-3; max_iter = 500; for a = 2:100 % Starting point for searching next position new_r = 0.5 * r(end); % Search finished = 0; iter = 0; previous_new_r = r(end); while ~finished iter = iter + 1; % Do we need to get more precise? new_t = location_to_timedelay( p.geometry, p.pairs, new_r * the_circle ); aux = sum( (new_t - t) .^ 2, 1 ) / n_pairs; the_dist_square = mean( aux ); current_precision = abs( the_dist_square - t_step_square ) / t_step_square; finished = current_precision < the_precision ; % Can we iter more? if ~finished finished = iter >= max_iter; end % Can we??? if ~finished the_diff = abs(new_r - previous_new_r); if the_dist_square < t_step_square previous_new_r = new_r; new_r = new_r - the_diff / 2; else aux = previous_new_r; previous_new_r = new_r; new_r = new_r + the_diff / 2; end end end % DEBUG disp(sprintf(['a:%d done in %d iterations (final precision:' ... ' %.5f)'], a, iter, current_precision)); % Put it into the memory r = [r, new_r]; t = new_t; % Overflow? if iter >= max_iter break; end % Finished? (too close to the array) if r(end) < p.r_min r = r(1:end-1) break; end end %%%%%%%%%%%%%%%%%%%%%%%%%%%%%% % Now that we have found radiuses, % let's determine which points we'll pick from each sphere rand('state',sum(100*clock)); % List of all points X = []; t = []; % Abortion constants the_precision = 1e-3; max_iter = 500; for a = 1:length(r) % DEBUG disp(sprintf('starting sphere #%d - radius %.4f, starts at point #%d', ... a, r(a), size(X,2)+1)); start_index = size(X,2) + 1; % Sphere's radius sr = r(a); % We start in the horizontal plane (elevation 0) el = 0; % Starting vertical angle between two circles v_angle = 10/180*pi; % Go around horizontal circles, picking points with % constant interval in time-delay space finished = 0; while ~finished %DEBUG disp(sprintf(['starting circle at elevation %.3f rad - starts at' ... ' point #%d'], el, size(X,2) + 1)); % 1) Go around horizontal circle at current elevation circle_finished = 0; % Starting horizontal angle between two points h_angle = 5/180*pi; % Pick a starting point at random % az_start = -pi + 2 * pi * rand; % No, let's put aside randomness for a second az_start = 0; az = az_start; X_start = [ sr * cos(el) * cos(az) ; sr * cos(el) * sin(az) ; sr * sin(el) ]; t_start = location_to_timedelay( p.geometry, p.pairs, X_start ); X = [ X, X_start ]; t = [ t, t_start ]; %DEBUG %disp(sprintf( 'point of azimuth %.3f added', az )); while ~circle_finished % Find next point previous_new_az = az; new_az = az + h_angle; next_point_found = 0; iter = 0; while (~next_point_found) & (iter 2 * pi % Yes: move to higher elevation circle_finished = 1; else % Update h_angle: this is not necessary, % but might improve speed h_angle = new_az - az; % No: add the new point X = [X, new_X]; t = [t, new_t]; az = new_az; %DEBUG %disp(sprintf( 'point of azimuth %.3f added' , az)); end end end %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% % 2) Find next elevation previous_new_el = el; new_el = el + v_angle; next_elevation_found = 0; iter = 0; while (~next_elevation_found) & (iter < max_iter) iter = iter + 1; new_X = [ sr * cos(new_el) * cos(az_start) ; sr * cos(new_el) * sin(az_start) ; sr * sin(new_el) ]; new_t = location_to_timedelay( p.geometry, p.pairs, new_X ); the_dist_square = sum( (new_t - t_start) .^ 2 ) / n_pairs; next_elevation_found = abs( the_dist_square - t_step_square ) / t_step_square < the_precision ; if ~next_elevation_found the_diff = abs( new_el - previous_new_el ); if the_dist_square < t_step_square previous_new_el = new_el; new_el = new_el + the_diff / 2; else previous_new_el = new_el; new_el = new_el - the_diff / 2; end end end finished = ~next_elevation_found; if ~finished % Update v_angle: not necessary but might improve speed v_angle = new_el - el; el = new_el; %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% finished = el > min( p.el_max, pi / 2 ); end end % DEBUG disp(sprintf('%d points in sphere #%d\n', 1+size(X,2) - start_index, a)) end