Files
templates/python/set_devices/ump_logger_demo.py

62 lines
3.0 KiB
Python
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# Синтетический снимок регистратора УМП для работы GUI без контроллера. Данные формируются в
# ожидаемом представлении клиента, чтобы проверять выбор каналов и отображение одной и той же
# моделью.
"""Синтетические записи УМП для проверки графиков без подключения платы."""
import math
from set_devices import ump_logger as codec
def sample(time_ms, period_ms=20, *, repeat=True):
"""Повторяемый цикл: пуск, разгон 6–16 мА, отключение и спад тока."""
phase = time_ms % 6000 if repeat else time_ms
started = 1000 <= phase < 5000
reset = 5000 <= phase < 5300
# Как в прошивке: фронт команды включает выход на 1000 мс.
start_out = 1000 <= phase < 2000
stop_out = 5000 <= phase < 6000
ramp = max(0, min(2500, phase - 1000))
if started:
current = 6 + 10 * ramp / 2500 + 0.2 * math.sin(phase / 90)
elif phase >= 5000:
current = 4 + 12 * max(0, 1 - (phase - 5000) / 300)
else:
current = 4
words = [0] * codec.WORDS
words[0], words[1] = time_ms & 65535, (time_ms >> 16) & 65535
words[2] = 1 | (0x100 if 5000 <= phase < 5000 + period_ms else 0)
words[3] = (int(started) << 7) | (int(reset) << 6)
words[4] = int(1200 <= phase < 5100) | (int(started) << 1) | (int(reset) << 2)
words[5] = int(start_out) | (int(stop_out) << 1) | (int(started) << 2)
words[6] = (2000 - phase) if start_out else ((6000 - phase) if stop_out else 0)
words[7] = max(0, 250 - phase)
words[8] = round(500 + (current - 4) * 3000 / 16)
words[9] = round(current * 10)
for channel in range(4):
measured = round(120 * math.sin(phase / (180 + channel * 70) + channel))
words[10 + channel] = measured & 65535
words[14 + channel] = (1 << channel) if 5100 <= phase < 5400 else 0
words[36 + channel] = 2048 + measured * 4
words[18:24] = [0xE07F, words[3], 6, 16, (time_ms // 100) & 65535, 0]
words[24:31] = [6, 16, 500, 3500, 2000, 500, 3500]
words[31:36] = [ramp if started else 0, 2500, 60, 160, round(ramp * 1000 / 2500)]
return codec.sample(words)
def capture(period_ms):
"""Пример архива: 10% ёмкости банка записывается после отключения."""
post_points = codec.CAPACITY // 10
before = list(range(5000, -1, -period_ms))[1:codec.CAPACITY - post_points][::-1]
after = [5000 + i * period_ms for i in range(1, post_points + 1)]
records = [sample(t, period_ms) for t in before + [5000]]
for t in after:
# Continue the stopped state instead of starting another demo cycle.
record = sample(t, period_ms, repeat=False)
record['event'] = 1
record['off_trigger'] = 0
records.append(record)
records[-1]['event'] = 5
return records