Loudness measures and vector measures for 2-channel stereo

for level differences, Franz Zotter, 2016.

The simplest loudness measure for panning with the gains $g_{1,2}$ and an undetermined broadband signal of normalized loudness is quadratic

\begin{equation} V=g_1+g_2\qquad\qquad E=g_1^2+g_2^2, \end{equation}

and given any unnormalized panning gains $\tilde g_{1,2}$, it is wise to normalize them to $\sqrt{E}$

\begin{equation} g_{1,2}=\frac{\tilde g_{1,2}}{\sqrt{g_1^2+g_2^2}}. \end{equation}

We may choose a level difference of $-30\mathrm{dB}\dots+30\mathrm{dB}$ for $g_1,g_2$ for a $\pm30^\circ$ loudspeaker setup. We will see what the modeled localization is that we get from the vector models using the direction vectors $\boldsymbol\theta_{1}=[\sin30^\circ,\cos30^\circ]^\mathrm{T}$ and $\boldsymbol\theta_{2}=[-\sin30^\circ,\cos30^\circ]^\mathrm{T}$

\begin{equation} \boldsymbol r_\mathrm{V}=\frac{g_1\boldsymbol{\theta}_1+g_2\boldsymbol{\theta}_2}{g_1+g_2}, \qquad\qquad \boldsymbol r_\mathrm{E}=\frac{g_1^2\boldsymbol{\theta}_1+g_2^2\boldsymbol{\theta}_2}{g_1^2+g_2^2}. \end{equation}

In [1]:
import numpy as np
from bokeh.plotting import figure, output_file, show
from bokeh.io import output_notebook

def r_vector(g,theta):
    L=theta.size
    g1=g[0,:]
    g2=g[1,:]
    normalizer=g1+g2
    g1/=normalizer
    g2/=normalizer
    th1x=np.cos(theta[0])
    th1y=np.sin(theta[0])
    th2x=np.cos(theta[1])
    th2y=np.sin(theta[1])
    rx=g1*th1x+g2*th2x
    ry=g1*th1y+g2*th2y
    r=np.array([rx,ry])
    return r

L=np.linspace(-30,30,31)
g=np.array([10**(-L/40), 10**(L/40)])
g/=np.sum(g,0)
theta=np.array([-30,30])*np.pi/180.0;
output_notebook()
p1=figure(title="r vector direction",plot_width=300,plot_height=250,x_range=[-30,30],y_range=[-30,30])
p2=figure(title="r vector length",plot_width=300,plot_height=250,x_range=[-30,30],y_range=[0,100])

r=r_vector(g,theta)
mr=np.sqrt(r[1,:]**2+r[0,:]**2)
p2.line(L,2*np.arccos(mr)*180/np.pi,legend="2acos||rV||",line_width=2)
p1.line(L,np.arctan2(r[1,:],r[0,:])*180/np.pi,legend="rV",line_width=2)

r=r_vector(g**2,theta)
mr=np.sqrt(r[1,:]**2+r[0,:]**2)
p2.line(L,2*np.arccos(mr)*180/np.pi,legend="2acos||rE||",line_width=2,color="red")
p1.line(L,np.arctan2(r[1,:],r[0,:])*180/np.pi,legend="rE",line_width=2,color="red")

g[1,:]/=2
r=r_vector(g**1.5,theta)
mr=np.sqrt(r[1,:]**2+r[0,:]**2)
p2.line(L,2*np.arccos(mr)*180/np.pi,legend="2acos||r1.5||",line_width=2,color="green")
p1.line(L,np.arctan2(r[1,:],r[0,:])*180/np.pi,legend="r1.5+3dB",line_width=2,color="green")

p1.legend.location="top_left"
p2.legend.background_fill_alpha = 0.5
show(p1)
show(p2)


Loading BokehJS ...

In [ ]: