Limpkin's blog - Tag - cdm324<div>An electronics geek blog, dedicated to sharing and open source. Check out my stores: <a href="https://lectronz.com/stores/stephanelec" hreflang="en" title="Lectronz store">EU</a> / <a href="https://www.tindie.com/stores/stephanelec" hreflang="en" title="tindie store">EU & US</a>.</div>2024-03-29T00:41:47+00:00Mathieuurn:md5:51de6a3d917257edeff5a252fe925b02DotclearCDM324 Doppler Speed Sensor, with FFTs!urn:md5:c6c13a8d10a780d3192761eae924d3c32023-08-23T17:14:00+01:002023-12-07T09:28:24+00:00limpkinMy Projectscdm324dopplerfftstm32<p><img src="https://www.limpkin.fr/public/cdm324_v2/cdm_and_exp.JPG" alt="" class="media-center" />
A very small form factor project, not only measuring an object's speed but also displaying it!<br />
With its UART interface, interfacing with Arduino platforms is dead simple too!</p> <h2>Introduction<br /></h2>
<p>If you follow this blog, you may have noticed that this is my third project using doppler sensors, and my second with the <strong>CDM324</strong>. This tiny sensor is just so neat for its price!<br /><br />
<img src="https://www.limpkin.fr/public/HB100/doppler-effect.png" alt="Doppler effect" class="media-center" title="Doppler effect, août 2013" /><br />
A quick refresher on the <strong>Doppler effect</strong>: when sending an RF tone at a given frequency towards a moving target, the <strong>reflected signal's frequency will be shifted</strong>. This is the reason why a fire truck's siren has a <strong>higher pitch</strong> when the truck is going towards you than when it is still.<br /><br />
<img src="https://www.limpkin.fr/public/cdm324_v2/cdm324_zoom.jpg" alt="" class="media-center" /><br />
And what's nice with the CDM324 sensor above is that it actually <strong>outputs that frequency shift</strong>, so you "just" need to measure that frequency to compute the moving object's speed!<br /></p>
<h2>The project in action<br /></h2>
<p>Before I start getting into the technical details of this project, I figured you may want to see it in action:<br /></p>
<div class="external-media" style="margin: 1em auto; text-align: center;">
<iframe width="700" height="400" src="https://www.youtube.com/embed/76kO2TxzD54" frameborder="0" allowfullscreen></iframe>
</div>
<h2>Why re-do this project? Why is it better now?<br /></h2>
<p><a href="https://www.limpkin.fr/public/cdm324_v2/cdm_cool.JPG"><img src="https://www.limpkin.fr/public/cdm324_v2/cdm_cool.JPG" alt="" class="media-center" /></a><br />
I learned quite a few things about electronics since I first made that amplification circuit for the CDM324 <strong>6 years ago</strong>.<br />
Here are the main changes implemented in this new version:<br />
- <strong>using an FFT to extract the measured speed</strong> from the CDM324 output<br />
- using an <strong>automatic gain circuit</strong> to increase the detection range<br />
- adding an <strong>onboard speed display</strong> for reading convenience<br />
Computing the Fast Fourrier Transform (FFT) of a given signal esssentially <strong>extracts all its frequency contents</strong>.<br />
It is therefore more reliable and sensitive than <a href="https://www.limpkin.fr/index.php?post/2017/02/22/Making-the-Electronics-for-a-24GHz-Doppler-Motion-Sensor">the simple comparator circuit</a> I had previously used, as you effectively <strong>look for a big peak in the FFT output</strong> and divide its X coordinate by a constant to get your detected object speed.<br />
Sure, it required adding a microcontroller to first digitize that analog signal, but the <strong>detected speed can now directly be output through UART.</strong><br />
The previous CDM324 amplification circuit had <strong>84dB</strong> of gain which <strong>in some cases was not enough</strong>. Instead of two fixed gain stages, I'm now using <strong>one fixed gain stage and a variable one</strong> for up to <strong>92dB</strong> of gain (or <strong>40000x</strong> voltage gain!). This second gain stage has <strong>automatic gain control</strong>, automatically varying the overall gain between <strong>72dB and 92dB</strong> to hopefully not saturate the overall amplification circuit output.<br />
Finally, as it didn't really make sense for the previous project to require an extra micro-controller to compute the detected speed, this new CDM324 project <strong>includes a small display</strong> directly displaying the detected object speed to the user.<br /></p>
<h2>Digging into the Analog Circuit<br /></h2>
<p><a href="https://www.limpkin.fr/public/cdm324_v2/cdm324_analog.png"><img src="https://www.limpkin.fr/public/cdm324_v2/cdm324_analog.png" alt="" class="media-center" /></a><br />
Starting from left to right, you'll first see the fixed gain stage of 130 (42.3dB) with a 7.2Hz high pass filter (C2 & R1) and a 6.1kHz low pass filter (R3 & C4). This allows progressively <strong>filtering out speeds not between 0.16km/h and 138km/h</strong>.<br />
This particular op-amp was selected for its <strong>low input noise and high power-supply rejection ratio</strong>.<br />
As it's only powered by 3v3, its positive input is set to a fixed voltage generated by the next amplification IC. This effectively allows us to bias (or center) the op-amp output to a voltage between its two power supply rails (0V and 3.3V).<br />
The second amplification stage... <strong>is a microphone amplifier</strong>!<br />
Thinking about it, it made perfect sense using an amplifier made for the exact same frequencies I was interested in, especially <strong>when it comes with automatic gain circuitry</strong>. It'll therefore automatically amplify less if your speeding object is close to the sensor, and amplify more if the the object is far away. Cherry on top of the cake, its output voltage is already centered around 1.23V so there's no need to re-bias it before feeding it to the microcontroller's Analog to Digital Converter (ADC).<br /></p>
<h2>What About the Digital Circuitry?<br /></h2>
<p><a href="https://www.limpkin.fr/public/cdm324_v2/cdm324_digital.PNG"><img src="https://www.limpkin.fr/public/cdm324_v2/cdm324_digital.PNG" alt="" class="media-center" /></a><br />
The digital circuitry is simply composed of an STM32F301 microcontroller and an I2C-controlled LCD segment driver.<br />
The STM32F301 was selected for its <strong>small package, relatively low price and Cortex M4 core</strong> which can easily compute FFTs (more on that later).<br /><br />
<a href="https://www.limpkin.fr/public/cdm324_v2/exp_pinout.png"><img src="https://www.limpkin.fr/public/cdm324_v2/exp_pinout.png" alt="" class="media-center" /></a><br />
As there was still some board space available during the layout stage, I also <strong>broke out a full I2C and SPI bus</strong> to 2 expansion connectors... and that's <strong>on top of the existing UART bus</strong> for MCU flashing and the spare IOs/reset/boot signals!<br />
I therefore fully hope to develop some expansion boards that would plug to that module.<br /><br />
<a href="https://www.limpkin.fr/public/cdm324_v2/tn_display.PNG"><img src="https://www.limpkin.fr/public/cdm324_v2/tn_display.PNG" alt="" class="media-center" /></a><br />
A TN display was selected for its <strong>size and readability</strong>: it's of the same type that the ones used in multimeters.<br />
Reading the measured speed in a bright environment therefore shouldn't be an issue! It's however quite tricky to drive as <strong>it requires some interesting waveforms</strong>, and while I had thought of letting the MCU directly drive it for a moment, the number of resistors required to do so made me go for the embedded controller you see in the above schematics. Interestingly, you'll find online <a href="http://awawa.hariko.com/avr_lcd_drive.html" hreflang="ja">some people who did manage to pull it off!</a><br />
As a side note, I had originally gone for a 7 segments display, but the <strong>current transient when changing digits</strong> was so high that the introduced perturbation on the CDM324 5V rail <strong>would lead to glitches in its output</strong>:<br /><br />
<a href="https://www.limpkin.fr/public/cdm324_v2/cdm324_cur_transient_issue.png"><img src="https://www.limpkin.fr/public/cdm324_v2/cdm324_cur_transient_issue.png" alt="" class="media-center" /></a><br /></p>
<h2>Things Worth Mentioning<br /></h2>
<p><a href="https://www.limpkin.fr/public/cdm324_v2/gui_demonstrator.png"><img src="https://www.limpkin.fr/public/cdm324_v2/gui_demonstrator.png" alt="" class="media-center" /></a><br />
I figured I'd make a dedicated paragraph to mention the things I really like about this little board.<br />
<strong>No programmers are required to update the MCU</strong>: the STM32F301 comes with an embedded UART bootloader! By simply connecting a USB-UART adapter to the dedicated connector, tying the BOOT0 pin to 3V3 and then briefly bringing the RESET pin to ground, the STM32F301 will enter bootloader mode.<br />
<strong>The overall circuit is very simple and expandable</strong>: there are only a handful of components and the two expansion connectors with I2C, SPI, UART and IOs will hopefully enable projects from electronics enthusiasts!<br /></p>
<h2>The PCB<br /></h2>
<p><a href="https://www.limpkin.fr/public/cdm324_v2/cdm_pcb.JPG"><img src="https://www.limpkin.fr/public/cdm324_v2/cdm_pcb.JPG" alt="" class="media-center" /></a><br />
The folks at <a href="https://www.pcbway.com/" hreflang="en">PCBWay.com</a> were kind enough to sponsor this project!<br />
As usual, the quality was great, shipping was fast with DHL, PCB assembly was without any issue so the PCB worked right away... these days I always go with them.<br />
I'm pretty sure this is the one of the most compact PCB I've ever laid out. It's only <strong>32 by 32.5mm</strong> and is made to be put behind the CDM324. A general rule when amplifying small signals is to have as short traces as possible!<br /></p>
<h2>Measuring the Transfer Function<br /></h2>
<p><a href="https://www.limpkin.fr/public/cdm324_v2/Omicron_BODE-100.jpg"><img src="https://www.limpkin.fr/public/cdm324_v2/Omicron_BODE-100.jpg" alt="" class="media-center" /></a><br />
To make sure the amplification chain could sense the speeds I was interested in, I needed to measure the circuit amplification across frequency.<br />
To do so, I used my Bode100 but could definitely had manually done it using a signal generator and an oscilloscope (it just would have taken longer). Given the extremely high amplification present in the analog circuitry, I used <strong>many</strong> attenuators (for a <strong>total of 80dB</strong>!) at the Bode100 output to present a -100dBm signal at the amplification chain input (that's <strong>6.3uV peak peak</strong>).<br />
Using a large averaging factor and a 10Hz measurement bandwidth, the following graph was gotten 10 hours later:<br /><br />
<a href="https://www.limpkin.fr/public/cdm324_v2/cdm_s21.PNG"><img src="https://www.limpkin.fr/public/cdm324_v2/cdm_s21.PNG" alt="" class="media-center" /></a><br />
Let's ignore for the moment the overall gain and focus on the <strong>-3dB corner frequencies</strong>, even though it's a bit ironic to do so when dealing with such a high circuit gain. While the measured low pass corner frequency was bang on (6.1kHz), the same couldn't be said of the high pass filter corner frequency. The reason was then found inside the microphone amplifier datasheet:<br /><br />
<a href="https://www.limpkin.fr/public/cdm324_v2/max9814_gain.PNG"><img src="https://www.limpkin.fr/public/cdm324_v2/max9814_gain.PNG" alt="" class="media-center" /></a><br />
Even though this is actually fine as a 100Hz frequency corresponds to a <strong>2.3km/h speed</strong>, I still took that opportunity to update my first amplification stage to the following:<br /><br />
<a href="https://www.limpkin.fr/public/cdm324_v2/updated_first_stage.PNG"><img src="https://www.limpkin.fr/public/cdm324_v2/updated_first_stage.PNG" alt="" class="media-center" /></a><br />
I then ran another frequency sweep (this time with 70dB of external attenuation) and got this:<br /><br />
<a href="https://www.limpkin.fr/public/cdm324_v2/transf_func_cdm324_updated_filter.png"><img src="https://www.limpkin.fr/public/cdm324_v2/transf_func_cdm324_updated_filter.png" alt="" class="media-center" /></a><br />
... and if we zoom in between the -3dB corner frequencies:<br /><br />
<a href="https://www.limpkin.fr/public/cdm324_v2/transf_func_cdm324_updated_filter_zoomed_in.png"><img src="https://www.limpkin.fr/public/cdm324_v2/transf_func_cdm324_updated_filter_zoomed_in.png" alt="" class="media-center" /></a><br />
Taking into account the 70dB of external attenuation, the overall amplification gain ended up being <strong>95.4dB</strong>, with 3dB corner frequencies of <strong>150Hz</strong> (3.4km/h) and <strong>~7.9kHz</strong> (180km/h).<br />
Finally, here's a very interesting way to test the microphone amplifier automatic gain control feature: in the below measurement, I not only perform a frequency sweep <strong>but also a power sweep</strong>:<br /><br />
<a href="https://www.limpkin.fr/public/cdm324_v2/power_sweep.png"><img src="https://www.limpkin.fr/public/cdm324_v2/power_sweep.png" alt="" class="media-center" /></a><br />
Given that I'm linearly sweeping between -90dBm and -60dBm between 1kHz and 1.3kHz, we can conclude that the AGC starts kicking at an input power of <strong>-89.9dBm</strong> and seems to stop intervening at <strong>-66.3dBm</strong>. This 23.6dB range is however a bit high as the datasheet mentions 20dB.</p>
<h2>Checking for Oscillations<br /></h2>
<p><a href="https://www.limpkin.fr/public/cdm324_v2/output_adc_noise_floor.png"><img src="https://www.limpkin.fr/public/cdm324_v2/output_adc_noise_floor.png" alt="" class="media-center" /></a><br />
An <strong>extremely common issue</strong> when having an amplification chain with such a massive gain is <strong>oscillations</strong>: without any signal present at your device input, when probing your output you'd typically see a rogue sine wave.<br />
This happens when some of your output signal gets coupled into the device input (imagine putting a live microphone in front of speakers).<br />
<em>But how does it get coupled?</em> you may then ask. <br />
In my experience either through <strong>electromagnetic coupling</strong> (output PCB trace close to the input trace) or through <strong>power supplies</strong> (a current draw proportional to the output signal introduces a voltage drop on the first amplifier supply which then gets coupled into the input signal).<br />
While one could typically use an oscilloscope to measure the amplification chain output signal to check for small oscillations, one would be limited by said oscilloscope <strong>input noise level</strong>. One way to get around that could be to use my <a href="https://www.limpkin.fr/index.php?post/2022/09/20/The-Low-Noise-Amplifier-Board">low noise amplifier board</a> but I instead went with my <strong>SA44B spectrum analyzer</strong> and got the following spectrum:<br /><br />
<a href="https://www.limpkin.fr/public/cdm324_v2/output_spectrum_with_backpack_50r_vs_sensor.png"><img src="https://www.limpkin.fr/public/cdm324_v2/output_spectrum_with_backpack_50r_vs_sensor.png" alt="" class="media-center" /></a><br />
The black trace is the output spectrum with a CDM324 connected and the blue trace is the output spectrum with a <strong>50 ohms resistor connected to the amplification chain input</strong>.<br />
The blue curve being below the black curve <strong>means that my amplification chain noise floor is below the CDM324 output "noise"!</strong> This means the complete device is "limited" by the CDM324.... which is what I wanted to see.<br />
Also worth mentioning is the relative <strong>lack of pronounced spikes</strong> that could be caused the AC grid frequency, TN display scanning or USB lines: remember that the above measurement was taken with a very sensitive spectrum analyzer while the cdm324 was standing still. What really matters is that the spectrum computed by the STM32 is flat when nothing is moving around.<br />
If we "walk back" the amplification chain we can try to compute our amplification chain input noise rating: -80dB (noise level at 1kHz) + 21dB (500 / 50r resistor divider at the specan input) - 95.4dB (circuit amplification) = -154.4dB/sq(Hz) = <strong>4.26nV RMS/sq(Hz)</strong>.<br />
Comparing that value to the theoretical one can be done using the following formula from <a href="https://www.renesas.com/kr/en/document/apn/r13an0010-noise-calculations-op-amp-circuits" hreflang="en" title="opamp noise calculations">that document</a> (from page 6):<br /><br />
<a href="https://www.limpkin.fr/public/cdm324_v2/inv_opamp_noise_calc.png"><img src="https://www.limpkin.fr/public/cdm324_v2/inv_opamp_noise_calc.png" alt="" class="media-center" /></a><br />
Rather than doing these math however, one may notice that <strong>this 4.26nV/sq(Hz) measurement is already below the 4k7 input resistor johnson noise of 8.7nV/sq(Hz)</strong>... and I'm not even mentioning the LMP7731 input voltage noise (2.7nV/sq(Hz)) and LMP7731 input current noise (1.1pA/sq(Hz)) going to the 4k7//620k.<br />
I wish I had an explanation for that difference... but I repeated that measurement several times, even used a signal generator and a table top multimeter to double check the circuit amplification (I actually measured more than 95.4dB)... but still couldn't find an explanation on that better than expected result. If you're reading this and have an idea, send me a message and <strong>I'll send you a device for free</strong>!<br /></p>
<h2>Mechanical Assembly<br /></h2>
<p><a href="https://www.limpkin.fr/public/cdm324_v2/cdm_antenna.JPG"><img src="https://www.limpkin.fr/public/cdm324_v2/cdm_antenna.JPG" alt="" class="media-center" /></a><br />
Similarly to my previous CDM324 project, I've designed and 3D printed a small support to hold everything together.<br />
The overal assembly <strong>only measures 36x36.5x17.5mm</strong>. Tiny!<br /></p>
<h2>MCU Performance & ADC Sampling Rate<br /></h2>
<p><a href="https://www.limpkin.fr/public/cdm324_v2/stm_adc.png"><img src="https://www.limpkin.fr/public/cdm324_v2/stm_adc.png" alt="" class="media-center" /></a><br />
You may know that FFT computation is quite resource intensive.<br />
In a "release' build configuration, by toggling a MCU pin I measured that <strong>2.4ms</strong> was needed to:<br />
- convert 1024 ADC samples to floats<br />
- compute a 1024 points FFT<br />
- compute the magnitude of the FFT output vector elements<br />
This effectively translates to a maximum of 417 FFTs per second, which is more than enough for our purposes!<br />
I therefore selected an ADC sampling rate of <strong>35.7ks/s</strong>, meaning that for a 1024 samples buffer I should theoretically be able to measure frequencies between 34.9Hz and 17.8KHz (or a <strong>minimum of 0.8km/h</strong>). That also meant an FFT frequency bin width of <strong>0.8km/h (0.5mph)</strong>.<br />
By using double buffering (one buffer filling with data while another is getting processed), 34.9 FFTs per second can be computed. If we want to stream raw ADC values and FFT data through UART, a minimum bit rate of 34.9*(1024*uint16 + 512*float32)*10/8 = <strong>1428kb/s</strong> is required. But because of baud rate incompatibilities between the MCU & possible USB to UART adapters, that actually means a 2Mbit/s minimum baud rate.<br />
However, it turned out that many USB to UART adapters <strong>couldn't handle a continuous 2Mbit/s stream</strong>.<br />
In the scripts located at the end of this page, you'll therefore notice that I actually use <strong>1Mbit/s</strong>, and am only sending the "interesting" part of the FFT data.<br />
One last thing to mention: I did find that the required impedance between signal source and ADC input needed to be small, as otherwise what seems to be a current bias would be introduced during the sampling phase.... odd.<br /></p>
<h2>On the topic of Hardware Abstraction Layers<br /></h2>
<p>When it comes to Hardware Abstraction Layers (HALs) everyone has his/her own opinions.<br />
I personally tried several of them (for different platforms and IDEs) and until now have been quite against using them as it'd always take me as much time learning the HAL as I'd spend reading the datasheet.<br />
With the STM32 environment, things are quite different: you actually get a nice graphical user interface (STM32CubeMX, also embedded in the STM32CubeIDE) that allows you to fully configure your microcontroller and its internal peripherals (think Clocks, SPIs, UARTs, Timers, Interrupts, DMA transfers...). Once you save your .ioc file, the IDE will automatically generate the HAL initialization code and interrupt routines in 3 files (main.c, stm32f3xx_hal_msp.c, stm32f3xx_it.c) and you'll be more or less good to go.<br />
Why more or less? Well in the case of configured timers, it'll still be up to you to call the actual HAL start routines depending on your use case (HAL_TIM_Base_Start, HAL_TIM_Base_Start_IT, HAL_TIM_Base_Start_DMA...). Luckily, given the STM32 platform is used all over the globe, the time between realizing something doesn't work and the time you find a solution online will be less than a few minutes. Getting something up and running is therefore extremely quick.<br />
However... there are times where the code generation tool messes with your complete software solution. It happened to me once that when changing an SPI baud rate in STM32CubeMX and saving the changes my platform wouldn't boot anymore. After comparing my main.c with a previous version (don't forget to use code versioning!) I discovered that the generated code initializing the external crystal driver had simply disappeared!<br />
Moreover, while relying on this code generation tool is great when wanting to rapidly tweak a few settings... it actually prevents you from compartimentalizing your code in different files. Even though I managed to do so, identifying all the functions and global variables that are required for a given feature rapidly gets annoying (think interrupt routines for peripherals and DMA transfers, end of transfer HAL callbacks, HAL descriptor objects...).<br />
You also obviously get a performance hit as the HAL performs a few checks before letting you do what you'd like to. For a simple 24bits SPI TX transfer I actually measured a performance penalty factor of 9 between using the HAL and directly writing the registers myself. STM however does also provide a Low Layer API (LL), with "better optimization but less portability, requiring deep knowledge of the MCU and peripheral specifications."... but at this point you may as well go bare-metal :).<br /></p>
<h2>Writing a Debug GUI<br /></h2>
<p><a href="https://www.limpkin.fr/public/cdm324_v2/debug_tool.png"><img src="https://www.limpkin.fr/public/cdm324_v2/debug_tool.png" alt="" class="media-center" /></a><br />
Can you guess the cars passing me by and the ones stopping next to me?<br />
As previously mentioned, the onboard MCU can use its UART peripheral to output data to the outside world.<br />
For debugging purposes (and nice demo effect), I therefore wrote a python GUI that leverages the Enthought Chaco framework (itself <strong>based on qt4</strong>) to display live data on your computer screen.<br />
Depending on your computer configuration, it can (surprisingly) handle a 1600*1200 pixels window at a refresh rate of 34 frames per second to show <strong>raw ADC samples, computed FFT data and detected peaks over time</strong>.<br /></p>
<h2>So sensitive that it can debug your computer<br /></h2>
<p><a href="https://www.limpkin.fr/public/cdm324_v2/disappearing_noise.jpg"><img src="https://www.limpkin.fr/public/cdm324_v2/disappearing_noise.jpg" alt="" class="media-center" /></a><br />
Remember when I mentioned that I switched from a 7 segment display to a TN display because of voltage transients?<br />
In the picture above you can see the output spectrogram when no movement is happening in front of the sensor. At that moment, the AGC is not kicking in and <strong>the gain is at its maximum</strong> (94dB). That means the board amplifies.... <strong>everything</strong>, and that includes potential noise present on your USB power supply!<br />
So what happened at the end of that green arrow? I'm pretty sure it has something to do with either my trackpad or power saving features as this transition <strong>only happens when not touching my laptop for 30 seconds</strong>. I'm assuming the noise is picked up through the USB +5V power line, but it could also also be picked up through RF.... fun, right?<br />
<a href="https://www.limpkin.fr/public/cdm324_v2/usb_isolator.png"><img src="https://www.limpkin.fr/public/cdm324_v2/usb_isolator.png" alt="" class="media-center" /></a><br />
A way to improve things is to use a <strong>USB isolator</strong> as the one pictured above though!<br /></p>
<h2>Making a Companion Board<br /></h2>
<p><a href="https://www.limpkin.fr/public/cdm324_v2/cdm_exp.JPG"><img src="https://www.limpkin.fr/public/cdm324_v2/cdm_exp.JPG" alt="" class="media-center" /></a><br />
As it seems I was particularly motivated by this project, I then took some additional time to make a breakout board.<br />
It offers the following features:<br />
- a <strong>USB to UART converter</strong>, connected to the RESET & BOOT0 lines<br />
- a <strong>jack connector</strong> so you can listen to the doppler noise<br />
- a switch to toggle between MPH and KM/H display<br />
- a <strong>uSD card connector</strong> to log speeds<br />
That 1.6mm PCB with its two 8pins connectors means that it's firmly attached to the CDM324 module!<br />
Something great that is now enabled is <strong>one click firmware updates</strong> using the RTS & DTS lines of the USB-UART converter and the <a href="https://pypi.org/project/stm32loader/" hreflang="en" title="stm32loader">stm32loader project</a>... how awesome is that? All you need to type is:<br />
<a href="https://www.limpkin.fr/public/cdm324_v2/stm32loader.png"><img src="https://www.limpkin.fr/public/cdm324_v2/stm32loader.png" alt="" class="media-center" /></a><br /></p>
<h2>Tying it all together: making a Control GUI<br /></h2>
<p><a href="https://www.limpkin.fr/public/cdm324_v2/cdm_tool.png"><img src="https://www.limpkin.fr/public/cdm324_v2/cdm_tool.png" alt="" class="media-center" /></a><br />
Rather than having a collection of scripts, I decided to make a single python tool that:<br />
- automatically fetches and displays the detected object's speed<br />
- launches the speed debug tool I previously mentioned<br />
- allows you to <strong>flash the device</strong><br />
This is just the beginning, pull requests are strongly welcome!<br /></p>
<h2>Project source files<br /></h2>
<p><a href="https://www.limpkin.fr/public/cdm324_v2/cdm_and_exp.JPG"><img src="https://www.limpkin.fr/public/cdm324_v2/cdm_and_exp.JPG" alt="" class="media-center" /></a><br />
As with all my other projects, you'll find all source files made for this project <a href="https://github.com/limpkin/cdm324_fft" hreflang="en" title="cdm324 project sources">here</a>!<br />
Want to buy the complete assembled device? Have a look at my <a href="https://www.tindie.com/products/stephanelec/cdm324-doppler-speed-sensor/" hreflang="en" title="US shop">US shop</a> or <a href="https://lectronz.com/products/cdm324-doppler-speed-sensor" hreflang="en" title="CDM324 shop for EU">EU shop</a>!<br />
Want to interface that sensor to an Arduino? Have a look at the <a href="https://github.com/limpkin/cdm324_fft" hreflang="en" title="cdm324 project sources">getting started instructions.</a><br />
Thanks a lot for reading!</p>https://www.limpkin.fr/index.php?post/2022/03/31/CDM324-Doppler-Motion-Sensor-Backpack%2C-now-with-FFTs%21#comment-formhttps://www.limpkin.fr/index.php?feed/atom/comments/215Making the Electronics for a 24GHz Doppler Sensorurn:md5:0e5a89133911f8f8a16bf796d6000a292017-02-22T08:52:00+00:002024-03-09T11:09:53+00:00limpkinMy Projectscdm324doppler<p><img src="https://www.limpkin.fr/public/cdm324/.cdm324_assembled_quarter_m.jpg" alt="cdm324_assembled_quarter.JPG" class="media-center" title="cdm324_assembled_quarter.JPG, mar. 2017">
I couldn't believe my eyes when I saw how tiny that sensor is !</p> <h2>2023 Edit - New Project Version!<br></h2>
<p>I just made an improved version of this project, <a href="https://www.limpkin.fr/index.php?post/2022/03/31/CDM324-Doppler-Motion-Sensor-Backpack%2C-now-with-FFTs%21" hreflang="en">check it out here</a>!<br>
Otherwise, feel free to read about the non-MCU based version below:<br><br></p>
<h2>The Doppler Effect<br></h2>
<p><img src="https://www.limpkin.fr/public/HB100/doppler-effect.png" alt="Doppler effect" class="media-center" title="Doppler effect, août 2013"><br>
I'm sure you're quite familiar with the Doppler effect: you send an RF signal at a given frequency to a target, and if this object/person is moving the <strong>reflected signal's frequency will be shifted</strong>. This is the reason why a fire truck's siren has a <strong>higher pitch</strong> when the truck is going towards you than when it is going away.<br><br></p>
<h2>The CDM324 / IPM165 Motion Sensor<br></h2>
<p><a href="https://www.limpkin.fr/public/cdm324/cdm324_size.JPG" title="cdm324_size.JPG"><img src="https://www.limpkin.fr/public/cdm324/.cdm324_size_m.jpg" alt="cdm324_size.JPG" class="media-center" title="cdm324_size.JPG, mar. 2017"></a><br>
You may recall <a href="https://www.limpkin.fr/index.php?post/2013/08/09/Making-the-electronics-for-a-%247-USD-doppler-motion-sensor">the article I wrote a couple of years ago</a> about a nearly identical Doppler sensor, <strong>the HB100</strong>.<br>
While the HB100 is using a 10.525GHz frequency, this new module uses <strong>24.125GHz</strong>! This has the main advantage of being compatible with European regulations (ETSI #300 400) and having good penetration in dry materials. Moreover, as the main frequency is higher the patch antennas are smaller, hence the tiny 25x25x6mm module.<br>
This motion sensor can easily be purchased on eBay under the name <strong>CDM324</strong>. Oddly enough, looking for "cdm324" on your favorite search engine won't bring any interesting results.<br>
I therefore spent several hours tracing the origins of this tiny sensor. I finally arrived to the conclusion that it likely is a clone of the <a href="https://www.digikey.com/en/products/detail/innosent-gmbh/80-00000062/10482982" hreflang="en">InnoSenT IPM 165</a>, which is itself very similar to the <a href="http://agilsense.com" hreflang="en">AP96 from Agilsense</a>.<br>
Specification-wise, the CDM324 antenna pattern is slightly narrower than the HB100's: 80° azimuth and 32° elevation versus 80° azimuth and 40° elevation. The Radiated Power (EIRP) is more or less the same: 16dBm vs 15dBm. Finally, the advertised power consumption is identical to the HB100's: up to <strong>40mA @ 5V</strong>.<br><br></p>
<h2>Finding the Right Amplification Circuit<br></h2>
<p><a href="https://www.limpkin.fr/public/cdm324/cdm324_ampl_innosent.png" title="cdm324_ampl_innosent.png"><img src="https://www.limpkin.fr/public/cdm324/.cdm324_ampl_innosent_m.png" alt="cdm324_ampl_innosent.png" class="media-center" title="cdm324_ampl_innosent.png, fév. 2017"></a><br>
Now that I had traced the origins of this CDM324, I could find its recommended amplifier schematics.<br>
The one you see above comes from InnoSenT. It consists in 2 cascaded inverting band pass filter circuits:<br>
<a href="https://www.limpkin.fr/public/cdm324/pass_band_amplifier.png" title="pass_band_amplifier.png"><img src="https://www.limpkin.fr/public/cdm324/.pass_band_amplifier_m.png" alt="pass_band_amplifier.png" class="media-center" title="pass_band_amplifier.png, fév. 2017"></a><br>
You'll however notice that the op-amp positive input in our suggested schematics is tied to vcc/2, allowing us to have a <strong>centered amplification output</strong> as well.<br>
From the formulas above, we can compute the circuit <strong>total gain</strong> and <strong>cutoff frequencies</strong>. I'll spare you the maths, the suggested amplification is <strong>1018 (60dB)</strong> and a band pass filter from <strong>3.4Hz to 1.06kHz</strong>.<br>
The InnoSenT application note allows us to put these frequencies in context:<br>
<a href="https://www.limpkin.fr/public/cdm324/Innosent_app_note_doppler.png" title="Innosent_app_note_doppler.png"><img src="https://www.limpkin.fr/public/cdm324/.Innosent_app_note_doppler_m.png" alt="Innosent_app_note_doppler.png" class="media-center" title="Innosent_app_note_doppler.png, fév. 2017"></a><br>
The high cutoff frequency is therefore set for a <strong>24km/h or 15.4m/h speed</strong>. However, this isn't exactly true as the filter cutoff slope isn't vertical. Here's the simulated amplification output generated using LTspice:<br><br>
<a href="https://www.limpkin.fr/public/cdm324/simul_seller.png" title="simul_seller.png"><img src="https://www.limpkin.fr/public/cdm324/.simul_seller_m.png" alt="simul_seller.png" class="media-center" title="simul_seller.png, fév. 2017"></a><br>
You may therefore be able to measure much higher speeds if the moving object is <strong>close to the sensor</strong>.<br><br></p>
<h2>Amplification Circuit from Chinese Sellers<br></h2>
<p><a href="https://www.limpkin.fr/public/cdm324/cdm324_ampl_ebay.jpg" title="cdm324_ampl_ebay.jpg"><img src="https://www.limpkin.fr/public/cdm324/.cdm324_ampl_ebay_m.jpg" alt="cdm324_ampl_ebay.jpg" class="media-center" title="cdm324_ampl_ebay.jpg, fév. 2017"></a><br>
This is the (very low resolution) recommended amplification circuit that you will find online.<br>
Simulating it leads to raising eyebrows:<br><br>
<a href="https://www.limpkin.fr/public/cdm324/simul_ebay.png" title="simul_ebay.png"><img src="https://www.limpkin.fr/public/cdm324/.simul_ebay_m.png" alt="simul_ebay.png" class="media-center" title="simul_ebay.png, fév. 2017"></a><br><br>
Many many things are odd with this recommended amplification circuit:<br>
- <strong>No high pass filter</strong> on the second amplifier (remember, the cutoff slope in the first amplifier stage isn't vertical)<br>
- I don't see any reason for that 1nF capacitor when the high pass filter is done using the first op-amp<br>
- Amplification on the first stage is <strong>510</strong> while the amplification on the second stage is <strong>100</strong><br>
- Which leads to a total gain of <strong>51000 (94dB)</strong><br>
- ... while the LM258 has a <strong>gain bandwidth product of 1MHz</strong>!<br>
The last point is crucial. Given the first amplification stage has a gain of 510, this means there's only 1.96kHz of bandwith "left" inside the LM258. As the cutoff slope isn't vertical, this means that the LM258 isn't the right op-amp for the job! For example, at 10kHz the amplification is 3162, which is a GBW product of <strong>31.6MHz</strong>!<br><br></p>
<h2>Chosen Amplification Circuit<br></h2>
<p><a href="https://www.limpkin.fr/public/cdm324/cdm324_ampl_limpkin.png" title="cdm324_ampl_limpkin.png"><img src="https://www.limpkin.fr/public/cdm324/.cdm324_ampl_limpkin_m.png" alt="cdm324_ampl_limpkin.png" class="media-center" title="cdm324_ampl_limpkin.png, mar. 2017"></a><br>
After lots of experimentation and performance comparisons with my previous HB100 module, you can see above the final amplification circuit I chose.<br>
- As you can imagine, it is based on the manufacturer's<br>
- Each amplification stage has a gain of <strong>125.5</strong><br>
- Total gain is therefore <strong>15758 (84dB)</strong><br>
- Cutoff frequencies are <strong>3.4Hz and 999Hz</strong> (< 1 km/h or m/h and 22.7km/h / 14.5m/h respectively)<br>
Not so surprisingly the total gain is quite close to the one I had set on the HB100 (12100) and I'm fairly sure I could have set the same one. It was simply more convenient to choose the same resistors & capacitors values in my circuit.<br><br>
<a href="https://www.limpkin.fr/public/cdm324/simul_limpkin.png" title="simul_limpkin.png"><img src="https://www.limpkin.fr/public/cdm324/.simul_limpkin_m.png" alt="simul_limpkin.png" class="media-center" title="simul_limpkin.png, mar. 2017"></a><br>
As with my previous HB100 amplification circuit, I chose the <a href="http://www.ti.com/product/OPA2365" hreflang="en" title="OPA2365">OPA2365</a> operational amplifier. It has a 50MHz Gain Bandwidth product, which is more than the 15758*(84dB-3dB) = <strong>11.2MHz</strong> product at the high cutoff frequency point.<br><br></p>
<h2>Final Schematics<br></h2>
<p><a href="https://www.limpkin.fr/public/cdm324/cdm324_backpack_schematics.png" title="cdm324_backpack_schematics.png"><img src="https://www.limpkin.fr/public/cdm324/.cdm324_backpack_schematics_m.png" alt="cdm324_backpack_schematics.png" class="media-center" title="cdm324_backpack_schematics.png, mar. 2017"></a><br>
You can see above the final schematics:<br>
- FB1 is here to <strong>filter</strong> the power supply noise<br>
- the voltage at the C10/R11 node is proportional to the amount of reflected RF energy<br>
- Q1 allows <strong>pulse mode operation</strong>: you may power on/off the CDM324 using the module nEN pin<br>
- U2 is a simple comparator that will transform our amplified output to a neat <strong>square wave</strong>:<br><br>
<a href="https://www.limpkin.fr/public/cdm324/cdm324_print.png" title="cdm324_print.png"><img src="https://www.limpkin.fr/public/cdm324/.cdm324_print_m.png" alt="cdm324_print.png" class="media-center" title="cdm324_print.png, mar. 2017"></a><br>
In the scope capture above the yellow trace is the amplified output while the pink one is the comparator's output.<br>
Using a comparator is a simple way to 'extract' the amplified output main frequency but I'm quite sure running an FFT on that signal would be quite interesting!<br><br></p>
<h2>Assembled PCB<br></h2>
<p><a href="https://www.limpkin.fr/public/cdm324/cdm324_pcb2.JPG" title="cdm324_pcb2.JPG"><img src="https://www.limpkin.fr/public/cdm324/.cdm324_pcb2_m.jpg" alt="cdm324_pcb2.JPG" class="media-center" title="cdm324_pcb2.JPG, mar. 2017"></a><br>
Here's what the assembled PCB looks like! It has the same size as the CDM324 (<strong>25x25mm</strong>) and uses a 3pins header to connect with the sensor. <strong>0805 passive components</strong> were chosen to make the soldering job easier.<br>
Please do not pay attention to the silkscreen as some values have changed since then: have a look at the end of this article to <strong>download all the source files</strong>.<br><br></p>
<h2>3D Printed Holder<br></h2>
<p><a href="https://www.limpkin.fr/public/cdm324/cdm324_assembled.JPG" title="cdm324_assembled.JPG"><img src="https://www.limpkin.fr/public/cdm324/.cdm324_assembled_m.jpg" alt="cdm324_assembled.JPG" class="media-center" title="cdm324_assembled.JPG, mar. 2017"></a><br>
The HB100 doppler module had 4 connectors at each corner to solder my 'backpack PCB' to.<br>
Unfortunately the CDM324 only offers a single 3 pins connection, which is why I designed and <strong>3D printed</strong> a neat assembly holder: the CDM324 with its amplification circuit simply slide in it!<br><br></p>
<h2>The Sensors in Action & Sample Code<br></h2>
<p>Here's the video of the HB100 and CDM324 working side by side!<br></p>
<div class="external-media" style="margin: 1em auto; text-align: center;">
<iframe width="700" height="400" src="https://www.youtube.com/embed/PCI9bbN7HsE" frameborder="0" allowfullscreen></iframe>
</div>
<p>I'm guessing that if you were to use such a module you'd definitely like some <strong>sample code</strong>.<br>
Below is some arduino code that will <strong>output the detected speed in your favorite terminal</strong>:<br></p>
<pre>
// Below: pin number for FOUT
#define PIN_NUMBER 4
// Below: number of samples for averaging
#define AVERAGE 4
// Below: define to use serial output with python script
//#define PYTHON_OUTPUT
unsigned int doppler_div = 44;
unsigned int samples[AVERAGE];
unsigned int x;
void setup() {
Serial.begin(115200);
pinMode(PIN_NUMBER, INPUT);
}
void loop() {
noInterrupts();
pulseIn(PIN_NUMBER, HIGH);
unsigned int pulse_length = 0;
for (x = 0; x < AVERAGE; x++)
{
pulse_length = pulseIn(PIN_NUMBER, HIGH);
pulse_length += pulseIn(PIN_NUMBER, LOW);
samples[x] = pulse_length;
}
interrupts();
// Check for consistency
bool samples_ok = true;
unsigned int nbPulsesTime = samples[0];
for (x = 1; x < AVERAGE; x++)
{
nbPulsesTime += samples[x];
if ((samples[x] > samples[0] * 2) || (samples[x] < samples[0] / 2))
{
samples_ok = false;
}
}
if (samples_ok)
{
unsigned int Ttime = nbPulsesTime / AVERAGE;
unsigned int Freq = 1000000 / Ttime;
#ifdef PYTHON_OUTPUT
Serial.write(Freq/doppler_div);
#else
//Serial.print(Ttime);
Serial.print("\r\n");
Serial.print(Freq);
Serial.print("Hz : ");
Serial.print(Freq/doppler_div);
Serial.print("km/h\r\n");
#endif
}
else
{
#ifndef PYTHON_OUTPUT
Serial.print(".");
#endif
}
}
</pre>
<p><br>
Text written in serial terminals is so small though... why not print it bigger using ASCII art?<br><br>
<img src="https://www.limpkin.fr/public/cdm324/python_script.png" alt="python_script.png" class="media-center" title="python_script.png, mar. 2017"><br>
Simply define PYTHON_OUTPUT in the script above, install python on your computer, run "pip install pyfiglet pyserial" and use that awesome little python script (don't forget to replace COM3 with your COM port):<br></p>
<pre>
from pyfiglet import *
import serial
import os
ser = serial.Serial('COM3', 115200)
while True:
speed = ord(ser.read())
os.system('cls||clear')
print(figlet_format(" ",font="clb8x10"))
print(figlet_format(" ",font="clb8x10"))
print(figlet_format(str(speed)+" km/h",font="clb8x10"))
print(figlet_format(" ",font="clb8x10"))
</pre>
<p><br></p>
<h2>Want to Make or Buy One?<br></h2>
<p>Here's the GitHub repository I made for this project: <a href="https://github.com/limpkin/cdm324_backpack" hreflang="en" title="cdm324 repository">https://github.com/limpkin/cdm324_backpack</a>.<br>
If you're interested by this module and don't want to produce it by yourself, you may buy it from <a href="https://www.tindie.com/products/stephanelec/cdm324-doppler-speed-sensor-arduino-compatible/" hreflang="en" title="Buy Your CDM324 Module">my store here</a>.<br>
You may also purchase my <strong>cheaper</strong> HB100 module <a href="https://www.tindie.com/products/limpkin/hb100-doppler-speed-sensor-arduino-compatible/" hreflang="en" title="HB100 store">there</a>.<br></p>https://www.limpkin.fr/index.php?post/2017/02/22/Making-the-Electronics-for-a-24GHz-Doppler-Motion-Sensor#comment-formhttps://www.limpkin.fr/index.php?feed/atom/comments/211