## How does Quantization Noise sound?ΒΆ

In a last article, we explained the mathematical effect of quantization and what the resulting quantization noise is. In this article, we will hear, how the quantization noise actually sounds. As a teaser, listen to the following:

# For running this code, the code snippets below need to be run beforehand
display(HTML("Original signal:" + Audio(data=data_music, rate=rate)._repr_html_()))
showQuantization(data_music, U=1,bits=4, showSignals=False);
Original signal:
 Quantized to q=4 bits Quantization Noise Your browser does not support the audio element. Your browser does not support the audio element.

Clearly, we hear a significant noise floor below the original music signal. Let's look deeper into what actually happens. First, we define a function to load some audio file from the internet:

R = requests.get(url)
with open("sound.mp3", "wb") as f:
f.write(R.content)
!ffmpeg -y -i sound.mp3 sound.wav > /dev/null 2>&1
if len(data.shape) > 1:  # stereo to mono conversion
data = data.sum(axis=1)
data = (1.0 * data / abs(data).max()).astype(np.float32)

dataPart = data[rate*start+np.arange(min(rate*length, len(data)))]
targetRate = 10000   # Resample signal to 10kHz sampling rate
targetSamples = int(len(dataPart) * targetRate / rate)
resampled = signal.resample(dataPart, targetSamples)
return targetRate, resampled / abs(resampled).max()

# Utility function two display two audios side by side in the notebook
def audioSideBySide(name1, audio1, name2, audio2):
text = '
 %s %s %s %s
'
% (name1, name2, audio1._repr_html_(), audio2._repr_html_()) display(HTML(text))

Then, we load some music from the internet and extract a portion of 10 seconds length out of it:

url_music = "http://www.scientificinvesting.eu/a/Mozart%20-%20Symphony%20n.10%20K.74%20in%20G%20-%201%20Allegro.mp3"
rate_music, data_music = loadAudio(url_music, 40, 10)
rate = rate_music

Next, we define the functions for calculation of the quantization thresholds and for performing the actual quantization. Sure, we have shamelessly copied them from our previous article:

# Calculate the quantization levels with a uniform quantizer
def calcLevels(U, b, quantization_type):
N_levels = 2**b
delta = 2*U / N_levels

if quantization_type == 'mid-rise':
levels = -U + delta/2 + np.arange(N_levels) * delta
levels = -U + np.arange(N_levels) * delta
else:
raise RuntimeError("Unknown quantization type!")

return levels

# Map the input array x to the nearest values in S
def quantize(x, S):
X = x.reshape((-1,1))
S = S.reshape((1,-1))
dists = abs(X-S)

nearestIndex = dists.argmin(axis=1)
quantized = S.flat[nearestIndex]

return quantized.reshape(x.shape)

Let us now define a convenience function that performs the quantization of a signal, shows the resulting signals and creates the audio objects:

def showQuantization(audio, U, bits, quantization_type='mid-rise', showNoise=True, showSignals=True):
S = calcLevels(U=U, b=bits, quantization_type=quantization_type)
quantized = quantize(audio, S)    # Perform quantization
q_noise = audio - quantized       # Calculate quantization noise

P_signal = sum(abs(audio**2))        # Calculate SNR in dB
P_noise = sum(abs(q_noise**2))
SNR = 10*np.log10(P_signal/P_noise)

audioSideBySide("Quantized to q=%d bits" % bits, Audio(data=quantized, rate=rate),
"Quantization Noise", Audio(data=q_noise, rate=rate))
t = np.arange(len(audio)) / rate
if showSignals:
plt.plot(t, audio, label='Original')
plt.plot(t, quantized, label='Quantized to q=%d bits' % bits)
if showNoise:
plt.plot(t, q_noise, label='Quantization Noise')

return t, quantized, q_noise

Now, we are ready to listen to the quantized music and also look at the resulting quantized signals. First, listen to the original signal once again:

Audio(data=data_music, rate=rate)