2020年6月19日 星期五

Signal Generators (en)

(Including AD9833AD9834AD9850ADF4351)


Why this

 I started learning SDR recently, and need to use signal generator . Some modules on the market have sophisticated functions, but are usually expensive. AD9833  is a cheap and popular DDS / signal generator module. I bought a few and tested with home-brew driver for Python, so that I can use  PC (Windows / Linux, with USB-SPI converter), Raspberry Pi , ESP32  to control AD9833.

The GitHub repository is  here , which also includes drivers for several popular signal generator modules AD9833,  AD9834,  AD9850,  ADF4351) . 

Categories of signal generators

I personally divide signal generators into three categories:

1. Independent set:
There are many models ( examples ), and the functions will be slightly different depending on the application field. 
Pros: 
  • Operates independently, without relying on and consuming PC resources.
  • It is composed of many hardware components and has high operating efficiency.
  • Sophisticated functionalities.
Cons:  
  • Although with sophisticated functionalities, it is still limited, and expansion is not easy/free.
  • Some models come with API/protocol  for communicating with the PC, but learning  curve may be steep.
  • The driver / API / utilities provided by the manufacturer may not cross-platform (Windows / Linux).
  • It cannot be operated with MCU (eg. ESP32, Arduino).
  • Usually expensive.

2. Signal generator in an USB dongle ( example ):
Pros: 
  • Small and very portable.
  • With dedicated hardware components for performance. 
  • It can be controlled by software on PC, and therefore flexible.
Cons:
  • Usually with limited functionality.
  • It still needs to be controlled by the PC, consume some resources. 
  • The driver / utilities may not cross OS (Windows / Linux).
  • It cannot be used with ESP32 and Arduino.
  • Not quite cheap.
3.  Arduino-like based signal generator ( example ):
Pros:
  •   Can operate independently, without consuming PC resources.
  •   Cheap.
Cons:
  •   Not easy to interface with PC.
  •   Operating independently, but may not be easy to co-operate with other devices.
  •   Limited functionality.
There are many examples on the Internet where Arduino / ESP32 is used with the AD9833 module. This is also what I tried to do at the beginning.

Device driver development models
To develop a device driver in order to "using Arduino /  ESP32 or other controller with AD9833 to generate various signals ", we can takes one of following development models :
1. Do it all on a real device:
Write/compile the program on the PC and upload it to the device (Arduino /  ESP32 ) which controls AD9833 For debugging, insert commands such as "print" into the program to display the status. Repeat the above steps until bugs are fixed. 
Pros: 
  • Tested in a real device, the result is absolutely real. 
Cons: 
  • It is necessary to insert the many "print" instructions one by one at the points of interest, and then recompile and upload again, which is cumbersome. 
  • Can't set break points, no way to pause the running program and inspect the status and value of variables.
  • Not possible to dynamically modify the variable value or re-direct the flow. The only way to do that is to revise, re-compile, and upload again, which takes time and patience.
  • Low cross-platform portability, driver developed for Arduino may not be used directly on ESP32, Raspberry Pi, or PC.   
Pros: 
  • No need to manually add "print" instructions. 
  • Break points can be set to pause the program to check the status.
  • Value of variable and flow can be dynamically modified. 
Cons:
  • With complex configuration and operations, the learning  curve may be steep.
  • Not every MCU supports JTag.   
  • Not every IDE supports JTag.   
  • Low cross-platform portability, driver developed for Arduino may not be used directly on ESP32, Raspberry Pi, or PC.    

Goals
 I use ESP32+ (Micro)Python most of the time, so I will skip Arduino here.
The goals of this project are as following:
  • To build drivers, with which you can use ESP32 / Raspberry Pi to drive AD9833 module to generate signals.
  • PC (Windows / Linux) also can be used to control the AD9833, therefore enormous resources on the PC side are available to AD9833, many tasks are possible, such as sending data from PC via the AD9833 generated signal.
  • One or many AD9833 modules can be used for variety of  modulation (BFSK, BPSK, QPSK, IQ, FM, PM, OOK, DTMF) .
  • The driver can be used to control AD9833, across OS (Windows / Linux) and hardware (PC / Raspberry Pi / ESP32).
  • During the driver development:
    • No need to upload code to MCU repeatedly .
    • Break points can be set to pause the code, variables and flow can be inspected and modified. JTag is not required, therefore there is not learning curve.

  • Use Python
    • OS is somewhat abstract to Python. With minor to no modification , the same Python code is likely to work on  Windows / Linux,  PC / Raspberry / ESP32.
  • Use Adapter design pattern :
    • Wrap the bus (SPI / I2C / GPIO) on different platforms into adapters which obey an unified interface definition, so that the same driver can be used with different OS (Windows / Linux) and hardware (PC / Raspberry Pi / ESP32) , by selecting corresponding adapter, the required adjustment is minimized.
  • Register as a software class:
    • With software classes of registers, according to the specification of AD9833, reading/writing of register is no longer tedious. Only the name of the field needs to be specified, no need to calculate how many bits to shift. For example, to control the SLEEP1 field, just:
      • def _enable_internal_clock(self, value = True):
            self.control_register.elements['SLEEP1'].value = int(not bool(value))
            self._update_control_register()
    
    
    • Status of a register can be "printed" , for example:
    • ad.control_register.print()
      
      << Control >>    :  ('0x2000', '0b10000000000000')
      [ D15 ]        :  0
      [ D14 ]        :  0
      [ B28 ]        :  1
      [ HLB ]        :  0
      [ FSELECT ]    :  0
      [ PSELECT ]    :  0
      [ PIN_SW ]     :  0
      [ Reset ]      :  0
      [ SLEEP1 ]     :  0
      [ SLEEP12 ]    :  0
      [ OPBITEN ]    :  0
      [ SIGN_PIB ]   :  0
      [ DIV2 ]       :  0
      [ Reserved_2 ] :  0
      [ Mode ]       :  0
      [ Reserved_0 ] :  0
    • Registers value comparision:
      • We can compare two sets of register values, showing all register fields or just the mis-matched ones. This is very useful during device driver development.
  • Directly control AD9833 with PC
    • Use USB-SPI converter (such as FT232H or FX2LP ) , so we can control AD9833 directly from PC using SPI interface.
    • With the Bridges package, pretend your PC as a Raspberry Pi or an ESP32:
      • Let a PC with USB-SPI converter have the SPI function of  the same interface definition with that on ESP32 / Raspberry Pi, so we can pretend a PC  as if it's a Raspberry Pi / ESP32, so the driver developed can be copied directly to the PC / ESP32 / Raspberry Pi  with no modification required .
      • That is to say, existing Python drivers of AD9833 on Raspberry Pi or ESP32 can be used on PC with little or no modification.
    • Impact on driver development:
      • Develop the program on the PC and directly control the AD9833 for testing, without repeatedly uploading the code to MCU.
      • Taking advantage of the powerful development environment on PC, such as advanced IDEs (for example:  PyCharm ) , you can set breakpoints, pause and check the status, view or modify variable values whenever you want.
      • You can test and use the AD9833 with Jupyter Notebook ,  development and documentation are both taken care of at the same time.
    • Impact on the usage of AD9833:
      • Easy connecting AD9833 with PC.
      • Enormous resources on the PC side now are available to a signal generator like AD9833, which can greatly expend the functionality of a signal generator. 
        • Data can be prepared with Numpy and various Python modules.
        • You can send modulated information via AD9833 directly from PC .
      • Like SDR,  now AD9833 can be controlled without a separated MCU. Total cost is lower .
      • In addition to the AD9833, other devices can be controlled by a PC in the same way for collaborative operation (such as test-automation).

Test Results
Basic functional tests:
Waveform manipulation
  • Tested with this notebook:
  • Frequency sweeping:
Control AD9833 with PC + FT232H (USB-SPI converter) 
using Jupyter notebook

Control AD9833 with ESP32 
(which in turns is controlled via Jupyter + MicroPython Remote Kernel)

  • Waveform juggling:

Control AD9833 with PC + FT232H (USB-SPI converter) 
using Jupyter notebook

Control AD9833 with ESP32 
(which in turns is controlled via Jupyter + MicroPython Remote Kernel)

 Modulations 



  • IQ (using two AD9833 modules)





  • DTMF  (using two AD9833 modules):



Other modules:
  • AD9834

  • AD9850 (I forgot to record video)
  • ADF4351



Dependencies:

Signal Generators

(Including AD9833AD9834AD9850ADF4351)

緣由
最近在學習 SDR,會需要用到 訊號產生器市面上有的機型 具有非常強的功能,但是通常也不便宜。在網路上找一下,發現這塊 AD9833 模組,它雖然比較偏向音頻的用途,但價錢非常便宜而且取得方便,所以就買了幾塊來試試,並且用 Python 寫了對應的 driver,可以跨平台適用在 PC (Windows / Linux,需使用 USB-SPI converter)、Raspberry PiESP32 上面。
後來索性把市面上較常見的幾種 signal generator 模組 (AD9833AD9834AD9850ADF4351的 python drivers 都寫一寫,GitHub repository 在 這裡。 

訊號產生器 的 種類與特點
我將 訊號產生器 大致區分為以下三個種類:
1. 獨立機台:
機種非常多 (例子),功能會因為應用領域而有些微不同。特色為:
優點: 
  • 可以獨立使用,不需要依賴與耗用 PC 的資源。
  • 由很多硬體元件所組成,運行效率高。
  • 功能齊全完備。
缺點:  
  • 功能雖多但還是受到限制,擴充不易 (可能需要額外的費用)。
  • 有的機型 可以需依照廠商所定的 API / protocol 來與 PC介接溝通,但仍有學習門檻。
  • 廠商所提供的 driver / API / utility 不一定能跨平台 (Windows / Linux)。
  • 無法透過 MCU (例如 ESP32、Arduino) 來操作。
  • 價位較高。
2. Signal generator in an USB dongle (例子):
優點: 
  • 體積小,便於攜帶。
  • 仍含有專用的硬體元件,維持執行效率。
  • 可由 PC 上的軟體控制,應用上較為彈性。
缺點:
  • 通常較小型,功能有限。
  • 仍需透過 PC控制,某種程度地占用 PC 的資源。
  • driver / utility 不見得能跨 OS (Windows / Linux)。
  • 無法透過 ESP32、Arduino 使用。
  • 不是非常便宜。
3. Arduino-like based signal generator (例子):
優點
  •   可以獨立使用,不需要依賴與耗用 PC 的資源。
  •   便宜。
缺點
  •   不易與 PC 介接。
  •   可以獨立使用,但較難與其他設備協同作業。
  •   功能較有限。
網路上就有很多以 Arduino / ESP32 搭配 AD9833 模組的 例子,這也是我原本所採取的模式,但是有以下的考量。

Device driver 的開發模式
就以 "使用  Arduino / ESP32 或其他控制器 搭配 AD9833 來產生各種訊號" 這個目的來說,通常可以採用以下幾種開發模式:
1. 一般的開發模式:
在 PC 上編寫/編譯程式之後上傳到控制 AD9833 的裝置 (Arduino / ESP32)上,在程式中插入一些例如 "print" 的指令將執行狀況顯示出來,以作為 tracing / debugging 的依據;修正錯誤之後 再次重複以上的步驟。 
優點: 
  • 在真實的裝置中執行,其結果絕對真實。 
缺點: 
  • 須根據要檢測的點,逐一插入相對的 "print" 指令,並且要重新編譯,費工費時。
  • 無法設定中斷點,也就無法暫停程式的執行 以檢視流程與狀態。
  • 無法動態地 修改變數值 或 改變程式流程,必須重新修改編譯才行,費工費時。
  • 每次修改之後都需要重新編譯,並重新上傳到 MCU 上面,相當耗時。  
  • 跨平台的移植性較弱,為 Arduino 開發的程式 不見得可以在 ESP32、Raspberry Pi、PC 上面執行。   
優點: 
  • 不再需要手工加入 "print" 指令。 
  • 可以設定中斷點 暫停程式的執行 以檢視流程與狀態。
  • 可以動態地 修改變數值 或 改變程式流程。 
缺點:
  • 操作與設定較複雜,學習門檻較高。
  • 不是每種 MCU 都有支援。  
  • 不是每種 語言都可搭配 in-line debugger 使用 
  • 需要 IDE 有支援。 
  • 跨平台的移植性較弱,為 Arduino 開發的程式不見得可以在 ESP32、Raspberry Pi、PC 上面執行。   
 

目標
因為我比較常用 ESP32+ (Micro)Python,這邊就沒有考慮 Arduino。
這次實作 想達到的目標如下:
  • 建構必要的軟體,可以用 ESP32 / Raspberry Pi 來控制 AD9833 模組 來產生訊號。
  • 也可以使用 PC (Windows / Linux)來做控制 AD9833,這樣就可與 PC上的資源連接,例如將 PC 上的資料透過 AD9833 產生訊號發送出去。
  • 可以控制一個或多個 AD9833 來做多種 modulation (BFSK、BPSK、QPSK、IQ、FM、PM、OOK、DTMF)
  • 開發出來的成果,可以跨 OS (Windows / Linux) 與硬體 (PC / Raspberry Pi / ESP32) 地用來控制 AD9833。
  • 開發的過程中:
    • 不需要反反覆覆的上傳程式到 MCU 上。
    • 可以設定中斷點,也可以 監看或改變 變數的內容值,不需要使用 JTag,沒有學習門檻。

  • 使用 Python
    • Python 某種程度地將 OS 與 硬體平台 抽象化,同一套 Python 程式很可能可以在 Windows / Linux,Raspberry / ESP32上面執行,只需要經過些微修改,甚至不需要修改就可以運行。
  • 使用 Adapter 設計模式:
    • 將不同平台上驅動 bus (SPI / I2C / GPIO)的方式 包裹成 統一介面 的 adapters,同一套程式可以適用在 不同的 OS (Windows / Linux) 與硬體 (PC / Raspberry Pi / ESP32) 上,僅須依據不同的環境 選用不同的 adapter 即可,所需的調整微乎其微。
  • 將 registers 元件化:
    • 依照 AD9833 的規格書,將煩人的 register 讀寫透過元件來處理,只需要指定 欄位的名稱,不需要去計算左移、右移 的位數,例如要控制 SLEEP1 的欄位,只需:
      • def _enable_internal_clock(self, value = True):
        self.control_register.elements['SLEEP1'].value = int(not bool(value))
        self._update_control_register()
    • 可以隨時列出一個 register中 各個欄位的值,例如:
    • ad.control_register.print()
      
      << Control >>    :  ('0x2000', '0b10000000000000')
      [ D15 ]        :  0
      [ D14 ]        :  0
      [ B28 ]        :  1
      [ HLB ]        :  0
      [ FSELECT ]    :  0
      [ PSELECT ]    :  0
      [ PIN_SW ]     :  0
      [ Reset ]      :  0
      [ SLEEP1 ]     :  0
      [ SLEEP12 ]    :  0
      [ OPBITEN ]    :  0
      [ SIGN_PIB ]   :  0
      [ DIV2 ]       :  0
      [ Reserved_2 ] :  0
      [ Mode ]       :  0
      [ Reserved_0 ] :  0
    • Registers 狀態的比較:
      • 可以針對 兩組不同的 registers 設定值 做比較,並列出各個欄位的差異,這在 development 階段 debug 時候非常有用。
  • 可以直接在 PC 上直接控制 AD9833 模組
    • 使用 USB-SPI converter (例如 FT232H FX2LP),讓 PC 可以直接連接  使用 SPI 介面的 AD9833。
    • 透過 Bridges package,將 PC 假扮成 ESP32 / Raspberry Pi:
      • 讓 使用 USB-SPI converter 的 PC 具有 和 ESP32 / Raspberry Pi 相同介面定義的 SPI功能,將 PC 假扮成 ESP32 / Raspberry Pi,所以開發出來的 Python 程式不需要修改,直接複製過去 就可以在 PC / ESP32 / Raspberry Pi 上使用
      • 反過來說,網路上既有裝置的 Python driver,不論是為了 Raspberry Pi 或 ESP32 寫的,都很可能 只需經過極少的調整,甚是不需要修改,就可以在 PC 上面使用極大化地拓展 裝置可用的資源 與 PC可使用的裝置品項
    • 對開發上的影響:
      • 在 PC 上開發程式並直接控制 AD9833 來測試,不需要反反覆覆地上傳程式到 ESP32 上。
      • 利用 PC 上的開發環境優勢,例如先進的 IDE (如 PyCharm) 來開發程式,可以設定中斷點,隨時監看執行狀況並檢視變數值
      • 網路上既有的 Python device driver,只需經過極少的調整,就可以在 PC 上面使用,我們可以使用 PC 上 IDE 的 debug 功能,加速我們對 device 運作原理的了解,縮短開發時程
      • 可以透過 Jupyter Notebook 來測試與使用 AD9833,兼顧程式的發展與文件的累積。
    • 對 AD9833 使用上的影響:
      • 可以透過 PC 來使用 AD9833,與PC介接 沒問題。
      • 可以與 PC 上豐富的資源做連接,可最大化且彈性的擴充功能。 
        • 可以透過 Numpy 與各式各樣的 Python modules 來準備資料。
        • 可以直接在 PC 上透過 AD9833 做 modulation 發送資訊
      • 控制軟體化,不需要獨立的 MCU 就可以控制 AD9833。就如 SDR 的發展,可以省下部分硬體元件的成本
      • 除了 AD9833,也可以依照相同的模式 透過 PC 控制其他的裝置,達到協同作業的目的 (例如測試自動化)。

測試結果
Basic functional tests:
Waveform manipulation
  • Tested with this notebook:
  • Frequency sweeping:
Control AD9833 with PC + FT232H (USB-SPI converter) 
using Jupyter notebook


Control AD9833 with ESP32 
(which in turns is controlled via Jupyter + MicroPython Remote Kernel)


  • Waveform juggling:
Control AD9833 with PC + FT232H (USB-SPI converter) 
using Jupyter notebook


Control AD9833 with ESP32 
(which in turns is controlled via Jupyter + MicroPython Remote Kernel)


 Modulations 



  • IQ (using two AD9833 modules)





  • DTMF  (using two AD9833 modules):


其他模組:
  • AD9834


  • AD9850 (忘了錄影)
  • ADF4351



Dependencies: