Contenido principal

Model, Evaluate, and Design Acoustic Spaces

Since R2026a

In this example, you model, analyze, and optimize the acoustics of an indoor space. You will:

  • Define a room with sources and receivers

  • Estimate reverberation time (RT-60) using analytical and physical models

  • Simulate room impulse responses using the acousticRoomResponse function

  • Evaluate acoustics using standard-based metrics RT-60 and speech transmission index (STI) with the rt60 and speechTransmissionIndex functions

  • Evaluate the room acoustics and scenario effects on speech using the popular metrics short-time objective intelligibility (STOI) and virtual speech and quality objective listener (ViSQOL) with the stoi and visqol functions

  • Analyze the effects of source, noise, and listener positions on acoustics and speech transmission

  • Choose a material to optimize an acoustic metric

The workflow is applicable to classrooms, lecture halls, studios, and other indoor spaces.

Define and Visualize Room

Use the supporting function iGetClassroom to return a struct array containing the dimensions, surface material coefficients, and locations for a source, receiver, and noise source. Dimensions and locations are given in meters. The center frequencies are given in hertz.

room = iGetClassroom()
room = struct with fields:
             Dimensions: [14 12 5]
      CenterFrequencies: [125 250 500 1000 2000 4000]
     MaterialAbsorption: [6×6 double]
     MaterialScattering: [6×6 double]
         SourceLocation: [2 6 2]
       ReceiverLocation: [12 6 1.5000]
    NoiseSourceLocation: [7.3000 5.3000 3.9000]
            Description: "Empty Classroom"

Use the supporting function iPlotRoom to visualize. An empty rectangular room, as shown here, is called a "shoe-box" model and can be used for some gross analysis and pedagogy. A more realistic analysis would include models of furniture and occupants.

iPlotRoom(room)

Figure contains an axes object. The axes object with title Empty Classroom, xlabel X (m), ylabel Y (m) contains 13 objects of type patch, line. One or more of the lines displays its values using only markers These objects represent Source, Receiver, Noise Source.

Estimate RT-60 Using Sabine's Formula

The Sabine equation estimates the reverberation time (RT-60), which is the time it takes for sound to decay 60 decibels after the source stops. Published by Wallace Clement Sabine in 1900, it is the first reverberation-time equation and continues to be a fundamental tool of architectural acoustics [1]. The formula relates the reverberation time with a room's volume and absorption:

RT60=0.161VA,

where RT60 is the reverberation time in seconds, V is the room volume in m3, and A is the total absorption of the room in metric sabins. The total absorption is computed as the sum of the surface areas multiplied by their respective absorption coefficients, iSiαi.

Material absorption coefficients vary with frequency, so RT-60 values are frequency-dependent:

RT60(f)=0.161ViSi,fαi,f.

The Sabine equation does not account for the source/receiver positions, scattering or air absorption; it is a general formula best for rooms with average absorption coefficients below 0.25.

Use the supporting function iRT60model to estimate the frequency-dependent RT-60.

t60 = iRT60model(room)
t60=1×6 table
      125       250      500      1000      2000      4000 
    _______    ______    ____    ______    ______    ______

    0.85087    1.2645    1.68    1.5737    1.3832    1.4895

Simulate Room Impulse Response

To analyze a room with a more complex physical model, use acousticRoomResponse to estimate an impulse response based on dimensions, materials, and source/receiver locations. The function supports the image-source, stochastic ray tracing, and hybrid methods. For image-source modeling, estimate the required order (number of reflections) by:

N=max(c×RT60(f)4V/S),

where

  • N is the image source order

  • c is the speed of sound

  • RT60(f) is the frequency-dependent RT-60

  • V is the volume

  • S is the surface area

The quantity 4V/S is sometimes called the mean free path and is the average distance a sound travels between two successive reflections. The quantity c×RT60(f) represents the total distance traveled to achieve the frequency-dependent RT-60.

Use the supporting function iEstimateImageSourceOrder to estimate the image source order required to achieve the estimated RT-60 value.

imageSourceOrder = iEstimateImageSourceOrder(room,t60)
imageSourceOrder = 
29

Use the acousticRoomResponse function to model the room's impulse response. Use the order derived analytically to set the ImageSourceOrder. The NumStochasticRays and MaxNumRayReflections parameters were chosen empirically to balance speed and accuracy.

fs = 16e3; % Sample rate
rirt = acousticRoomResponse(room.Dimensions,room.SourceLocation,room.ReceiverLocation, ...
    BandCenterFrequencies=room.CenterFrequencies, ...
    MaterialAbsorption=room.MaterialAbsorption, ...
    MaterialScattering=room.MaterialScattering, ...
    ImageSourceOrder=imageSourceOrder, ...
    NumStochasticRays=5120, ...
    MaxNumRayReflections=40, ...
    SampleRate=fs);

The acousticRoomResponse function returns an idealized room impulse response. Use the supporting function iAddNoiseFloor to add a noise floor to better simulate a real measurement. A -60 dB noise floor provides enough range for the impulse response for accurate RT-60 estimations.

noiseFloor = -60;
rir = iAddNoiseFloor(rirt,fs,noiseFloor);

Visualize the impulse response.

tvec = (0:numel(rir)-1)/fs;

figure
plot(tvec,rir)
xlabel("Time (s)")
axis tight
title("Impulse Response",room.Description)
grid minor

Figure contains an axes object. The axes object with title Impulse Response, xlabel Time (s) contains an object of type line.

Evaluate Acoustic Metrics

Audio Toolbox™ provides the rt60 function and the speechTransmissionIndex function to evaluate acoustic spaces. RT-60 characterizes the suitability of a space as a listening environment for various uses, such as concert venues and lecture halls. Speech transmission index is a measurement of a room's ability to transmit intelligible speech. It is used to analyze and improve the intelligibility of an acoustic space and is often a required metric of regulatory bodies, especially in cases where public address systems are present.

Reverberation Time (RT-60)

Use the rt60 function to calculate the RT-60 value according to the ISO 3382-1 standard. The function returns a table listing the frequency-dependent reverberation time as well as additional metrics described in the standard such as the early decay time, clarity and definition. T20, T30, and Topt represent measurements of the reverberation time. T20 is the time it takes for the impulse response energy to decay 20 dB after an initial decay of 5 dB which represents the early reflections. T30 is the time it takes the impulse response energy to decay 30 dB after the initial decay. Topt represents an RT-60 estimate by choosing the part of the energy decay curve that provides the best linear fit and then extrapolating the RT-60 value from that. For more details on the algorithm and metric interpretation, see rt60 and [2]. Note that for real standard-compliant measurements, there are requirements on the source and receiver locations detailed in [2].

The RT-60 values calculated here are considerably different than the RT-60 values predicted by the Sabine equation. This is because the RT-60 values given by the Sabine equation represent a rough and simplistic approximation. The equation was derived empirically and does not account for positions in the room, frequency dependency except through absorption coefficients, or scattering coefficients. The acousticRoomResponse physical modeling is also a rough approximation, although it can be improved by modeling the room with a triangulation object providing more specific material coefficients, as well as by increasing the image-source order and the number of stochastic rays and reflections.

t60comp = rt60(rir,fs)
t60comp=6×11 table
    CenterFrequencies     EDT       T20       T30       Topt             DegreeOfNonLinearity            Curvature      C50         C80        D50         Ts   
    _________________    ______    ______    ______    ______    ____________________________________    _________    ________    ________    ______    ________

           125           2.5728    2.8546       NaN    2.9283    26.903    9.5564    5.3586    5.3586         NaN       -1.934     0.47656    39.048      0.1715
           250            2.915    2.5307       NaN     3.344    47.432      45.2    28.606    8.1987         NaN      -1.4725    0.083539    41.604     0.15582
           500           2.1941    2.4148    1.9375     3.126    12.659    37.882    27.623     6.758     -19.768      -3.0027     -1.3877    33.372     0.15362
          1000           1.8708    1.8505    1.6627    2.1498    18.285    6.2116     10.88    3.9525     -10.147     -0.83248      1.1621    45.223     0.11703
          2000           1.2677     2.067    1.9284    2.0499    13.365     4.608    10.901    3.6836     -6.7047     -0.40792      1.8912    47.654    0.091253
          4000           1.2017    1.6407    1.6326     1.304    5.3573    11.011    6.5666    1.8196    -0.49203     -0.60364      1.9523    46.531    0.086731

Call the rt60 function a second time without any input arguments to visualize the frequency-dependent RT-60 and inspect the energy decay and best fit lines for individual octave bands. You can use this view to inspect the energy decay curve (EDC) and the fit of T20, T30, and Topt. It is a good diagnostic tool for verifying measurements and identifying potential sources of error in your measurement.

figure
rt60(rir,fs)

Figure contains 2 axes objects. Axes object 1 with title RT-60, xlabel Octave Center Frequency (Hz), ylabel Time (s) contains 9 objects of type stair, line, patch. One or more of the lines displays its values using only markers These objects represent EDT, T20, T30, Topt. Axes object 2 with title Octave Center Frequency - 1000 Hz, xlabel Time (s), ylabel dB contains 6 objects of type line. These objects represent IR, EDC, EDT [0,-10] : 1.871 s, T20 [-5,-25] : 1.851 s, T30 [-5,-35] : 1.663 s, Topt [-5,-15] : 2.15 s.

Speech Transmission Index (STI)

Call the speechTransmissionIndex function to characterize the room's ability to transmit intelligible speech according to IEC 60268-16:2020. The speech transmission index is a scalar in the interval [0,1]. As the value increases from 0 to 1, the quality of speech transmission index increases. An STI value of 0.46 is considered the lower limit for voice alarm systems. For details on the algorithm and metric interpretation, see speechTransmissionIndex and [3].

When speechTransmissionIndex is called with no additional arguments, the room impulse response (RIR) is assumed to be a high SNR capture and is calculated with values suggested by the standard for the operational signal and noise levels.

stiMetric = speechTransmissionIndex(rir,fs)
stiMetric = 
0.5020

Call speechTransmissionIndex a second time without any output arguments to visualize the modulation transfer function as well. The speech transmission index algorithm uses the modulation transfer function (MTF) as an intermediate representation before deriving the STI. Analyzing the MTF provides insight into the causes of poor speech intelligibility. For example, if the MTF is relatively flat, low speech intelligibility is mainly determined by background noise. A continuously decreasing MTF indicates the influence of reverberation.

figure
speechTransmissionIndex(rir,fs)

Figure contains an axes object. The axes object with title Modulation Transfer Function, xlabel Modulation Frequency (Hz), ylabel Modulation Index contains 14 objects of type line. One or more of the lines displays its values using only markers These objects represent 125 MTI: 0.40002, 250 MTI: 0.50225, 500 MTI: 0.45126, 1000 MTI: 0.52468, 2000 MTI: 0.54687, 4000 MTI: 0.51839, 8000 MTI: 0.44105, 125, 250, 500, 1000, 2000, 4000, 8000.

Evaluate Speech Metrics

Audio Toolbox™ provides the stoi and visqol functions to evaluate speech transmission using a referenced (source) and degraded (receiver) pair. These functions are agnostic to how the speech was processed and are often used for the evaluation of communication systems and speech enhancement systems.

Model a prototypical speech signal at the receiver by convolving with the RIR. The subsequent metrics are level-independent so there is no need to account for level differences at the source and receiver.

[speech,xfs] = audioread("CleanSpeech-16-mono-3secs.ogg");
speech = audioresample(mean(speech,2),InputRate=xfs,OutputRate=fs);

receivedSpeech = fftfilt(rir,speech);

Short-Time Object Intelligibility (STOI)

Call the stoi function specifying the received and transmitted speech to view the effect of the acoustic space on speech intelligibility. The STOI metric is a scalar in the range [-1,1]. A higher value for the metric corresponds to a more intelligible speech signal.

stoiMetric = stoi(receivedSpeech,speech,fs)
stoiMetric = 
0.2713

Virtual Speech Quality Objective Listener (ViSQOL)

Call the visqol function specifying the received and transmitted speech to view the effect of the acoustic space on speech intelligibility. The default ViSQOL metric represents the mean opinion score (MOS) and is a scalar in the range [1,5], where a higher value corresponds to higher quality.

visqolMetric = visqol(receivedSpeech,speech,fs,Mode="speech")
visqolMetric = 
2.3480

Analyze Effect of Noise Source

In this section, you add a noise source to your acoustic model.

Re-estimate the image-source order required to model the impulse response. Use the reverberation time derived from the acousticRoomResponse and rt60 functions.

imageSourceOrder = iEstimateImageSourceOrder(room,t60comp.Topt)
imageSourceOrder = 
58

Use the acousticRoomResponse function to model the room's impulse response given a noise source location. Add a noise floor to the simulated measurement.

noiseRIR = acousticRoomResponse(room.Dimensions,room.NoiseSourceLocation,room.ReceiverLocation, ...
    BandCenterFrequencies=room.CenterFrequencies, ...
    MaterialAbsorption=room.MaterialAbsorption, ...
    MaterialScattering=room.MaterialScattering, ...
    ImageSourceOrder=imageSourceOrder, ...
    NumStochasticRays=5120, ...
    MaxNumRayReflections=40, ...
    SampleRate=fs);
noiseRIR = iAddNoiseFloor(noiseRIR,fs,noiseFloor);

Model a prototypical noise signal at the receiver by convolving with the RIR.

[noise,xfs] = audioread("WashingMachine-16-44p1-stereo-10secs.wav");
noise = audioresample(mean(noise,2),InputRate=xfs,OutputRate=fs);
noise = resize(noise,size(receivedSpeech),Side="both");

receivedNoise = fftfilt(noiseRIR(:),noise);

Model the speech signal at the source as having an overall sound pressure level (SPL) of 62.35 dB.

levelatsource = 62.35;

Calculate the speech signal at the receiver using a common dB energy decay approximation.

distance = norm(room.ReceiverLocation - room.SourceLocation);
levelatreceiver = levelatsource - 20*log10(distance);

Scale the source speech signal to the target receiver levels.

scaleAudio = @(x,targetSPL) x * ((20e-6 * 10^(targetSPL/20)) / rms(x));
receivedSpeechScaled = scaleAudio(receivedSpeech,levelatreceiver);

Model the noise signal as having an overall SPL level of 50 dB.

noiselevelatsource = 50;

Calculate the noise signal at the receiver using a common dB energy decay approximation.

noisedistance = norm(room.ReceiverLocation - room.NoiseSourceLocation);
noiselevelatreceiver = noiselevelatsource - 20*log10(noisedistance);

Scale the source noise signal to the target receiver levels.

receivedNoiseScaled = scaleAudio(receivedNoise,noiselevelatreceiver);

Determine the octave SPL of the received speech and noise signals. Use the splMeter function to measure the equivalent continuous SPL for the entire time interval.

SPL = splMeter( ...
    Bandwidth="1 octave", ...
    FrequencyRange=[100,8500], ...
    FrequencyWeighting="A-weighting", ...
    OctaveFilterOrder=56, ...
    TimeInterval=fs/numel(speech), ...
    SampleRate=fs);
[~,Leq] = SPL(receivedSpeechScaled);
speechLevels = Leq(end,:);
reset(SPL)
[~,Leq] = SPL(receivedNoiseScaled);
noiseLevels = Leq(end,:);

OctaveSPL = array2table([speechLevels;noiseLevels], ...
RowNames=["Speech (dB)", "Noise (dB)"], ...
VariableNames=["125","250","500","1000","2000","4000","8000"])
OctaveSPL=2×7 table
                    125       250       500       1000      2000       4000       8000  
                   ______    ______    ______    ______    ______    ________    _______

    Speech (dB)    15.195    20.682    30.666    32.955    23.037      7.2959    -1.6008
    Noise (dB)     4.6182    7.6166     14.07    14.145    6.3618    -0.97225    -23.931

Evaluate Acoustic Metrics with Noise Source

The rt60 metric is independent of any noise sources. The associated measurements should be made under noiseless conditions.

The speechTransmissionIndex metric does account for noise sources. When measuring STI directly under noisy conditions, you can remove the effect of noise and add operational noise using RemoveRawAmbientNoise and AddOperationalAmbientNoise, respectively. When calculating STI using the indirect method, the RIR is assumed to be captured under noiseless conditions and you can set expected noise and signal levels by specifying OperationalNoiseLevel and OperationalSignalLevel. By default, AddOperationalAmbientNoise is set to true.

Speech Transmission Index (STI) with Noise

Calculate the speech transmission index for the scenario by specifying the operational signal and noise levels.

stiMetric_noisePresent = speechTransmissionIndex(rir,fs, ...
    OperationalNoiseLevel=noiseLevels, ...
    OperationalSignalLevel=speechLevels);
fprintf('STI: %.2f\nSTI with Noise Source: %.2f\n',stiMetric,stiMetric_noisePresent);
STI: 0.50
STI with Noise Source: 0.41

Evaluate Speech Metrics with Noise Source

Model the received signal by combining the speech and noise. Use Audio Viewer to plot and listen to the transmitted speech and the received speech.

receivedNoisySpeech = receivedSpeechScaled + receivedNoiseScaled;
audioViewer(speech./max(abs(speech)),fs)

Figure Audio Viewer contains an object of type uiaudioplayer.

audioViewer(receivedNoisySpeech./max(abs(receivedNoisySpeech)),fs)

Figure Audio Viewer contains an object of type uiaudioplayer.

Short-Time Object Intelligibility (STOI) with Noise Source

Call the stoi function specifying the received and transmitted speech to view the effect of the acoustic space with noise on speech intelligibility. Compare the metrics before and after modeling the noise source. The STOI metric improves under the low-level noise.

stoiMetric_noisePresent = stoi(receivedNoisySpeech,speech,fs);
fprintf('STOI: %.2f\nSTOI with Noise Source: %.2f\n',stoiMetric,stoiMetric_noisePresent);
STOI: 0.27
STOI with Noise Source: 0.30

Virtual Speech Quality Objective Listener (ViSQOL) with Noise Source

Call the visqol function specifying the received and transmitted speech to view the effect of the acoustic space on speech intelligibility. Compare the metrics before and after modeling the noise source.

visqolMetric_noisePresent = visqol(receivedNoisySpeech,speech,fs,Mode="speech");
fprintf('ViSQOL: %.2f\nViSQOL with Noise Source: %.2f\n',visqolMetric,visqolMetric_noisePresent);
ViSQOL: 2.35
ViSQOL with Noise Source: 1.81

Analyze Effect of Listener Position

In this next section, you build upon the previous model by moving the listener position and recording the resulting STI, STOI, and ViSQOL.

Model Received Signal at Variable Position

Create a grid of the X-Y (floor) plane of the room. Vary the listener (receiver) location. Reduce the image-source order and number of stochastic rays to complete this parameter sweep in a reasonable amount of time. If you have Parallel Computing Toolbox™, the parameter sweep takes place using your default pool configuration.

numxtiles = 10;
numytiles = 9;
xlocs = linspace(0,room.Dimensions(1),numxtiles);
ylocs = linspace(0,room.Dimensions(2),numytiles);
stoiloc = nan(numxtiles,numytiles);
visqolloc = nan(numxtiles,numytiles);
stiloc = nan(numxtiles,numytiles);

parfor xlocidx = 1:numxtiles
    for ylocidx = 1:numytiles
        receiverLocation = [xlocs(xlocidx),ylocs(ylocidx),room.Dimensions(3)];
        rirAtLoc = acousticRoomResponse(room.Dimensions,room.SourceLocation,receiverLocation, ...
            BandCenterFrequencies=room.CenterFrequencies, ...
            MaterialAbsorption=room.MaterialAbsorption, ...
            MaterialScattering=room.MaterialScattering, ...
            ImageSourceOrder=30, ...
            NumStochasticRays=2048, ...
            MaxNumRayReflections=20, ...
            SampleRate=fs);
        rirAtLoc = iAddNoiseFloor(rirAtLoc,fs,noiseFloor);
        noiseRIRatLoc = acousticRoomResponse(room.Dimensions,room.NoiseSourceLocation,receiverLocation, ...
            BandCenterFrequencies=room.CenterFrequencies, ...
            MaterialAbsorption=room.MaterialAbsorption, ...
            MaterialScattering=room.MaterialScattering, ...
            ImageSourceOrder=30, ...
            NumStochasticRays=2048, ...
            MaxNumRayReflections=20, ...
            SampleRate=fs);
        noiseRIRatLoc = iAddNoiseFloor(noiseRIRatLoc,fs,noiseFloor);

        receivedSpeechScaled = fftfilt(rirAtLoc,speech);
        receivedNoiseScaled = fftfilt(noiseRIR,noise);

        speechTotalLevel = levelatsource - 20*log(norm(room.SourceLocation - receiverLocation));
        noiseTotalLevel = noiselevelatsource - 20*log(norm(room.NoiseSourceLocation - receiverLocation));

        receivedSpeechScaled = scaleAudio(receivedSpeechScaled,speechTotalLevel);
        receivedNoiseScaled = scaleAudio(receivedNoiseScaled,noiseTotalLevel);

        receivedNoisySpeech = receivedSpeechScaled + receivedNoiseScaled;

        stoiloc(xlocidx,ylocidx) = stoi(receivedNoisySpeech,speech,fs);
        visqolloc(xlocidx,ylocidx) = visqol(receivedNoisySpeech,speech,fs);

        reset(SPL)
        [~,Leq] = SPL(receivedNoiseScaled);
        noiseLevels = Leq(end,:);

        reset(SPL)
        [~,Leq] = SPL(receivedSpeechScaled);
        speechLevels = Leq(end,:);

        stiloc(xlocidx,ylocidx) = speechTransmissionIndex(rirAtLoc,fs, ...
            OperationalNoiseLevel=noiseLevels, ...
            OperationalSignalLevel=speechLevels);
    end
end

Visualize Effect of Listener Position on Metrics

Use the supporting function iPlotMetricSweep to display how the STI, STOI, and ViSQOL metrics vary with the receiver position. As expected, all metrics increase as the receiver gets close to the source and decrease as the receiver gets close to the noise source.

iPlotMetricSweep(xlocs,ylocs,stiloc,room,"STI")

Figure contains an axes object. The axes object with title STI, xlabel Receiver X Position (m), ylabel Receiver Y Position (m) contains 5 objects of type surface, line, text. One or more of the lines displays its values using only markers

iPlotMetricSweep(xlocs,ylocs,stoiloc,room,"STOI")

Figure contains an axes object. The axes object with title STOI, xlabel Receiver X Position (m), ylabel Receiver Y Position (m) contains 5 objects of type surface, line, text. One or more of the lines displays its values using only markers

iPlotMetricSweep(xlocs,ylocs,visqolloc,room,"ViSQOL")

Figure contains an axes object. The axes object with title ViSQOL, xlabel Receiver X Position (m), ylabel Receiver Y Position (m) contains 5 objects of type surface, line, text. One or more of the lines displays its values using only markers

Select Surface Material for Metric Optimization

In this section, you evaluate different ceiling materials for their effect on the STI.

Define some material absorption coefficients. Each material has octave-band absorption coefficients (125 Hz to 4 kHz). These coefficients are given in [1]. Scattering coefficients are less readily available. For simplicity, use the same scattering coefficients for all materials.

materialChoices = {"Acoustical Tile, ave, 1/2-in thick",[0.07,0.21,0.66,0.75,0.62,0.49]; ...
    "Acoustical Tile, ave, 3/4-in thick",[0.09,0.28,0.78,0.84,0.73,0.64]; ...
    "Owens-Corning Frescor: painted, 5/8-in thick, mounting 7",[0.69,0.86,0.68,0.87,0.90,0.81]; ...
    "Gypsum board: 1/2-in",[0.29,0.10,0.05,0.04,0.07,0.09]};

Model the room impulse response for each material and record the resulting speech transmission index.

stiCeilingMaterial = zeros(size(materialChoices,1),1);
for ii = 1:size(materialChoices,1)
    roomAbsorption = [room.MaterialAbsorption(1:5,:);materialChoices{ii,2}];
    rir = acousticRoomResponse(room.Dimensions,room.SourceLocation,room.ReceiverLocation, ...
        BandCenterFrequencies=room.CenterFrequencies, ...
        MaterialAbsorption=roomAbsorption, ...
        MaterialScattering=room.MaterialScattering, ...
        ImageSourceOrder=imageSourceOrder, ...
        NumStochasticRays=5120, ...
        MaxNumRayReflections=40, ...
        SampleRate=fs);
    rir = iAddNoiseFloor(rir,fs,noiseFloor);
    stiCeilingMaterial(ii) = speechTransmissionIndex(rir,fs);
end

Display the STI for each ceiling material and the STI category and interpretation. Use the supporting function iGetQualificationBand to retrieve the STI category and interpretation defined in the IEC 60268-16 standard.

[band,type,example,comment] = iGetQualificationBand(stiCeilingMaterial);
T = table( ...
    string(materialChoices(:,1)), ...
    stiCeilingMaterial, ...
    string(band), ...
    string(type), ...
    string(example), ...
    string(comment), ...
    VariableNames=["Ceiling Material","STI","Category","Type of Message Information","Typical Uses","Comment"]);
T = sortrows(T,"STI","descend");
disp(T)
                         Ceiling Material                           STI      Category        Type of Message Information                                           Typical Uses                                                 Comment           
    __________________________________________________________    _______    ________    ____________________________________    ________________________________________________________________________________    _____________________________

    "Owens-Corning Frescor: painted, 5/8-in thick, mounting 7"    0.52501      "F"       "complex messages, familiar context"    "PA systems in shopping malls, public buildings offices, VA systems, cathedrals"    "good quality PA systems"    
    "Acoustical Tile, ave, 3/4-in thick"                          0.51588      "G"       "complex messages, familiar context"    "shopping malls, public buildings offices, VA systems"                              "target value for VA systems"
    "Acoustical Tile, ave, 1/2-in thick"                          0.50958      "G"       "complex messages, familiar context"    "shopping malls, public buildings offices, VA systems"                              "target value for VA systems"
    "Gypsum board: 1/2-in"                                        0.41714      "I"       "simple messages, familiar context"     "VA and PA systems in very difficult acoustic environments"                         "limited intelligibility"    

Supporting Functions

Get Qualification Band

function [band, type, example, comment] = iGetQualificationBand(STI)
% Returns qualification banding for each STI value in vector
% Based on Annex G of IEC 60268-16:2020

n = numel(STI);
band = cell(n,1);
type = cell(n,1);
example = cell(n,1);
comment = cell(n,1);

for k = 1:n
    s = STI(k);
    if s < 0.36
        band{k}    = "U";
        type{k}    = "";
        example{k} = "not suitable for PA systems";
        comment{k} = "";
    elseif s < 0.40
        band{k}    = "J";
        type{k}    = "";
        example{k} = "not suitable for PA systems";
        comment{k} = "";
    elseif s < 0.44
        band{k}    = "I";
        type{k}    = "simple messages, familiar context";
        example{k} = "VA and PA systems in very difficult acoustic environments";
        comment{k} = "limited intelligibility";
    elseif s < 0.48
        band{k}    = "H";
        type{k}    = "simple messages, familiar words";
        example{k} = "VA and PA systems in difficult acoustic environments";
        comment{k} = "normal lower limit for VA systems";
    elseif s < 0.52
        band{k}    = "G";
        type{k}    = "complex messages, familiar context";
        example{k} = "shopping malls, public buildings offices, VA systems";
        comment{k} = "target value for VA systems";
    elseif s < 0.56
        band{k}    = "F";
        type{k}    = "complex messages, familiar context";
        example{k} = "PA systems in shopping malls, public buildings offices, VA systems, cathedrals";
        comment{k} = "good quality PA systems";
    elseif s < 0.60
        band{k}    = "E";
        type{k}    = "complex messages, familiar context";
        example{k} = "concert halls, modern churches";
        comment{k} = "high quality PA systems";
    elseif s < 0.64
        band{k}    = "D";
        type{k}    = "complex messages, familiar words";
        example{k} = "lecture theatres, classrooms, concert halls";
        comment{k} = "good speech intelligibility";
    elseif s < 0.68
        band{k}    = "C";
        type{k}    = "complex messages, unfamiliar words";
        example{k} = "theaters, speech auditoria, parliaments, courts, teleconferencing";
        comment{k} = "high speech intelligibility";
    elseif s < 0.72
        band{k}    = "B";
        type{k}    = "complex messages, unfamiliar words";
        example{k} = "theaters, speech auditoria, parliaments, courts, assistive hearing systems (AHS)";
        comment{k} = "high speech intelligibility";
    elseif s < 0.76
        band{k}    = "A";
        type{k}    = "complex messages, unfamiliar words";
        example{k} = "theaters, speech auditoria, parliaments, courts, assistive hearing systems (AHS)";
        comment{k} = "high speech intelligibility";
    else
        band{k}    = "A+";
        type{k}    = "";
        example{k} = "recording studios";
        comment{k} = "excellent intelligibility but rarely achievable in most environments";
    end
end
end

Add Noise Floor

function ir = iAddNoiseFloor(ir,fs,noiseFloor)
% Minimum duration for IR captures for ISO 3382 compliance
flength = ceil(1.6*fs);

% Zero-pad IR to minimum length
if numel(ir) < flength
    ir = resize(ir(:),flength);
else
    ir = ir(:);
end

% Generate pink noise and normalize rms.
noise = pinknoise(numel(ir),1);
noise = noise./rms(noise);

% Scale pink noise to desired rms.
noise_rms = max(abs(ir(:))) * 10^(noiseFloor/20);
noise = noise*noise_rms;

ir = ir + noise;

end

RT-60 Model (Sabine)

function t60table = iRT60model(room,options)
arguments
    room
    options.SoundSpeed (1,1) = 343 % (m/s)
end

alpha = room.MaterialAbsorption;

Lx = room.Dimensions(1); % Length
Ly = room.Dimensions(2); % Width
Lz = room.Dimensions(3); % Height

% Floor/ceiling
Sxy = Lx*Ly;
Syx = Sxy;

% Front/back
Sxz = Lx*Lz;
Szx = Sxz;

% Left/right
Syz = Ly*Lz;
Szy = Syz;

S = [Sxy;Syx;Sxz;Szx;Syz;Szy];

% Total Volume
V = prod(room.Dimensions);

% Compute the frequency-dependent effective absorbing area of the room surfaces.
A = sum(S.*alpha,1);

% Apply formula
t60 = (55.25/options.SoundSpeed)*V./A;

t60table = array2table(t60,VariableNames=arrayfun(@num2str,room.CenterFrequencies,UniformOutput=false));

end

Estimate Max Image-Source Order

function maxOrder = iEstimateImageSourceOrder(room,t60,options)
arguments
    room
    t60
    options.SoundSpeed (1,1) double = 343
end
Lx = room.Dimensions(1); % Length
Ly = room.Dimensions(2); % Width
Lz = room.Dimensions(3); % Height

if istable(t60)
    t60 = table2array(t60);
end

% Floor/ceiling
Sxy = Lx*Ly;
Syx = Sxy;

% Front/back
Sxz = Lx*Lz;
Szx = Sxz;

% Left/right
Syz = Ly*Lz;
Szy = Syz;

S = [Sxy;Syx;Sxz;Szx;Syz;Szy];

% Total Volume
V = prod(room.Dimensions);

meanFreePath = 4*V./S;
maxOrder = ceil(max((options.SoundSpeed.*t60)./meanFreePath,[],"all"));
end

Plot Room

function iPlotRoom(room)
% PLOTROOM Plot room, transmitter, receiver, and noise source with colored faces and projection lines
figure()

roomDimensions = room.Dimensions;
receiverCoord = room.ReceiverLocation;
sourceCoord = room.SourceLocation;
noiseCoord = room.NoiseSourceLocation;

L = roomDimensions(1);
W = roomDimensions(2);
H = roomDimensions(3);

% Define vertices and faces
verts = [0 0 0; L 0 0; L W 0; 0 W 0; 0 0 H; L 0 H; L W H; 0 W H];
faces = [1 2 3 4;   % Bottom
    5 6 7 8;   % Top
    1 2 6 5;   % Front
    4 3 7 8;   % Back
    1 4 8 5;   % Left
    2 3 7 6];  % Right

% Colors for each face
faceColors = [0.9 0.5 0.5;  % Bottom
    0.5 0.9 0.5;  % Top
    0.5 0.5 0.9;  % Front
    0.9 0.9 0.5;  % Back
    0.9 0.5 0.9;  % Left
    0.5 0.9 0.9]; % Right

patch(Vertices=verts,Faces=faces, ...
    FaceColor="flat",FaceVertexCData=faceColors, ...
    FaceAlpha=0.6,EdgeColor="k")
hold on

% Plot source, receiver, and noise source
h1 = plot3(sourceCoord(1),sourceCoord(2),sourceCoord(3),"xb",MarkerSize=10,LineWidth=2);

h2 = plot3(receiverCoord(1),receiverCoord(2),receiverCoord(3),"or",MarkerSize=10,LineWidth=2);

h3 = plot3(noiseCoord(1),noiseCoord(2),noiseCoord(3),"xm",MarkerSize=10,LineWidth=2);

% Projection lines for source (blue)
plot3([sourceCoord(1),sourceCoord(1)], [sourceCoord(2),sourceCoord(2)], [0,sourceCoord(3)],"--b")
plot3([sourceCoord(1),sourceCoord(1)], [0,sourceCoord(2)], [sourceCoord(3),sourceCoord(3)],"--b")
plot3([0 sourceCoord(1)], [sourceCoord(2),sourceCoord(2)], [sourceCoord(3),sourceCoord(3)],"--b")

% Projection lines for receiver (red)
plot3([receiverCoord(1),receiverCoord(1)], [receiverCoord(2),receiverCoord(2)], [0,receiverCoord(3)],"--r")
plot3([receiverCoord(1),receiverCoord(1)], [0,receiverCoord(2)], [receiverCoord(3),receiverCoord(3)],"--r")
plot3([0 receiverCoord(1)], [receiverCoord(2),receiverCoord(2)], [receiverCoord(3),receiverCoord(3)],"--r")

% Projection lines for noise source (magenta)
plot3([noiseCoord(1),noiseCoord(1)], [noiseCoord(2),noiseCoord(2)], [0,noiseCoord(3)],"--m")
plot3([noiseCoord(1),noiseCoord(1)], [0,noiseCoord(2)], [noiseCoord(3),noiseCoord(3)],"--m")
plot3([0,noiseCoord(1)], [noiseCoord(2),noiseCoord(2)], [noiseCoord(3),noiseCoord(3)],"--m")

% Labels and view
xlabel("X (m)")
ylabel("Y (m)")
zlabel("Z (m)")
grid on
axis equal
title(room.Description)

legend([h1 h2 h3],"Source","Receiver","Noise Source")

view(3)

hold off
end

Classroom Specifications

function room = iGetClassroom()
room = struct( ...
    Dimensions = [14, 12, 5], ...
    CenterFrequencies = [125, 250, 500, 1000, 2000, 4000], ...
    MaterialAbsorption = [ ...
    0.35 0.25 0.18 0.12 0.07 0.04;   % left - Ordinary window
    0.29 0.10 0.05 0.04 0.07 0.09;   % right - Gypsum board
    0.29 0.10 0.05 0.04 0.07 0.09;   % front - Gypsum board
    0.12 0.10 0.06 0.05 0.04 0.03;   % back - Plaster on lath
    0.02 0.06 0.14 0.37 0.60 0.65;   % floor - carpet
    0.36 0.51 0.43 0.51 0.51 0.36;   % ceiling - panels
    ], ...
    MaterialScattering = [ ...
    0.03 0.03 0.03 0.03 0.03 0.03;   % left
    0.03 0.03 0.03 0.03 0.03 0.03;   % right
    0.03 0.03 0.03 0.03 0.03 0.03;   % front
    0.05 0.05 0.05 0.05 0.05 0.05;   % back
    0.01 0.01 0.01 0.01 0.01 0.01;   % floor
    0.01 0.01 0.01 0.01 0.01 0.01;   % ceiling
    ], ...
    SourceLocation = [2.0, 6.0, 2], ...
    ReceiverLocation = [12.0, 6.0, 1.5], ...
    NoiseSourceLocation = [7.3,5.3,3.9], ...
    Description = "Empty Classroom" ...
    );
end

Plot Metric Sweep

function iPlotMetricSweep(xlocs,ylocs,metricsweep,room,metricname)

figure()
surf(xlocs,ylocs,metricsweep',EdgeColor="interp",FaceColor="interp")

hold on

plot3(room.SourceLocation(1),room.SourceLocation(2),5,"ro", ...
    MarkerSize=8,MarkerFaceColor="r")
text(room.SourceLocation(1),room.SourceLocation(2),5," Source", ...
    FontSize=12, Color="k",VerticalAlignment="top",HorizontalAlignment="left"),
plot3(room.NoiseSourceLocation(1),room.NoiseSourceLocation(2),5,"ko", ...
    MarkerSize=8,MarkerFaceColor="k")
text(room.NoiseSourceLocation(1),room.NoiseSourceLocation(2),5,' Noise Source', ...
    FontSize=12,Color="k",VerticalAlignment="top",HorizontalAlignment="left")
view([360,90])
title(metricname)
xlabel("Receiver X Position (m)")
ylabel("Receiver Y Position (m)")
colorbar
hold off
end

References

[1] Everest, F. Alton, and Ken C. Pohlmann. Master Handbook of Acoustics. 7th ed, McGraw-Hill, 2021.

[2] ISO 3382-1:2009. "Acoustics — Measurement of room acoustic parameters — Part 1: Performance spaces." International Organization for Standardization.

[3] IEC 60268-16:2020. "Sound system equipment — Part 16: Objective rating of speech intelligibility by speech transmission index." International Electrotechnical Commission.

See Also

Apps

Functions