Chip_Case_Generator/4ch-Z_Generator/FourChZEnvelopeGenerator.py

194 lines
7.8 KiB
Python
Raw Normal View History

2026-07-28 17:57:28 +08:00
import numpy as np
import os
import logging
import copy
import matplotlib.pyplot as plt
import sys
from typing import Any, Dict, List, Optional, Union, Callable
from enum import Enum
from env_gen.flattop import flattop
from env_gen.acz import aczwave
from env_gen.accz_gen import accz_wave
from matplotlib import gridspec
from FourChZreg_define import *
class EnvelopeGenerator:
_axes_list: List[tuple] = []
PLOT_STYLES = [
'ggplot', 'bmh', 'fivethirtyeight', 'Solarize_Light2',
'fast', 'tableau-colorblind10', 'seaborn-poster', 'seaborn-bright'
]
PLOT_COLORS = ['C0', 'C1', 'C2', 'C3', 'C4', 'C5', 'C6', 'C7']
SINGLE_PLOT_CONFIG = {
'figsize': (8, 6),
'dpi': 220,
'style': 'seaborn-v0_8-poster',
'linewidth': 3,
'fontsize': {'xlabel': 22, 'ylabel': 22, 'title': 20, 'legend': 18, 'tick': 18}
}
MULTI_PLOT_CONFIG = {
'dpi': 200,
'fontsize': {'xlabel': 18, 'ylabel': 18, 'title': 16, 'tick': 16},
'grid_alpha': 0.3
}
def __init__(self, mk_instance, **kwargs):
self.mk = mk_instance
self.config_file = kwargs.get('config_file')
def write_register(self, address, value):
self.mk.rw_once('w', address, value, self.config_file)
def _generate_rect_envelope(self, **kwargs):
amp = kwargs.pop('amp')
wave_time = kwargs.pop('wave_time')
rect_wave = [amp] * wave_time
return rect_wave
def _generate_rect_hold_envelope(self, **kwargs):
amp = kwargs.pop('amp')
rect_rising_edge = [amp] * 4
rect_falling_edge = [0] * 4
return rect_rising_edge, rect_falling_edge
def _generate_flattop_envelope(self, **kwargs):
amp = kwargs.pop('amp')
edge_time = kwargs.pop('edge_time')
wave_time = kwargs.pop('wave_time')
flattop_wave = flattop(float(amp), float(edge_time), float(wave_time), 1.0)
return flattop_wave
def _generate_flattop_hold_envelope(self, **kwargs):
amp = kwargs.pop('amp')
edge_time = kwargs.pop('edge_time')
wave_time = kwargs.pop('wave_time')
flattop_wave = flattop(float(amp), float(edge_time), float(wave_time), 1.0)
hold_value = flattop_wave.max()
hold_idx = np.where(flattop_wave == hold_value)[0]
rising_edge_end_idx = hold_idx[0]
falling_edge_start_idx = hold_idx[-1]
flattop_rising_edge = flattop_wave[:rising_edge_end_idx + 1]
flattop_falling_edge = flattop_wave[falling_edge_start_idx:-2]
return flattop_rising_edge, flattop_falling_edge
def _generate_acz_envelope(self, **kwargs):
amp = kwargs.pop('amp')
wave_time = kwargs.pop('wave_time')
acz_wave = aczwave(amp, wave_time, 0.0, 0.0, 0.0, 0.864, 0.05, -0.18, 0.04)
acz_wave_real = [val.real for val in acz_wave]
return acz_wave_real
def _generate_accz_envelope(self, **kwargs):
wave_time = kwargs.pop('wave_time')
env_accz = accz_wave(T=wave_time, A=0.8, plot=False)
return env_accz
def _cosine_envelope(self, **kwargs):
alpha = kwargs.pop('alpha', 1)
phi = kwargs.pop('phi', np.pi)
amp = kwargs.pop('amp')
wave_time = kwargs.pop('wave_time')
t_norm = np.arange(wave_time) / wave_time
cosine_wave = amp * (1 + alpha * np.cos(2 * np.pi * t_norm + phi)) / 2
return cosine_wave
def _generate_envelope_data(self, envelope_type, **kwargs):
if envelope_type == 'rect':
env_data = self._generate_rect_envelope(**kwargs)
elif envelope_type == 'rect_hold':
env_data = self._generate_rect_hold_envelope(**kwargs)
elif envelope_type == 'flattop':
env_data = self._generate_flattop_envelope(**kwargs)
elif envelope_type == 'flattop_hold':
env_data = self._generate_flattop_hold_envelope(**kwargs)
elif envelope_type == 'acz':
env_data = self._generate_acz_envelope(**kwargs)
elif envelope_type == 'accz':
env_data = self._generate_accz_envelope(**kwargs)
elif envelope_type == 'cosine':
env_data = self._cosine_envelope(**kwargs)
elif envelope_type == 'file_read_direct':
env_data = kwargs.get('external_envelope_data', [])
elif envelope_type == 'file_read_txt':
file_path = kwargs.get('file_path')
if file_path is None:
raise ValueError("Missing 'file_path'")
txt_data = np.loadtxt(file_path)
env_data = np.asarray(txt_data, dtype=float).reshape(-1).tolist()
return env_data
def _next_env_idx(self, idx_num, env_idx_mem, envelope_length):
if idx_num == 0:
return envelope_length
else:
last_env_idx = env_idx_mem[-1]
env_base_addr = (last_env_idx >> 16) + ((last_env_idx & 0xFFFF) << 1)
return env_base_addr << 16 | envelope_length
def _env_data_pack(self, float_data_array):
data_int = np.round(float_data_array).astype(int)
data_int[data_int < 0] += 65536
hex_pairs = []
for data0, data1 in zip(data_int[::2], data_int[1::2]):
hex_pairs.append((data1 << 16) | data0)
return hex_pairs
def _generate_envelope_batch(self, **kwargs):
kwargs_copy = copy.deepcopy(kwargs)
channel = kwargs_copy.pop('channel')
envelope_configs = kwargs_copy.pop('envelope_configs', [])
env_data_mem = []
env_idx_mem = []
idx_num = 0
for envelope_config in envelope_configs:
envelope_type = envelope_config.pop('envelope_type')
env_data = self._generate_envelope_data(envelope_type, **envelope_config)
if isinstance(env_data, tuple):
retun_param_count = len(env_data)
else:
retun_param_count = 1
if retun_param_count == 1:
envelope = env_data
envelope_arr = np.asarray(envelope, dtype=float).reshape(-1)
if envelope_arr.size % 4 != 0:
raise ValueError("Envelope length must be multiple of 4")
env_data_mem += envelope_arr.astype(int).tolist()
envelope_length = int(envelope_arr.size)
current_env_idx = self._next_env_idx(idx_num, env_idx_mem, envelope_length)
env_idx_mem.append(current_env_idx)
idx_num += 1
elif retun_param_count == 2:
rising_edge, falling_edge = env_data
rising_edge_arr = np.asarray(rising_edge, dtype=float).reshape(-1)
falling_edge_arr = np.asarray(falling_edge, dtype=float).reshape(-1)
if rising_edge_arr.size % 4 != 0:
raise ValueError("Envelope length must be multiple of 4")
env_data_mem += rising_edge_arr.astype(int).tolist()
rising_edge_length = int(rising_edge_arr.size)
rising_edge_idx = self._next_env_idx(idx_num, env_idx_mem, rising_edge_length)
env_idx_mem.append(rising_edge_idx)
idx_num += 1
env_data_mem += falling_edge_arr.astype(int).tolist()
falling_edge_length = int(falling_edge_arr.size)
falling_edge_idx = self._next_env_idx(idx_num, env_idx_mem, falling_edge_length)
env_idx_mem.append(falling_edge_idx)
idx_num += 1
env2mem_format = self._env_data_pack(env_data_mem)
ENVI_BASE = addr_base['ENVI0_BASE'] + channel*0x600000
ENVM_BASE = addr_base['ENVM0_BASE'] + channel*0x600000
self.write_register(ENVI_BASE, env_idx_mem)
self.write_register(ENVM_BASE, env2mem_format)
def env_config(mk_instance, **kwargs):
env_gen = EnvelopeGenerator(mk_instance, **kwargs)
env_gen._generate_envelope_batch(**kwargs)