Commit b4b3e5e2 authored by henryjandrew's avatar henryjandrew

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

parents 768dcc84 aae1714d
......@@ -119,7 +119,7 @@ classdef itaMSTFni < itaMSTF
if isempty(this.niSession) || isempty(this.niSession.Channels)
this.niSession = init_NI_card(this);
end
% has the samplingRate been changed (NI rate is no exact)
% has the samplingRate been changed (NI rate is not exact)
if abs(this.niSession.Rate - this.samplingRate) > 1
this.niSession = init_NI_card(this);
end
......@@ -171,13 +171,23 @@ classdef itaMSTFni < itaMSTF
imcIdx(chIdx) = find(this.inputMeasurementChain.hw_ch == inputChannels(chIdx));
end
tmpChain = this.inputMeasurementChain(imcIdx);
% save IEPE settings for later
inputIDs = [];
isIEPE = [];
for iTmp = 1:numel(this.niSession.Channels)
if contains(this.niSession.Channels(iTmp).ID,'ai')
inputIDs = [inputIDs str2double(this.niSession.Channels(iTmp).ID(3:end))+1]; %#ok<AGROW>
isIEPE = [isIEPE contains(lower(this.niSession.Channels(iTmp).MeasurementType),'iepe')]; %#ok<AGROW>
end
end
[inputIDs,sortIDs] = sort(inputIDs);
isIEPE = isIEPE(sortIDs);
% we need this to have the correct dimensions for the zeros at the output
outputChannels = this.outputChannels;
this.outputChannels = outputChannels(1);
% element by element
for iElement = elementIds
for iCh = 1:numel(imcIdx)
this.inputChannels = inputChannels(iCh);
if numel(tmpChain(iCh).elements) >= iElement
hw_ch = tmpChain(iCh).hardware_channel;
disp(['Calibration of sound card channel ' num2str(hw_ch)])
......@@ -185,6 +195,9 @@ classdef itaMSTFni < itaMSTF
if tmpChain(iCh).elements(iElement).calibrated ~= -1 % only calibratable devices
disp([' Calibration of ' upper(tmpChain(iCh).elements(iElement).type) ' ' tmpChain(iCh).elements(iElement).name])
this.inputChannels = inputChannels(iCh);
if strcmpi(tmpChain(iCh).elements(iElement).type,'sensor') && isIEPE(hw_ch)
this.set_IEPE_channels(hw_ch);
end
[tmpChain(iCh).elements(iElement).sensitivity] = measurement_chain_elements_calibration_ni(this.niSession,tmpChain(iCh),iElement); %calibrate each element
end
end
......@@ -193,6 +206,7 @@ classdef itaMSTFni < itaMSTF
this.inputMeasurementChain(imcIdx) = tmpChain;
this.inputChannels = inputChannels;
this.outputChannels = outputChannels;
this.set_IEPE_channels(inputIDs(logical(isIEPE)));
disp('****************************** FINISHED *********************************')
end
......@@ -320,17 +334,22 @@ classdef itaMSTFni < itaMSTF
if isempty(channelIds)
error('Nothing to do, maybe your channels are not active?');
end
inputChannels.mapping = inputChannels.mapping(channelIds);
inputChannels.name = inputChannels.name(channelIds);
inputChannels.type = inputChannels.type(channelIds);
inputChannels.sensitivity = inputChannels.sensitivity(channelIds);
inputChannels.isActive = inputChannels.isActive(channelIds);
% Add analog input channels with IEPE supply
for iChannel = 1:numel(channelIds)
channelIdsAll = [channelIds setdiff(this.inputChannels,channelIds)];
isIEPE = [ones(numel(channelIds),1); zeros(numel(channelIdsAll)-numel(channelIds),1)];
[channelIdsAll,channelSort] = sort(channelIdsAll);
isIEPE = isIEPE(channelSort);
% inputChannels.mapping = inputChannels.mapping(channelIds);
% inputChannels.name = inputChannels.name(channelIds);
% inputChannels.type = inputChannels.type(channelIds);
% inputChannels.sensitivity = inputChannels.sensitivity(channelIds);
% inputChannels.isActive = inputChannels.isActive(channelIds);
% First remove all input channels
for iChannel = 1:numel(channelIdsAll)
devIdx = [];
for iCh = 1:numel(this.niSession.Channels)
if strcmpi(inputChannels.name{iChannel},this.niSession.Channels(iCh).Name)
if strcmpi(inputChannels.name{channelIdsAll(iChannel)},this.niSession.Channels(iCh).Name)
devIdx = iCh;
end
end
......@@ -339,11 +358,18 @@ classdef itaMSTFni < itaMSTF
else
error('Could not find your channel');
end
end
% Then add all input channels, and turn on IEPE supply where desired
for iChannel = 1:numel(channelIdsAll)
% then add again
iDevice = inputChannels.mapping{iChannel}(1);
iDeviceChannel = inputChannels.mapping{iChannel}(2);
this.niSession.addAnalogInputChannel(get(niDevices(iDevice),'ID'),iDeviceChannel-1,'IEPE');
this.niSession.Channels(end).Name = inputChannels.name{iChannel};
iDevice = inputChannels.mapping{channelIdsAll(iChannel)}(1);
iDeviceChannel = inputChannels.mapping{channelIdsAll(iChannel)}(2);
if isIEPE(iChannel)
this.niSession.addAnalogInputChannel(get(niDevices(iDevice),'ID'),iDeviceChannel-1,'IEPE');
else
this.niSession.addAnalogInputChannel(get(niDevices(iDevice),'ID'),iDeviceChannel-1,inputChannels.type{channelIdsAll(iChannel)});
end
this.niSession.Channels(end).Name = inputChannels.name{channelIdsAll(iChannel)};
end
end % function
......
......@@ -124,9 +124,14 @@ classdef itaComsolStudy < itaComsolNode
%% Frequency Vector
methods
function SetAllFrequencyVectors(obj, freqVector)
function SetAllFrequencyVectors(obj, varargin)
%Sets the frequency vector for all frequency domain studies.
assert(isnumeric(freqVector) && isrow(freqVector), 'Input must be a numeric row vector')
% Possible inputs:
% 1) numeric vector with frequency data
% 2) char row vector with valid expression
% 3) Three frequencies fStart, fStep and fStop that will be
% used to create a vector fStart:fStep:fStop
frequencies = obj.checkForValidFreqVectorInput(varargin{:});
studies = obj.All();
idxFreqStudies = false(size(studies));
......@@ -137,27 +142,57 @@ classdef itaComsolStudy < itaComsolNode
freqStudies = studies(idxFreqStudies);
if isempty(freqStudies); warning([class(obj) ': No frequency domain study found']); end
for idxFreqStudy = 1:numel(freqStudies)
obj.setFrequencyVectorOfGivenStudy(freqStudies{idxFreqStudy}, freqVector)
obj.setFrequencyVectorOfGivenStudy(freqStudies{idxFreqStudy}, frequencies)
end
end
function SetFrequencyVector(obj, freqVector)
function SetFrequencyVector(obj, varargin)
%Sets the frequency vector for the active study. Throws an error
%if this is not a frequency domain study.
% Possible inputs:
% 1) numeric vector with frequency data
% 2) char row vector with valid expression
% 3) Three frequencies fStart, fStep and fStop that will be
% used to create a vector fStart:fStep:fStop
assert(~isempty(obj.activeNode), 'No active study found')
obj.setFrequencyVectorOfGivenStudy(obj.activeNode, freqVector);
frequencies = obj.checkForValidFreqVectorInput(varargin{:});
obj.setFrequencyVectorOfGivenStudy(obj.activeNode, frequencies);
end
end
methods(Static = true, Access = private)
function setFrequencyVectorOfGivenStudy(study, freqVector)
function frequencies = checkForValidFreqVectorInput(varargin)
if nargin == 1
frequencies = varargin{1};
assert(isnumeric(frequencies) && isvector(frequencies) ||...
ischar(frequencies) && isrow(frequencies),...
'Input must be a numeric vector or a char row vector')
elseif nargin == 3
fStart = varargin{1};
fStep = varargin{2};
fStop = varargin{3};
assert(isnumeric(fStart) && isscalar(fStart) &&...
isnumeric(fStep) && isscalar(fStep)&&...
isnumeric(fStop) && isscalar(fStop), 'If there are three inputs, all must be numeric scalars')
frequencies = itaComsolStudy.createFrequencyRangeStr(fStart, fStep, fStop);
else
error('Invalid number of input arguments')
end
end
function freqString = createFrequencyRangeStr(fStart, fStep, fStop)
freqString = ['range(' num2str(fStart) ','...
num2str(fStep) ',' num2str(fStop) ')'];
end
function setFrequencyVectorOfGivenStudy(study, frequencies)
%Sets the frequency vector for the given study. Throws an error
%if this is not a frequency domain study.
assert(isa(study, 'com.comsol.clientapi.impl.StudyClient'), 'First input must be a Comsol Study node')
assert(isnumeric(freqVector) && isrow(freqVector), 'Second input must be a numeric row vector')
[freqNodeDefined, freqNode] = itaComsolStudy.hasFeatureNode( study, 'freq' );
if ~freqNodeDefined; error('Given Comsol study is no frequency study'); end
freqNode.set('plist', num2str(freqVector));
if isnumeric(frequencies)
if iscolumn(frequencies); frequencies=frequencies.'; end
frequencies = num2str(frequencies);
end
freqNode.set('plist', frequencies);
end
end
......
%% RAVEN simulation: Example for HOA simulation of a shoebox (only encoded RIRs)
% Author: las@akustik.rwth-aachen.de
% date: 2019/06/26
%
% <ITA-Toolbox>
% This file is part of the application Raven for the ITA-Toolbox. All rights reserved.
% You can find the license for this m-file in the application folder.
% </ITA-Toolbox>
%% project settings
ravenBasePath = 'C:\ITASoftware\Raven\';
myLength=9;
myWidth=7;
myHeight=3;
projectName = [ 'myHOA_ShoeboxRoom' num2str(myLength) 'x' num2str(myWidth) 'x' num2str(myHeight) ];
%% create project and set input data
rpf = itaRavenProject([ ravenBasePath 'RavenInput\Classroom\Classroom.rpf' ]); % modify path if not installed in default directory
rpf.copyProjectToNewRPFFile([ ravenBasePath 'RavenInput\' projectName '.rpf' ]);
rpf.setProjectName(projectName);
rpf.setModelToShoebox(myLength,myWidth,myHeight);
rpf.setNumParticles(60000); % 60,000 particles for ray tracing simulation
rpf.setFilterLength(2000); % FilterLength (in ms)
rpf.setISOrder_PS(2); % set Image source order
%% HOA configuration
rpf.setGenerateBRIR(0); % deactivate binaural filters
rpf.setGenerateRIR(0); % deactivate mono filters
rpf.setGenerateISHOA(1); % activate HOA for image sources
rpf.setGenerateRTHOA(1); % activate HOA for ray tracing
rpf.setAmbisonicsOrder(2); % set HOA Order
%% adjust wall materials of room
for iMat=1:6
myAbsorp = 0.1 * ones(1,31); % 10% absorption for all walls
myScatter = 0.3 * ones(1,31); % 30% scattering for all walls
rpf.setMaterial(rpf.getRoomMaterialNames{iMat},myAbsorp,myScatter);
end
%% start simulation
rpf.run;
%% get results: RAVEN HOA results use the ANC notation: https://en.wikipedia.org/wiki/Ambisonic_data_exchange_formats#ACN
RIRs = rpf.getAmbisonicsImpulseResponseItaAudio; % as ITA audio object
RIRs_raw = rpf.getAmbisonicsImpulseResponse; % as matrix
%% check results
ita_plot_time_dB(RIRs);
%% and now?
% results need to be convolved with an anechoic signal (ita_convolve)
% and then decoded using a HOA decoder, e.g., using
% ita_hoa_decode(Bformat, LoudspeakerPos, varargin) for B-Format signals
\ No newline at end of file
%% RAVEN simulation: Example to start an acoustic animation script from MATLAB
% Author: las@akustik.rwth-aachen.de
% date: 2019/06/25
%
% Example script to configure and run an acoustic animation.
% Running an acoustic animation is more efficient if operated from a batch
% script instead of this matlab script (see bin64\runAnimationTest.bat)
%
%
% <ITA-Toolbox>
% This file is part of the application Raven for the ITA-Toolbox. All rights reserved.
% You can find the license for this m-file in the application folder.
% </ITA-Toolbox>
% set raven base path if not installed in default directory
ravenBasePath = 'C:\ITASoftware\Raven\';
% load raven project test file for acoustic animation
animationRPFfile = [ ravenBasePath 'RavenInput\Animation\AnimationTest.rpf' ];
animationMatlabObject = itaRavenProject(animationRPFfile); % to modify simulation settings
%% load and modify acoustic animation settings file
animationSettings = [ ravenBasePath 'RavenInput\Animation\AnimationTest.ini' ];
animationSettingsFile = IniConfig();
animationSettingsFile.ReadFile(animationSettings); % load the settings file to the matlab workspace to modify configuration
% example settings
animationSettingsFile.SetValues('AcousticAnimation', 'blockSize', 1024); % set blocksize length to 1024
animationSettingsFile.SetValues('AcousticAnimation', 'overlap', 0.2); % set block overlap to 20%
animationSettingsFile.SetValues('AcousticAnimation', 'rayTracingUpdateRadius', 0.35); % change to ray tracing update to 35 cm
% change path to source position file. Note: if relative paths are used,
% paths are relative to the raven binary, not relative to current your matlab path
% Info: Format creating files for receiver and source positions
% time posx posy poz viewx viewy viewz upx upy upz
animationSettingsFile.SetValues('AcousticAnimation', 'sourcePositionFile','..\RavenInput\Animation\AnimationTestSource.ini');
% save acoustic animation settings file
animationSettingsFile.WriteFile(animationSettings);
%% run animation script.
% Note: The acoustic animation script uses a special binary to run the simulation (bin64/RavenConsoleAcousticAnimation64)
prevPath = pwd;
cd([ravenBasePath 'bin64\']);
dos([ 'RavenConsoleAcousticAnimation64.exe "' animationRPFfile '" -acousticanimation "' animationSettings '"' ],'-echo');
cd(prevPath);
%% check / play results
animationMatlabObject.openOutputFolder
outputFilePath=animationSettingsFile.GetValues('AcousticAnimation','outputSignal');
outputFile=ita_read([ravenBasePath outputFilePath(4:end) ]);
outputFile.play
\ No newline at end of file
......@@ -11,14 +11,14 @@ opts.virtualSpeaker = false; % true || Indicates whether to
opts.coordSystem = 'itaCoordinates'; % 'openGL' || indicates in which coordinate system the output is
opts.isItaCoordinates = true; % true || indicates whether the output is a itaCoordinate or not (warning: if combined with coordSystem='opneGL', the angles for azimuth and elevation are not correct
opts.heightCorrection = 0; % in meter || ensures that the loudspeakers are around the point (0 0 0), standard value is height of the bigger loudspeaker in the horizontal plane
opts.average = false; % false || Mittel Werte um ein gleichmäßiges Array zu erhalten
opts=ita_parse_arguments(opts, varargin);
% X Y Z (openGL)
pos = itaCoordinates(zeros(12,3));
pos.r= [2.283 2.293 2.273 2.278 2.344 2.324 2.333 2.336 2.233 2.228 2.231 2.233];
pos.phi_deg=[45.317 313.757 225.547 134.557 0 270 180 90 0 270 180 90];
pos.theta_deg=[90 90 90 90 58.148 57.783 57.980 58.228 117.411 117.391 117.524 117.700];
pos.theta_deg=[90 90 90 90 56.0587 55.7247 55.8851 55.9909 117.411 117.391 117.524 117.7];
if opts.virtualSpeaker
pos.cart = [pos.cart;...
......@@ -26,6 +26,12 @@ if opts.virtualSpeaker
0 0 2.3]; % virtual speaker
end
if opts.average
end
% Correction of head height
pos.z=pos.z-opts.heightCorrection;
......
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