Продолжаем цикл изучения открытых 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 фазных провода и нулевой провод обозначены одной линией. А шины, то есть места соединений, обозначены перпендикулярной утолщенной линией. Трансформатор, имеющий высоковольтную и низковольтную обмотки, обозначен, как вы поняли, двумя пересекающимися окружностями.
Вот код, создающий модель такой простейшей сети с комментариями:
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)
Разомкнутый выключатель отключает шину нагрузки от источника питания. Это можно проверить, запустив расчет потоков мощности и проверив результаты. Напряжение на шине с индексом 2 показано как NaN, то есть отсутствует:
pp.runpp(net) net.res_bus

Нагрузка/мощность не подается на потребителя:
net.res_load
И линия находится в разомкнутом режиме:
net.res_line
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()
Здесь можно посмотреть код создания данной сети вручную со всеми параметрами.
А код net = pandapower.networks.example_multivoltage() создаст нам сложную сеть с ветрогенератором, балансирующей его газовой турбиной, подключением ко внешней сети, с 4 уровнями напряжения (110 кВ, 20 кВ, 10 кВ и 0,4 кВ) и с массой нагрузок… Вот ссылка на пример.
7. Дополнительные возможности
Мы рассмотрели несколько элементов сети, но в pandapowerих существенно больше — вот весь список.
Более того, некоторые типовые элементы (линии, трансформаторы) можно брать из библиотеки, либо создать свою библиотеку типовых элементов сети.
Как мы и упоминали, есть много вариантов уже встроенных сложных сетей, с которыми можно сразу начать играться, а не создавать их с нуля.
pandapower плотно интегрирован как с pandas, что позволяет использовать ее богатые возможности для обработки наших данных, так и с NetworkX — библиотекой для построения и анализа графов. Поэтому сеть можно представить в виде графа и использовать богатые возможности NetworkX.
Еще одна мощная возможность — оптимизация потоков в сети. Есть возможность задавать различные ограничения для элементов сети, а также стоимостную функцию (и находить оптимальное решение с учетом стоимости). Подробнее об оптимизации.
Также есть возможность рассчитать целую временную серию параметров (изменение параметров сети во времени). Подробнее о временных сериях.
Наконец, данные о сети можно загружать и сохранять в различных форматах и использовать конвертеры для других систем расчета сетей.
ссылка на оригинал статьи https://habr.com/ru/articles/721658/
Добавить комментарий