Измерения импеданса с DSO Quad и Numpy

Приехал ко мне вчерась с dealextreme китайский клон DSO Quad a.k.a. DSO203 (раз, два). Ссылка у него на корпусе на www.minidso.com (сайт на китайском). Работал только один канал, был дефект травления платы, обнаружил, запаял, но история не об этом.

Захотелось мне измерять им параметры RCL-цепочек. Взял приложение для измерения ЛАФЧХ с essentialscrap.com/dsoquad/freq.html, поставил. Приложеньице ставится в четвертый слот, запускается при включении с зажатой кнопкой «треугольник», простое, как валенок. Фиксированный диапазон сканирования 10Гц-200кГц, два варианта шага по частоте — 44 или 216 точек, сохранение в BMP или в CSV. Про CSV это неправда, там нет ни одной запятой, столбцы разделены пробелами.

Пример сохраненного графика



Для начала проверим АФЧХ самой измерительной системы соединив выход с входом.
Получаем (файлы FREQ_PROBE10.CSV и FREQ_PROBE1.CSV):



и



В режиме 1:10 совсем не фонтан, но это лучшее, чего удалось добиться при настройке делителей. Исходно амплитуда выше 1кГц вообще проваливалась на 3дБ, а не на 1, как сейчас. Но и с трехдецибельной кривизной всё последующее получалось идеально, поскольку на известную АФЧХ всегда можно поделить.

Для разминки определим импеданс щупа банальным методом, соединив выход генератора со щупом через резистор в 1МОм. Будет вот такая эквивалентная схема

      +----+
    --+ R1 +---+----+----
      +----+   |    |
               |   +++
            C ---  | | R2
              ---  +++
               |    |
              ---  ---

Проделаем это для 1:1 и 1:10 (файлы FREQ_1M_Z.CSV и FREQ_1M_Z_div10.CSV соответственно). C и R2 будут разными. Пойдем самым суровым методом получения C и R2 из АФЧХ — подгонкой кривой (fitting). Для этого сваялась програмка

#!/usr/bin/env python
# -*- coding: utf-8 -*-
import numpy as np
from scipy import optimize
from pylab import *

def hc(ptheta, f):
    '''
    Комплексная передаточная функция цепочки
      +----+
    --+ R1 +---+----+----
      +----+   |    |
               |   +++
            C ---  | | R2
              ---  +++
               |    |
              ---  ---
               
    :param ptheta: вектор параметров r2/1e6, c/1e-12
    :param f: вектор частот
    '''
    r1 = 1e6
    r2 = ptheta[0] * 1e6
    c = ptheta[1] * 1e-12
    jom = 1j * 2 * np.pi * f
    zc = 1 / jom / c
    zpar = 1 / (1 / zc + 1 / r2)
    zser = r1
    hc = zpar / (zpar + zser)
    return hc
    
def fit_crit(theta, f, hc4, hc5):
    '''
    Функция для минимизации
    :param theta: вектор параметров r21, r22, c1, c2
    :param f: вектор частот
    :param hc_: измеренная компл. перед. фун.
    '''
    (r21, r22, c1, c2) = theta
    hct4 = hc((r21, c1), f)
    hct5 = hc((r22, c2), f)
    diff1 = np.abs(hct4 - hc4)
    diff2 = np.abs(hct5 - hc5)
    ans = 1 * np.sum(diff1) + 1 * np.sum(diff2)
    return ans

def load_fr_resp(fn):
    '''
    Загрузка перед. фун.
    :param fn: имя файла
    '''
    data = np.loadtxt(fn)
    freq = data[:, 0]
    magn = np.power(10, data[:, 1] / 20)
    phase = data[:, 2] / 180 * np.pi
    resp = magn * (np.cos(phase) + 1j * np.sin(phase))
    return (freq, resp)

def main():
    f, hc4 = load_fr_resp('FREQ_1M_Z.CSV')
    unused, hc5 = load_fr_resp('FREQ_1M_Z_div10.CSV')

    unused, hcprobe10 = load_fr_resp('FREQ_PROBE10.CSV')
    unused, hcprobe1 = load_fr_resp('FREQ_PROBE1.CSV')

    probe_correction = False
    
    if probe_correction:
        hc5r = hc5 / hcprobe10
        hc4r = hc4 / hcprobe1
    else:
        hc5r = hc5 * 10
        hc4r = hc4
    
    theta0 = [1, 10, 100, 10]

    theta = optimize.fmin_powell(fit_crit, theta0,
        args=(f, hc4r, hc5r),
    )

    (r21, r22, c1, c2) = theta
    if probe_correction:
        hct4 = hc((r21, c1), f) * hcprobe1
        hct5 = hc((r22, c2), f) * hcprobe10
    else:
        hct4 = hc((r21, c1), f)
        hct5 = hc((r22, c2), f) / 10
    
    print theta
    subplot(221)
    loglog(f, np.abs(hct4), f, np.abs(hc4), 'x')
    ylabel('Magnitude')
    subplot(222)
    loglog(f, np.abs(hct5), f, np.abs(hc5), 'x')
    subplot(223)
    semilogx(f, np.angle(hct4, deg=True), f, np.angle(hc4, deg=True), 'x')
    xlabel('f, Hz')
    ylabel('Phase, deg')
    subplot(224)
    semilogx(f, np.angle(hct5, deg=True), f, np.angle(hc5, deg=True), 'x')
    xlabel('f, Hz')
    show()
    
if __name__ == '__main__':
    main()

Я думаю, всё в ней довольно очевидно для знающих python, numpy и scipy. Одновременно для двух АФЧХ минимизируется сумма модулей комплексных отклонений измеренной передаточной характеристики от рассчитанной.
probe_correction = True — учитывать собственную АФЧХ
probe_correction = False — не учитывать

Вот результаты
probe_correction = False

Целевая функция = 1.6, для 1:1 R2=0.98МОм C=140пФ, для 1:10 R2=7.1МОм C=21пФ.

probe_correction = True

Целевая функция = 0.41, для 1:1 R2=0.93МОм C=137пФ, для 1:10 R2=10МОм C=18пФ.

Ну и главное, ради чего всё затевалось — определение индуктивности, сопротивления и емкости ВВ обмотки ТВС90-ПЦ8. Снимал АФЧХ 3 раза, с двумя разными резисторами, 10k и 100k (с 10k вообще-то лишнее), через которые подавался сигнал и с двумя коэффициентами деления щупа (а это нужно, чтобы определить емкость).
  • 100k 1:10 FREQ_tvs100k_div10.CSV
  • 100k 1:1 FREQ_tvs100k.CSV
  • 10k 1:1 FREQ_tvs10k.CSV

Схема подключения

      +----+
    --+ R1 +-------+----
      +----+       |
                   |
                  C
                  C   L
                  C
                   |
                  ---

А эквивалентная схема в комментариях ко второй программе. А программа в прикрепленном файле. Тоже два варианта — с делением на собственную АФЧХ и без.
Емкость щупа учитывается, а с его сопротивлением поленился.

Результаты
probe_correction = False

Целевая функция = 4.8, L=0.83Гн, Rl=390Ом, С=19пФ.

probe_correction = True

Целевая функция = 2.6, L=0.84Гн, Rl=360Ом, С=13пФ.

Проверка правдоподобия, на всякий случай. По омметру сопротивление обмотки 375Ом. Расчетная резонансная частота в первом случае 40кГц, во втором 48кГц, а третья гармоника строчной частоты, на которую обычно настроена обмотка — 47кГц.

Вот такие дела. Я удивлен, насколько всё хорошо и просто получается. Надо бы переписать это на С и всунуть в сам осциллограф, с автоматическим перебором нескольких схем, было бы мило.

Ну не совсем всё хорошо, на последних двух картинках виден глюк приложения — перевернута верхняя часть АЧХ (верхний правый график).
  • +3
  • 01 сентября 2012, 22:12
  • alpo
  • 1
Файлы в топике: rclfit2.py.txt

Комментарии (5)

RSS свернуть / развернуть
ЯННП
+2
Он пишет про режим АФЧХ-анализатора в DSO Quad и его использование совместно с Python+Numpy для экспериментального определения частотных характеристик (АЧХ и ФЧХ) цепей и определения по ним значений параметров элементов эквивалентных схем этих цепей.
Довольно ценная и интересная тема.
Ну и для меня — достаточно понятная. Но требует достаточно подготовленного читателя.
0
  • avatar
  • Vga
  • 02 сентября 2012, 15:50
Круто! Не помешало бы немного теории, а то в сухомятку не идет! В каких пределах можно измерить С и L? Оч. интересно!
0
Хм. Теория. Если речь о теории цепей и сигналов, некоторые ее по несколько лет учат. Можно и сверхзвуковое изложение попробовать — первые 3 главы Кауфмана и Сидмана.
Про подгонку кривых en.wikipedia.org/wiki/Curve_fitting и en.wikipedia.org/wiki/Mathematical_optimization
Пределы по емкости определяются пределами по реактивному сопротивлению. Наибольшая емкость — наименьшее измеряемое сопротивление на наименьшей рабочей частоте. Наименьшее измеряемое сопротивление определяется нагрузочной способностью генератора сигналов осциллографа и чувствительностью входа. Я пробовал нагружать до 500 Ом без искажений, построитель АФЧХ нормально работает от амплитуд выше -50дБ, минимальная рабочая частота 10 Гц, возьмем запас в 1 декаду, будет 100 Гц. В итоге коэффициент ослабления RC-цепочки R*omega*C <= 50дБ или 500*2*pi*100*C<=10^(50/20) или C<=0.1Ф=100000мкФ.
Наименьшая емкость — наибольшее сопротивление на наибольшей рабочей частоте. Договоримся не использовать > 1МОм, наибольшая рабочая частота 200кГц, с десятикратным запасом — 20кГц. R*omega*C <= 1 или 1e6*2*pi*20e3*C <= 1 или С>=8e-12Ф=8пФ.
Наименьшая индуктивность — наименьшее сопротивление на наибольшей частоте. Коэффициент ослабление RL-цепочки R/(omega*L) <=50дБ или L>=500/(2*pi*20e3*10^(50/20))=1.3e-5Гн=13мкГн
Наибольшая индуктивность R/(omega*L)<=1 или L<=1e6/(2*pi*100)=1600Гн — невменяемая величина, наверняка тут другие факторы вмемаются и ограничат.
Итог, по первой прикидке 10пФ<С<100000мкФ, 10мкГн<L<1000Гн
0
А этим результатам можно верить? Вроде бы по спецификации DSO Quad выдает синус только до 20 кГц, получается, что испытательный сигнал здесь не синус а прямоугольник?
0
  • avatar
  • and
  • 15 августа 2013, 19:11
Только зарегистрированные и авторизованные пользователи могут оставлять комментарии.