# Embedding digital ID in audio signal, and retrieving it

## The problem

I am working on an interesting challenge -- to encode a 32 bit ID blip in an audio stream, and subsequently retrieve it.

EDIT Thanks for comments pointing out I need to specify the task in more detail.

• bit rate N/A (only a single byte needs to be sent)

• I need to work in the 4-10KHz region so that this works on cheap speakers / sound card / even compressed streaming audio would be nice

• I'm trying to get the pulse time down to a minimum (maybe 1 FFT frame ie 1024 samples or 1/44 sec)

• I need this to work on a blip being emitted by a typical laptop internal speaker, received on an iPhone in the same room. currently it is only working if I put the iPhone right next to the speaker.

## Current technique

The method I'm trying out at the moment is to composite sine waves corresponding to various FFT bins

So my receiver uses a 10 bit (1024 sample) FFT which will generate 512 bins

I'm using 3 adjacent bins for each bit, so bit #0 will be bins 99, 100, 101

I would energise bin 99 to 0%, bin 101 to 100% and bin 100 to either zero or 100% depending on whether the bit is a 0 or a 1

## Sample data output shows problem

Problem is I am getting a fair few erroneous bits

BINS: bin 0 = { 0.628, 7.798, 6.554 } -> 1.210 --> 1
bin 1 = { 0.471, 0.624, 7.312 } -> 0.022 --> 0
bin 2 = { 0.948, 0.374, 14.156 } -> -0.043 --> 0
bin 3 = { 1.783, 16.634, 16.600 } -> 1.002 --> 1
bin 4 = { 0.893, 0.697, 13.286 } -> -0.016 --> 0
bin 5 = { 0.511, 11.385, 9.277 } -> 1.240 --> 1
bin 6 = { 1.074, 9.621, 15.472 } -> 0.594 --> 1
bin 7 = { 0.381, 0.580, 14.623 } -> 0.014 --> 0
bin 8 = { 1.037, 0.554, 17.310 } -> -0.030 --> 0

the first eight are correct; 1001 1100 is my start sentinel!

bin 9 = { 0.817, 1.220, 5.544 } -> 0.085 --> 0
bin 10 = { 1.316, 1.193, 2.589 } -> -0.097 --> 0
bin 11 = { 2.246, 1.681, 15.257 } -> -0.043 --> 0
bin 12 = { 1.387, 2.950, 29.683 } -> 0.055 --> 0
bin 13 = { 1.534, 3.786, 24.015 } -> 0.100 --> 0
bin 14 = { 1.523, 2.386, 15.959 } -> 0.060 --> 0
bin 15 = { 2.995, 2.066, 17.060 } -> -0.066 --> 0
bin 16 = { 1.262, 1.679, 17.068 } -> 0.026 --> 0
bin 17 = { 1.374, 1.332, 12.165 } -> -0.004 --> 0
bin 18 = { 1.060, 1.514, 13.036 } -> 0.038 --> 0
bin 19 = { 1.099, 0.892, 9.148 } -> -0.026 --> 0
bin 20 = { 0.906, 0.523, 4.556 } -> -0.105 --> 0
bin 21 = { 0.483, 0.299, 4.575 } -> -0.045 --> 0
bin 22 = { 0.776, 1.023, 5.269 } -> 0.055 --> 0
bin 23 = { 0.216, 0.475, 4.232 } -> 0.065 --> 0
bin 24 = { 0.518, 0.162, 2.393 } -> -0.190 --> 0
bin 25 = { 0.369, 0.643, 0.737 } -> 0.744 --> 1
bin 26 = { 0.294, 0.258, 3.712 } -> -0.011 --> 0
bin 27 = { 0.228, 0.354, 2.114 } -> 0.067 --> 0
bin 28 = { 0.272, 0.212, 1.836 } -> -0.039 --> 0
bin 29 = { 0.139, 0.115, 2.036 } -> -0.013 --> 0
bin 30 = { 0.241, 0.275, 1.532 } -> 0.026 --> 0
bin 31 = { 0.118, 0.089, 1.509 } -> -0.020 --> 0
bin 32 = { 0.315, 0.256, 1.339 } -> -0.057 --> 0
bin 33 = { 0.111, 0.171, 0.222 } -> 0.534 --> 1
bin 34 = { 0.103, 0.117, 0.351 } -> 0.054 --> 0
bin 35 = { 0.039, 0.091, 0.637 } -> 0.087 --> 0
bin 36 = { 0.087, 0.045, 0.404 } -> -0.131 --> 0
bin 37 = { 0.057, 0.129, 0.586 } -> 0.136 --> 0
bin 38 = { 0.034, 0.040, 0.771 } -> 0.008 --> 0
bin 39 = { 0.094, 0.448, 0.791 } -> 0.507 --> 1

BITS:
1 0 0 1 0 1 1 0
0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0
0 1 0 0 0 0 0 0
0 1 0 0 0 0 0 1

but only the last bin (39) should be containing a 1. I'm getting false positives at 25, 33. and this is from playing the sound straight out of my laptop speaker and picking it up on an iPhone that is a few centimetres away. if this is failing, it doesn't bode well...

So what can I do to get a more reliable reading?

## Possible solutions

Possible solutions I am thinking about include:

a) parity checking, maybe an extra eight bits for parity check
b) building energy in the bins so eg new_bin[17] = 0.9*old_bin[17] + 0.1*in_bin[17] etc
c) using phase

I am also a little bit concerned that some sort of beating effect occurs in the target signal ie amplitude spikes at certain points -- once the waveform is normalised it is very possible that data gets lost this way.

Is there any established technique for doing this? Are there any more robust options?

• This is essentially a digital communications systems problem. There are many approaches for encoding digital data into a transmitted (audio, in this case) waveform. Your approach seems to amount to a multi-tone on-off-keying system. What are your requirements for background interference, noise, processing power, transmit time, transmitter (i.e. speaker) quality, receiver (i.e. microphone) quality, etc.? Feb 14, 2012 at 22:36
• More requirements to orient you towards the right watermarking technique: what is your target bitrate (is it OK to embed only 10 or so bits per second to gain robustness?) ; or do you want this to be perceptually undetectable? It looks like you are trying to shove all your data in a single (detectable) frame which might not be the most robust approach... Feb 14, 2012 at 22:52
• @Jason R, pichenettes, to sorry for incomplete spec, I have fixed this in the original post
– P i
Feb 15, 2012 at 4:48

Data communications is a well studied field with 100's of textbooks on the subject. You seem to be doing a variant of OFDM, with lots and lots of pilot tones, no cyclic prefix, and no redundancy. There are tons of coding options for adding redundancy (including maybe ECC, RLL group codes, Reed-Solomon, Trellis, & etc). Your observation that OFDM can have a peak power issue is correct. There seem to be algorithms for changing the phase of the carriers to help reduce PAPR.

Added: A longer data frame or the addition of a long enough cyclic prefix may help deal with multipath or reflections when working at a greater distance.

• Thanks! This is very useful as it gives me a lot of terms to Google
– P i
Feb 15, 2012 at 5:08

You approached the problem of Embedding the ID by custom encoding. This is limiting.

From the URL you send:

A startup called SonicNotify embeds inaudibly high-pitched audio signals within music or any other audio track.

What you are looking for is Watermarking. Either for the purpose of protection or to trigger appropriate actions, you just add a watermark in the signal and detect it whoever plays it.

Basically, any signal can be watermarked with a known pattern. Essentially, this watermark is added with the original signal like a tolerable noise. (Addition is just one of the functions). This is an interesting problem where in, your watermark (noise) should be strong enough to survive modifications but should be weak enough that doesn't disturb the ear. Unlike Video, audio has an advantage that you can embed tones of higher frequency that are otherwise not audible to ears.

This is quite broader subjects, so i am leaving you with some further reading.

There is an alternative approach to this. Instead of embedding anything in the signal, extract the most critical features that aids identifying what the content is. This finger print then resides on separate database (without modifying original content). If on a portal if someone uploads the copy, it would receive same finger print which will capture that such a content is not unique. This is equivalent of Digital Signature of the stream.

One of the earliest work on this area was by Fraunhofer Institute called AudioID. YouTube also has similar ContentID framework.