AD5933使用外部時鐘獲得更低的分析頻率

 

■ 前言


在博文 AD5933不同頻率下轉換結果 中分析了 AD5933阻抗變換模塊 使用內部時鐘(fosc=16.776MHz)時,測量結果受到採集時間窗口的影響,所能夠達到的最低阻抗激勵正弦信號頻率。

那麼,在有些應用中,對象的帶寬和工作頻率會很低,那麼如果能夠使用AD5933對這些對象進行測量呢?

雖然,AD5933內部的DSS(數字信號合成 )器可以輸出很低的頻率,但受到前面提到的數據採集窗口的窗口的影響,所以還是不能夠使用。

一種可行的方式就是利用AD5933外部時鐘,來降低內部ADC採樣的頻率,從而可以有效擴大數據採集時間窗口,減少因爲 頻譜泄漏 對於測量結果的影響。

  • 通過實驗驗證MCLK對於AD5933的影響
  • 驗證AD5933究竟是否可以達到很低的分析能力?

 

01使用STC8G1K08的T0輸出脈衝信號1,2


AD5933阻抗轉換器、網絡分析儀初步實驗 中給出了基於STC8G1K081K(SOP8)的實驗電路,完成對AD5933模塊的I2C總線命令的控制。實驗電路板還包括有T0/T1CLKO管腳輸出,這部分可以用來產生AD5933的MCLK的時鐘信號。

▲ 設置T1CLKO的STC8G相關寄存器

▲ 設置T1CLKO的STC8G相關寄存器

在STC8G1K08的main程序初始化子程序中,定義如下命令,設置T1CLKO爲輸出信號。

▲ 實驗電路板 STC8G1K08

▲ 實驗電路板 STC8G1K08

#define T1CLKO_PIN      5,4
void MainInit(void) {
    PM_BIDIR(LED);
    AD5933Init();
    
    INTCLKO |= 0x2;
    PM_PP(T1CLKO_PIN);
    
}

測量P5.4(T1CLKO)管腳的波形如下。頻率爲:ft1=921.3kHzf_{t1} = 921.3kHz

由於此時T1用於UART1的波特率(460800bps),所以它的頻率爲921.3Khz。

▲ STC8G1k的P5.4(T1CLKO)管腳的輸出波形

▲ STC8G1k的P5.4(T1CLKO)管腳的輸出波形

 

02產生輸出信號


1.設置輸出激勵正弦信號

在初始化AD5933中,選擇外部CLK。在設置SetSweep的時候,設置參數oscf=0.92。輸出3kHz。

ad5933.init(20, 1)
stm32cmd('reada')
startf = 2000
stepf = 100
numf = 10

ad5933.setsweep(startf, stepf, numf, oscf=0.9216)
ad5933.sweep(1)

下面是採集到的輸出波形。它的頻率爲3KHz。這說明AD5933的確是按照外部得始終產生激勵信號的。
▲ 輸出3KHz的正弦波形

▲ 輸出3KHz的正弦波形

2. 測試新的最低工作頻率

內部工作頻率 fin=16.776Mhzf_{in} = 16.776Mhz時,按照AD5933不同頻率下轉換結果 中的結果,最低工作頻率大約是:fmin=2kHzf_{\min } = 2kHz左右。現在外部時鐘頻率爲:fext=0.9216MHzf_{ext} = 0.9216MHz。那麼對應的最低工作頻率:

下面是在不同的輸出工作頻率下,測量負載爲無窮大時,測到所得到的電流幅度。可以看到在頻率大約爲110Hz的時候,輸出接近於零。這與上述計算結果是相符合的。▲ 在不同的工作頻率下測量結果,此時工作電阻爲無窮大

▲ 在不同的工作頻率下測量結果,此時工作電阻爲無窮大

3.修改模塊中的耦合電容

使用AD5933上的運放緩衝電路的時候,由於AD5933通過 0.01uF的電容耦合到AD8606運放。當輸出頻率很低的時候,會極大衰減輸出信號。

將該耦合電容修改到20uF;這樣對應的截止頻率爲:C0=20uFC_0 = 20uF,後期的分壓電阻爲R0=10kΩR_0 = 10k\Omega。後期的截止頻率爲:

▲ 不同頻率下輸出激勵電壓

▲ 不同頻率下輸出激勵電壓

▲ 不同頻率下輸出激勵電壓

▲ 不同頻率下輸出激勵電壓

從上圖來看,輸出信號的截止頻率大約是10Hz左右。

爲了進一步降低截止頻率,將原來的分壓電壓的電阻從原來的22kΩ,修改成200kΩ.

▲ 修改緩衝運放

▲ 修改緩衝運放

經過改造之後,重新測量輸出電壓與激勵信號頻率之間的關係。可以看到截止頻率降低到1Hz左右。
▲ 不同頻率輸出激勵電壓幅值

▲ 不同頻率輸出激勵電壓幅值

 

03使用信號源產生工作頻率


1.工作時鐘頻率

使用DS345產生AD5933的工作時鐘信號。首先設置輸出頻率:100kHz, 幅度:Vpp=2V;偏置:1V。

▲ 信號源DS345

▲ 信號源DS345

由於輸出信號是按照負載爲50Ω來設定的。帶動AD5933工作時,由於負載遠遠大於50Ω,所以輸出的幅值基本上是上述設置兩倍。

下圖是實際測量DS345輸出的時鐘信號。Vpp大約爲2V,重心偏移量爲2V。

▲ 工作時鐘信號

▲ 工作時鐘信號

通過測試,需要將時鐘的幅值設置爲峯峯值2V才能夠滿足觸發AD5933的工作。

▲ 設置信號的幅值和波形

▲ 設置信號的幅值和波形

如果輸入信號超過的3.3V,有可能導致電流回灌。

  • 正確的設置方式:Vpp:1.5V,Vbias=1V,方波。

2.測試輸出信號頻率

在Vin,Vout之間連接Rload=300kΩR_{load} = 300k\Omega。在不同的頻率下測量的結果如下圖所示。

  • 工作頻率:0.1MHz
    ▲ 不同頻率下測量的結果
    ▲ 不同頻率下測量的結果

根據在 AD5933不同頻率下的轉換結果 測量結果,在fosc=16.776MHzf_{osc} = 16.776MHz下,頻率泄露所引起的最低工作頻率爲2000Hz。那麼工作在f1=0.1Mhzf_1 = 0.1Mhz下的最低工作頻率爲:


從前面的測量結果來看,的確最低的工作頻率大約10Hz左右。

(1)工作頻率0.01MHz:

下面顯示了在不同的頻率下的測量結果。

在工作頻率爲fosc=16.776MHzf_{osc} = 16.776MHz下,數據採樣頻率爲1MHz。在工作頻率f1=0.01MHzf_1 = 0.01MHz時,對應的數據採樣頻率爲:

▲ 不同頻率下測量的結果

▲ 不同頻率下測量的結果

▲ 普通頻率下的測量結果

▲ 普通頻率下的測量結果

下圖顯示了在596MHz下,對應的採集到的數據。其中存在兩個奇怪的地方:

  • 測量結果中存在一個線性相位
    這可能是由於轉換過程存在一個特定的時間延時tADt_{AD}。從圖像中可以看到該延遲大約是2ms。也就是在1000Hz的時候,相位相差了2個2π2\pi
  • 當頻率大於550Hz長輩,結果中存在噪聲
    由於採集頻率爲596Hz,所以當信號的頻率超過500Hz之後,實際上信號已經處於欠採樣過程。所以這個過程存在着比較明顯的噪聲。
    ▲ 普通頻率下的測量結果
    ▲ 普通頻率下的測量結果
(2)工作頻率:0.02MHz:

從測量結果來看:

  • 存在着 一個1ms左右的延遲
    可以猜測,固定的延遲大約等於兩個工作時鐘信號週期。
    ▲ 普通頻率下的測量結果
    ▲ 普通頻率下的測量結果

下圖顯示了最低的工作頻率大約在2.5Hz。
▲ 普通頻率下的測量結果

▲ 普通頻率下的測量結果

(3)工作頻率:0.05MHz

最低的工作頻率大約E座5.5Hz.
▲ 普通頻率下的測量結果

▲ 普通頻率下的測量結果

3. AD5933的工作頻率對結果的影響

  • 工作頻率:0.01MHz
    ▲ 不同頻率下的測量結果

    ▲ 不同頻率下的測量結果

  • 工作頻率:0.02MHz

▲ 不同頻率下的測量結果

▲ 不同頻率下的測量結果

  • 工作頻率:0.05MHz
    ▲ 不同頻率下的測量結果
    ▲ 不同頻率下的測量結果

 

※ 結論


可以使用外部加入測MCLK信號,來改變AD5933的測量信號頻率範圍。

輸入信號的幅度需要儘可能解決0~3.3V,可以使用正弦波,或者方波信號來驅動MCLK。

總結上述測量結果,可以近似得到如下的結果:
(1)AD5933存在一個固定的延遲tdelayt_{delay},這與工作頻率fMCLKf_{MCLK}之間的關係爲:tdelay=20fMCLt_{delay} = {20 \over {f_{MCL} }}
(2) 數據採樣頻率:fs=fMCL/16.776×106Hzf_s = f_{MCL} /16.776 \times 10^6 HzfMCLf_{MCL}的單位MHz。 輸入信號的頻率需要小於fs的一半。
(3)最低工作頻率:fmin=fMCL/16.776×2000f_{\min } = f_{MCL} /16.776 \times 2000fMCLf_{MCL}的單位MHz。
(4)測量保證數據精確性,至少在採樣數據中,正弦信號的週期:最小5個;最大的週期512(滿足採樣定理)。因此AD5933的測量信號的頻率範圍大約是100倍(兩個數量級)。
#!/usr/local/bin/python
# -*- coding: gbk -*-
#============================================================
# TEST1.PY                     -- by Dr. ZhuoQing 2020-06-25
#
# Note:
#============================================================

from headm import *
import ad5933
from tsmodule.tsstm32       import *
from tsmodule.tsvisa        import *

#------------------------------------------------------------
printf('\a')
ad5933.init(2, 1)

startf = 5
stepf = 2
numf = 200

#------------------------------------------------------------
freqn = ad5933.setsweep(startf, stepf, numf, oscf=1)
#printf(freqn)

#------------------------------------------------------------
ad5933.sweep(1)

while True:
    time.sleep(.5)
    val = stm32val()

    if val[12] > 0: break

R,I = stm32memo(2)
printf(R, I)

#------------------------------------------------------------

#f = linspace(startf, startf + stepf * numf, len(R), endpoint=True)
f = freqn

A = [sqrt(r**2+i**2) for r,i in zip(R,I)]

plt.plot(f, R, label="Real")
plt.plot(f, I, label="Imaginary")
plt.plot(f, A, label='Amplitude')
plt.xlabel("Frequency(Hz)")
plt.ylabel("Value")
plt.grid(True)
plt.legend(loc="upper right")
plt.show()

#------------------------------------------------------------
#        END OF FILE : TEST1.PY
#============================================================

#!/usr/local/bin/python
# -*- coding: gbk -*-
#============================================================
# AD5933.PY                    -- by Dr. ZhuoQing 2020-06-25
#
# Note:
#============================================================

from head import *
from tsmodule.tsstm32       import *

#------------------------------------------------------------

def init(settletime=100, extclock=0):
    if extclock > 0:
        stm32cmd('writeb 81 8')
    else:
        stm32cmd('writeb 81 0')

    time.sleep(0.02)
    stm32cmd('writeb 80 b1')    # Enter standby mode
    stm32cmd('writei 8a %x'%settletime)
    time.sleep(0.02)

def temperature():
    data = stm32cmdata('readt', wait=200)
    if len(data) > 0:
        return data[0] / 32
    else: return 0

def setsweep(startf, incf, num=100, oscf=16.557):
    startn = int(startf * (2**27) / (oscf*1e6/4))
    incn   = int(incf * (2**27) / (oscf*1e6/4))

#    printff('%x %x %x'%(startn, incn, num))

    stm32cmd('writel 82 %x'%startn)
    time.sleep(.02)
    stm32cmd('writel 85 %x'%incn)
    time.sleep(.02)
    stm32cmd('writei 88 %x'%num)
    time.sleep(.02)

#    stm32cmd('writeb 81 0')         # D3: 0:Internal system clock 1:External
#    time.sleep(.02)
    stm32cmd('writeb 80 b1')        # Standby

    time.sleep(.02)
    stm32cmd('writeb 80 11')
    time.sleep(.02)

    fdim = []
    for n in linspace(startn, startn + incn * num, num+1, endpoint=True):
        fdim.append(n * oscf * 1e6/4/(2**27))

    return fdim

def startf(resultflag = 0):
    if resultflag > 0:
        stm32cmd('writeb 80 21 1')
    else:
        stm32cmd('writeb 80 21')

def incf(resultflag = 0):
    if resultflag > 0:
        stm32cmd('writeb 80 31 1')
    else:
        stm32cmd('writeb 80 31')

def repeatf(resultflag = 0):
    if resultflag > 0:
        stm32cmd('writeb 80 41 1')
    else:
        stm32cmd('writeb 80 41')

def readdata():
    return stm32cmdata('readd', wait=100)

def sweep(code=0x1):
    stm32cmd('CLEAR')
    time.sleep(.02)

    stm32cmd('sweep %x'%code)

#------------------------------------------------------------

if __name__ == '__main__':

    tdim = []

    for i in range(10):
        data = temperature()
        tdim.append(data)
        time.sleep(.1)

    printf(tdim)

#------------------------------------------------------------
#        END OF FILE : AD5933.PY
#============================================================


  1. 實驗STC8G1K08 Keil工程文件:C51\STC\Test\2020\AD5933\AD59338G1K\AD59338G1K.uvproj ↩︎

  2. 實驗AD電路工程文件:AD\Test\2020\AD5933\AD59338G1K.SchDoc ↩︎

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章