Simple example: Echo

When you make a sound, for example say “Hello”, in a large room, the sound takes some time to get reflected by the walls. The sound you hear is the sound you make coupled with the echo. If you are standing in the center of a square room then your sound and the echo, and the echo of the echo, will continue to get reflected off the walls. The strength of the echo depends on the type of reflector which is captured by an attenuation factor. In a simple model, the echo is determined by a delay and an attenuation factor.

A convenient way to start designing many applications is to draw a diagram showing the streams and the operations on them. The diagram for the echo is shown below.

Echo: attenuate and delay heard sound.

Echo: attenuate and delay heard sound.

The attenuated sound is the heard sound multiplied by the attenuation factor. We use the multiply function from the IoTPy library.

A delay of a stream is implemented by prepending the stream with a list of initial values. For example, if the attenuated stream is 10, 20, 30, …. and the echo is the attenuated stream delayed by two time steps, then the echo is 0, 0, 10, 20, 30, …. Thus, the echo is obtained by prepending the attenuated stream with [0, 0], a list of zeroes whose length is the delay time. We use the prepend function from the IoTPy library.

The function that returns the heard sound from the spoken sound, the attenuation factor A and the delay D is:

def make_echo(spoken, D, A):
    echo = Stream('echo')
    heard = spoken + echo
    prepend([0]*D, 
            in_stream=multiply(heard, multiplicand=A), 
            out_stream=echo)
    return heard

This function terminates when spoken terminates. This is because the stream spoken + echo terminates when either of the two terminates. You can represent a speaker listening to echoes after having stopped speaking by appending the spoken sound with silence (zeroes).

You don’t need to implement the following functions because they are part of the IoTPy library. We show possible implementations for convenience.

@fmap_e
multiply(x, multiplicand): return x * multiplicand

def prepend(lst, in_stream, out_stream):
    out_stream.extend(lst)
    map_element(lambda v: v, in_stream, out_stream)