FEMM 5

Электростатика · Плоскопараллельная

Провод над землёй: метод изображений и внешняя граница

Вычислите погонную ёмкость провода над идеально проводящей землёй. Сравните конечную FEMM-область с точным решением методом изображений и оцените влияние её верхней границы.

Самостоятельная учебная модель FEMM 5: от физических соотношений к полевому решению и проверке результата.

Допущения и устройство учебной модели

Принятые допущения и их назначение
Учебная модель FEMM 5Причина
Верхняя полуокружность и нижний отрезок образуют замкнутую расчётную областьМоделируется воздух только над землёй.
Две локальные воздушные подобластиУточняется сильный градиент около провода.

Все размеры, свойства материалов и условия возбуждения заданы ниже. Численные результаты относятся к опубликованной версии модели FEMM 5.

Физическая и математическая постановка

Земля и зеркальный провод

Заземлённая плоскость заменяется зеркальным проводом противоположного заряда на таком же расстоянии под землёй. Разность потенциалов между реальным и зеркальным проводами вдвое больше напряжения реального провода относительно земли. Отсюда следует формула ёмкости к земле.

C=\frac{2\pi\varepsilon_0 l}{\operatorname{arcosh}(h/a)}=\frac{2\pi\varepsilon_0 l}{\ln(h/a+\sqrt{(h/a)^2-1})}

Две причины погрешности

Нижняя граница точно задаёт землю. Верхняя полуокружность также имеет V=0 и заменяет удалённую область. Три сетки при R=160 мм контролируют дискретизацию; дополнительный расчёт при R=320 мм показывает влияние внешней границы.

Воздух около провода сгущён независимо от дальней области. В отчёте отдельно приведены аналитическая ошибка и изменение ответа при увеличении области; совпадение энергии с зарядом является проверкой одного поля, а не доказательством отсутствия погрешности границы.

Исходные данные

Плоскопараллельная

Величины, единицы и происхождение параметров
ПараметрЗначениеЕдиницаПроисхождение
Радиус провода a2ммУсловие учебной задачи
Высота оси над землёй h20ммУсловие учебной задачи
Длина участка1мУсловие учебной задачи
Напряжение1ВУсловие учебной задачи
Радиусы дальней границы160; 320ммУсловие учебной задачи

Порядок воспроизведения

  1. Изучите размеры, материалы, возбуждение и выбранную двумерную постановку. Сначала вычислите аналитический ориентир в единицах СИ.
  2. Скачайте файлы по отдельным ссылкам в отдельную рабочую папку. Откройте reproduce.py во встроенном редакторе Python FEMM 5 и выполните сохранённый файл.
  3. Программа строит русифицированные модели, сохраняет их, закрывает и открывает заново. Затем выполняет расчёт и читает свойства проводников по точному русскому имени.
  4. Сравните три уровня пространственной сетки. В таблицах сохранены число узлов и элементов, интегральные величины и независимые критерии. Дополнительные режимы указаны в постановке.
  5. Откройте самый подробный сохранённый вход и соответствующее решение. Проверьте смысл единиц, знаков и объёмного множителя; новый запуск сохранит результаты в новой папке calculated-NN.

Скачайте нужные файлы по отдельным ссылкам ниже в одну рабочую папку, затем откройте reproduce.py во встроенном Python FEMM 5 и выполните его. Сохраните имена файлов и структуру подпапок. Условия конкретного запуска и путь новых результатов указаны в комментариях программы.

Программа встроенного Python FEMM 5
Python · reproduce.py
"""Ёмкость провода над заземлённой плоскостью.
Среда: встроенный MicroPython FEMM 5; команды FEMM доступны глобально.
Геометрические размеры: миллиметры; поля и интегралы возвращаются в СИ.
Все материалы и проводники имеют русские имена. Каждая модель сохраняется,
закрывается и повторно открывается до нового расчёта, включая кириллицу.
Запуск создаёт новую папку calculated-NN рядом с программой; опубликованные
модели и предыдущие расчёты не перезаписываются. Все необходимые
исходные данные включены. Условия задачи и ограничения описаны в README.md.
"""
import os
import sys
import math
import json

saved = globals().get('__file__', '') or (sys.argv[0] if sys.argv else '')
base = os.path.dirname(os.path.abspath(saved)) if saved else os.getcwd()
index = 1
while os.path.exists(base + '/calculated-%02d' % index):
    index += 1
directory = base + '/calculated-%02d' % index
os.mkdir(directory)
records = []
checks = []
EPS0 = 8.85418781762e-12


def real(value):
    if isinstance(value, (list, tuple)):
        return real(value[0])
    return complex(value).real


def check(name, value, limit):
    checks.append({'name': name, 'value': value, 'limit': limit,
                   'passed': math.isfinite(value) and value <= limit})


def label(x, y, material, mesh, group=1):
    ei_addblocklabel(x, y)
    ei_selectlabel(x, y)
    ei_setblockprop(material, 0, mesh, group)
    ei_clearselected()


def circle(x, radius, conductor, angle):
    ei_addnode(x - radius, 0)
    ei_addnode(x + radius, 0)
    ei_addarc(x - radius, 0, x + radius, 0, 180, angle)
    ei_addarc(x + radius, 0, x - radius, 0, 180, angle)
    ei_selectarcsegment(x, radius)
    ei_selectarcsegment(x, -radius)
    ei_setarcsegmentprop(angle, '<None>', 0, 0, conductor)
    ei_clearselected()


def solve(model):
    ei_saveas(model)
    ei_close()
    opendocument(model)
    ei_analyze(1)
    ei_loadsolution()
    eo_smooth('off')


def electric_result(mesh, model, input_name, output_name, exact_C):
    voltage_in, charge_in = eo_getconductorproperties(input_name)
    voltage_out, charge_out = eo_getconductorproperties(output_name)
    voltage = real(voltage_in) - real(voltage_out)
    charge = real(charge_in)
    eo_groupselectblock(1)
    energy = real(eo_blockintegral(0))
    eo_clearblock()
    capacitance = charge / voltage
    energy_C = 2 * energy / voltage ** 2
    row = {'mesh_mm': mesh, 'model': os.path.basename(model),
           'nodes': eo_numnodes(), 'elements': eo_numelements(),
           'voltage_V': voltage, 'charge_C': charge, 'energy_J': energy,
           'capacitance_F': capacitance, 'energy_capacitance_F': energy_C,
           'analytic_capacitance_F': exact_C,
           'analytic_C_relative_error': abs(capacitance / exact_C - 1),
           'energy_charge_relative_error': abs(energy_C / capacitance - 1)}
    records.append(row)
    check('Энергия и заряд: ' + os.path.basename(model),
          row['energy_charge_relative_error'], 1e-5)
    return row


def circle_xy(cx, cy, radius, conductor, angle):
    ei_addnode(cx - radius, cy)
    ei_addnode(cx + radius, cy)
    ei_addarc(cx - radius, cy, cx + radius, cy, 180, angle)
    ei_addarc(cx + radius, cy, cx - radius, cy, 180, angle)
    ei_selectarcsegment(cx, cy + radius)
    ei_selectarcsegment(cx, cy - radius)
    ei_setarcsegmentprop(angle, '<None>', 0, 0, conductor)
    ei_clearselected()


def polygon(points, conductor='<None>', mesh=0):
    for x, y in points:
        ei_addnode(x, y)
    for k, (x, y) in enumerate(points):
        x2, y2 = points[(k + 1) % len(points)]
        ei_addsegment(x, y, x2, y2)
        if conductor != '<None>':
            ei_selectsegment((x + x2) / 2, (y + y2) / 2)
            ei_setsegmentprop('<None>', mesh, 0, 0, 0, conductor)
            ei_clearselected()


def terminal(x, y, name, mesh):
    ei_selectsegment(x, y)
    ei_setsegmentprop('<None>', mesh, 0, 0, 0, name)
    ei_clearselected()


def summary(mesh, model, source, ground, exact_C=None):
    v1, q1 = eo_getconductorproperties(source)
    v0, q0 = eo_getconductorproperties(ground)
    v1, v0, q1, q0 = real(v1), real(v0), real(q1), real(q0)
    voltage = v1 - v0
    eo_groupselectblock(1)
    energy = real(eo_blockintegral(0))
    eo_clearblock()
    capacitance = q1 / voltage
    row = {'mesh_mm': mesh, 'model': os.path.basename(model),
           'nodes': eo_numnodes(), 'elements': eo_numelements(),
           'voltage_V': voltage, 'charge_C': q1, 'energy_J': energy,
           'capacitance_F': capacitance,
           'energy_capacitance_F': 2 * energy / voltage ** 2}
    if exact_C is not None:
        row['analytic_capacitance_F'] = exact_C
        row['analytic_C_relative_error'] = abs(capacitance / exact_C - 1)
    records.append(row)
    check('Энергия и терминальный заряд: ' + os.path.basename(model),
          abs(2 * energy / voltage ** 2 / capacitance - 1), 1e-5)
    return row


def field(x, y):
    values = eo_getpointvalues(x, y)
    return math.sqrt(real(values[3]) ** 2 + real(values[4]) ** 2)


def rectangle_field(mesh, filename, epsx=2, epsy=2, voltage=100, width=10, height=10, depth=100):
    newdocument(1)
    ei_probdef('millimeters', 'planar', 1e-10, depth, 30)
    ei_addmaterial('Диэлектрик учебного образца', epsx, epsy, 0)
    ei_addconductorprop('Питающий электрод', voltage, 0, 1)
    ei_addconductorprop('Заземлённый электрод', 0, 0, 1)
    polygon(((0, 0), (width, 0), (width, height), (0, height)))
    terminal(0, height / 2, 'Питающий электрод', mesh)
    terminal(width, height / 2, 'Заземлённый электрод', mesh)
    label(width / 2, height / 2, 'Диэлектрик учебного образца', mesh)
    model = directory + '/' + filename + '.fee'
    solve(model)
    return model


h, a = 20, 2
exact = 2 * math.pi * EPS0 / math.log(h / a + math.sqrt((h / a) ** 2 - 1))
for level, settings in enumerate(((160, 6, 4), (160, 3, 2), (160, 1.5, 1), (320, 3, 1))):
    radius, mesh, angle = settings
    newdocument(1)
    ei_probdef('millimeters', 'planar', 1e-10, 1000, 30)
    ei_addmaterial('Воздух над землёй', 1, 1, 0)
    ei_addconductorprop('Провод линии', 1, 0, 1)
    ei_addconductorprop('Земля и удалённая граница', 0, 0, 1)
    ei_addnode(-radius, 0)
    ei_addnode(radius, 0)
    ei_addarc(radius, 0, -radius, 0, 180, 4)
    ei_selectarcsegment(0, radius)
    ei_setarcsegmentprop(4, '<None>', 0, 0, 'Земля и удалённая граница')
    ei_clearselected()
    ei_addsegment(-radius, 0, radius, 0)
    terminal(0, 0, 'Земля и удалённая граница', mesh)
    circle_xy(0, h, a, 'Провод линии', angle)
    circle_xy(0, h, 6, '<None>', angle)
    circle_xy(0, h, 12, '<None>', angle)
    label(0, h, '<No Mesh>', mesh, 0)
    label(0, h + 4, 'Воздух над землёй', 0.4 / (2 ** min(level, 2)))
    label(0, h + 9, 'Воздух над землёй', 0.8 / (2 ** min(level, 2)))
    label(0, h + 30, 'Воздух над землёй', mesh)
    model = directory + '/overhead-%02d.fee' % (level + 1)
    solve(model)
    row = summary(mesh, model, 'Провод линии', 'Земля и удалённая граница', exact)
    row['outer_radius_mm'] = radius
    eo_close()
    ei_close()
check('Провод над бесконечной землёй: аналитическая ёмкость', records[-1]['analytic_C_relative_error'], 0.01)
check('Сеточный контроль при R=160 мм', abs(records[2]['capacitance_F'] / records[1]['capacitance_F'] - 1), 0.005)
check('Удаление верхней границы 160→320 мм', abs(records[3]['capacitance_F'] / records[2]['capacitance_F'] - 1), 0.01)

columns = {
    'mesh_mm': 'Размер сетки, мм', 'model': 'Файл модели',
    'nodes': 'Узлов', 'elements': 'Элементов',
    'voltage_V': 'Разность потенциалов, В', 'charge_C': 'Заряд, Кл',
    'energy_J': 'Энергия, Дж', 'capacitance_F': 'Ёмкость по заряду, Ф',
    'energy_capacitance_F': 'Ёмкость по энергии, Ф',
    'analytic_capacitance_F': 'Аналитическая ёмкость, Ф',
    'analytic_C_relative_error': 'Относительная ошибка ёмкости',
    'energy_charge_relative_error': 'Невязка энергии и заряда',
    'E_7p5mm_V_m': 'Поле при r=7,5 мм, В/м',
    'analytic_E_7p5mm_V_m': 'Аналитическое поле при r=7,5 мм, В/м',
    'E_150mm_V_m': 'Поле при r=150 мм, В/м',
    'analytic_E_150mm_V_m': 'Аналитическое поле при r=150 мм, В/м',
    'outer_radius_mm': 'Радиус внешней границы, мм',
    'insulation': 'Изоляция', 'analytic_Emax_kV_mm': 'Аналитический максимум поля, кВ/мм',
    'Emax_from_charge_kV_mm': 'Максимум поля по заряду, кВ/мм',
    'E_10mm_kV_mm': 'Поле при r=10 мм, кВ/мм',
    'E_25mm_kV_mm': 'Поле при r=25 мм, кВ/мм',
    'conductivity_S_m': 'Эквивалентная проводимость, См/м',
    'I_real_A': 'Активная компонента амплитуды тока, А',
    'I_imag_A': 'Квадратурная компонента амплитуды тока, А',
    'analytic_I_real_A': 'Аналитическая активная компонента, А',
    'analytic_I_imag_A': 'Аналитическая квадратурная компонента, А',
    'losses_W': 'Диэлектрические потери, Вт',
    'analytic_losses_W': 'Аналитические потери, Вт',
    'terminal_power_W': 'Средняя мощность электрода, Вт',
    'apparent_power_VA': 'Полная мощность, ВА',
    'U_RMS_V': 'Действующее напряжение, В', 'U_amplitude_V': 'Амплитуда напряжения, В'
}
columns.update({'orientation': 'Ориентация главных осей', 'E_center_V_m': 'Поле в центре, В/м', 'E_first_V_m': 'Поле первого слоя, В/м', 'E_second_V_m': 'Поле второго слоя, В/м', 'interface_V': 'Потенциал интерфейса, В', 'floating_voltage_V': 'Потенциал изолированного электрода, В', 'floating_charge_C': 'Заряд изолированного электрода, Кл', 'overlap_mm': 'Перекрытие электродов, мм', 'rounding_radius_mm': 'Радиус скругления, мм', 'E_corner_sample_V_m': 'Поле в 0,2 мм от скругления, В/м', 'screen': 'Исполнение', 'E_inner_sample_V_m': 'Поле в контрольной точке, В/м', 'excited_phase': 'Возбуждённая фаза', 'C_Aj_F': 'Коэффициент строки A, Ф', 'C_Bj_F': 'Коэффициент строки B, Ф', 'C_Cj_F': 'Коэффициент строки C, Ф'})
result = {'runtime': 'FEMM 5.0; встроенный MicroPython', 'records': records,
          'checks': checks, 'columns': columns,
          'passed': all(item['passed'] for item in checks)}
with open(directory + '/result.json', 'w') as output:
    json.dump(result, output)
print(json.dumps(result))
assert result['passed'], 'Не выполнен численный критерий'

Картина рассчитанного поля

Потенциал, В: overhead-04.res
Визуализация сохранённого решения FEMM 5 overhead-04.res. Электрический потенциал по сохранённым узловым значениям. Показан увеличенный фрагмент расчётной области. Контуры деталей взяты из той же модели. Области вне сохранённых треугольников не заполняются. Это научный график сохранённых данных. Нажмите на карту, чтобы открыть её отдельно и увеличить.

Окна FEMM 5

Снимки интерфейса FEMM показывают геометрию, настройки и работу с результатами в FEMM 5. Откройте изображение, чтобы рассмотреть подписи и значения в полном размере.

Рабочая область провода над заземлённой плоскостью. Вспомогательные окружности задают локальные области сетки; удалённая внешняя граница за кадром.
Рабочая область провода над заземлённой плоскостью. Вспомогательные окружности задают локальные области сетки; удалённая внешняя граница за кадром. Открыть в полном размере
Сохранённое решение «Провод над землёй: метод изображений и внешняя граница». Потенциал V, В, и эквипотенциали провода над заземлённой плоскостью; увеличенная рабочая область.
Сохранённое решение «Провод над землёй: метод изображений и внешняя граница». Потенциал V, В, и эквипотенциали провода над заземлённой плоскостью; увеличенная рабочая область. Открыть в полном размере

Результаты и численные проверки

Сохранено решений FEMM: 4. Выполнено проверок: 7. Полная точность чисел и условия сравнения доступны в таблицах результатов JSON.

Результаты расчётов и производные итоги
Радиус внешней границы, ммРазмер сетки, ммРазность потенциалов, ВЗаряд, КлЭлементовАналитическая ёмкость, ФФайл моделиЁмкость по энергии, ФЁмкость по заряду, ФОтносительная ошибка ёмкостиЭнергия, ДжУзлов
1606118,840614 × 10⁻¹²927718,586155 × 10⁻¹²overhead-01.fee18,840614 × 10⁻¹²18,840614 × 10⁻¹²0,0136908259,4203072 × 10⁻¹²4788
1603118,809861 × 10⁻¹²2242118,586155 × 10⁻¹²overhead-02.fee18,809861 × 10⁻¹²18,809861 × 10⁻¹²0,0120361619,4049303 × 10⁻¹²11459
1601,5118,790112 × 10⁻¹²8776818,586155 × 10⁻¹²overhead-03.fee18,790112 × 10⁻¹²18,790112 × 10⁻¹²0,010973619,395056 × 10⁻¹²44384
3203118,65877 × 10⁻¹²8841518,586155 × 10⁻¹²overhead-04.fee18,65877 × 10⁻¹²18,65877 × 10⁻¹²0,00390698149,3293852 × 10⁻¹²44709
Проверки опубликованного расчёта
КритерийПолученоДопуск или ожидаемое значениеИтог
Энергия и терминальный заряд: overhead-01.fee84,67 × 10⁻¹²1e-05Выполнен
Энергия и терминальный заряд: overhead-02.fee866,3 × 10⁻¹²1e-05Выполнен
Энергия и терминальный заряд: overhead-03.fee637,1 × 10⁻¹²1e-05Выполнен
Энергия и терминальный заряд: overhead-04.fee767,6 × 10⁻¹²1e-05Выполнен
Провод над бесконечной землёй: аналитическая ёмкость0,0039070,01Выполнен
Сеточный контроль при R=160 мм0,001050,005Выполнен
Удаление верхней границы 160→320 мм0,006990,01Выполнен

Допуски относятся к указанной учебной задаче и способу сравнения. Число показанных цифр не означает такой же физической точности.

Модели, решения и программа

Для нового расчёта сохраните программу, модели и необходимые данные в одну рабочую папку, сохраняя структуру подпапок.

Полные численные результаты

Границы применимости