As part of my diploma thesis I'm implementing digital communication system based on audio transmission in free space (STMF401RE + analog microphone). I'm using BPSK modulation and I've implemented costas loop for frequency and phase recovery and symbol (which is byte in this case) starts detector using correlation and known preamble (Barker code), but despite lots of time it's a game of chance. I'm new to DSP, could anyone check my code and concepts and give me some suggestions (especially costas loop). Link to repo: https://github.com/asiemasz/AcousticDataTransmitter

  • $\begingroup$ What do you mean by "free space".? What's the acoustic environment like and what are the elements in your signal chain? $\endgroup$
    – Hilmar
    Jan 23 at 13:54
  • $\begingroup$ I mean it's just acoustic waves through air - elements are just: microcontroller + speaker - microphone + microcontroller. All data is processed on microcontroller. $\endgroup$
    – asiemasz
    Jan 23 at 13:59
  • 2
    $\begingroup$ I don’t have time to review all your code, but I have a suggestion. When doing larger coding projects like this, it helps to design and test each part of the system separately before bringing it all together. Designing an engineering system should never be a game of chance. Also, what I typically do when designing a real time system is develop and test the system and algorithms in Matlab or python before developing the C or assembly code that implements it on the target device. Good luck. $\endgroup$
    – Ryan
    Jan 23 at 15:21
  • $\begingroup$ @Ryan I'm currently working on model of system in Simulink. If you just had some time, could you review just part with costas loop? (DSP_own/BPSK.c -> BPSK_syncSignalCarrier function) $\endgroup$
    – asiemasz
    Jan 23 at 15:34

2 Answers 2


First of all: I'm 100% with Hilmar. I'm really not an acoustic expert, but I remember helping students build a minimal audio data transmission system, and the take aways are really these; you can, if you limit volume to "nice and far below max volume of the system" practically ignore 1., 2., and 6., and if you filter harmonics well enough at the receiver also 3..

But you do have to know your channel. I'd start by measuring the channel impulse response through channel sounding, e.g. with a pseudo white noise sequence. Do these in the different types of rooms you want things to work in. The resulting estimate lets you bound the length/complexity of the equalizer your system will need.

I've implemented costas loop for frequency and phase recovery

phase recovery: this is a digital system in a sampling rate regime that's "computationally trivial" enough, I'd not go with costas loop, but a simple preamble-based phase estimation and correction.

You probably won't need frequency recovery at all.

Why? Because your oscillators will be good enough: 25 ppm is pretty much standard for such, and at the bandwidth you can work with, you get low symbol rates (less than 16 kSym/s, for sure), so before the combined frequency error of receiver and transmitter have rotated your constellation diagram enough to contribute to significant error probability, seconds will have passed – and at that point, your channel equalizer will have to be updated anyway, as things move.

That's not saying that tracking phase with a Costas loop isn't a good idea — your equalizer might be adaptive and update itself while operating, too — it's just something that you could very well add later on to improve your error performance slightly. For a start, the real problem you need to solve is compensating the room impulse response (leading to inter-symbol interference), and the honestly easiest way (at least as I'd see it) is by sending a known preamble of symbols, and using them to initialize equalizer taps – which right after the preamble continue to be used by a decision-feedback equalizer.

Only after the equalizer you'd do phase recovery.

I'm new to DSP, could anyone check my code and concepts and give me some suggestions (especially costas loop)

Don't start with the Costas loop. Write unit tests, and test with synthetic signals on your PC; C code can be compiled natively for PCs, after all! First pure, clean signals without any noise, phase offset, or ISI should be demodulated by your BPSK receiver. Then, add simulated noise. Then, add simulated phase offset. Then, add simulated room impulse response. Later, test with recordings from a real room.

Only after simulation works of the minimum viable product (no, not any minute before), you'd start porting things to your microcontroller. Microcontroller programming and DSP are both hard enough each for themselves, and the professionals write their hardware simulators first, before porting proven-to-be-correct algorithms to their hardware platforms. It's way harder to test and debug on a microcontroller board compared to your PC, where you can just save megabytes of data to a hard drive, with no problem whatsoever, where your debugger can run on the same machine, and where you have CPU and an operating system that will tell you when you access memory that you mustn't access accidentally.

You've got three problems you need to solve:

  1. the signals/DSP side of things ("algorithmics")
  2. the embedded/programming side of things ("code")
  3. the software engineering side of things (what's the "minimum viable product"? How do you write your tests so that you can actually test the code that will later run on the microcontroller?…)

You'll really need to start by writing down your requirements: What data rate do you need to achieve? In which rooms? Which noise? Which bit error rates?


I mean it's just acoustic waves through air

No it's not. Not unless you are operating in an anechoic chamber (which is unlikely). The total transfer function of your channel can be quite complicated. You have

  1. Driver and codecs (if any)
  2. D/A & Amplifier. You have to make sure that you get decent signal to noise ratio and not overdriving or clipping anything
  3. Loudspeaker: electrodynamic loudspeakers are inherently non-linear. Cheap loudspeakers can also have nasty break up modes.
  4. The room itself is a very complicated system. You have the direct sound but also many thousands of reflections. Unless the speaker is very close to the microphone, the reflected energy is typically higher than the direct sound energy. The channel transfer function is highly dependent on the geometry and acoustic properties of all the walls, surfaces and other stuff in the room.
  5. Residential rooms also have quite a bit of background noise, specifically at lower frequencies.
  6. Microphone: these are typically well behaved unless you overdrive them.
  7. Pre-amp, power supply and A/D: make sure this have good signal to noise ratio but are not overdriven or clipping either.

Your problem may not be with the code, but with the physical properties of your channel. I would start with the requirements: what bit rate do you want to achieve, what max distance between microphone and speaker do you need to accommodate, what's the max reverb time of the room, max background noise level as a function of frequency, etc an then design the algorithms to this requirement.


Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.