Creating police siren sounds with frequency modulation

Yesterday I was looking into calculating fluctuation strength and playing around with some examples. Along the way I discovered how to create files that sound like police sirens. These are sounds with high fluctuation strength.

police car lights

The Python code below starts with a carrier wave at fc = 1500 Hz. Not surprisingly, this frequency is near where hearing is most sensitive. Then this signal is modulated with a signal with frequency fm. This frequency determines the frequency of the fluctuations.

The slower example produced by the code below sounds like a police siren. The faster example makes me think more of an ambulance or fire truck. Next time I hear an emergency vehicle I’ll pay more attention.

If you use a larger value of the modulation index ╬▓ and a smaller value of the modulation frequency fm you can make a sound like someone tuning a radio, which is no coincidence.

Here are the output audio files in .wav format:



from import write
from numpy import arange, pi, sin, int16

def f(t, f_c, f_m, beta):
    # t    = time
    # f_c  = carrier frequency
    # f_m  = modulation frequency
    # beta = modulation index
    return sin(2*pi*f_c*t - beta*sin(2*f_m*pi*t))

def to_integer(signal):
    # Take samples in [-1, 1] and scale to 16-bit integers,
    # values between -2^15 and 2^15 - 1.
    return int16(signal*(2**15 - 1))

N = 48000 # samples per second
x = arange(3*N) # three seconds of audio

data = f(x/N, 1500, 2, 100)
write("slow.wav", N, to_integer(data))

data = f(x/N, 1500, 8, 100)
write("fast.wav", N, to_integer(data))

Related posts:

Click to learn more about consulting help with signal processing


12 thoughts on “Creating police siren sounds with frequency modulation

  1. Note that this code works for smooth modulating functions. You are smoothly distorting the time axis and calculating cos(2pi f*distorted_time).

    If, for example, you want a 2-tone siren, then the modulating function would be a square wave, and the code above will return a wave with phase discontinuities at each tone change.

    In general, to produce a frequency modulated wave, you need to integrate the instantaneous frequency in order to get a continuous phase, and then calculate cos(phase).

  2. Your ‘to_integer’ function is accessing the global ‘data’ variable instead of the ‘signal’ argument that is passed to it.

  3. Brett: Thanks. I fixed that bug in my source code but forgot to copy the fix to the blog post.

  4. I think you might be mistaken on the “most sensitive” part. I’ve heard 4000 before, and a quick googling suggests 2000-5000.

  5. The difference between those numbers isn’t so much on a log scale, and perception is kinda flat in that range.

  6. I tried the code on my computer. The code produces two .wav files, but no sound (I’ve tried both iTunes and VLC). Your sound files work fine, though. I would expect identical code to produce identical sound files, but apparently not. Do you have any idea of what might be the issue? Thank you.

  7. Fredrik,

    I too generated soundless .wav files. Examination showed that it was because all zeroes were getting written to them. I fixed this by making sure that the data generated was using floats:

    x = arange(3*N, dtype=float32)

    I’m using Python 2, and numpy.arange() produces integers by default.

Leave a Reply

Your email address will not be published. Required fields are marked *