Repetition Pitch

Repetition Pitch is the sensation of tonality in a sound, in which this tonal quality is solely obtained due to a repeated pattern, rather than a sinusoïdal waveform. Often this occurs when a sound is reflected against surfaces with equal intervals, for example a staircase. The effect is perceived most prominently if the reflected sound contains a wide spectrum of frequencies, such as traffic noise. Repetition Pitch has been described by Christiaan Huygens in a setting of the reflected sound of a fountain against a staircase.

An algorithm has been used to conceive an optimal staircase for reproducing this phenomenon, based on a given location of a sound source and listener and a frequency equivalent of the tone that is to be reproduced by the effect. The resulting sound of traffic noise as it sounds reflected against the staircase is given below. What will follow is quite a lengthy and technical outline of the workflow leading to the algorithm, staircase geometry and sound.

Sage

Sage has been used to generate an optimum staircase to induce tonality at a specified frequency. The problem that needed to be solved is that, if the risers of the stair are spaced equally, the difference in length between successively reflections would increase. The following script has been written to address this problem by solving a number of formulas, which describe the coordinates of the risers. The total length of a reflection, against a given riser, must be longer than the previous reflection by a specified amount (343/f, with f being the frequency of the induced tonality) and the step of the stair must be of a comfortable distance from the previous step (dS, set to 620mm). The other variables that need to be set are the position of the listener (Lx,Ly), sound source (Sx,Sy) and first riser (Px,Py).

# Script to calculate a sequence of stair steps
# that reflect sound waves on the steps entering
# the listener's ears successively with a fixed
# interval. Distances are in meters.

Sx,Sy = 1,1       # Location of sound source
Lx,Ly = 3,10      # Location of listener
Px,Py = 10,2      # Location of first step
f = 880           # Repetition pitch frequency
dS = 0.62         # Step size
Ns = 20           # Number of steps
 
# Initialize some other variables
X,Y = Px,Py
By,By = X,Y
R1,R2,L = var('R1 R2 L')

# Returns the four constraints to be solved
def constraints():
    return (
        (X-Sx)**2 + (Y-Sy)**2 == R1**2,
        (X-Lx)**2 + (Y-Ly)**2 == R2**2,
        R1 + R2 == L,
        2.4*(X-Px)**2 + 4.8*(Y-Py)**2 == dS**2,
    )

# Solve for the first three constraints to obtain the
# length of the first reflection. Only accept positive measures
for s in solve(constraints()[:-1],R1,R2,L,solution_dict=True):
    if len([v for v in s.values() if v < 0]): continue
    L = n(s[L]+343/f)
    break

# Reinitialize variables
X,Y,R1,R2 = var('X Y R1 R2')

steps_ngon = []
steps_output = []

# Determine the position of the risers by solving
# the constraints, accepting only solutions to the
# upper right of the previous riser.
for i in range(Ns):
    ss = solve(constraints(),X,Y,R1,R2,solution_dict=True)
    ss = [s for s in ss if s[X] > Px and s[Y] > Py]
    if not len(ss): break
    steps_ngon.append((Px,Py))
    steps_ngon.append((Px,ss[0][Y]))
    steps_output.append((Px,Py))            
    Px = ss[0][X]
    Py = ss[0][Y]
    L += 343/f

# Append the final riser
steps_ngon.append((Px,Py))
steps_ngon.append((Px,By))
steps_output.append((Px,Py))

def pt(x,y,t):
    return point((x,y),color='black')+\
    text(t,(x+0.15,y+0.15),color='black')

show(polygon(steps_ngon,rgbcolor=(0.3,0.3,0.3))+pt(Sx,Sy,"S")+pt(Lx,Ly,"L"),figsize=11)

print "coords=["
print "".join(["  (%.6f,%.6f),\n"%s for s in steps_output])[:-2]
print "]"

Output

Running the script in sage results in the following output: a schematic overview of the generated staircase and a list of coordinates of the risers that can be loaded into blender to be subject of an acoustical analysis in E.A.R

coords=[
  (10.000000,2.000000),
  (10.303411,2.184538),
  (10.600529,2.374127),
  (10.891426,2.568479),
  (11.176181,2.767327),
  (11.454880,2.970420),
  (11.727612,3.177525),
  (11.994465,3.388423),
  (12.255539,3.602907),
  (12.510927,3.820787),
  (12.760726,4.041883),
  (13.005034,4.266027),
  (13.243945,4.493060),
  (13.477556,4.722835),
  (13.705964,4.955210),
  (13.929258,5.190057),
  (14.147534,5.427252),
  (14.360882,5.666678),
  (14.569388,5.908228),
  (14.773140,6.151798),
  (14.972222,6.397290)
]

The coordinates can be turned into a geometrical staircase in blender by running the following script. The impulse response, as it is calculated by E.A.R, follows.

import bpy

xs = [x for x,y in coords]
ys = [y for x,y in coords]

xs = sum([list(q) for q in zip(xs[:-1],xs[:-1])],[])
ys = sum([list(q) for q in zip(ys[:-1],ys[1:])],[])
zs = [0.0] * len(xs)

vs = list(zip(xs,ys,zs))
es = [(x,x+1) for x in range(len(xs)-1)]

me = bpy.data.meshes.new('stair')
me.from_pydata(vs,es,[])
ob = bpy.data.objects.new('stair',me)
scn = bpy.context.scene
scn.objects.link(ob)

If evenly spaced riser were to be used, the spacing between the lobes in the impulse response would gradually increase. Rendering the impact of the repetition pitch much less pronounced. This can be demonstrated by instead generating a staircase in blender with the following sequence of coordinates.

dx,dy = 0.303411,0.184538
coords=[(10+dx*i,2+dy*i) for i in range(20)]

Notes