Files
templates/tools/dsview/tests/check_pwm_npc_native.py
T

50 lines
9.0 KiB
Python

"""Нативная проверка опций NPC, θ, треугольника и фазовых сдвигов в одном DSView.""" # Скрипт запускает только собственный экземпляр с синтетической записью, не обращаясь к оборудованию.
import argparse # Параметры выбирают тестовый runtime и режим отображения.
import json # Метаданные DSL содержат обычные настройки того же анализатора PWM waveform.
import math # Выравнивание длины записи соответствует 64-битным блокам DSView.
from pathlib import Path # Абсолютные пути исключают зависимость от каталога запуска.
import sys # Стандартная нативная проверка вызывается с собственным контролируемым списком аргументов.
import zipfile # DSL является архивом метаданных и упакованных цифровых каналов.
import check_pwm_native as native # Повторно используем проверку окончания декодирования, отзывчивости и штатного закрытия.
from test_pwm_npc import npc_frames, INDICES # Генератор совпадает с численно проверенными входными векторами четырёх затворов на фазу.
def fixture(path, seconds=.06, carrier_hz=2000, layout='combined', max_height='1X', show_text=False, text_only=False): # Сигнатура сохраняет совместимость с существующим нативным сценарием.
count = math.ceil(seconds * 1000000 / 64) * 64 # Частота 1 МГц и длина, кратная 64 битам, согласованы с цифровыми потоками DSL.
options = dict(active_a='high', active_b='high', active_c='high', input_mode='npc-three-level', waveform_mode=MODE, waveform_layout=layout, carrier_hz=2000, smoothing_ms=0.0, show_theta='yes', show_carrier='yes', show_phase_angles='yes') # Все новые опции включаются штатными параметрами одного экземпляра PWM waveform.
channels = [{('abc'[ch] if gate == 0 else 'abc'[ch] + str(gate + 1)): index} for ch in range(3) for gate, index in enumerate(INDICES[ch])] # S1 сохраняет прежние имена A/B/C, дополнительные затворы имеют явные номера S2…S4.
show = {'pwm_waveform': True} # Видимость относится к строкам результата, а не отключает цифровые входы затворов.
show.update({'pwm_waveform: ' + ch + ' duty / frequency': False for ch in 'ABC'}) # Короткие заполнения скрыты, чтобы все расчётные графики помещались на контрольном экране.
show.update({'pwm_waveform: ' + ch + ' PWM carrier / field': False for ch in 'ABC'}) # Значения частот уже проверяются численными тестами и не заслоняют θ, несущую и фазовые углы.
decoders = [dict(id='pwm_waveform', version=2, label='NPC ABC / theta / carrier / phase lag', view_index=12, channel=channels, options=options, **{'stacked decoders': [], 'show': show})] # Запись загружается обычным механизмом сохранённого анализатора DSView.
session = dict(Device='virtual-session', DeviceMode=0, Version=3, Title='DSView v1.3.2', decoder=decoders, channel=[dict(index=index, enabled=True, name='D' + str(index), colour='default', strigger=0, type=10000, view_index=index) for index in range(12)], **{'Sample count': str(count), 'Sample rate': '1000000', 'Max Height': max_height}) # Все двенадцать физических входов остаются доступными декодеру.
header = '[version]\nversion = 3\n[header]\ndriver = virtual-session\ndevice mode = 0\ncapturefile = data\ntotal samples = {}\ntotal probes = 12\ntotal blocks = 1\nsamplerate = 1000000 Hz\ntrigger time = 0\ntrigger pos = 0\n'.format(count) # Заголовок фиксирует ту же временную шкалу, что генератор фронтов.
header += ''.join('probe{} = D{}\n'.format(index, index) for index in range(12)) # Каждый физический затвор имеет собственную цифровую дорожку.
bits = [bytearray(count // 8) for _ in range(12)] # Пакуются реальные логические уровни, а не готовые кривые результата.
frames = list(npc_frames(seconds=seconds)) # Последовательность содержит только фактические изменения допустимых комбинаций NPC.
frames.append((count, frames[-1][1])) # Последний уровень достраивается до конца записи без выдуманного переключения.
for (start, pins), (end, _) in zip(frames, frames[1:]): # Между соседними снимками все цифровые входы постоянны.
for index, level in enumerate(pins): # Двенадцать входов обрабатываются независимо.
if level: # Нулевые биты уже присутствуют в исходных bytearray.
for sample in range(start, min(end, count)): # Синтетический короткий сценарий допускает прямое заполнение каждого отсчёта.
bits[index][sample // 8] |= 1 << (sample % 8) # Младший бит соответствует первому отсчёту байта в формате DSL.
with zipfile.ZipFile(path, 'w', zipfile.ZIP_DEFLATED) as archive: # Полная фикстура хранится одним файлом и открывается без оборудования.
archive.writestr('header', header) # Стандартный заголовок определяет частоту и число проб.
archive.writestr('session', json.dumps(session)) # Видимость и расположение дорожек восстанавливаются штатным путём.
archive.writestr('decoders', json.dumps(decoders)) # Выбранная топология и новые опции сохраняются вместе с записью.
for index, data in enumerate(bits): # Один блок каждого входа содержит все отсчёты сценария.
archive.writestr('L-{}/0'.format(index), data) # Пути соответствуют индексу физического канала DSView.
if __name__ == '__main__': # Проверка запускается явно после сборки нативного компонента.
parser = argparse.ArgumentParser(description=__doc__) # Интерфейс не добавляет зависимостей к обычному unittest.
parser.add_argument('--runtime', type=Path, required=True) # Используется отдельный тестовый runtime либо явно выбранный локальный компонент.
parser.add_argument('--output', type=Path, required=True) # Все журналы и изображения сохраняются в выделенной папке сценария.
parser.add_argument('--mode', choices=('envelope', 'switching'), default='switching') # Один сценарий проверяет оба пользовательских вида основного графика.
parser.add_argument('--layout', choices=('split', 'combined'), default='combined') # Общая компоновка должна сохранять отдельные области θ и треугольника.
args = parser.parse_args() # Параметры проверяются до запуска дочернего DSView.
MODE = args.mode # Выбранный вид встраивается в обычные настройки декодера DSL.
native.fixture = fixture # Стандартный сценарий получает двенадцатиканальную NPC-запись вместо прежнего двоичного ШИМ.
sys.argv = [sys.argv[0], '--runtime', str(args.runtime), '--output', str(args.output), '--seconds', '.06', '--layout', args.layout] # Остальные проверки выполняются тем же существующим нативным инструментом.
native.main() # Дочерний процесс обязан завершить декодирование и закрыться штатно, оставив контрольный скриншот.