Commit cd5f187c authored by Jan Brouwer's avatar Jan Brouwer
Browse files

add quantization error tracking to generate_acoustic_environments_metadata.py,...

add quantization error tracking to generate_acoustic_environments_metadata.py, add input files for hospital patient room and recreation configurations
parent 7e01d104
Loading
Loading
Loading
Loading
Loading
+28 −0
Original line number Diff line number Diff line
[frequencyGrid:0]
method = individualFrequencies
frequencies = [
        20.0, 25.0, 31.5, 40.0, 
        50.0, 63.0, 80.0, 100.0, 
        125.0, 160.0, 200.0, 250.0, 
        315.0, 400.0, 500.0, 630.0, 
        800.0, 1000.0, 1250.0, 1600.0, 
        2000.0, 2500.0, 3150.0, 4000.0, 
        5000.0, 6300.0, 8000.0, 10000.0, 
        12500.0, 16000.0, 20000.0]

[acousticEnvironment:0]
id = 0
frequencyGridIndex = 0
predelay = 0.08163
rt60 = [
        0.81275, 0.61888, 0.45111, 0.34672, 0.46683, 0.53987, 0.61874, 0.70291, 0.66657, 0.73037,
        0.75090, 0.72470, 0.75486, 0.75857, 0.76844, 0.74999, 0.77622, 0.78227, 0.77441, 0.74688, 
        0.73521, 0.73782, 0.71928, 0.71708, 0.71465, 0.60592, 0.52031, 0.51768, 0.52102, 0.37956,
        0.30786]

dsr = [
        0.00019952621, 0.00019952621, 7.9432844e-05, 5.0118702e-05, 7.943284e-06, 6.3095763e-06, 6.3095763e-06, 7.943284e-06, 1e-05, 1e-05,
        7.943284e-06, 1e-05, 1e-05, 1e-05, 7.943284e-06, 1e-05, 1e-05, 7.943284e-06, 7.943284e-06, 6.3095763e-06,
        6.3095763e-06, 6.3095763e-06, 6.3095763e-06, 6.3095763e-06, 6.3095763e-06, 3.1622776e-06, 3.1622776e-06, 3.1622776e-06, 6.3095763e-07, 3.1622776e-07,
        3.1622776e-07]
+28 −0
Original line number Diff line number Diff line
[frequencyGrid:0]
nBands = 31
method = individualFrequencies
frequencies = [
    20.0, 25.0, 31.5, 40.0, 
    50.0, 63.0, 80.0, 100.0, 
    125.0, 160.0, 200.0, 250.0, 
    315.0, 400.0, 500.0, 630.0, 
    800.0, 1000.0, 1250.0, 1600.0, 
    2000.0, 2500.0, 3150.0, 4000.0, 
    5000.0, 6300.0, 8000.0, 10000.0, 
    12500.0, 16000.0, 20000.0]

[acousticEnvironment:0]
id = 0
frequencyGridIndex = 0
predelay = 0.43031
rt60 = [
        4.51916, 4.89553, 4.83276, 5.00198, 5.34468, 5.76026, 6.36818, 6.95503, 7.27557, 7.62559,
        8.08892, 8.16002, 8.13900, 8.17919, 8.16280, 8.46226, 9.61806, 9.93048, 9.81353, 8.59340, 
        8.38885, 8.36823, 6.51845, 3.76089, 3.75374, 3.57451, 1.28724, 1.22174, 1.22448, 1.71631,
        2.14343]

dsr = [
        1e-06, 7.943284e-07, 1e-06, 1e-06, 1.5848925e-06, 1.9952631e-06, 3.1622776e-06, 3.9810707e-06, 6.3095763e-06, 7.943284e-06,
        1e-05, 7.943284e-06, 7.943284e-06, 7.943284e-06, 7.943284e-06, 7.943284e-06, 5.01187e-06, 5.01187e-06, 3.9810707e-06, 3.1622776e-06,
        3.1622776e-06, 2.511887e-06, 7.943284e-07, 6.3095763e-07, 6.3095763e-07, 5.01187e-08, 1.2589251e-08, 1.2589251e-08, 1.2589265e-09, 1.2589266e-11,
        3.981075e-12]
+58 −41
Original line number Diff line number Diff line
@@ -43,8 +43,24 @@ from enum import Enum
import numpy as np


# Set to True to print values suitable for inclusion into .cfg configuration files
print_cfg = False
# Set to True to print quantized values
print_quantized = False


max_quantization_error = {
    'duration' : 0,
    'frequency' : 0,
    'dsr' : 0,
    'distance' : 0,
    'absorption' : 0
}


def update_quantization_error(name, quantized_value, value):
    max_quantization_error[name] = max(abs(quantized_value - value) / value, max_quantization_error[name])
    if print_quantized:
        print('    {}: {}'.format(name, quantized_value))


def get_id_code(id):
    code = format(id % 128, '07b') + '0'
@@ -118,8 +134,9 @@ def get_duration_code(duration):
        '110100101',  '111111', '110111010', '111100', '110111011',  '111101', '110111000',  '11000',  '110111001' ]

    duration_dus = round(np.float32(duration) * np.float32(100000))   # [deca us]
    if print_cfg:
        print('duration: ', duration_dus, 'dus')

    quantized_duration = round(np.float32(duration), 5)
    update_quantization_error('duration', quantized_duration, duration)

    dus = duration_dus          # [deca us]
    s = dus // 100000           # 0, 1, ... 30  [s]
@@ -155,42 +172,36 @@ def get_duration_code(duration):
    return code


def get_frequency_code(f):
def get_frequency_code(frequency):
    frequencyCode = {
        16   : '100011',  20   : '001110',  25   : '001111',    31.5 : '1001',      40   : '001100',
        50   : '001101',  63   : '0000',    80   : '011010',    100  : '011011',    125  : '0001',
        160  : '011000',  200  : '011001',  250  : '1110',      315  : '011110',    400  : '011111',
        500  : '1111',    630  : '011100',  800  : '011101',    1000 : '1100',      1250 : '010010',
        1600 : '010011',  2000 : '1101',    2500 : '010000',    3150 : '010001',    4000 : '1010',
        5000 : '010110',  6300 : '010111',  8000 : '1011',      10000: '010100',    12500: '010101',
        16000: '0010',    20000: '10000',   25000: '10001010',  31500: '10001011',  40000: '1000100',  }

    assert 16 <= f <= 40000
    if f in frequencyCode.keys():
        if print_cfg:
            print('frequency:', f, 'Hz')
        return frequencyCode[f] + '0'
    else:
        # exact frequency not found, use frequency refinement to aproximate
        # (largest relative deviation seen for range(16, 40000) was 0.006818)
        # find  frequencies enveloping f
        f_low = 16
        f_high = 40000
        for key in frequencyCode.keys():
            if key < f:
                f_low = max(f_low, key)
        16.0   : '100011',  20.0   : '001110',  25.0   : '001111',    31.5   : '1001',      40.0   : '001100',
        50.0   : '001101',  63.0   : '0000',    80.0   : '011010',    100.0  : '011011',    125.0  : '0001',
        160.0  : '011000',  200.0  : '011001',  250.0  : '1110',      315.0  : '011110',    400.0  : '011111',
        500.0  : '1111',    630.0  : '011100',  800.0  : '011101',    1000.0 : '1100',      1250.0 : '010010',
        1600.0 : '010011',  2000.0 : '1101',    2500.0 : '010000',    3150.0 : '010001',    4000.0 : '1010',
        5000.0 : '010110',  6300.0 : '010111',  8000.0 : '1011',      10000.0: '010100',    12500.0: '010101',
        16000.0: '0010',    20000.0: '10000',   25000.0: '10001010',  31500.0: '10001011',  40000.0: '1000100',  }

    assert 16 <= frequency <= 40000
    if frequency in frequencyCode.keys():
        quantized_frequency = frequency
        code = frequencyCode[quantized_frequency] + '0'
    else:
                f_high = min(f_high, key)
        refinement = round(51 * math.log(f / f_low, 2)) - 1
        if refinement >= 16:
            # choose next higer frequency
            if print_cfg:
                print('frequency:', list(frequencyCode)[f_high], 'Hz')
            return frequencyCode[f_high] + '0'
        # exact frequency not found, use frequency refinement to approximate
        f_low = max([k for k in frequencyCode.keys() if k < frequency])
        refinement = round(51 * math.log(frequency / f_low, 2)) - 1
        if 0 <= refinement <= 15:
            quantized_frequency = f_low * 2 ** ((refinement + 1) / 51)
            code = frequencyCode[f_low] + '1' + format(refinement, '04b')
        else:
            if print_cfg:
                print('frequency:', list(frequencyCode)[f_low], ', Hz, refined: ', f_low * 2 ** ((refinement + 1) / 51), 'Hz')
            return frequencyCode[f_low] + '1' + format(refinement, '04b')
            # choose next lower / higher frequency
            f_high = min([k for k in frequencyCode.keys() if k > frequency])
            quantized_frequency = f_low if refinement < 0 else f_high
            code = frequencyCode[quantized_frequency] + '0'

    update_quantization_error('frequency', quantized_frequency, frequency)

    return code


def get_frequency_hop_code(index):
@@ -227,8 +238,10 @@ def get_dsr_code(dsr):
    d = math.log10(dsr) * 10
    d = round(d + 150)
    assert 0 <= d <= 140
    if print_cfg:
        print('dsr:',  np.float32(np.power(np.float32(10), np.float32(d - 150) / np.float32(10))))  # C decoder uses float precision math

    quantized_dsr = np.float32(np.power(np.float32(10), np.float32(d - 150) / np.float32(10)))  # C decoder uses float precision math
    update_quantization_error('dsr', quantized_dsr, dsr)

    return dsrCode[d]


@@ -279,8 +292,9 @@ def get_distance_code(distance, isSmallScene):
       '1111000',  '1111001',  '1111110',  '1111111',  '1111100',  '1111101',   '111010',   '111011',   '111000',   '111001' ]

    distance_cm = round(np.float32(distance) * np.float32(100))      # distance in cm
    if print_cfg:
        print('distance: ', distance_cm, 'cm')

    quantized_distance = round(np.float32(distance), 2)
    update_quantization_error('distance', quantized_distance, distance)

    cm = distance_cm            # [cm]
    m = cm // 100               # [m]
@@ -327,6 +341,9 @@ def get_absorption_code(absorption):

    index = round(absorption * 10.0)

    quantized_absorption = round(np.float32(absorption), 1)
    update_quantization_error('absorption', quantized_absorption, absorption)

    return ['110', '100', '101', '0110', '0111', '111', '0100', '0101', '0010', '0011', '000' ][index]


+8 −1
Original line number Diff line number Diff line
@@ -33,7 +33,7 @@
#
#   Read a text-based configuration file and generate the equivalent binary payload.
#   Makes use of the pyhton configuration file parser configparser,
#   and of the payload configuration functions in generate_acoustic_environments_metadata.
#   and of the payload configuration functions in generate_acoustic_environments_metadata.py.
#   The configuration file format is as follows:
#
#   [<section>:<index>]
@@ -43,6 +43,7 @@
#   <section> is one of the supported section names (frequencyGrid, acousticEnvironment).
#   <index> is an integer used as acoustic environment ID (revAcEnvID), and to refer to (revFreqGridIdx).
#   There is no leading white space for sections and options, and no trailing ';'.
#


from bitarray import bitarray
@@ -151,3 +152,9 @@ if __name__ == "__main__":
    parse_reverb_text_configuration_and_generate_binary_payload(args.configuration_file)

    print("\nNote: the conversion algorithm uses quantization, which may lead to quantization errors.")
    print('Maximum relative quantization errors:')
    print('    duration  : {:.1e}'.format(max_quantization_error['duration']))
    print('    frequency : {:.1e}'.format(max_quantization_error['frequency']))
    print('    DSR       : {:.1e}'.format(max_quantization_error['dsr']))
    print('    distance  : {:.1e}'.format(max_quantization_error['distance']))
    print('    absorption: {:.1e}'.format(max_quantization_error['absorption']))