Commit 73f30a2a authored by jonasstienen's avatar jonasstienen
Browse files

Adding news methods to calculate auralisation wavefont coefficients

parent 11835220
function [ mags_linear, valid ] = mags_diffraction_utd( obj, anchor, source_pos, receiver_pos, f )
%mags_diffraction_utd Calculates the diffraction mgnitudes based on uniform
%theory of diffraction (with Kawai approximation).
valid = false;
if ~isfield( anchor, 'anchor_type' )
error( 'The anchor argument does not contain a field "anchor_type"' )
end
% Assemble wedge
n1 = anchor.main_wedge_face_normal( 1:3 );
n2 = anchor.opposite_wedge_face_normal( 1:3 );
loc = anchor.vertex_start( 1:3 );
endPt = anchor.vertex_end( 1:3 );
len = norm( endPt - loc );
aperture_dir = ( endPt - loc ) / len;
% check if wedge is a screen
if abs( cross(n1, n2) ) < itaInfiniteWedge.set_get_geo_eps
w = itaSemiInfinitePlane( n1, loc, aperture_dir );
else
w = itaInfiniteWedge( n1, n2, loc );
end
% Validate
apex_point = w.get_aperture_point_far_field( source_pos, source_pos );
if all( apex_point == source_pos ) || ...
all ( apex_point == source_pos )
warning( 'Skipping a path segment with a double anchor point' )
return
elseif any( isnan( apex_point ) )
warning( 'Skipping a path segment with an invalid aperture point' )
return
end
apx = w.apex_point_approx( source_pos, receiver_pos );
[ ~, D, A ] = ita_diffraction_utd( w, source_pos, receiver_pos, f, obj.c, apx );
mags_linear = abs( A .* D );
valid = true;
end
function [ wavefronts ] = run_for_auralisation( obj, with_progress_bar )
%RUN Calculates the auralisation coefficients (wavefronts) of each (geometrical) propagation path
if ~isfield( obj.pps, 'identifier' )
obj.pps = ita_propagation_paths_add_identifiers( obj.pps );
end
wavefronts = struct();
if nargin < 2 || ~with_progress_bar
with_progress_bar = false;
else
h = waitbar( 0, 'Hold on, running propagation modeling for auralisation' );
end
% Iterate over propagation paths, calculate coefficients per wavefront
N = numel( obj.pps );
for n = 1:N
if with_progress_bar
waitbar( n / N )
end
pp = obj.pps( n );
[ gain, delay, mags, odir, idir, v ] = obj.wavefront_coeffs( pp );
[ ro, do ] = ita_propagation_path_orders( pp );
% Wavefront coefficients struct as required by VA, binaural outdoor renderer
wavefront = struct();
wavefront.gain = gain;
wavefront.delay = delay;
wavefront.frequency_magnitudes = mags;
wavefront.outgoing_direction = odir;
wavefront.incoming_direction = idir;
wavefront.valid = v;
wavefront.reflection_order = ro;
wavefront.diffraction_order = do;
wavefronts.( pp.identifier ) = wavefront;
end
if with_progress_bar
close( h )
end
end
function [ g_sign ] = sign_diffraction_utd( obj, anchor, source_pos, receiver_pos )
%sign_diffraction_utd Calculates the diffraction sign (+1 or -1) based on uniform
%theory of diffraction (illumination region)
if ~isfield( anchor, 'anchor_type' )
error( 'The anchor argument does not contain a field "anchor_type"' )
end
% Assemble wedge
n1 = anchor.main_wedge_face_normal( 1:3 );
n2 = anchor.opposite_wedge_face_normal( 1:3 );
loc = anchor.vertex_start( 1:3 );
endPt = anchor.vertex_end( 1:3 );
len = norm( endPt - loc );
aperture_dir = ( endPt - loc ) / len;
% check if wedge is a screen
if abs( cross(n1, n2) ) < itaInfiniteWedge.set_get_geo_eps
w = itaSemiInfinitePlane( n1, loc, aperture_dir );
else
w = itaInfiniteWedge( n1, n2, loc );
end
% Define section where reflection will occur
receiver_closer_main = ( dot( n1 - n2, receiver_pos - loc ) > 0 );
source_closer_main = ( dot( n1 - n2, source_pos - loc ) > 0 );
if receiver_closer_main && source_closer_main % but not in main face reflection zone ...
reflection_at_main_face = true;
elseif ~receiver_closer_main && ~source_closer_main % but not in opposite face reflection zone ...
reflection_at_main_face = false;
else
% mixed situation
if( dot( n1 - n2, receiver_pos - loc ) + dot( n1 - n2, source_pos - loc ) > 0 )
reflection_at_main_face = true;
else
reflection_at_main_face = false;
end
end
if ita_diffraction_shadow_zone( w, source_pos, receiver_pos )
g_sign = +1.0; % if inside shadow zone, always use positive sign
elseif ita_diffraction_reflection_zone( w, source_pos, receiver_pos, reflection_at_main_face )
g_sign = -1.0; % if inside reflection zone always use negative sign
else
g_sign = ita_diffraction_utd_illumination_sign( w, source_pos, receiver_pos, reflection_at_main_face ); % switch sign roughly half-way
end
end
function [ g, d, mags, odir, idir, valid ] = wavefront_coeffs( obj ,pp )
%WAVEFRONT_COEFFS
if ~isfield( pp, 'propagation_anchors' )
error( 'The propagation_path argument does not contain a field "propagation_anchors"' )
end
d = ita_propagation_path_length( pp ) / obj.c;
f = ita_ANSI_center_frequencies';
g = 1;
mags = ( 1 - ita_atmospheric_absorption_factor( f, d ) ); % Air absorption
valid = true;
incident_spreading_loss_applied = false;
N = numel( pp.propagation_anchors );
if N < 2
error( 'Propagation path %s has less than two anchor points', pp.identifier )
end
for n = 1 : N
if isa( pp.propagation_anchors, 'cell' )
anchor = pp.propagation_anchors{ n };
else
anchor = pp.propagation_anchors( n );
end
assert( strcmpi( anchor.class, 'propagation_anchor' ) )
assert( isfield( anchor, 'anchor_type' ) )
switch( anchor.anchor_type )
case { 'source', 'emitter', 'receiver', 'sensor' }
if n == N
if isa( pp.propagation_anchors, 'cell' )
target_pos = pp.propagation_anchors{ n - 1 }.interaction_point;
else
target_pos = pp.propagation_anchors( n - 1 ).interaction_point;
end
idir = ( anchor.interaction_point - target_pos ) / norm( anchor.interaction_point - target_pos );
% If not already applied by a corresponding anchor type
% (i.e. diffraction), include incident field now
if ~incident_spreading_loss_applied
if ~obj.sim_prop.diffraction
effective_source_distance = ita_propagation_path_length( pp ); % whole distance in this case
else
effective_source_distance = ita_propagation_effective_source_distance( pp, n );
end
g = ita_propagation_spreading_loss( effective_source_distance, 'spherical' );
incident_spreading_loss_applied = true;
end
else
if isa( pp.propagation_anchors, 'cell' )
target_pos = pp.propagation_anchors{ n + 1 }.interaction_point;
else
target_pos = pp.propagation_anchors( n + 1 ).interaction_point;
end
if n == 1
odir = ( target_pos - anchor.interaction_point ) / norm( target_pos - anchor.interaction_point );
end
end
target_position_relative = target_pos( 1:3 ) - anchor.interaction_point( 1:3 ); % Icoming or outgoing direction vector
if obj.sim_prop.directivity && false
mags = mags .* obj.mags_directivity( anchor, target_position_relative / norm( target_position_relative ), f ); % todo
end
case 'specular_reflection'
if n == 1 || n == N
error( 'Detected a specular reflection at beginning or end of propagation path.' )
end
source_pos = pp.propagation_anchors{ n - 1 }.interaction_point;
target_pos = pp.propagation_anchors{ n + 1 }.interaction_point;
effective_source_position = anchor.interaction_point - source_pos;
target_position_relative = target_pos - anchor.interaction_point;
incident_direction_vec = effective_source_position / norm( effective_source_position );
emitting_direction_vec = target_position_relative / norm( target_position_relative );
if obj.sim_prop.reflection
%mags = mags .* obj.mags_reflection( anchor, incident_direction_vec, emitting_direction_vec, f ); % todo
mags = mags .* db2mag( -0.9 );
end
case { 'outer_edge_diffraction', 'inner_edge_diffraction' }
if n == 1 || n == N
error( 'Detected a diffraction at beginning or end of propagation path.' )
end
% Diffraction values are summed up using the source /
% receiver effective distances.
% Spreading loss is spherical until first diffraction, after
% that its a combination of spherical and cylindrical
source_pos = pp.propagation_anchors{ n - 1 }.interaction_point( 1:3 );
target_pos = pp.propagation_anchors{ n + 1 }.interaction_point( 1:3 );
source_direction = ( source_pos - anchor.interaction_point( 1:3 ) ) / norm( source_pos - anchor.interaction_point( 1:3 ) );
target_direction = ( target_pos - anchor.interaction_point( 1:3 ) ) / norm( target_pos - anchor.interaction_point( 1:3 ) );
effective_source_distance = ita_propagation_effective_source_distance( pp, n );
effective_target_distance = ita_propagation_effective_target_distance( pp, n );
effective_source_position = anchor.interaction_point( 1:3 ) + source_direction * effective_source_distance;
effective_target_position = anchor.interaction_point( 1:3 ) + target_direction * effective_target_distance;
if obj.sim_prop.diffraction
if ~incident_spreading_loss_applied
g = ita_propagation_spreading_loss( effective_source_distance, 'spherical' );
g = g * obj.sign_diffraction_utd( anchor, effective_source_position, effective_target_position ); % flip sign to cover phase inversion, TODO
incident_spreading_loss_applied = true;
end
[ temp_mags, valid ] = obj.mags_diffraction_utd( anchor, effective_source_position, effective_target_position, f );
mags = mags .* temp_mags;
if ~valid
disp( 'Invalid path detected: %s', pp.identifier );
end
end
otherwise
sprintf( 'Detected unrecognized anchor type "%s", attempting to continue', anchor.anchor_type )
end
end
assert( incident_spreading_loss_applied )
end
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment