function [ gt_mat, p ] = static_gt_2_sector_gt( static_gt, in_p ) error( [ mfilename ' is deprecated. Use "static_gt_2_sector_gt_middle" instead.' ] ); % FUNCTION GT_MAT = STATIC_GT_2_SECTOR_GT( STATIC_GT, IN_P ) % % Convert the concise GT information, stored in the STATIC_GT % structure into a N_instances-long cell array of N_sectors - by - % N_frames sparse matrices of integer values (0 or object id) that can % be used for evaluating a sector-based multiple source localization % result. % % Note: we use a cell array of 2D matrices instead of a 3D matrix % because sparse matrices cannot be more than 2-dimensional. % % The motivation behind this is to represent each object with SEVERAL % active source instances (e.g. each speech utterance of a % person). The instances of different objects can overlap in space % and/or time, hence the 3rd dimension of the output GT_MAT matrix % (see below for description). % % See also EVAL_SECTOR_PERF. % % %%%%%%%%%%%%%%% % INPUT ARGUMENTS % % STATIC_GT: a structure containing the following MANDATORY fields: % % ARRAY( IN_P.ARRAY_IND ).Pmat: 4 - by - 4 rigid transformation matrix defining each microphone array's referent. % % P3D: 4 - by - N_locations matrix of homogeneous Cartesian coordinates: each column points to a location. % % POS_IND: 1 - by - N_instances vector of location indices ( from 1 to N_locations ). % % OBJECT_ID: 1 - by - N_instances vector of integers, identifying the object to which each active source instance belongs. ( one object can be represented by several instances, e.g. several speech utterances of a given speaker ). % % SP_SEG: 2 - by - N_instances matrix of time values in seconds. Each column is the beginning (row 1) and end (row 2) of an active source instance. % % Note that a given location can be shared by multiple active source % instances, that's what the 3rd dimension of the output matrix % "GT_MAT" is for. For example, this implicitely allows overlaps in % space and/or time between active source instances of (supposedly) % different objects. % % % % % IN_P: a structure containing several parameters (one field per parameter): % % THETA_MIN ( mandatory ): 1 - by - N_sectors vector of azimuth values in radians, one for each sector. % THETA_MAX ( mandatory ): 1 - by - N_sectors vector of azimuth values in radians, one for each sector. % PHI_MIN ( mandatory ): 1 - by - N_sectors vector of elevation values in radians, one for each sector. % PHI_MAX ( mandatory ): 1 - by - N_sectors vector of elevation values in radians, one for each sector. % R_MIN ( mandatory ): 1 - by - N_sectors vector of radius values in meters, one for each sector. % R_MAX ( mandatory ): 1 - by - N_sectors vector of radius values in meters, one for each sector. % FRAME_LENGTH ( mandatory ): scalar, duration of a time frame in seconds. % FRAME_SHIFT ( optional ): scalar, shift between two consecutive time frames, in seconds. Default value: FRAME_LENGTH / 2. % ARRAY_IND ( mandatory ): integer, index of the microphone array used as reference. This is an index in the structure array STATIC_GT.ARRAY. % TOTAL_DURATION ( mandatory ): scalar, total duration of the recording, in seconds. % VERBOSE ( optional ): 0 or 1, if 1 then the content of P is displayed ( default value is 1 ). % % %%%%%%%%%%%%%%%% % OUTPUT ARGUMENTS % % GT_MAT: N_instances - long cell array of N_sectors - by - N_frames sparse matrices of integer values (zero or object id). Non-zero values locate in both space and time the activity of a given active source instance. The value itself gives the identity of the object. % % Note that within a given time frame, there can be multiple sectors containing a given active source instance ( e.g. when the source's location is at the precise border between two sectors ). % % P: copy of IN_P, incorporating possible default values of the parameters. if nargin < 2 error( 'static_gt_2_sector_gt needs 2 input arguments' ); end % ------------------------------------------------------------ % ( 1 ) Check parameters % p p = in_p; required_fields = { 'theta_min', 'theta_max', 'phi_min', 'phi_max', 'r_min', 'r_max', 'frame_length', 'array_ind', 'total_duration' }; check_param( required_fields, fieldnames( p ) ); p_default.frame_shift = []; p_default.small_value = 1e-10; p_default.verbose = 1; p = fill_default( p, p_default ); if isempty( p.frame_shift ) p.frame_shift = p.frame_length / 2; end % static_gt required_fields = { 'array', 'p3d', 'pos_ind', 'object_id', 'sp_seg' }; check_param( required_fields, fieldnames( static_gt ) ); check_param( { 'Pmat' }, fieldnames( static_gt.array( p.array_ind ) ) ); if p.verbose disp( 'static_gt_2_sector_gt parameters:' ); disp( p ); end % ------------------------------------------------------------ % ( 2 ) Convert % Discretize time N_frames = max( 0, 1 + floor( ( p.total_duration - p.frame_length ) / p.frame_shift ) ); frame_start = 0 + (0:N_frames-1) * p.frame_shift; frame_end = frame_start + p.frame_length; % Discretize space N_sectors = length( p.theta_min ); % Discretize active source instances N_instances = length( static_gt.pos_ind ); % Product: discretization of space-time-active instances gt_mat = cell( N_instances, 1 ); for a = 1:N_instances gt_mat{ a } = sparse( N_sectors, N_frames ); end if N_sectors < 1 if ~strcmp( warning, 'off' ) warning( 'static_gt_2_sector_gt: WARNING! Zero sector, returning empty GT' ); end return; end if N_frames < 1 if ~strcmp( warning, 'off' ) warning( 'static_gt_2_sector_gt: WARNING! Zero time frame, returning empty GT' ); end return; end if N_instances < 1 if ~strcmp( warning, 'off' ) warning( 'static_gt_2_sector_gt: WARNING! Zero active source instance, returning empty GT' ); end return; end % Extract ground-truth from "static_gt" and put it into "gt_mat" % Move spatial ground-truth to array's referent X = static_gt.array( p.array_ind ).Pmat * static_gt.p3d; % Transform to spherical coordinates [ theta, phi, r ] = cart2sph( X(1,:), X(2,:), X(3,:) ); % Align theta within [ 0 2pi ] theta = mod( theta, 2*pi ); p.theta_min = mod( p.theta_min, 2*pi ); p.theta_max = p.theta_min + mod( p.theta_max - p.theta_min, 2*pi ); if any( p.theta_max > 2*pi + p.small_value ) error( 'static_gt_2_sector_gt: problem of type I' ); end % Special case (most likely: 1 sector) ind = find( p.theta_max < p.theta_min + p.small_value ); p.theta_max( ind ) = p.theta_max( ind ) + 2 * pi; % Align phi within [ -pi/2, +pi/2 ]; phi = -pi/2 + mod( phi + pi/2, 2*pi ); if any( abs( phi ) > pi/2 + p.small_value ) error( 'static_gt_2_sector_gt: problem of type II' ); end p.phi_min = -pi/2 + mod( p.phi_min + pi/2, 2*pi ); if any( abs( p.phi_min ) > pi/2 + p.small_value ) error( 'static_gt_2_sector_gt: problem of type III' ); end p.phi_max = p.phi_min + mod( p.phi_max - p.phi_min, 2*pi ); if any( abs( p.phi_max ) > pi/2 + p.small_value ) error( 'static_gt_2_sector_gt: problem of type IV' ); end % Convert each location into a list of sectors that contain it N_locations = length( theta ); sector_list = cell( N_locations, 1 ); for a = 1:N_locations % Find the sector(s) containing this location % % This "+2*pi" additional test is here to take care of % some very special cases due to the looping nature % of angle space (=toroidal nature). % % E.g. with theta(a) = 0 and one sector on [0, pi/4] and another % sector in [2*pi-pi/5 2*pi], the location belongs to BOTH sectors. tmp_theta = ( ( p.theta_min < theta( a ) + p.small_value ) & ... ( theta( a ) < p.theta_max + p.small_value ) ) | ... ( ( p.theta_min < theta( a ) + 2*pi + p.small_value ) & ... ( theta( a ) + 2*pi < p.theta_max + p.small_value ) ); tmp_phi = ( ( p.phi_min < phi( a ) + p.small_value ) & ... ( phi( a ) < p.phi_max + p.small_value ) ) | ... ( ( p.phi_min < phi( a ) + 2*pi + p.small_value ) & ... ( phi( a ) + 2*pi < p.phi_max + p.small_value ) ); tmp_r = ( p.r_min < r( a ) + p.small_value ) & ... ( r( a ) < p.r_max + p.small_value ); tmp = find( tmp_theta & tmp_phi & tmp_r ); % ...there must be at least one ! if isempty( tmp ) error(sprintf( 'static_gt_2_sector_gt could not find at least one sector containing location #%d', a )); end sector_list{ a } = tmp; end % Copy the ground-truth active source instances % into the "gt_mat" matrix if p.verbose chrono = chrono_start( N_instances, 10 ); end for a = 1:N_instances % Find the frames occupied by this instance seg_frames = find( ( static_gt.sp_seg( 1, a ) < frame_start + p.small_value ) & ( frame_end < static_gt.sp_seg( 2, a ) + p.small_value ) ); % Find the location occupied by this instance ind_loc = static_gt.pos_ind( a ); % Find the object to which this instance belongs object_id = static_gt.object_id( a ); % Mark all possible pairs ( sector_list{ ind_loc }(i), seg_frames(j) ) % as belonging to that instance and that object gt_mat{ a }( sector_list{ ind_loc }(:).', seg_frames(:).' ) = object_id; if p.verbose chrono = chrono_check( chrono, a ); end end if p.verbose chrono_stop( chrono ); end