Commit 44213cb2 authored by Lukas Aspöck's avatar Lukas Aspöck

Merge branch 'master' of https://git.rwth-aachen.de/ita/toolbox

parents da448aa3 ba929e71
...@@ -471,6 +471,7 @@ classdef itaHRTF < itaAudio ...@@ -471,6 +471,7 @@ classdef itaHRTF < itaAudio
chCoord.theta(2:2:2*props.numRecords) = thetaM; chCoord.theta(2:2:2*props.numRecords) = thetaM;
this.mMetadata = metadata; this.mMetadata = metadata;
this.samplingRate = props.samplerate;
this.data = data; this.data = data;
this.mDirCoord = itaCoordinates([radius thetaM phiM],'sph'); this.mDirCoord = itaCoordinates([radius thetaM phiM],'sph');
this.channelCoordinates = chCoord; this.channelCoordinates = chCoord;
......
...@@ -51,12 +51,15 @@ ms.twait = 0.03; ...@@ -51,12 +51,15 @@ ms.twait = 0.03;
coords = ita_generateSampling_equiangular(5,5); coords = ita_generateSampling_equiangular(5,5);
coords_cut = coords.n(coords.theta_deg == 90); coords_cut = coords.n(coords.theta_deg == 90);
iMS.measurementSetup = ms;
iMS.measurementPositions = coords_cut; iMS.measurementPositions = coords_cut;
iMS.waitBeforeMeasurement = 1;
saveName = 'test'; saveName = 'test';
iMS.dataPath = saveName; iMS.dataPath = saveName;
iMS.reference; iMS.reference;
iMS.doSorting = 0;
iMS.run; iMS.run;
% always leave the turntable in reference position % always leave the turntable in reference position
......
...@@ -10,7 +10,7 @@ function result = ita_HRTFarc_postProcess(varargin) ...@@ -10,7 +10,7 @@ function result = ita_HRTFarc_postProcess(varargin)
% 'opt2' (defaultopt1) : description % 'opt2' (defaultopt1) : description
% 'opt3' (defaultopt1) : description % 'opt3' (defaultopt1) : description
% %
% Example: % Example:
% audioObjOut = ita_HRTF_arc_postProcess(audioObjIn) % audioObjOut = ita_HRTF_arc_postProcess(audioObjIn)
% %
% See also: % See also:
...@@ -111,7 +111,7 @@ for index = 1:numFiles ...@@ -111,7 +111,7 @@ for index = 1:numFiles
allMeasurementsRaw(index,index2) = tmp; allMeasurementsRaw(index,index2) = tmp;
data_crop = ita_time_window(tmp,options.tw);% Q: options.tw = [6ms 8ms] data_crop = ita_time_window(tmp,options.tw,'time');% Q: options.tw = [6ms 8ms]
% make end sample be div by 4 for daff export % make end sample be div by 4 for daff export
endSample = round(options.tw(2) .* tmp(1).samplingRate)+1; endSample = round(options.tw(2) .* tmp(1).samplingRate)+1;
endSample = endSample + mod(endSample,4); endSample = endSample + mod(endSample,4);
......
...@@ -183,7 +183,7 @@ classdef itaMotorNanotec_HRTFarc < itaMotorNanotec ...@@ -183,7 +183,7 @@ classdef itaMotorNanotec_HRTFarc < itaMotorNanotec
sArgs = this.sArgs_default_motor; sArgs = this.sArgs_default_motor;
sArgs.continuous = false; sArgs.continuous = false;
if ~isempty(varargin) if ~isempty(varargin)
sArgs = ita_parse_arguments(sArgs,varargin); [sArgs,~] = ita_parse_arguments(sArgs,varargin);
end end
if sArgs.continuous if sArgs.continuous
ret = this.prepare_move(position, sArgs); ret = this.prepare_move(position, sArgs);
......
...@@ -158,7 +158,7 @@ classdef itaMotorNanotec_Turntable < itaMotorNanotec ...@@ -158,7 +158,7 @@ classdef itaMotorNanotec_Turntable < itaMotorNanotec
sArgs.direct = true; sArgs.direct = true;
sArgs.speed = this.sArgs_default_motor.speed; sArgs.speed = this.sArgs_default_motor.speed;
if ~isempty(varargin) if ~isempty(varargin)
sArgs = ita_parse_arguments(sArgs,varargin); [sArgs,~] = ita_parse_arguments(sArgs,varargin);
end end
if sArgs.continuous if sArgs.continuous
ret = this.prepare_move(position, 'speed', sArgs.speed,'continuous', true); ret = this.prepare_move(position, 'speed', sArgs.speed,'continuous', true);
......
...@@ -111,11 +111,12 @@ classdef itaEimar < itaMeasurementTasksScan ...@@ -111,11 +111,12 @@ classdef itaEimar < itaMeasurementTasksScan
% </ITA-Toolbox> % </ITA-Toolbox>
properties properties
waitForSerialPort = 0.020; % Time to wait between two commands waitForSerialPort = 0.020; % Time to wait between two commands
timeout_response = 0.1; % Time in seconds within each motor has to response to a command! timeout_response = 0.1; % Time in seconds within each motor has to response to a command!
timeout_move = 300; % Time in seconds within each device has to reach their new position! timeout_move = 300; % Time in seconds within each device has to reach their new position!
failed_command_repititions = 5; % How often do we repeat commands until we throw an error? failed_command_repititions = 5; % How often do we repeat commands until we throw an error?
doSorting = true; % sort the measurement coordinates for arm due to shorter measurement time doSorting = true; % sort the measurement coordinates for arm due to shorter measurement time
armCorrectionAngle = 0; % Correct the position of the arm. Check at 90° if horizontal. Value <0 -> higher position
end end
% ********************************************************************* % *********************************************************************
properties (Access = protected, Hidden = true) properties (Access = protected, Hidden = true)
...@@ -924,7 +925,7 @@ classdef itaEimar < itaMeasurementTasksScan ...@@ -924,7 +925,7 @@ classdef itaEimar < itaMeasurementTasksScan
return; return;
end end
angle = angle - 119.01; % Larger substractive value: Higher position. Checkt at 90°. angle = angle - 119.01 + this.armCorrectionAngle; % Larger substractive value: Higher position. Checkt at 90�.
...@@ -938,7 +939,7 @@ classdef itaEimar < itaMeasurementTasksScan ...@@ -938,7 +939,7 @@ classdef itaEimar < itaMeasurementTasksScan
% 64. 254="Vorschubkonstantenmodus", 255=Adaptive Stepdivider % 64. 254="Vorschubkonstantenmodus", 255=Adaptive Stepdivider
% Closed_loop = Turn on the closed loop regulation % Closed_loop = Turn on the closed loop regulation
% Acceleration_ramp = Value in Hz/ms % Acceleration_ramp = Value in Hz/ms
% Gear_ratio = Getriebeübersetzung % Gear_ratio = Gear Ratio
% Current = Maximum current in percent % Current = Maximum current in percent
% Ramp_mode = 0=trapez, 1=sinus-ramp, 2=jerkfree-ramp % Ramp_mode = 0=trapez, 1=sinus-ramp, 2=jerkfree-ramp
% ------------------------------------------------------------- % -------------------------------------------------------------
...@@ -1000,11 +1001,11 @@ classdef itaEimar < itaMeasurementTasksScan ...@@ -1000,11 +1001,11 @@ classdef itaEimar < itaMeasurementTasksScan
this.add_to_commandlist(sprintf('#%d:CL_KD_v_Z=%d\r' , this.motorID_arm, D_zaehler)); this.add_to_commandlist(sprintf('#%d:CL_KD_v_Z=%d\r' , this.motorID_arm, D_zaehler));
this.add_to_commandlist(sprintf('#%d:CL_KD_v_N=%d\r' , this.motorID_arm, D_nenner)); this.add_to_commandlist(sprintf('#%d:CL_KD_v_N=%d\r' , this.motorID_arm, D_nenner));
% Pos-Kreis: % Pos-Kreis:
% Für 10°/s % For 10 deg/s
%P = 100;% (400 = default) %P = 100;% (400 = default)
%I = 1.5;% (2 = default) %I = 1.5;% (2 = default)
%D = 300;% (700 = default) %D = 300;% (700 = default)
% Für 3°/s % For 3 deg/s
P = 200;% (400 = default) P = 200;% (400 = default)
I = 1.0;% (2 = default) I = 1.0;% (2 = default)
D = 300;% (700 = default) D = 300;% (700 = default)
......
function varargout = ita_device_list_ITA(mode,token,varargin) function varargout = ita_device_list_ITA(mode,token,varargin)
% ITA_DEVICE_LIST - the ITA device List % ITA_DEVICE_LIST - the ITA device List
% %
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
% %
% PLEASE BE VERY CAREFUL WHEN EDITING THE DEVICE LIST % PLEASE BE VERY CAREFUL WHEN EDITING THE DEVICE LIST BY HAND, PLEASE
% BY HAND, CONSULT PDI OR MMT BEFORE MAKING CHANGES % CONSULT THE ITA-TOOLBOX DEVELOPER TEAM BEFORE MAKING ANY CHANGES
% %
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
% %
% Syntax: % Syntax:
% res = ita_device_list() returns all devices in a cell % res = ita_device_list() returns all devices in a cell
...@@ -31,12 +31,6 @@ function varargout = ita_device_list_ITA(mode,token,varargin) ...@@ -31,12 +31,6 @@ function varargout = ita_device_list_ITA(mode,token,varargin)
% </ITA-Toolbox> % </ITA-Toolbox>
% if exist('ita_device_list_ITA.m','file')
% varargout = ita_device_list_ITA(mode,token,varargin{:});
% return;
% end
if nargin == 3 if nargin == 3
hwch = varargin{1}; hwch = varargin{1};
else else
...@@ -49,7 +43,7 @@ if nargin >= 1 && isa(mode,'itaMeasurementChainElements') ...@@ -49,7 +43,7 @@ if nargin >= 1 && isa(mode,'itaMeasurementChainElements')
MCE = mode; MCE = mode;
devHandle = ita_device_list_handle; devHandle = ita_device_list_handle;
list = devHandle(); %get entire list list = devHandle(); %get entire list
[elementfound idx] = ismember(MCE.name,list(:,1)); %find element [elementfound, idx] = ismember(MCE.name,list(:,1)); %find element
if elementfound if elementfound
sens = list{idx,2}; sens = list{idx,2};
% picModel = ita_model2picture(list{idx,3}); % picModel = ita_model2picture(list{idx,3});
...@@ -64,7 +58,7 @@ if nargin >= 1 && isa(mode,'itaMeasurementChainElements') ...@@ -64,7 +58,7 @@ if nargin >= 1 && isa(mode,'itaMeasurementChainElements')
% MCE.picModel = picModel; % MCE.picModel = picModel;
end end
else else
ita_verbose_info('Element not in list',1); ita_verbose_info(['Element not found in the device list: ', MCE.name], 1);
end end
...@@ -111,29 +105,25 @@ if nargin >= 2 ...@@ -111,29 +105,25 @@ if nargin >= 2
start_idx = strfind(token,'['); start_idx = strfind(token,'[');
end_idx = strfind(token,']'); end_idx = strfind(token,']');
if ~isempty(start_idx) && ~isempty(end_idx) if ~isempty(start_idx) && ~isempty(end_idx)
token = token(start_idx+1:end_idx-1); %get the name name = token(start_idx+1:end_idx-1); %get the name
else
name = token;
end end
name = token;
for idx = 1:size(device,1) for idx = 1:size(device,1)
if strcmpi(token,device{idx,1}) if strcmpi(name,device{idx,1})
res = itaValue(device{idx,2}); res = itaValue(device{idx,2});
break break
end end
end end
% % etwas schoener
% idxDevice = find(strcmpi(device(:,1), token));
% if ~isempty(idxDevice)
% res = itaValue(device{idxDevice,2});
% end
start_idx = strfind(token,'(');
end_idx = strfind(token,')');
if ~isempty(start_idx) && ~isempty(end_idx)
res = itaValue(token(start_idx+1:end_idx-1));
end
if isempty(res) if isempty(res)
res = itaValue(-1); ita_verbose_info(['Element not found in the device list: ', token], 1)
disp(['element not in list: ' token '.']) start_idx = strfind(token,'(');
end_idx = strfind(token,')');
if ~isempty(start_idx) && ~isempty(end_idx)
res = itaValue(token(start_idx+1:end_idx-1));
else
res = itaValue(-1);
end
end end
end end
end end
...@@ -452,6 +442,11 @@ device(end+1,:) = { 'ITA-KK KE4 Child right','0.0098573 V/Pa','ke4',0}; ...@@ -452,6 +442,11 @@ device(end+1,:) = { 'ITA-KK KE4 Child right','0.0098573 V/Pa','ke4',0};
device(end+1,:) = { 'Neumann-KK left','1 V/Pa','schoeps',1}; device(end+1,:) = { 'Neumann-KK left','1 V/Pa','schoeps',1};
device(end+1,:) = { 'Neumann-KK right','1 V/Pa','schoeps',1}; device(end+1,:) = { 'Neumann-KK right','1 V/Pa','schoeps',1};
% values are taken from calibration sheets by DKD (Deutscher
% Kalibrierdienst)
device(end+1,:) = { 'GRAS Headphone Testfixture Left','0.01211 V/Pa','RA0401',1};
device(end+1,:) = { 'GRAS Headphone Testfixture Right','0.0124 V/Pa','RA0401',1};
device(end+1,:) = { 'HEAD HMS III with ear simulator - IEC 711','0.01165 V/Pa','none',0}; device(end+1,:) = { 'HEAD HMS III with ear simulator - IEC 711','0.01165 V/Pa','none',0};
device(end+1,:) = { 'Hoertnix BTE right front_hwch01','0.0159 V/Pa','none',1}; device(end+1,:) = { 'Hoertnix BTE right front_hwch01','0.0159 V/Pa','none',1};
......
...@@ -348,6 +348,10 @@ classdef itaOptitrack < handle ...@@ -348,6 +348,10 @@ classdef itaOptitrack < handle
%% DESTRUCTOR %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% %% DESTRUCTOR %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
function destroy(Optitrack_obj) function destroy(Optitrack_obj)
delete(Optitrack_obj);
warning('[itaOptitrack] Method .destroy will be changed to Method .delete in future versions');
end
function delete(Optitrack_obj)
% delete Optitrack_obj (invalid handle remains -> clear('Optitrack_obj')) % delete Optitrack_obj (invalid handle remains -> clear('Optitrack_obj'))
if Optitrack_obj.isConnected if Optitrack_obj.isConnected
......
function [ ref_factor, ref_db ] = calibrate( obj, cal_time, channels, method )
% Default track_id and channel_num is 1, time can be relative
% seconds of record or absolute date
% methods: 'rms', 'maximum' or 'wideband' (default)
if nargin < 4
method = 'wideband';
end
if nargin < 3
channels = 1;
end
% Extract non-calibrated (!) signal
cal_signal = obj.extract( cal_time, channels, false );
if strcmp( method, 'maximum' )
% Variates the sample truncation and uses (jst)
max_samples = 60;
for l = 1:max_samples
calibration_signal_chunk = ita_time_crop( cal_signal, [1 cal_signal.nSamples-l], 'samples' );
power(l) = max( abs( calibration_signal_chunk.freqData ) );
end
ref_db = 20*log10( max( power ) ); % == 94 dB (Sound Calibrator Type 4231)
ref_factor = max( power );
elseif strcmp( method, 'wideband' )
% Include neighbouring frequency bins around target frequency
% of 1kHz (mgu)
neighborBins = 20;
nSamplesMaxCut = 100;
justMaxVec = zeros(nSamplesMaxCut,1);
maxAndNeighborVec = zeros(nSamplesMaxCut,1);
for iSamplesCut = 1:nSamplesMaxCut
tmpSine = cal_signal; % copy original
tmpSine.timeData = tmpSine.timeData(1:end-iSamplesCut,1); % truncate signal
[justMaxVec(iSamplesCut), idxMax] = max(abs(tmpSine.freqData));
maxAndNeighborVec(iSamplesCut) = sqrt( sum(abs(tmpSine.freqData(idxMax-neighborBins:idxMax+neighborBins)).^2) );
end
ref_db = 20*log10( max( maxAndNeighborVec ) );
ref_factor = max( maxAndNeighborVec );
else
% Use root-mean-square (ITA Toolbox RMS)
rms = cal_signal.rms;
if rms > 0
ref_db = 20*log10( rms );
else
ref_db = -Inf;
end
ref_factor = rms;
end
track_ids = obj.get_track_ids( channels );
for t = 1:numel( track_ids )
obj.tracks{ track_ids( t ) }.cal_ref_factor = ref_factor;
end
end
function disp( obj )
% Displays itaZOOMSession
% <ITA-Toolbox>
% This file is part of the ITA-Toolbox. All rights reserved.
% You can find the license for this m-file in the application folder.
% </ITA-Toolbox>
disp_str = '';
disp_str = [ disp_str sprintf( ' -- itaZOOMSession -----------\n' ) ];
disp_str = [ disp_str sprintf( '\tProject name: %s\n', obj.project_name ) ];
disp_str = [ disp_str sprintf( '\tPath: %s\n', obj.path ) ];
disp_str = [ disp_str sprintf( '\tStartdate: %s\n', datestr( obj.startdate ) ) ];
disp( disp_str )
end
function snippet = extract( obj, extract_seconds, channels, calibrated )
% Default channel_num is 1, time can be relative
% seconds of record or absolute date
if numel( extract_seconds ) ~= 2
error( 'Time for extraction has to be a 1-by-2 vector with start and end value' )
end
if ( sum( extract_seconds < 0 ) || sum( extract_seconds > obj.trackLength ) )
error( 'Requested time [ %1.1fs %1.1fs ] is not (or only partly) contained in this session with track length of %1.1fs', extract_seconds( 1 ), extract_seconds( 2 ), obj.trackLength )
end
if nargin < 4
calibrated = true;
end
if nargin < 3
channels = 1;
end
if ~obj.has_channels( channels )
error( 'Could not find tracks for requested channels %i', channels )
end
snippet = itaAudio();
for c = 1:numel( channels )
track_ids = obj.get_track_ids( channels( c ) );
ets = extract_seconds; % sliding
bFirstPart = false;
bSecondPart = false;
for i=1:numel( obj.tracks{ track_ids }.part_ids )
if obj.tracks{ track_ids }.part_ids( i ) > 0
track_part_str = sprintf( '%04d', obj.tracks{ track_ids }.part_ids( i ) );
track_base_name = [ obj.identifier '_Tr' num2str( channels ) '-' track_part_str ];
else
track_base_name = [ obj.identifier '_Tr' num2str( channels ) ];
end
track_full_path = fullfile( obj.path, [ track_base_name '.wav' ] );
track_part_meta = ita_read_wav( track_full_path, 'metadata' );
part_track_length = obj.tracks{ track_ids }.trackLength_parts( i );
if ets > track_part_meta.trackLength
ets = ets - part_track_length;
continue;
end
if ets <= track_part_meta.trackLength
if ets >= 0
% requested snippet is completely in this part.
snippet = ita_read( track_full_path, ets, 'time' );
snippet.channelUnits = obj.tracks{ track_ids }.channelUnits;
if obj.tracks{ track_ids }.cal_ref_factor ~= 1 && calibrated
snippet = ita_amplify( snippet, 1 / obj.tracks{ track_ids }.cal_ref_factor );
end
return;
end
end
% Snippet overlaps track parts
if ets( 1 ) < track_part_meta.trackLength && ets( 2 ) > track_part_meta.trackLength
% beginning if snippet is in this part.
snippet_first = ita_read( track_full_path, [ ets( 1 ) track_part_meta.trackLength ], 'time' );
bFirstPart = true;
if obj.tracks{ track_ids }.cal_ref_factor ~= 1 && calibrated
snippet_first = ita_amplify( snippet_first, 1 / obj.tracks{ track_ids }.cal_ref_factor );
end
ets = ets - part_track_length;
elseif ets( 1 ) < 0 && ets( 2 ) > 0
% end of snippet is in this part.
snippet_second = ita_read( track_full_path, [ 0 ets( 2 ) ], 'time' );
bSecondPart = true;
if obj.tracks{ track_ids }.cal_ref_factor ~= 1 && calibrated
snippet_second = ita_amplify( snippet_second, 1 / obj.tracks{ track_ids }.cal_ref_factor );
end
end
end
if bFirstPart && bSecondPart
snippet = ita_append( snippet_first, snippet_second ); % Concat time data, already calibrated
snippet.channelUnits = 'Pa';
return
end
end
error( 'Requested time snippet is not found in this session, unkown error' )
end
function [ ref_factor, ref_db ] = get_calibration_factors( obj, channels )
% Returns the calibration factor (number time data has to be
% devided) and level to be subtrated for given channels
% (or all if channels option missing)
if nargin < 2
channels = 1:obj.channels;
end
ref_factor = zeros( numel( channels ), 1 );
for c=1:channels
assert( numel( c ) == 1 );
track_id = obj.get_track_ids( c );
ref_factor( c ) = obj.tracks{ track_id }.cal_ref_factor;
end
ref_db = 20 * log10( ref_factor );
end
function [ track_ids ] = get_track_ids( obj, channels )
% Returns the tracks that correspond to a certain audio channel
% on the ZOOM device (track ids are not necessarily in the same order
% as channels and there might be less tracks than the used
% channel number (i.e. if only channel 3 has been recorded)
track_ids = [];
for t = 1:numel( obj.tracks )
if obj.tracks{ t }.channel_idx == channels
track_ids( end + 1 ) = t;
end
end
end
function [ ret ] = has_channels( obj, channels )
% Checks if given channels are available
ret = zeros( numel( channels ), 1 );
for t = 1:numel( obj.tracks )
for c = 1:numel( channels )
if obj.tracks{ t }.channel_idx == channels( c )
ret( c ) = true;
end
end
end
end
\ No newline at end of file
classdef itaZOOMSession < handle
%ITAZOOMSESSION Lightweight class around a ZOOM session (a 'ZOOM0001' folder with
%recorded tracks) that supports easier calibration and extraction of
%time data
% <ITA-Toolbox>
% This file is part of the ITA-Toolbox. All rights reserved.
% You can find the license for this m-file in the application folder.
% </ITA-Toolbox>
properties(Hidden = true, Access = private)
session_valid = false;
session_ready = false;
session_calibrated = false;
tracks = cell( 0 );
end
properties( Hidden = false, Access = public )
path = '';
subfolder = '';
project_name = 'Unnamed ZOOM session';
identifier = '';
index = 0;
startdate;
channels = 0;
trackLength = 0;