Электричество без регистрации и sms: быстрое введение в pandapower
Продолжаем цикл изучения открытых python-библиотек с разбора pandapower
— с надстроенными над pandas
функциями расчета электрических сетей.
Даже если вы раньше ни разу не имели дела с расчетом электрических сетей, с библиотекой pandapower
вы можете быстро войти-в-айти-начала-прошлого-века… Подробные комментарии прилагаются.
В предыдущей статье большой обзор открытых электрических библиотек на питоне.
Библиотека pandapower
создана группой специалистов в Университете Касселя, Германия, распространяется под лицензией BSD
pandapower
предоставляет возможность расчетов и оптимизации потоков мощности, оценку состояния сети и расчёт токов коротких замыканий согласно стандарту IEC 60909. Есть возможность моделирования постоянных токовых нагрузок, сетей с несколькими балансирующими узлами и проверки связности сети. С этой библиотекой вы быстро погрузитесь в мир расчета электрических сетей. Зачем? А почему бы и нет?
Библиотека pandapower
на гитхабе
Документация библиотеки
Сайт проекта
Установка
Установим pandapower
с помощью pip install pandapower
Кроме того, должны быть установлены:
numpy
scipy
numba
matplotlib
1. Расчет простейшей сети
Рассмотрим простейшую сеть (пример на гитхабе), где есть:
Grid Connection — присоединение к внешней сети
Voltage Level 20 kV — шина напряжением 20 киловольт (шина — это проводник с низким сопротивлением, к которому могут присоединяться отдельные электрические цепи или устройства — подстанции, распредустройства и т.д.)
Transformer — Трансформатор 20 киловольт по верхней стороне / 0,4 кВ по нижней стороне, мощностью 400 кВА (киловольт-ампер, в этих величинах выражается полная мощность, в то время как ее часть, активная мощность, производящая работу, выражается в киловаттах, кВт)
Voltage Level 400 V — шина напряжением 0,4 киловольт
Line — линия длиной 100 метров, максимальный ток 142 А
Voltage Level 400 V — шина напряжением 0,4 киловольт
Load — нагрузка (потребитель электрической энергии) с активной мощностью 100 кВт (активная мощность выполняет полезную работу) и реактивной 50 кВАр (киловольт-ампер реактивной мощности, не выполняющей полезную работу).
Простейший участок сети с 3 шинами, потребителем, линией, трансформатором, присоединением к внешней сети
Заметим, что на рисунке приведена так называемая однолинейная схема — то есть физические 3 фазных провода и нулевой провод обозначены одной линией. А шины, то есть места соединений, обозначены перпендикулярной утолщенной линией. Трансформатор, имеющий высоковольтную и низковольтную обмотки, обозначен, как вы поняли, двумя пересекающимися окружностями.
Вот код, создающий модель такой простейшей сети с комментариями:
import pandapower as pp
# Создадим пустую сеть, частотой 50 Гц (по умолчанию f_hz=50.0)
# и с заданием мощности в мегавольтамперах (по умолчанию sn_mva=1):
net = pp.create_empty_network()
# Создадим 3 шины, в сети net, где vn_kv - номминальное напряжение в кВ,
# c именем name="Bus 1" ... "Bus 3"
bus1 = pp.create_bus(net, vn_kv=20., name="Bus 1")
bus2 = pp.create_bus(net, vn_kv=0.4, name="Bus 2")
bus3 = pp.create_bus(net, vn_kv=0.4, name="Bus 3")
# Создадим присоединение к внешней сети, в сети net,
# с именем name = "Grid Connection"
# присоединенную к шине 1 (bus=bus1)
# с коэффициентом напряжения в балансирующем узле 1,02
pp.create_ext_grid(net, bus=bus1, vm_pu=1.02, name="Grid Connection")
# Создадим нагрузку в сети net, с именем name="Load"
# с активной мощностью p_mw= 100 кВт, реактивной q_mvar 50 кВА
# (по умолчанию при создании сети sn_mva=1,
# т.е. все в мегаваттах, мегавольтамперах, поэтому p_mw=0.100)
pp.create_load(net, bus=bus3, p_mw=0.100, q_mvar=0.05, name="Load")
# Создадим трансформатор в сети net, с именем name="Trafo"
# стандартного типа (0,4 МВА мощностью 20/0,4 кВ)
# std_type="0.4 MVA 20/0.4 kV" - данные подтягиваются из библиотеки,
# присоединенный верхней стороной к шине bus1 (hv_bus=bus1)
# и нижней стороной к шине bus2 (lv_bus=bus2)
trafo = pp.create_transformer(net, hv_bus=bus1, lv_bus=bus2,
std_type="0.4 MVA 20/0.4 kV", name="Trafo")
# И, наконец, создадим линию в сети net, с именем name="Line"
# длиной 0,1 км (length_km=0.1)
# стандартного типа std_type="NAYY 4x50 SE" - это кабель из 4 алюминиевых
# жил сечением 50 мм2 каждая
# std_type="0.4 MVA 20/0.4 kV" - данные подтягиваются из библиотеки,
# присоединенной по направлению перетока мощности от шины bus2 (from_bus=bus2)
# к шине bus3 (to_bus=bus3)
line = pp.create_line(net, from_bus=bus2, to_bus=bus3,
length_km=0.1, std_type="NAYY 4x50 SE", name="Line")
Созданная структура данных сети хранится в нескольких датафреймах pandas
, их можно вызвать по имени сети net
и соответствующему атрибуту:
# Датафрейм с данными всех шин сети net:
net.bus
Датафрейм с данными всех шин
Датафрейм шины содержит столбцы:
name -
имя, которое мы задали;vn_kv -
номинальное напряжение в киловольтах;type
— тип шины. По умолчанию b, — busbar, что означает металлическая шина, шинопровод. (Есть еще «n» — node, узел, «m» — muff, муфта);zone
— регион/район сети для группировки шин, в данном случае мы его не задавали;in_service
— находится в рабочем состоянии (True
) или в нерабочем (False
).
Теперь выведем данные всех линий:
# Датафрейм с данными всех линий сети net:
net.line
Датафрейм с данными всех линий
Здесь мы видим одну линию с заданными нами:
именем (
name
),стандартным типом проводника из встроенной библиотеки данных
std_type
= NAYY 4×50 SE, он выглядит вот так,ссылками на индексы шин, откуда и куда идет линия (от 1 к 2, то есть от Bus 2 к Bus 3),
длиной
length_km
.
Остальные данные подтянула powerpandas
исходя из заданного стандартного типа кабеля (std_type = NAYY 4×50 SE) — в противном случае нам пришлось бы задать их вручную, путем метода create_line_from_parameters()
. Это:
Параметры линии:
r_ohm_per_km
(float) — сопротивление линии в Ом на км;x_ohm_per_km
(float) — реактивное сопротивление линии в Ом на км;c_nf_per_km
(float) — емкость линии (линия-земля) в нанофарадах на км;max_i_ka
(float) — максимальный ток (ток термической стойкости, при превышении которого металл проводников начнет плавиться) в килоамперах;type
(str) — тип линии («ol» для воздушной линии или «cs» для кабельной линии);parallel
(integer) — количество параллельных линий;in_service
— находится в рабочем состоянии (True
).
Датафрейм с данными всех трансформаторов:
# Датафрейм с данными всех трансформаторов сети net:
net.trafo
Как видим, у трансформатора намного больше параметров. Мы создавали один двухобмоточный трансформатор, поэтому и показаны данные одного трансформатора двухобмоточного.
Если трансформатор трёхобмоточный, то используем create_transformer3w()
для создания и net.trafo3w
(описание) для отображения датафрейма данных.
Итак, данные которые мы задали:
name
— имя «Trafo»std_type
— »0.4 MVA 20/0.4 kV» — заданный стандартный тип, примерно такойhv_bus
= 0 — шина, к которой подключена высокая сторона трансформатораlv_bus
= 1 — шина, к которой подключена низкая сторона трансформатора
Данные, которые были вычислены по заданному стандартному типу:
Рассмотрим остальные данные, если мы задаем параметры через create_transformer_from_parameters ()
Обязательные данные:
sn_mva -
номинальная мощность трансформатора, МВА (мегавольт-амперы);vn_hv_kv -
номинальное напряжение ВН (обмотки высокого напряжения);vn_lv_kv
— номинальное напряжение НН (обмотки низкого напряжения);vk_percent
— напряжение короткого замыкания,%vkr_percent
— активная составляющая напряжения короткого замыкания,%pfe_kw -
потери в железе (в проводящих частях), кВт,i0_percent
— ток холостого хода трансформатора, %,Необязательные данные:
shift_degree
— угловой сдвиг трансформатора (необходим для расчёта потокораспределения)tap_side
(int) — расположение РПН трансформатора (это устройство для регулирования напряжения путем изменения количества витков обмотки под нагрузкой). «hv» — на ВН (на стороне высокого напряжения), «lv» — на НН (на стороне низкого напряжения);tap_neutral
(int) — положение РПН, при котором коэффициент трансформации равен отношению номинальных напряженийtap_min
(int) — минимально допустимое положение РПНtap_max
(int) — максимально допустимое положение РПНtap_step_percent
(float) — величина шага изменения для величины напряжения в процентахtap_step_degree
(float) — величина шага изменения для угла напряжения в градусахtap_pos
(int) — текущее положение РПН трансформатора. По умолчанию среднее положение (tap_neutral)tap_phase_shifter
(bool) — еслиTrue
, РПН моделирует работу идеального фазорегулятора, то есть при каждом переключении ответвления изменяется фаза на постоянную величину шагаparallel
— количество параллельных трансформаторов;df
(float) — коэффициент снижения: максимальный ток трансформатора по отношению к номинальному току трансформатора (от 0 до 1)in_service -
находится в рабочем состоянии (True).
Датафрейм с данными всех нагрузок / потребителей сети net:
# Выведем данные всех нагрузок
net.load
Здесь мы видим имя (load), индекс 2-й шины, к которой подключена нагрузка (bus), p_mv
— активную мощность в мегаваттах и q_mvar
— реактивную мощность в мегавольт-ампер реактивных,
а также еще несколько параметров:
const_z_percent
— (float, по умолчанию 0) — доля нагрузки, характеризующаяся постоянным сопротивлением;const_i_percent
— (float, по умолчанию 0) — доля нагрузки, потребляющая постоянный ток;sn_mva
— (float, по умолчанию None) — номинальная мощность нагрузки, МВА;scaling
— (float, по умолчанию 1) — коэффициент масштабирования;in_service
— находится в рабочем состоянии (True).type
— тип нагрузки, 'wye'/'delta'
2. Расчет установившегося режима сети
Задав данные нашей сети и изучив их, запустим, наконец, её расчёт! Просто передадим в функцию runpp
нашу сеть net
.
# Запустим расчет без параметров
pp.runpp(net)
Установившийся режим — это режим работы энергосистемы, при котором параметры режима могут приниматься неизменными.
Результаты расчета установившегося режима сети также будут в датафреймах и для каждого вида элементов сети они будут иметь префикс res_ :
Датафрейм результатов расчета для шин:
# Выведем результаты расчета для шин
net.res_bus
Мы видим рассчитанные p_mv
— активную мощность в мегаваттах и q_mvar
— реактивную мощность в мегавольт-амперах:
на шине Bus 1 (с индексом 0) мощность со знаком '-' — она входит из внешней сети
на шине Bus 2 (с индексом 1) (шина между трансформатором и линией) — здесь мощность не потребляется, входящая на шину равна исходящей
на шине Bus 3 (с индексом 2) мощность равна мощности нагрузки, она «выходит» из шины на нагрузку, поэтому с противоположным шине 1 знаком
И еще 2 параметра для шин:
vm_pu — напряжение на шине, в относительных единицах (заметно, что от внешней сети оно постепенно снижается, поскольку трансформатор и сеть потребляют мощность на потери)
va_degree — угол напряжения в градусах
Датафрейм результатов расчета для линий:
# Выведем результаты расчета для линий
net.res_line
Что мы видим в результатах расчета линии:
p_from_mw и p_to_mw — активная мощность, входящая в линию и исходящая (на нагрузку), МВт
q_from_mvar и q_to_mvar — реактивная мощность, входящая в линию и исходящая (на нагрузку), МВАр
pl_mw и ql_mvar — активные и реактивные потери мощности на нагрузке
i_from_ka, i_ka и i_to_ka — ток в килоамперах на входе в линию, в линии и на выходе на нагрузку
vm_from_pu и vm_to_pu — относительное напряжение (относительно номинального) на входе в линию и на выходе на нагрузку
loading_percent — процент загрузки линии
Датафрейм результатов расчета для трансформаторов:
# Выведем результаты расчета для трансформаторов
net.res_trafo
Что мы видим в результатах расчета трансформатора:
p_hv_mw и q_hv_mvar — активная и реактивная мощность на высокой стороне
p_lv_mw и q_lv_mvar — активная и реактивная мощность на низкой стороне
pl_mw и ql_mvar — потери мощности в трансформаторе
i_hv_ka и i_lv_ka — ток на высокой и низкой стороне в килоамперах
vm_hv_pu и vm_lv_pu — относительное (относительно номинального) напряжение на высокой и низкой стороне
loading_percent — процент загрузки линии
Датафрейм результатов расчета для нагрузки и присоединения к внешней сети:
# Выведем результаты расчета для нагрузки
net.res_load
# Выведем результаты расчета для присоединения к внешней сети
net.res_ext_grid
Мы видим рассчитанные p_mv
— активную мощность в мегаваттах и q_mvar
— реактивную мощность в мегавольт-амперах. Почему эти значения отличаются — мощность из внешней сети больше? Мощность из внешней сети покрывает не только потребление мощности нашей нагрузки, но и потребление трансформатора на собственные нужды, и потребление линии на потери в ее проводниках.
Изменяем положение переключателя обмоток трансформатора
В трансформаторе есть возможность изменять количество витков, чтобы поддерживать нормальный уровень напряжения у потребителей.
# Теперь мы изменяем положение переключателя обмоток с положения 0 на -1
net.trafo.tap_pos.at[trafo] = -1
# и запускаем заново расчет сети:
pp.runpp(net)
Посмотрим на результаты, и увидим, что напряжение шины на стороне низкого напряжения трансформатора увеличилось с 0,964 до 0,992 номинального:
net.res_bus
А вот потребляемая из внешней сети мощность немного уменьшилась:
net.res_ext_grid
Вау! Мы только что оптимизировали работу нашей сети!
3. Поработаем рубильником!
Наверное, у вас уже возникал вопрос:, а где же здесь рубильник? Давайте его создадим, причем в разомкнутом состоянии, отключив нашу нагрузку!
# Создадим переключатель, указав нашу сеть, место (до шины нагрузки)
# closed=False означает, что переключатель разомкнул сеть (у включенного True)
# element=line - индекс элемента, в данном случае - линии;
# et: «l» — выключатель между шиной и линией,
# «t» — выключатель между шиной и трансформатором,
# «t3» — выключатель между шиной и 3-х обмоточным трансформатором,
# «b» — выключатель между двумя шинами
pp.create_switch(net, bus=bus3, element=line, et="l", closed=False)
Так теперь выглядит схема нашей сети. Квадратиком обозначен выключатель. Поскольку он разомкнут, то всё, что после него (шина 3 и нагрузка) обозначены серым.
Разомкнутый выключатель отключает шину нагрузки от источника питания. Это можно проверить, запустив расчет потоков мощности и проверив результаты. Напряжение на шине с индексом 2 показано как NaN
, то есть отсутствует:
pp.runpp(net)
net.res_bus
Нагрузка/мощность не подается на потребителя:
net.res_load
Нагрузка отключена и не потребляет мощность
И линия находится в разомкнутом режиме:
net.res_line
Мощность и ток в линии отсутствуют, но линия остаётся под напряжением (vm_from_pu 1.046 от номинального!)
4. Топологический анализ сети
Структуру сети можно анализировать с помощью пакета топологии. Он использует интерфейс библиотеки NetworkX для поиска по графу. Есть несколько предустановленных алгоритмов поиска, например, поиск не нагруженных шин:
# Загрузим пакет топологии
import pandapower.topology as top
# Выведем множество шин, которые не под нагрузкой:
top.unsupplied_buses(net)
{2}
В данном случае это шина с индексом 2 (Bus 3) — мы же её отключили!
Когда мы замыкаем переключатель, не запитанных шин больше нет:
# Когда мы замыкаем переключатель, не запитанных шин больше нет:
net.switch.closed.at[0] = True
top.unsupplied_buses(net)
set()
Помимо предопределенных функций поиска, также можно преобразовать сеть pandapower в граф NetworkX и выполнять поиск непосредственно на этом графе.
Предположим, мы хотим найти все шины с тем же уровнем напряжения, что и шина нагрузки. Мы переводим сеть в граф, но исключая трансформаторы:
# Переводим сеть в граф, но исключая трансформаторы
mg = top.create_nxgraph(net, include_trafos=False)
print(mg)
MultiGraph with 3 nodes and 1 edges
# Найдем все шины, подключенные к шине нагрузки, на этом графе:
list(top.connected_component(mg, 2))
[2, 1]
Поиск по графу находит все шины с одинаковым уровнем напряжения. Подобные поиски можно использовать, например, для идентификации фидеров.
Кроме того, с помощью пакета топологии можно найти:
calc_distance_to_bus(net, bus, respect_switches=True, nogobuses=None, notravbuses=None)-
вычисляет кратчайшее расстояние между исходной шиной и всеми подключенными к ней шинами
connected_component(mg, bus, notravbuses=[])
— находит все шины в графе NetworkX, которые подключены к определенной шине
connected_components
(mg, notravbuses={}) — кластеризирует все шины в графе NetworkX, которые соединены друг с другом
Подробнее здесь
5. Расчет короткого замыкания
Pandapower
включает модуль короткого замыкания, соответствующий стандарту IEC 60909. Чтобы выполнить анализ короткого замыкания, нам необходимо определить параметры короткого замыкания для внешней сети:
# Определим максимальную мощность короткого замыкания [МВА]
net.ext_grid["s_sc_max_mva"] = 100
# Максимальное отношение R/X (активного сопротивления к реактивному)
# импеданса короткого замыкания
# Импеданс является всеобъемлющим выражением всех видов сопротивлений
# потоку электронов (включая активное и реактивное сопротивления)
net.ext_grid["rx_max"] = 0.1
Теперь мы можем рассчитать короткие замыкания. Здесь мы рассчитываем максимальный (case="max"
) ток при замыкании трех фаз (по умолчанию аргумент fault='3ph'
). Возможно также »2ph» — замыкание фазы на фазу и »1ph» — замыкание фазы на землю.
Сопротивление короткого замыкания в расчете — 2 Ом (r_fault_ohm=2.
).
Еслиip=True
, то выполняется расчёт апериодической составляющей тока короткого замыкания (она затухает по экспоненциальному закону). Есть еще периодическая составляющая тока КЗ.
# Импортируем специальную библиотеку для расчета КЗ:
import pandapower.shortcircuit as sc
sc.calc_sc(net, case="max", ip=True, r_fault_ohm=2.)
# Выведем начальные и пиковые токи короткого замыкания
# для повреждений на всех шинах:
net.res_bus_sc
Какие параметры мы видим при расчете КЗ:
ikss_ka
— расчётный ток короткого замыкания в килоамперах (кА)skss_mw
— максимальная мощность короткого замыкания в мегавольтамперах (МВА)ip_ka
— расчётное значение апериодической составляющей в килоамперах (кА)rk_ohm, xk_ohm
— активное и реактивное сопротивление КЗ
Кроме net.res_bus_sc
можно вызвать net.res_line_sc
— таблицу с результатами расчёта по линиям электропередачи и net.res_trafo_sc
— таблицу с результатами расчёта по трансформаторам.
6. Встроенные примеры сетей
pandapower
содержит несколько встроенных примеров сети — вам даже не нужно задавать все элементы вручную:
# Импортируем модуль с экземлярами предустановленных сетей:
import pandapower.networks
# Выберем простейшую сеть, содержащую генератор:
net = pandapower.networks.example_simple()
pandapower.networks.example_simple () загружает нам вот такую сеть с внешним подключением, генератором и нагрузкой.
Здесь можно посмотреть код создания данной сети вручную со всеми параметрами.
А код net = pandapower.networks.example_multivoltage()
создаст нам сложную сеть с ветрогенератором, балансирующей его газовой турбиной, подключением ко внешней сети, с 4 уровнями напряжения (110 кВ, 20 кВ, 10 кВ и 0,4 кВ) и с массой нагрузок… Вот ссылка на пример.
7. Дополнительные возможности
Мы рассмотрели несколько элементов сети, но в pandapower
их существенно больше — вот весь список.
Более того, некоторые типовые элементы (линии, трансформаторы) можно брать из библиотеки, либо создать свою библиотеку типовых элементов сети.
Как мы и упоминали, есть много вариантов уже встроенных сложных сетей, с которыми можно сразу начать играться, а не создавать их с нуля.
pandapower
плотно интегрирован как с pandas, что позволяет использовать ее богатые возможности для обработки наших данных, так и с NetworkX — библиотекой для построения и анализа графов. Поэтому сеть можно представить в виде графа и использовать богатые возможности NetworkX.
Еще одна мощная возможность — оптимизация потоков в сети. Есть возможность задавать различные ограничения для элементов сети, а также стоимостную функцию (и находить оптимальное решение с учетом стоимости). Подробнее об оптимизации.
Также есть возможность рассчитать целую временную серию параметров (изменение параметров сети во времени). Подробнее о временных сериях.
Наконец, данные о сети можно загружать и сохранять в различных форматах и использовать конвертеры для других систем расчета сетей.