Commit ad3f6de7 authored by Michael Kohnen's avatar Michael Kohnen

added metadata handling to itaHRTF

parents 9b2df9f3 2a77cc7c
function [ cThis ] = reduce_spatial( this, newCoordinates, varargin )
%
% This function is used to reduce the spatial sampling from the current
% directions. This is done with a findnearest search. For a reduction to
% interpolated values use interp
%
% INPUT:
%
%
% OUTPUT:
%
%
%
% Author: Jan-Gerrit Richter <jri@akustik.rwth-aachen.de>
% Version: 2017-11-23
oldCoords = this.getEar('L').channelCoordinates;
% if the desired sampling has more points, its probably unfeasable with
% findnearest search. Abort
if oldCoords.nPoints < newCoordinates.nPoints
error('There are more points in the wanted sampling than are available. You probably want the interp function');
end
% the new coords should have the same radius as the old ones to reduce
% errors
newCoordinates.r = mean(oldCoords.r);
% don't use the mex file to make use of bugfix as poles
% oldCoords = oldCoords.build_search_database;
newIndex = oldCoords.findnearest(newCoordinates);
% calculate all distances from the wanted points to the found points
pointDistances = getVectorLength(newCoordinates,oldCoords.n(newIndex));
% calculate the distance between two neighboring points of the new sampling
newSamplingDistance = getVectorLength(newCoordinates.n(1),newCoordinates.n(2));
% the maximum of the found points should always be smaller
if max(pointDistances) > newSamplingDistance
ita_verbose_info('The found points are further apart than the sampling allows. Something is wrong',0)
end
cThis = this.direction(newIndex);
end
function length = getVectorLength(pointsA, pointsB)
pointsA.r = pointsB.r;
vector = pointsA - pointsB;
length = sqrt(vector.x.^2 + vector.y.^2 + vector.z.^2);
end
\ No newline at end of file
function writeDAFFFile( this, file_path, metadata_user ) function writeDAFFFile( this, file_path, varargin )
% Exports itaHRTF to a DAFF file % Exports itaHRTF to a DAFF file using daffv17_write
%
% Will export the entire angle range of the itaHRTF data set from
% minimum angle to maximum angle in theta and phi by an angular
% resulution of the range divided by the number of available spatial
% points as a equi-angular grid (regular grid, Gaussian sampling).
% %
% Input: file_path (string) [optional] % Input: file_path (string) [optional]
% user metadata (struct created with daff_add_metadata) [optional] % write_daff_args optional arguments (passed to daffv17_write) [optional]
% %
% Required: OpenDAFF matlab scripts, http://www.opendaff.org % Required: OpenDAFF matlab scripts, http://www.opendaff.org
% (but included in ITA-Toolbox) % (but included in ITA-Toolbox)
% %
% Output: none % Output: none
metadata = this.mMetadata;
if nargin >= 3
metadata = metadata_user;
end
hrtf_variable_name = inputname( 1 ); hrtf_variable_name = inputname( 1 );
file_name = [ hrtf_variable_name '_' int2str( this.nSamples ) 'samples_' int2str( this.resAzimuth ) 'x' int2str( this.resElevation ) '.daff']; file_name = [ hrtf_variable_name '_' int2str( this.nSamples ) 'samples_' int2str( this.resAzimuth ) 'x' int2str( this.resElevation ) '.daff'];
if nargin >= 2 if nargin >= 2
...@@ -25,6 +25,37 @@ if nargin == 0 ...@@ -25,6 +25,37 @@ if nargin == 0
end end
%% Prepare daff_write arguments
if strcmp( this.domain, 'time' )
% Content type switcher between time domain (ir) and frequency domain (dft)
% (requires different data functions and content descriptor)
sIn.content = 'ir';
sIn.datafunc = @dfitaHRIRDAFFDataFunc;
sIn.zthreshold = -400; % zero threshold for discarding samples in beginning and end region of IR (where only noise is present)
elseif strcmp( this.domain, 'freq' )
sIn.content = 'dft';
sIn.datafunc = @dfitaHRTFDAFFDataFunc;
end
sIn.metadata = this.mMetadata;
sIn.quantization = 'float32';
sIn.userdata = this;
sIn.orient = [ 0 0 0 ];
sIn.quiet = false;
if ~isempty( varargin )
daff_write_args = ita_parse_arguments( sIn, varargin{ 1 } );
else
daff_write_args = ita_parse_arguments( sIn, varargin );
end
%% Inject content type indicator 'ir' or 'dft' into file name %% Inject content type indicator 'ir' or 'dft' into file name
ct_indicator = 'ir'; ct_indicator = 'ir';
...@@ -33,12 +64,14 @@ if strcmp( this.domain, 'freq' ) ...@@ -33,12 +64,14 @@ if strcmp( this.domain, 'freq' )
end end
[ file_path, file_base_name, file_suffix ] = fileparts( file_name ); [ file_path, file_base_name, file_suffix ] = fileparts( file_name );
if ~strcmp( file_suffix, '.daff' ) if ~strcmp( file_suffix, '.daff' ) && ~isempty( file_suffix )
file_path = fullfile( file_path, strjoin( {file_base_name file_suffix 'v17' ct_indicator 'daff' }, '.' ) ); file_path = fullfile( file_path, strjoin( {file_base_name file_suffix 'v17' ct_indicator 'daff' }, '.' ) );
else else
file_path = fullfile( file_path, strjoin( {file_base_name 'v17' ct_indicator 'daff'}, '.' ) ); file_path = fullfile( file_path, strjoin( {file_base_name 'v17' ct_indicator 'daff'}, '.' ) );
end end
daff_write_args.filename = file_path;
%% Prepare angle ranges and resolution %% Prepare angle ranges and resolution
...@@ -70,49 +103,58 @@ betarange = 180 - [ theta_start_deg theta_end_deg ]; % Flip poles (DAFF starts a ...@@ -70,49 +103,58 @@ betarange = 180 - [ theta_start_deg theta_end_deg ]; % Flip poles (DAFF starts a
assert( betarange( 2 ) >= 0.0 ) assert( betarange( 2 ) >= 0.0 )
assert( betarange( 1 ) <= 180.0 ) assert( betarange( 1 ) <= 180.0 )
daff_write_args.betarange = alpharange;
daff_write_args.alphares = alphares;
daff_write_args.betarange = betarange;
daff_write_args.betares = betares;
%% Assemble metadata %% Assemble metadata (if not already present)
keyname = 'Generation script';
if isempty(daff_write_args.metadata) || ~any( strcmpi( { daff_write_args.metadata(:).name }, keyname ) )
daff_write_args.metadata = daffv17_add_metadata( daff_write_args.metadata, keyname, 'String', 'writeDAFFFile.m' );
end
keyname = 'Generation toolkit';
if ~any( strcmpi( { daff_write_args.metadata(:).name }, keyname ) )
daff_write_args.metadata = daffv17_add_metadata( daff_write_args.metadata, keyname, 'String', 'ITA-Toolkit' );
end
keyname = 'Generation date';
if ~any( strcmpi( { daff_write_args.metadata(:).name }, keyname ) )
daff_write_args.metadata = daffv17_add_metadata( daff_write_args.metadata, keyname, 'String', date );
end
keyname = 'Git Version';
if ~any( strcmpi( { daff_write_args.metadata(:).name }, keyname ) )
versionHash = ita_git_getMasterCommitHash;
daff_write_args.metadata = daffv17_add_metadata( daff_write_args.metadata, keyname, 'String', versionHash );
end
keyname = 'Web resource';
if ~any( strcmpi( { daff_write_args.metadata(:).name }, keyname ) )
daff_write_args.metadata = daffv17_add_metadata( daff_write_args.metadata, keyname, 'String', 'http://www.ita-toolkit.org' );
end
%% Channels
metadata = daffv17_add_metadata( metadata, 'Generation script', 'String', 'writeDAFFFile.m' );
metadata = daffv17_add_metadata( metadata, 'Generation toolkit', 'String', 'ITA-Toolkit' );
metadata = daffv17_add_metadata( metadata, 'Generation date', 'String', date );
metadata = daffv17_add_metadata( metadata, 'Web resource', 'String', 'http://www.ita-toolkit.org' );
channels=this.nChannels/this.nDirections; channels=this.nChannels/this.nDirections;
if(channels<1) if( channels < 1 )
warning('Number of channels per record was not detected correctly, assuming 2 channel records'); warning( 'Number of channels per record was smaller than one, assuming 2 channel records' );
channels = 2; channels = 2;
elseif( mod( channels, 2 ) ~= 0 )
warning( [ 'Number of channels per record was not and integer number, trying floor() of ' num2str( channels ) ] );
channels = floor( channels );
end end
% Content type switcher between time domain (ir) and frequency domain (dft) daff_write_args.channels = channels;
% (requires different data functions)
if strcmp( this.domain, 'time' )
daffv17_write('filename', file_path, ...
'content', 'ir', ...
'datafunc', @dfitaHRIRDAFFDataFunc, ...
'channels', channels, ...
'alphares', alphares, ...
'alpharange', alpharange, ...
'betares', betares, ...
'betarange', betarange, ...
'orient', [ 0 0 0 ], ...
'metadata', metadata, ...
'userdata', this, ...
'quantization', 'float32' );
elseif strcmp( this.domain, 'freq' ) %% Call daff_write and pass argument list
daffv17_write( daff_write_args );
daffv17_write('filename', file_path, ...
'content', 'dft', ...
'datafunc', @dfitaHRTFDAFFDataFunc, ...
'channels', channels, ...
'alphares', alphares, ...
'alpharange', alpharange, ...
'betares', betares, ...
'betarange', betarange, ...
'orient', [ 0 0 0 ], ...
'metadata', metadata, ...
'userdata', this, ...
'quantization', 'float32' );
end end
function varargout = ita_HRTF_postProcessing_smoothLowFreq(varargin)
%ITA_HRTF_POSTPROCESSING_SMOOTHLOWFREQ - Fills low frequency of HRTF measurement
% This function will take a HRTF measurement and fills in low frequency content.
% Data is interpolated to 1 at 0 Hz
% Phase information is preserved.
%
% Syntax:
% audioObjOut = ita_HRTF_postProcessing_smoothLowFreq(audioObjIn, options)
%
% Options (default):
% 'cutOffFrequency' (100) : The lowest point of measured data
% 'upperFrequency' (300) : Frequency information up to this frequency is used during interpolation but not changed
% 'timeShift' (0) : Time shift the data to zero to help
% with unwrap phase
%
% Example:
% audioObjOut = ita_HRTF_postProcessing_smoothLowFreq(audioObjIn,'cutOffFrequency',100)
%
%
% Reference page in Help browser
% <a href="matlab:doc ita_HRTF_postProcessing_smoothLowFreq">doc ita_HRTF_postProcessing_smoothLowFreq</a>
% <ITA-Toolbox>
% This file is part of the ITA-Toolbox. Some rights reserved.
% You can find the license for this m-file in the license.txt file in the ITA-Toolbox folder.
% </ITA-Toolbox>
% Author: Jan-Gerrit Richter -- Email: jri@akustik.rwth-aachen.de
% Created: 21-Aug-2017
%% Initialization and Input Parsing
% all fixed inputs get fieldnames with posX_* and dataTyp
% optonal inputs get a default value ('comment','test', 'opt1', true)
% please see the documentation for more details
sArgs = struct('pos1_data','itaAudio', 'cutOffFrequency', 100,'upperFrequency',300,'timeShift',0);
[input,sArgs] = ita_parse_arguments(sArgs,varargin);
%% body
% for multi instances, do a for loop
for instIndex = 1:length(input)
% first, shift the HRTF to 0. This will allow better phase interpolation
if sArgs.timeShift
shiftSamples = ita_start_IR(input(instIndex));
[tmp] = ita_time_shift(input(instIndex),-shiftSamples,'samples');
else
tmp = input(instIndex);
end
% interpolate to 0
binIdxAtLower = tmp.freq2index(sArgs.cutOffFrequency);
binIdxAtUpper = tmp.freq2index(sArgs.upperFrequency);
dataFromLowerToUpper = tmp.freqData(binIdxAtLower:binIdxAtUpper,:);
interpValues1 = interp1([0 tmp.freqVector(binIdxAtLower:binIdxAtUpper)], [ones(1,tmp.nChannels); abs(dataFromLowerToUpper)], tmp.freqVector(1:binIdxAtUpper));
interpPhase = interp1(tmp.freqVector(binIdxAtLower:binIdxAtUpper),unwrap(angle(dataFromLowerToUpper)),tmp.freqVector(1:binIdxAtUpper),'linear','extrap');
% set the interpolated values into the shifted audio
tmp.freqData(1:binIdxAtUpper,:) = interpValues1.*exp(1i.*interpPhase);
%% Add history line
tmp = ita_metainfo_add_historyline(tmp,mfilename,varargin);
if sArgs.timeShift
% shift the audio back to its original position
data_full(instIndex) = ita_time_shift(tmp,shiftSamples,'samples');
else
data_full(instIndex) = tmp;
end
end
%% Set Output
varargout(1) = {data_full};
%end function
end
...@@ -123,6 +123,7 @@ classdef itaMotorControlNanotec < itaMotorControl ...@@ -123,6 +123,7 @@ classdef itaMotorControlNanotec < itaMotorControl
end end
end end
function moveTo(this,varargin) function moveTo(this,varargin)
% if itaCoordinates are given, the position is passed to all % if itaCoordinates are given, the position is passed to all
% motors. they have to decide if they move % motors. they have to decide if they move
...@@ -178,6 +179,13 @@ classdef itaMotorControlNanotec < itaMotorControl ...@@ -178,6 +179,13 @@ classdef itaMotorControlNanotec < itaMotorControl
end end
function freeFromStopButton(this)
for index = 1:length(this.motorList)
this.motorList{index}.freeFromStopButton();
end
end
function reference(this) function reference(this)
this.clear_commandlist; this.clear_commandlist;
for index = 1:length(this.motorList) for index = 1:length(this.motorList)
...@@ -190,6 +198,10 @@ classdef itaMotorControlNanotec < itaMotorControl ...@@ -190,6 +198,10 @@ classdef itaMotorControlNanotec < itaMotorControl
end end
this.wait4everything; this.wait4everything;
for index = 1:length(this.motorList)
this.motorList{index}.setReferenced(true);
end
end end
function prepareForContinuousMeasurement(this,varargin) function prepareForContinuousMeasurement(this,varargin)
...@@ -207,17 +219,21 @@ classdef itaMotorControlNanotec < itaMotorControl ...@@ -207,17 +219,21 @@ classdef itaMotorControlNanotec < itaMotorControl
% get the preangle and the speed % get the preangle and the speed
sArgs.preAngle = 0; sArgs.preAngle = 0;
sArgs.speed = 2; sArgs.speed = 2;
sArgs.postAngle = 10;
[sArgs notFound] = ita_parse_arguments(sArgs, varargin); [sArgs notFound] = ita_parse_arguments(sArgs, varargin);
% first, do a reference move % first, do a reference move
ita_verbose_info('Moving to reference',1) ita_verbose_info('Moving to reference',1)
this.reference this.reference
ita_verbose_info('Disable reference position',1)
this.motorList{1}.disableReference(1);
ita_verbose_info('Moving to pre angle',1) ita_verbose_info('Moving to pre angle',1)
this.moveTo(motorName,-sArgs.preAngle,'absolut',false,'speed',1) this.moveTo(motorName,-sArgs.preAngle,'absolut',false,'speed',2)
% now prepare the big move but don't start it % now prepare the big move but don't start it
this.moveTo(motorName,360+sArgs.preAngle+15,'speed',sArgs.speed,'absolut',false,'start',0,'limit',0); moveAngle = 360 + sArgs.preAngle + sArgs.postAngle;
this.moveTo(motorName,moveAngle,'speed',sArgs.speed,'absolut',false,'start',0,'limit',0,'direct',1);
this.preparedList = motorName; this.preparedList = motorName;
ita_verbose_info('Finished preparing',2) ita_verbose_info('Finished preparing',2)
end end
...@@ -246,6 +262,8 @@ classdef itaMotorControlNanotec < itaMotorControl ...@@ -246,6 +262,8 @@ classdef itaMotorControlNanotec < itaMotorControl
end end
this.wait4everything this.wait4everything
this.preparedList = []; this.preparedList = [];
ita_verbose_info('Enable reference position',1)
% this.sendControlSequenceAndPrintResults(':port_in_a=7');
end end
function success = add_to_commandlist(this, string_to_send) function success = add_to_commandlist(this, string_to_send)
...@@ -456,7 +474,11 @@ classdef itaMotorControlNanotec < itaMotorControl ...@@ -456,7 +474,11 @@ classdef itaMotorControlNanotec < itaMotorControl
ita_verbose_info('Position reached',1); ita_verbose_info('Position reached',1);
else else
ita_verbose_info('Position NOT reached! - Check for errors!', 0); ita_verbose_info('Position NOT reached! - Check for errors!', 0);
this.send_commandlist(this.failed_command_repititions); % mpo: bugfix: send_commandlist needs argument
%assuming stop button clicked
%call freefrombutton function
% this.freeFromStopButton
% this.send_commandlist(this.failed_command_repititions); % mpo: bugfix: send_commandlist needs argument
% this.isReferenced = false; % this.isReferenced = false;
end end
this.clear_receivedlist; this.clear_receivedlist;
......
...@@ -22,6 +22,7 @@ classdef itaMotorNanotec < itaHandle ...@@ -22,6 +22,7 @@ classdef itaMotorNanotec < itaHandle
stop(this); stop(this);
active = isActive(this); active = isActive(this);
setActive(this,value); setActive(this,value);
% isInitialized(this); % isInitialized(this);
getStatus(this); getStatus(this);
getMotorID(this); getMotorID(this);
...@@ -29,7 +30,14 @@ classdef itaMotorNanotec < itaHandle ...@@ -29,7 +30,14 @@ classdef itaMotorNanotec < itaHandle
% basic moves: requires execution to halt while something is moving % basic moves: requires execution to halt while something is moving
this = moveToReferencePosition(this); this = moveToReferencePosition(this);
this = startMoveToPosition(this); this = startMoveToPosition(this);
disableReference(this,value);
% this = freeFromStopButton(this);
ret = prepareMove(this,position,varargin); ret = prepareMove(this,position,varargin);
end end
methods
function setReferenced(this,value)
this.mIsReferenced = value;
end
end
end end
\ No newline at end of file
...@@ -13,7 +13,7 @@ classdef itaMotorNanotec_Arm < itaMotorNanotec ...@@ -13,7 +13,7 @@ classdef itaMotorNanotec_Arm < itaMotorNanotec
end end
properties properties
horizontalCorrectionFactor = 0;
end end
properties(Constant, Hidden = true) properties(Constant, Hidden = true)
...@@ -81,6 +81,10 @@ classdef itaMotorNanotec_Arm < itaMotorNanotec ...@@ -81,6 +81,10 @@ classdef itaMotorNanotec_Arm < itaMotorNanotec
name = this.motorName; name = this.motorName;
end end
function disableReference(this,value)
end
function sendConfiguration(this) function sendConfiguration(this)
motorControl = this.mMotorControl; motorControl = this.mMotorControl;
motorControl.add_to_commandlist(sprintf('#%d:port_in_a7\r' , this.motorID)); motorControl.add_to_commandlist(sprintf('#%d:port_in_a7\r' , this.motorID));
...@@ -220,14 +224,14 @@ classdef itaMotorNanotec_Arm < itaMotorNanotec ...@@ -220,14 +224,14 @@ classdef itaMotorNanotec_Arm < itaMotorNanotec
return; return;
end end
if (angle < this.ARM_limit(1)) || (angle > this.ARM_limit(2)) if (angle < this.motorLimits(1)) || (angle > this.motorLimits(2))
ita_verbose_info(['Arm: Only values between ' num2str(this.ARM_limit(1)) ' and ' num2str(this.ARM_limit(2)) ' are allowed!'], 0) ita_verbose_info(['Arm: Only values between ' num2str(this.motorLimits(1)) ' and ' num2str(this.motorLimits(2)) ' are allowed!'], 0)
ret = false; ret = false;
% this.wait = false; % this.wait = false;
return; return;
end end
angle = angle - 120.1; % Larger substractive value: Higher position. Checkt at 90�. angle = angle - 120-1.7+this.horizontalCorrectionFactor; % Larger substractive value: Higher position. Checkt at 90�.
motorControl = this.mMotorControl; motorControl = this.mMotorControl;
......
...@@ -17,14 +17,15 @@ classdef itaMotorNanotec_HRTFarc < itaMotorNanotec ...@@ -17,14 +17,15 @@ classdef itaMotorNanotec_HRTFarc < itaMotorNanotec
sArgs_default_motor = struct( ... sArgs_default_motor = struct( ...
'wait', true, ... 'wait', true, ...
'speed', 2, ... 'speed', 1, ...
'VST', 'adaptiv', ... 'VST', 'adaptiv', ...
'limit', true, ... 'limit', true, ...
'continuous', false, ...