Магнитное поле и электромеханика · Плоскопараллельная
Трансформатор тока с нагрузкой: связь поля и комплексного уравнения цепи
Трансформатор тока должен отдавать измерительный ток в нагрузку вторичной цепи. Нельзя одновременно независимо задавать оба тока и считать, что нагрузка уже учтена.
Самостоятельная учебная модель FEMM 5: от физических соотношений к полевому решению и проверке результата.
Допущения и устройство учебной модели
| Учебная модель FEMM 5 | Причина |
|---|---|
| Параметры и диапазон исследования выбраны для последовательного изучения в нашем курсе. | Учебная постановка FEMM 5 |
| Геометрия, источники, русские свойства, управление серией и проверки объединены в самостоятельную программу встроенного Python. | Учебная постановка FEMM 5 |
| Сеточная чувствительность и физические контроли показаны отдельно от основной параметрической характеристики. | Учебная постановка FEMM 5 |
Все размеры, свойства материалов и условия возбуждения заданы ниже. Численные результаты относятся к опубликованной версии модели FEMM 5.
Физическая и математическая постановка
Принцип действия и расчётные соотношения
Сначала двумя постоянными токовыми опытами определяются L11, L22 и взаимная индуктивность. Для выбранного сопротивления вторичный ток вычисляется из комплексного уравнения цепи при частоте 50 Гц. Затем именно этот ток задаётся в новом гармоническом полевом расчёте, а возвращённое напряжение проверяется по вторичной невязке. Активная мощность первичного источника должна совпасть с мощностью вторичной резистивной цепи. Поле и внешний резистор проверяются совместно, причём амплитуды отделены от действующих значений.
Численная проверка и новая серия расчётов
Сначала выполняются три независимых расчёта одной постановки с масштабами размеров элементов 1; 0,7; 0,5 относительно учебного входа. Фактический размер в узких местах задаётся программой отдельно и может быть меньше этого масштаба. Сравниваются наблюдаемая величина и число элементов, а не только вид поля. После этого на мелкой сетке выполняется параметрическая серия и независимые физические контроли. Каждый файл модели перед расчётом закрывается и открывается повторно; этим проверяется сохранение русских свойств в точной решаемой копии.
Для нового опыта скачайте файлы со страницы работы в отдельный каталог и откройте reproduce.py в редакторе встроенного Python FEMM 5. Программа использует непосредственные команды mi/ mo и не требует внешнего управления Python. Она создаёт новую папку calculated-NN рядом с программой. Прежние решения не используются для получения новых чисел. Результат и все входы сохраняются вместе, поэтому найденное число всегда можно связать с параметрами, сеткой и точным файлом.
Исходные данные
Плоскопараллельная
| Параметр | Значение | Единица | Происхождение |
|---|---|---|---|
| Геометрия и источники | Отдельная русская учебная копия геометрии нашего курса. Все координаты, витки, материалы и глубина заданы в input.fem; рабочие токи и угловая серия задаются программой. Сталь линейная, μr=1000. | СИ и мм | Выбранные учебные параметры |
| Рабочая координата | Сопротивление вторичной цепи, Ом | см. подписи результатов | Параметрическая серия |
Порядок воспроизведения
- Разберите физическую модель и соотношения до запуска программы. Найдите каждое число из таблицы в CONFIG и геометрических командах.
- Откройте reproduce.py во встроенном Python FEMM 5. Сохраните пользовательские документы и запустите программу.
- Сопоставьте три сетки одной постановки и независимые физические проверки. Не подменяйте сравнение сеток разными рабочими режимами.
- Изучите параметрическую серию: объясните знак, размерность и тенденцию каждой величины. Измените один параметр и повторите опыт в новой папке.
- Оцените, какие выводы требуют трёхмерного, теплового или динамического расчёта. Сохраните модель и результат новой серии вместе.
Скачайте нужные файлы по отдельным ссылкам ниже в одну рабочую папку, затем откройте reproduce.py во встроенном Python FEMM 5 и выполните его. Сохраните имена файлов и структуру подпапок. Условия конкретного запуска и путь новых результатов указаны в комментариях программы.
Программа встроенного Python FEMM 5
"""Самостоятельное полевое исследование во встроенном Python FEMM 5.
Все размеры геометрии указаны в миллиметрах, результаты — в СИ. Значения
гармонических токов являются амплитудами. Материалы и условия имеют русские
имена; номера групп описаны в README. Программа создаёт новую calculated-NN
рядом с собой, не заменяя предшествующих расчётов. Каждая входная модель
сохраняется, закрывается, открывается повторно и только затем решается.
Открытые пользовательские документы не изменяются. Параметры — в CONFIG.
"""
import os
import sys
import json
import math
MU0 = 4e-7 * math.pi
script = globals().get("__file__", "") or (sys.argv[0] if sys.argv else "")
HERE = os.path.dirname(os.path.abspath(script)) if script else os.getcwd()
number = 1
while True:
OUT = HERE + "/calculated-%02d" % number
try:
os.stat(OUT)
number += 1
except OSError:
os.mkdir(OUT)
break
def scalar(value):
if isinstance(value, (list, tuple)):
return scalar(value[0])
return complex(value).real
def complex_parts(value):
value = complex(value)
return [value.real, value.imag]
def point(radius, angle):
angle = angle * math.pi / 180
return (radius * math.cos(angle), radius * math.sin(angle))
def line(a, b, group=0, size=0):
mi_addnode(a[0], a[1])
mi_addnode(b[0], b[1])
mi_addsegment(a[0], a[1], b[0], b[1])
mi_selectsegment((a[0] + b[0]) / 2, (a[1] + b[1]) / 2)
boundary = (
"Внешняя граница A=0"
if globals().get("AXIS", False) and abs(a[0]) + abs(b[0]) < 1e-9
else "<None>"
)
mi_setsegmentprop(boundary, size, 0 if size else 1, 0, group)
mi_clearselected()
def polygon(points, group=0, size=0):
for index in range(len(points)):
line(points[index], points[(index + 1) % len(points)], group, size)
def rectangle(x1, y1, x2, y2, group=0, size=0):
polygon([(x1, y1), (x2, y1), (x2, y2), (x1, y2)], group, size)
def arc(radius, start, end, group=0, step=2):
a, b = point(radius, start), point(radius, end)
mi_addnode(a[0], a[1])
mi_addnode(b[0], b[1])
mi_addarc(a[0], a[1], b[0], b[1], end - start, step)
middle = point(radius, (start + end) / 2)
mi_selectarcsegment(middle[0], middle[1])
mi_setarcsegmentprop(step, "<None>", 0, group)
mi_clearselected()
def circle(radius, group=0, step=2):
for start in (0, 90, 180, 270):
arc(radius, start, start + 90, group, step)
def label(x, y, material, mesh, group=0, circuit="<None>", turns=1, angle=0):
mi_addblocklabel(x, y)
mi_selectlabel(x, y)
mi_setblockprop(material, 0, mesh, circuit, angle, group, turns)
mi_clearselected()
def begin(mesh, kind="planar", frequency=0, depth=40, radius=100, br=1.1, mur=1.05):
global AXIS
AXIS = kind == "axi"
newdocument(0)
mi_probdef(frequency, "millimeters", kind, 1e-9, depth, 25)
mi_addmaterial("Воздух", 1, 1, 0, 0, 0)
mi_addmaterial("Обмотка без вытеснения тока", 1, 1, 0, 0, 0)
mi_addmaterial("Медь 58 МСм на метр", 1, 1, 0, 0, 58)
mi_addmaterial("Сталь с линейной проницаемостью", 1000, 1000, 0, 0, 0)
mi_addmaterial("Сталь с учебной кривой насыщения", 1, 1, 0, 0, 0)
for b, h in (
(0, 0),
(0.3, 100),
(0.6, 200),
(1, 350),
(1.3, 700),
(1.5, 1800),
(1.65, 5000),
(1.8, 15000),
(2, 60000),
(2.2, 200000),
):
mi_addbhpoint("Сталь с учебной кривой насыщения", b, h)
mi_addmaterial("Постоянный магнит учебный NdFeB", mur, mur, br / (MU0 * mur), 0, 0)
mi_addboundprop("Внешняя граница A=0", 0, 0, 0, 0, 0, 0, 0, 0, 0)
if kind == "axi":
rectangle(0, -radius, radius, radius)
for x, y in ((0, 0), (radius, 0), (radius / 2, -radius), (radius / 2, radius)):
mi_selectsegment(x, y)
mi_setsegmentprop("Внешняя граница A=0", 0, 1, 0, 0)
mi_clearselected()
else:
circle(radius, step=4)
for angle in (45, 135, 225, 315):
x, y = point(radius, angle)
mi_selectarcsegment(x, y)
mi_setarcsegmentprop(4, "Внешняя граница A=0", 0, 0)
mi_clearselected()
def band(r1, r2, count, fraction, group, mesh, phase=0, mode="radial"):
"""Кольцевая сборка: заданные магнитные секторы и воздушные промежутки."""
pitch = 360 / count
for index in range(count):
start = index * pitch + phase
stop = start + pitch * fraction
for radius in (r1, r2):
arc(radius, start, stop, group, step=2)
if fraction < 0.999999:
arc(radius, stop, start + pitch, group, step=2)
line(point(r1, start), point(r2, start), group)
line(point(r1, stop), point(r2, stop), group)
angle = (start + stop) / 2
x, y = point((r1 + r2) / 2, angle)
if mode == "steel":
label(x, y, "Сталь с линейной проницаемостью", mesh, group)
else:
direction = 2 * angle if mode == "halbach" else angle + 180 * (index % 2)
label(x, y, "Постоянный магнит учебный NdFeB", mesh, group, angle=direction)
if fraction < 0.999999:
x, y = point((r1 + r2) / 2, (stop + start + pitch) / 2)
label(x, y, "Воздух", mesh, group)
def energy():
mo_clearblock()
mo_groupselectblock()
values = [scalar(mo_blockintegral(k)) for k in (2, 17, 4)]
mo_clearblock()
return values
def solve(tag, group=2, probe=(1, 0), circuits=()):
path = OUT + "/" + tag + ".fem"
mi_saveas(path)
mi_close()
opendocument(path)
mi_analyze(1)
mi_loadsolution()
e, w, p = energy()
row = {
"state": tag,
"elements": mo_numelements(),
"energy_J": e,
"coenergy_J": w,
"loss_W": p,
}
if group:
mo_groupselectblock(group)
if CONFIG.get("kind") != "course":
row["Fx_N"] = scalar(mo_blockintegral(18))
row["Fy_N"] = scalar(mo_blockintegral(19))
row["torque_Nm"] = scalar(mo_blockintegral(22))
if CONFIG.get("kind") != "course":
row["lorentz_x_N"] = scalar(mo_blockintegral(11))
row["lorentz_y_N"] = scalar(mo_blockintegral(12))
mo_clearblock()
if CONFIG.get("kind") == "gear":
for part in (2, 3, 4):
mo_groupselectblock(part)
row["T%d_Nm" % part] = scalar(mo_blockintegral(22))
mo_clearblock()
values = mo_getpointvalues(probe[0], probe[1])
row["Bx_T"] = scalar(values[1])
row["By_T"] = scalar(values[2])
row["Hx_Am"] = scalar(values[5])
row["Hy_Am"] = scalar(values[6])
for circuit in circuits:
i, v, psi = mo_getcircuitproperties(circuit)
row[circuit + "_I_A"] = scalar(i)
row[circuit + "_Psi_Wb"] = scalar(psi)
row[circuit + "_Psi_im_Wb"] = complex(psi).imag
row[circuit + "_V_V"] = scalar(v)
row[circuit + "_V_im_V"] = complex(v).imag
mo_close()
mi_close()
return row
def check(name, value, limit, passed):
CHECKS.append(
{"name": name, "value": value, "limit": limit, "passed": bool(passed)}
)
def relative(a, b, minimum=1e-15):
return abs(a - b) / max(abs(a), abs(b), minimum)
def finish(plot=None):
result = {
"title": CONFIG["title"],
"records": ROWS,
"checks": CHECKS,
"units": "Геометрия мм; магнитное поле Тл, А/м; энергия Дж; сила Н; момент Н·м; потокосцепление Вб.",
"passed": bool(CHECKS) and all(row["passed"] for row in CHECKS),
}
if plot:
result["plot"] = plot
with open(OUT + "/result.json", "w") as stream:
json.dump(result, stream)
print(CONFIG["id"], result["passed"], len(ROWS), "решений", OUT)
assert result["passed"], "Не пройдена независимая проверка физической модели."
ROWS = []
CHECKS = []
CONFIG = {
"id": "current-transformer-burden",
"kind": "course",
"study": "ct-burden",
"title": "Трансформатор тока с нагрузкой: связь поля и комплексного уравнения цепи",
"source_model": "transformer",
"baseline": 0,
"angle": 0,
"metric": "energy_J",
"sweep": [],
"metric_label": "Энергия поля, Дж",
"parameter_name": "Сопротивление вторичной цепи, Ом",
"circuits": ["Первичная обмотка", "Вторичная обмотка"],
"group": 0,
"probe": [0, 40],
"intro": "Трансформатор тока должен отдавать измерительный ток в нагрузку вторичной цепи. Нельзя одновременно независимо задавать оба тока и считать, что нагрузка уже учтена.",
"theory": "Сначала двумя постоянными токовыми опытами определяются L11, L22 и взаимная индуктивность. Для выбранного сопротивления вторичный ток вычисляется из комплексного уравнения цепи при частоте 50 Гц. Затем именно этот ток задаётся в новом гармоническом полевом расчёте, а возвращённое напряжение проверяется по вторичной невязке. Активная мощность первичного источника должна совпасть с мощностью вторичной резистивной цепи. Поле и внешний резистор проверяются совместно, причём амплитуды отделены от действующих значений.",
"formula": "\\widehat I_2=-j\\omega M\\widehat I_1/(R+j\\omega L_{22}),\\qquad P=\\tfrac12 R|\\widehat I_2|^2",
"scope": "Двумерная учебная геометрия; точные входы и русские свойства включены в комплект. Торцевые поля, механическая динамика, температурная зависимость и реальные потери стали требуют отдельных моделей.",
"related_lessons": ["I06.4", "II03.1", "meas-applications"],
"dimensions": "Отдельная русская учебная копия геометрии нашего курса. Все координаты, витки, материалы и глубина заданы в input.fem; рабочие токи и угловая серия задаются программой. Сталь линейная, μr=1000.",
"plot_metric": "load_power_W",
"plot_label": "Мощность вторичной нагрузки, Вт",
"mesh_scales": [1, 0.7, 0.5],
"magnet_hc": 909456.8176679733,
"depth": 40.0,
}
with open(HERE + "/input.fem", "r") as stream:
BASE_TEXT = stream.read()
def prepare(scale=1, angle=0, currents=None, frequency=0, defect=False):
lines = BASE_TEXT.split("\n")
start = next(
i for i in range(len(lines)) if lines[i].startswith("[NumBlockLabels]")
)
count = int(lines[start].split("=")[1])
for i in range(start + 1, start + 1 + count):
fields = lines[i].split("\t")
fields[3] = str(float(fields[3]) * scale)
lines[i] = "\t".join(fields)
path = OUT + "/текущая-настройка.fem"
with open(path, "w") as stream:
stream.write("\n".join(lines) + "\n")
opendocument(path)
mi_probdef(frequency, "millimeters", "planar", 1e-9, CONFIG.get("depth", 80), 25)
for name, value in (currents or {}).items():
mi_modifycircprop(name, 1, value)
if defect:
mi_addmaterial(
"NdFeB с ослабленной намагниченностью",
1.05,
1.05,
CONFIG["magnet_hc"] * 0.6,
0,
0,
)
mi_selectlabel(52, 0)
mi_setblockprop(
"NdFeB с ослабленной намагниченностью",
0,
1.5 * scale,
"<None>",
"theta",
2,
1,
)
mi_clearselected()
if angle:
mi_selectgroup(2)
mi_moverotate(0, 0, angle)
mi_clearselected()
def phase_currents(angle=0, amplitude=1, delta=0):
return {
name: amplitude * math.cos((2 * angle + delta - offset) * math.pi / 180)
for name, offset in (("Фаза A", 0), ("Фаза B", 120), ("Фаза C", 240))
}
study = CONFIG["study"]
names = CONFIG["circuits"]
opendocument(HERE + "/input.fem")
ROWS.append(solve("input", CONFIG.get("group", 0), CONFIG.get("probe", [1, 0]), names))
mesh_rows = []
mesh_scales = CONFIG.get("mesh_scales", (0.8, 0.5, 0.3))
fine_scale = mesh_scales[-1]
for index, scale in enumerate(mesh_scales):
angle = CONFIG.get("angle", 0)
if study in ("pm-emf", "pm-defect"):
currents = {name: 0 for name in names}
elif study == "pm-skew":
currents = phase_currents(angle, 3, 60)
elif study == "dc-reaction":
currents = {names[0]: 1, names[1]: 2}
elif study == "ct-burden":
currents = {names[0]: 1, names[1]: 0}
elif study == "three-phase":
currents = {names[0]: 1, names[1]: 0, names[2]: 0}
elif study == "induction-slip":
currents = {
names[0]: 1,
names[1]: complex(-0.5, -math.sqrt(3) / 2),
names[2]: complex(-0.5, math.sqrt(3) / 2),
}
else:
currents = {
names[0]: 1,
names[1]: -0.5 if study == "synrm-angle" else 0,
names[2]: -0.5 if study == "synrm-angle" else 0,
}
prepare(
scale,
angle,
currents,
frequency=CONFIG.get("frequency", 0),
defect=study == "pm-defect",
)
row = solve(
"сетка-%d" % (index + 1),
CONFIG.get("group", 0),
CONFIG.get("probe", [1, 0]),
names,
)
row["mesh_scale"] = scale
row["parameter"] = (
2
if study == "dc-reaction"
else CONFIG.get("frequency", 0)
if study == "induction-slip"
else angle
)
ROWS.append(row)
mesh_rows.append(row)
fine = mesh_rows[-1]
metric = CONFIG["metric"]
err = relative(mesh_rows[-2][metric], fine[metric])
check("Стабилизация наблюдаемой величины при сгущении сетки", err, 0.025, err < 0.025)
check(
"Фактическое увеличение числа элементов",
fine["elements"] / mesh_rows[0]["elements"],
1.2,
fine["elements"] > 1.2 * mesh_rows[0]["elements"],
)
if study in ("pm-emf", "pm-skew", "pm-defect", "synrm-angle", "srm-map"):
for angle in CONFIG["sweep"]:
if study in ("pm-emf", "pm-defect"):
currents = {name: 0 for name in names}
elif study == "pm-skew":
currents = phase_currents(angle, 3, 60)
else:
currents = {
names[0]: 1,
names[1]: -0.5 if study == "synrm-angle" else 0,
names[2]: -0.5 if study == "synrm-angle" else 0,
}
prepare(fine_scale, angle, currents, defect=study == "pm-defect")
row = solve(
"угол-" + str(angle),
CONFIG.get("group", 0),
CONFIG.get("probe", [1, 0]),
names,
)
row["parameter"] = angle
row["mesh_scale"] = fine_scale
ROWS.append(row)
data = ROWS[4:]
if study in ("pm-emf", "pm-skew", "pm-defect"):
# Первый и последний узлы — одинаковое положение после периода.
key = names[0] + "_Psi_Wb" if study != "pm-skew" else "torque_Nm"
amplitude = max(abs(r[key]) for r in data)
err = abs(data[-1][key] - data[0][key]) / max(amplitude, 1e-12)
check("Замыкание углового периода", err, 0.025, err < 0.025)
if study in ("pm-emf", "pm-defect"):
omega = 1000 * 2 * math.pi / 60
step = (data[1]["parameter"] - data[0]["parameter"]) * math.pi / 180
values = [r[names[0] + "_Psi_Wb"] for r in data[:-1]]
def derivative_emf(values, step):
size = len(values)
return [
-omega
* (
-values[(i + 2) % size]
+ 8 * values[(i + 1) % size]
- 8 * values[(i - 1) % size]
+ values[(i - 2) % size]
)
/ (12 * step)
for i in range(size)
]
emf = derivative_emf(values, step)
coarse_emf = derivative_emf(values[::2], 2 * step)
order = int(round((CONFIG["sweep"][-1] - CONFIG["sweep"][0]) * 2 / 360))
def amplitude(samples):
size = len(samples)
coefficient = 0j
for i, value in enumerate(samples):
phase = 2 * math.pi * order * i / size
coefficient += value * complex(math.cos(phase), -math.sin(phase))
return 2 * abs(coefficient) / size
fine_amplitude = amplitude(emf)
coarse_amplitude = amplitude(coarse_emf)
angular_error = relative(fine_amplitude, coarse_amplitude)
check(
"Сходимость основной гармоники ЭДС по угловому шагу 15 и 7,5 град",
angular_error,
0.01,
angular_error < 0.01,
)
for i, value in enumerate(emf):
data[i]["emf_A_V"] = value
check(
"Ненулевая ЭДС при вращении",
max(abs(v) for v in emf),
0,
max(abs(v) for v in emf) > 0,
)
else:
values = []
averaged = []
for center in data:
angle = center["parameter"]
currents = phase_currents(angle, 3, 60)
torques = [center["torque_Nm"]]
for offset in (-5, 5):
# У всех сечений одного положения ОДИН И ТОТ ЖЕ ток статора.
prepare(fine_scale, angle + offset, currents)
row = solve(
"сечение-%03d-%s" % (angle, str(offset)),
2,
CONFIG.get("probe", [1, 0]),
names,
)
row.update(global_angle_deg=angle, slice_offset_deg=offset)
ROWS.append(row)
torques.append(row["torque_Nm"])
center["skew_averaged_torque_Nm"] = sum(torques) / 3
if angle != CONFIG["sweep"][-1]:
values.append(center["torque_Nm"])
averaged.append(sum(torques) / 3)
factor = (1 + 2 * math.cos(2 * 5 * math.pi / 180)) / 3
err = relative(sum(averaged), factor * sum(values))
check(
"Средний момент и гармонический коэффициент трёх фиксированных токовых сечений",
err,
0.03,
err < 0.03,
)
elif study == "srm-map":
angle = CONFIG.get("angle", 15)
prepare(fine_scale, angle, {names[0]: 2, names[1]: 0, names[2]: 0})
double = solve("удвоенный-ток", 0, CONFIG.get("probe", [1, 0]), names)
ROWS.append(double)
err = relative(double[names[0] + "_Psi_Wb"], 2 * fine[names[0] + "_Psi_Wb"])
check("Линейное масштабирование потокосцепления", err, 0.001, err < 0.001)
err = relative(double["coenergy_J"], 4 * fine["coenergy_J"])
check("Квадратичное масштабирование коэнергии", err, 0.001, err < 0.001)
else:
controls = []
for angle in (CONFIG["angle"] - 0.5, CONFIG["angle"] + 0.5):
prepare(0.3, angle, {names[0]: 1, names[1]: -0.5, names[2]: -0.5})
row = solve(
"виртуальное-смещение-%d" % len(ROWS),
2,
CONFIG.get("probe", [1, 0]),
names,
)
ROWS.append(row)
controls.append(row)
derivative = (controls[1]["coenergy_J"] - controls[0]["coenergy_J"]) / (
math.pi / 180
)
err = relative(derivative, fine["torque_Nm"])
check(
"Момент и производная коэнергии при фиксированных токах",
err,
0.07,
err < 0.07,
)
elif study == "dc-reaction":
separate = []
for field, armature in ((1, 0), (0, 2)):
prepare(fine_scale, 0, {names[0]: field, names[1]: armature})
row = solve("раздельное-возбуждение-%d" % len(ROWS), 0, CONFIG["probe"], names)
ROWS.append(row)
separate.append(row)
err = max(
relative(fine[name + "_Psi_Wb"], sum(r[name + "_Psi_Wb"] for r in separate))
for name in names
)
check(
"Суперпозиция потокосцеплений двух систем возбуждения", err, 0.002, err < 0.002
)
for armature in (0, 1, 2, 3, 4):
prepare(fine_scale, 0, {names[0]: 1, names[1]: armature})
row = solve("реакция-якоря-%d" % armature, 0, CONFIG["probe"], names)
row["parameter"] = armature
ROWS.append(row)
elif study == "ct-burden":
prepare(fine_scale, 0, {names[0]: 0, names[1]: 1})
secondary = solve("вторичный-столбец", 0, CONFIG["probe"], names)
ROWS.append(secondary)
l1 = fine[names[0] + "_Psi_Wb"]
m1 = fine[names[1] + "_Psi_Wb"]
m2 = secondary[names[0] + "_Psi_Wb"]
l2 = secondary[names[1] + "_Psi_Wb"]
err = relative(m1, m2)
check("Взаимность связи обмоток", err, 0.001, err < 0.001)
for resistance in (0.01, 0.03, 0.1, 0.3, 1):
omega = 2 * math.pi * 50
ip = 100
secondary_current = -1j * omega * m1 * ip / (resistance + 1j * omega * l2)
prepare(fine_scale, 0, {names[0]: ip, names[1]: secondary_current}, 50)
row = solve("нагрузка-%d" % len(ROWS), 0, CONFIG["probe"], names)
i2 = secondary_current
v2 = complex(row[names[1] + "_V_V"], row[names[1] + "_V_im_V"])
v1 = complex(row[names[0] + "_V_V"], row[names[0] + "_V_im_V"])
residual = abs(v2 + resistance * i2) / max(abs(v2), 1e-12)
supplied = 0.5 * (v1 * ip).real
load = 0.5 * resistance * abs(i2) ** 2
err = relative(supplied, load)
row.update(
parameter=resistance,
secondary_amplitude_A=abs(i2),
load_power_W=load,
supplied_power_W=supplied,
kvl_residual=residual,
power_error=err,
)
ROWS.append(row)
check(
"Невязка уравнения вторичной цепи R=" + str(resistance),
residual,
0.002,
residual < 0.002,
)
check("Баланс активной мощности R=" + str(resistance), err, 0.002, err < 0.002)
elif study == "three-phase":
matrix = []
for i in range(3):
prepare(
fine_scale, 0, {name: 1 if j == i else 0 for j, name in enumerate(names)}
)
row = solve("столбец-%d" % i, 0, CONFIG["probe"], names)
ROWS.append(row)
row["parameter"] = i
matrix.append([row[name + "_Psi_Wb"] for name in names])
asym = max(relative(matrix[i][j], matrix[j][i]) for i in range(3) for j in range(3))
check("Взаимность трёхфазной матрицы", asym, 0.002, asym < 0.002)
for label_, currents in (
("нулевая-последовательность", [1, 1, 1]),
("несимметрия", [1, 2, -1]),
("баланс", [1, -0.5, -0.5]),
):
prepare(fine_scale, 0, {name: currents[i] for i, name in enumerate(names)})
row = solve(label_, 0, CONFIG["probe"], names)
ROWS.append(row)
expected = 0.5 * sum(
currents[i] * matrix[j][i] * currents[j] for i in range(3) for j in range(3)
)
err = relative(expected, row["energy_J"])
check("Энергия поля и матрица: " + label_, err, 0.002, err < 0.002)
elif study == "induction-slip":
for frequency in CONFIG["sweep"]:
currents = {
names[0]: 1,
names[1]: complex(-0.5, -math.sqrt(3) / 2),
names[2]: complex(-0.5, math.sqrt(3) / 2),
}
prepare(fine_scale, 0, currents, frequency)
row = solve("частота-%d" % len(ROWS), 0, CONFIG["probe"], names)
supplied = 0
for name, current in currents.items():
voltage = complex(row[name + "_V_V"], row[name + "_V_im_V"])
supplied += 0.5 * (voltage * complex(current).conjugate()).real
err = relative(supplied, row["loss_W"])
row.update(parameter=frequency, terminal_power_W=supplied, power_error=err)
ROWS.append(row)
check(
"Баланс потерь поля и выводов, f=" + str(frequency), err, 0.02, err < 0.02
)
finish(
{
"x": "parameter",
"y": CONFIG.get("plot_metric", CONFIG["metric"]),
"x_label": CONFIG.get("parameter_name", "Параметр"),
"y_label": CONFIG.get("plot_label", CONFIG["metric_label"]),
}
)
Картина рассчитанного поля
Окна FEMM 5
Снимки интерфейса FEMM показывают геометрию, настройки и работу с результатами в FEMM 5. Откройте изображение, чтобы рассмотреть подписи и значения в полном размере.
Результаты и численные проверки
В гармонических строках компоненты Bx, By, Hx, Hy и величины цепей I, V, Ψ представлены действительными частями фазоров (Re). Мнимые части подписаны отдельно. Заданные амплитуды возбуждения указаны в исходных данных. Для энергии, мощности и силы используется смысл соответствующего интеграла, описанный в постановке.
Сохранено решений FEMM: 4. Выполнено проверок: 13. Полная точность чисел и условия сравнения доступны в таблицах результатов JSON.
| Мнимая часть потокосцепления, Вб: Первичная обмотка | Элементов | Состояние | Мнимая часть напряжения, В: Вторичная обмотка | Действительная часть (Re): Ток, А: Первичная обмотка | Действительная часть (Re): Потокосцепление, Вб: Первичная обмотка | Действительная часть (Re): Напряжение, В: Первичная обмотка | Действительная часть (Re): Индукция Bx, Тл | Действительная часть (Re): Напряжённость Hy, А/м | Энергия, Дж | Потери, Вт | Мнимая часть напряжения, В: Первичная обмотка | Коэнергия, Дж | Действительная часть (Re): Потокосцепление, Вб: Вторичная обмотка | Мнимая часть потокосцепления, Вб: Вторичная обмотка | Действительная часть (Re): Напряжённость Hx, А/м | Действительная часть (Re): Напряжение, В: Вторичная обмотка | Действительная часть (Re): Индукция By, Тл | Действительная часть (Re): Ток, А: Вторичная обмотка | Параметр серии | Относительный масштаб сетки | Мощность нагрузки, Вт | Подведённая мощность, Вт | Относительная невязка мощности | Невязка закона напряжений Кирхгофа | Амплитуда вторичного тока, А |
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| 0 | 14900 | input | 0 | 1 | 3,1386402 × 10⁻⁶ | 0 | 0,0038514571 | -0,0032901483 | 1,5693201 × 10⁻⁶ | 0 | 0 | 1,5693201 × 10⁻⁶ | 313,17997 × 10⁻⁶ | 0 | 3,0648922 | 0 | -4,1345223 × 10⁻⁶ | 0 | — | — | — | — | — | — | — |
| 0 | 14900 | сетка-1 | 0 | 1 | 3,1386402 × 10⁻⁶ | 0 | 0,0038514571 | -0,0032901482 | 1,5693201 × 10⁻⁶ | 0 | 0 | 1,5693201 × 10⁻⁶ | 313,17997 × 10⁻⁶ | 0 | 3,0648922 | 0 | -4,1345221 × 10⁻⁶ | 0 | 0 | 1 | — | — | — | — | — |
| 0 | 20876 | сетка-2 | 0 | 1 | 3,140504 × 10⁻⁶ | 0 | 0,0038537223 | -0,0033485794 | 1,570252 × 10⁻⁶ | 0 | 0 | 1,570252 × 10⁻⁶ | 313,36194 × 10⁻⁶ | 0 | 3,0666947 | 0 | -4,2079489 × 10⁻⁶ | 0 | 0 | 0,7 | — | — | — | — | — |
| 0 | 37096 | сетка-3 | 0 | 1 | 3,1418371 × 10⁻⁶ | 0 | 0,0038551289 | -0,0033145884 | 1,5709185 × 10⁻⁶ | 0 | 0 | 1,5709185 × 10⁻⁶ | 313,48652 × 10⁻⁶ | 0 | 3,0678141 | 0 | -4,1652346 × 10⁻⁶ | 0 | 0 | 0,5 | — | — | — | — | — |
| 0 | 37096 | вторичный-столбец | 0 | 0 | 313,48652 × 10⁻⁶ | 0 | 0,38573517 | -0,32459874 | 0,015684949 | 0 | 0 | 0,015684949 | 0,031369898 | 0 | 306,9583 | 0 | -407,90281 × 10⁻⁶ | 1 | — | — | — | — | — | — | — |
| -317,87853 × 10⁻⁹ | 37096 | нагрузка-5 | 10,140097 × 10⁻⁶ | 100 | 909,83127 × 10⁻⁹ | 99,864487 × 10⁻⁶ | 39,368746 × 10⁻⁶ | -0,0070802763 | 22,745782 × 10⁻⁶ | 0 | 285,83192 × 10⁻⁶ | 22,745782 × 10⁻⁶ | 32,276932 × 10⁻⁹ | -31,809397 × 10⁻⁶ | 0,031328653 | 0,0099932169 | -8,8973376 × 10⁻⁶ | -0,99932169 | 0,01 | — | 0,0049932243 | 0,0049932243 | 2,4305188 × 10⁻¹² | 518,99487 × 10⁻¹² | 0,9993222 |
| -953,62775 × 10⁻⁹ | 37096 | нагрузка-6 | 91,260164 × 10⁻⁶ | 100 | 912,41165 × 10⁻⁹ | 299,59099 × 10⁻⁶ | 42,543825 × 10⁻⁶ | -0,0070829482 | 22,810291 × 10⁻⁶ | 0 | 286,64257 × 10⁻⁶ | 22,810291 × 10⁻⁶ | 290,49012 × 10⁻⁹ | -95,427406 × 10⁻⁶ | 0,0338553 | 0,029979404 | -8,9006952 × 10⁻⁶ | -0,99931346 | 0,03 | — | 0,01497955 | 0,01497955 | 849,90109 × 10⁻¹⁵ | 184,00986 × 10⁻¹² | 0,99931809 |
| -3,1784614 × 10⁻⁶ | 37096 | нагрузка-7 | 0,0010139069 | 100 | 941,76052 × 10⁻⁹ | 998,54308 × 10⁻⁶ | 78,65667 × 10⁻⁶ | -0,0071133374 | 23,544013 × 10⁻⁶ | 0 | 295,86279 × 10⁻⁶ | 23,544013 × 10⁻⁶ | 3,2273658 × 10⁻⁶ | -318,06155 × 10⁻⁶ | 0,062592989 | 0,099921984 | -8,9388834 × 10⁻⁶ | -0,99921984 | 0,1 | — | 0,049927154 | 0,049927154 | 4,2036 × 10⁻¹² | 61,926838 × 10⁻¹² | 0,99927128 |
| -9,5275371 × 10⁻⁶ | 37096 | нагрузка-8 | 0,0091176526 | 100 | 1,1995361 × 10⁻⁶ | 0,0029931641 | 395,84125 × 10⁻⁶ | -0,0073802503 | 29,988401 × 10⁻⁶ | 0 | 376,84536 × 10⁻⁶ | 29,988401 × 10⁻⁶ | 29,02239 × 10⁻⁶ | -953,39943 × 10⁻⁶ | 0,31500046 | 0,29951927 | -9,2742961 × 10⁻⁶ | -0,99839755 | 0,3 | — | 0,1496582 | 0,1496582 | 1,1288936 × 10⁻¹² | 16,842924 × 10⁻¹² | 0,99886003 |
| -31,463929 × 10⁻⁶ | 37096 | нагрузка-9 | 0,10036773 | 100 | 4,102149 × 10⁻⁶ | 0,009884685 | 0,003967414 | -0,010385753 | 102,55372 × 10⁻⁶ | 0 | 0,0012887281 | 102,55372 × 10⁻⁶ | 319,4804 × 10⁻⁶ | -0,0031485254 | 3,1571677 | 0,98913842 | -13,051122 × 10⁻⁶ | -0,98913842 | 1 | — | 0,49423425 | 0,49423425 | 665,25651 × 10⁻¹⁵ | 5,0644974 × 10⁻¹² | 0,99421753 |
| Критерий | Получено | Допуск или ожидаемое значение | Итог |
|---|---|---|---|
| Стабилизация наблюдаемой величины при сгущении сетки | 424,3 × 10⁻⁶ | 0,025 | Выполнен |
| Фактическое увеличение числа элементов | 2,49 | 1,2 | Выполнен |
| Взаимность связи обмоток | 565,5 × 10⁻¹⁵ | 0,001 | Выполнен |
| Невязка уравнения вторичной цепи R=0.01 | 519 × 10⁻¹² | 0,002 | Выполнен |
| Баланс активной мощности R=0.01 | 2,431 × 10⁻¹² | 0,002 | Выполнен |
| Невязка уравнения вторичной цепи R=0.03 | 184 × 10⁻¹² | 0,002 | Выполнен |
| Баланс активной мощности R=0.03 | 849,9 × 10⁻¹⁵ | 0,002 | Выполнен |
| Невязка уравнения вторичной цепи R=0.1 | 61,93 × 10⁻¹² | 0,002 | Выполнен |
| Баланс активной мощности R=0.1 | 4,204 × 10⁻¹² | 0,002 | Выполнен |
| Невязка уравнения вторичной цепи R=0.3 | 16,84 × 10⁻¹² | 0,002 | Выполнен |
| Баланс активной мощности R=0.3 | 1,129 × 10⁻¹² | 0,002 | Выполнен |
| Невязка уравнения вторичной цепи R=1 | 5,064 × 10⁻¹² | 0,002 | Выполнен |
| Баланс активной мощности R=1 | 665,3 × 10⁻¹⁵ | 0,002 | Выполнен |
Допуски относятся к указанной учебной задаче и способу сравнения. Число показанных цифр не означает такой же физической точности.
Модели, решения и программа
Для нового расчёта сохраните программу, модели и необходимые данные в одну рабочую папку, сохраняя структуру подпапок.
- Файл результатов: README.md4393 байт
- Магнитное решение: input.ans895695 байт
- Магнитная модель: input.fem3526 байт
- Программа встроенного Python: reproduce.py27483 байт
- Файл результатов: verification.json2602 байт
- Магнитное решение: сетка-1.ans895783 байт
- Магнитная модель: сетка-1.fem3543 байт
- Магнитное решение: сетка-2.ans1262064 байт
- Магнитная модель: сетка-2.fem3644 байт
- Магнитное решение: сетка-3.ans2308849 байт
- Магнитная модель: сетка-3.fem3544 байт
Границы применимости
- Двумерная учебная геометрия; точные входы и русские свойства включены в комплект. Торцевые поля, механическая динамика, температурная зависимость и реальные потери стали требуют отдельных моделей.
- Это результат численного исследования выбранной модели; физический макет и заявленное изготовителем изделие не проверялись.