Skip to content
Snippets Groups Projects

Compare revisions

Changes are shown as if the source revision was being merged into the target revision. Learn more about comparing revisions.

Source

Select target project
No results found

Target

Select target project
  • da/B-ASIC
  • lukja239/B-ASIC
  • robal695/B-ASIC
3 results
Show changes
Showing
with 794 additions and 98 deletions
......@@ -5,6 +5,7 @@ from qtpy.QtGui import QPainterPath, QPen
from qtpy.QtWidgets import QGraphicsItem, QGraphicsPathItem
from b_asic.scheduler_gui._preferences import (
SCHEDULE_INDENT,
SIGNAL_ACTIVE,
SIGNAL_INACTIVE,
SIGNAL_WIDTH,
......@@ -16,6 +17,21 @@ from b_asic.signal import Signal
class SignalItem(QGraphicsPathItem):
"""
Class representing a signal in the scheduler GUI.
Parameters
----------
src_operation : OperationItem
The operation that the signal is drawn from.
dest_operation : OperationItem
The operation that the signal is drawn to.
signal : Signal
The signal on the SFG level.
parent : QGraphicsItem, optional
The parent QGraphicsItem.
"""
_path: Optional[QPainterPath] = None
_src_operation: OperationItem
_dest_operation: OperationItem
......@@ -38,7 +54,7 @@ class SignalItem(QGraphicsPathItem):
self.set_inactive()
self.update_path()
def update_path(self):
def update_path(self) -> None:
"""
Create a new path after moving connected operations.
"""
......@@ -58,7 +74,7 @@ class SignalItem(QGraphicsPathItem):
dest_x - source_x <= -0.1
or self.parentItem().schedule._laps[self._signal.graph_id]
):
offset = 0.2 # TODO: Get from parent/axes...
offset = SCHEDULE_INDENT # TODO: Get from parent/axes...
laps = self.parentItem().schedule._laps[self._signal.graph_id]
path.lineTo(
self.parentItem().schedule.schedule_time + offset, source_y
......@@ -77,7 +93,8 @@ class SignalItem(QGraphicsPathItem):
path.cubicTo(ctrl_point1, ctrl_point2, dest_point)
self.setPath(path)
def refresh_pens(self):
def refresh_pens(self) -> None:
"""Create pens."""
pen = QPen(SIGNAL_ACTIVE)
pen.setWidthF(SIGNAL_WIDTH)
self._active_pen = pen
......@@ -85,8 +102,12 @@ class SignalItem(QGraphicsPathItem):
pen.setWidthF(SIGNAL_WIDTH)
self._inactive_pen = pen
def set_active(self):
def set_active(self) -> None:
"""
Set the signal color to represent that a connected operation is selected.
"""
self.setPen(self._active_pen)
def set_inactive(self):
def set_inactive(self) -> None:
"""Set the signal color to the default color."""
self.setPen(self._inactive_pen)
......@@ -81,13 +81,19 @@ class Ui_MainWindow(object):
self.info_table.setVerticalHeaderItem(1, item)
item = QtWidgets.QTableWidgetItem()
item.setTextAlignment(QtCore.Qt.AlignLeading | QtCore.Qt.AlignVCenter)
font = QtGui.QFont()
font.setBold(False)
font.setWeight(50)
item.setFont(font)
self.info_table.setHorizontalHeaderItem(0, item)
item = QtWidgets.QTableWidgetItem()
item.setTextAlignment(QtCore.Qt.AlignLeading | QtCore.Qt.AlignVCenter)
self.info_table.setHorizontalHeaderItem(1, item)
item = QtWidgets.QTableWidgetItem()
font = QtGui.QFont()
font.setBold(True)
font.setBold(False)
font.setWeight(50)
font.setKerning(True)
item.setFont(font)
brush = QtGui.QBrush(QtGui.QColor(160, 160, 164))
brush.setStyle(QtCore.Qt.SolidPattern)
......@@ -105,7 +111,8 @@ class Ui_MainWindow(object):
self.info_table.setItem(0, 0, item)
item = QtWidgets.QTableWidgetItem()
font = QtGui.QFont()
font.setBold(True)
font.setBold(False)
font.setWeight(50)
item.setFont(font)
brush = QtGui.QBrush(QtGui.QColor(160, 160, 164))
brush.setStyle(QtCore.Qt.SolidPattern)
......@@ -138,6 +145,8 @@ class Ui_MainWindow(object):
self.menu_Edit.setObjectName("menu_Edit")
self.menuWindow = QtWidgets.QMenu(self.menubar)
self.menuWindow.setObjectName("menuWindow")
self.menuHelp = QtWidgets.QMenu(self.menubar)
self.menuHelp.setObjectName("menuHelp")
MainWindow.setMenuBar(self.menubar)
self.statusbar = QtWidgets.QStatusBar(MainWindow)
self.statusbar.setObjectName("statusbar")
......@@ -193,6 +202,12 @@ class Ui_MainWindow(object):
icon = QtGui.QIcon.fromTheme("view-close")
self.menu_close_schedule.setIcon(icon)
self.menu_close_schedule.setObjectName("menu_close_schedule")
self.actionAbout = QtWidgets.QAction(MainWindow)
self.actionAbout.setObjectName("actionAbout")
self.actionDocumentation = QtWidgets.QAction(MainWindow)
self.actionDocumentation.setObjectName("actionDocumentation")
self.actionReorder = QtWidgets.QAction(MainWindow)
self.actionReorder.setObjectName("actionReorder")
self.menuFile.addAction(self.menu_load_from_file)
self.menuFile.addAction(self.menu_close_schedule)
self.menuFile.addAction(self.menu_save)
......@@ -201,16 +216,21 @@ class Ui_MainWindow(object):
self.menuFile.addAction(self.menu_quit)
self.menuView.addAction(self.menu_node_info)
self.menuWindow.addAction(self.menu_exit_dialog)
self.menuHelp.addAction(self.actionDocumentation)
self.menuHelp.addSeparator()
self.menuHelp.addAction(self.actionAbout)
self.menubar.addAction(self.menuFile.menuAction())
self.menubar.addAction(self.menu_Edit.menuAction())
self.menubar.addAction(self.menuView.menuAction())
self.menubar.addAction(self.menuWindow.menuAction())
self.menubar.addAction(self.menuHelp.menuAction())
self.toolBar.addAction(self.menu_load_from_file)
self.toolBar.addAction(self.menu_save)
self.toolBar.addAction(self.menu_save_as)
self.toolBar.addSeparator()
self.toolBar.addAction(self.menu_node_info)
self.toolBar.addAction(self.actionT)
self.toolBar.addAction(self.actionReorder)
self.retranslateUi(MainWindow)
QtCore.QMetaObject.connectSlotsByName(MainWindow)
......@@ -236,6 +256,7 @@ class Ui_MainWindow(object):
self.menuView.setTitle(_translate("MainWindow", "&View"))
self.menu_Edit.setTitle(_translate("MainWindow", "&Edit"))
self.menuWindow.setTitle(_translate("MainWindow", "&Window"))
self.menuHelp.setTitle(_translate("MainWindow", "&Help"))
self.toolBar.setWindowTitle(_translate("MainWindow", "toolBar"))
self.menu_load_from_file.setText(
_translate("MainWindow", "&Load Schedule From File...")
......@@ -267,3 +288,11 @@ class Ui_MainWindow(object):
self.menu_close_schedule.setText(
_translate("MainWindow", "&Close Schedule")
)
self.actionAbout.setText(_translate("MainWindow", "About"))
self.actionDocumentation.setText(
_translate("MainWindow", "Documentation")
)
self.actionReorder.setText(_translate("MainWindow", "Reorder"))
self.actionReorder.setToolTip(
_translate("MainWindow", "Reorder schedule based on start time")
)
"""
B-ASIC signal flow graph generators.
This module contains a number of functions generating SFGs for specific functions.
"""
from typing import Dict, Optional, Sequence, Union
import numpy as np
from b_asic.core_operations import Name, SymmetricTwoportAdaptor
from b_asic.port import InputPort, OutputPort
from b_asic.signal import Signal
from b_asic.signal_flow_graph import SFG
from b_asic.special_operations import Delay, Input, Output
def wdf_allpass(
coefficients: Sequence[float],
input_op: Optional[Union[Input, Signal, InputPort]] = None,
output: Optional[Union[Output, Signal, OutputPort]] = None,
name: Optional[str] = None,
latency: Optional[int] = None,
latency_offsets: Optional[Dict[str, int]] = None,
execution_time: Optional[int] = None,
) -> SFG:
"""
Generate a signal flow graph of a WDF allpass section based on symmetric two-port adaptors.
Parameters
----------
coefficients : 1D-array
Coefficients to use for the allpass section
input_op : Input, optional
The Input to connect the SFG to. If not provided, one will be generated.
output : Output, optional
The Output to connect the SFG to. If not provided, one will be generated.
name : Name, optional
The name of the SFG. If None, "WDF allpass section".
latency : int, optional
Latency of the symmetric two-port adaptors.
latency_offsets : optional
Latency offsets of the symmetric two-port adaptors.
execution_time : int, optional
Execution time of the symmetric two-port adaptors.
Returns
-------
Signal flow graph
"""
np.asarray(coefficients)
coefficients = np.squeeze(coefficients)
if coefficients.ndim != 1:
raise TypeError("coefficients must be a 1D-array")
if input_op is None:
input_op = Input()
if output is None:
output = Output()
if name is None:
name = "WDF allpass section"
order = len(coefficients)
odd_order = order % 2
if odd_order:
# First-order section
coeff = coefficients[0]
adaptor0 = SymmetricTwoportAdaptor(
coeff,
input_op,
latency=latency,
latency_offsets=latency_offsets,
execution_time=execution_time,
)
signal_out = Signal(adaptor0.output(0))
delay = Delay(adaptor0.output(1))
Signal(delay, adaptor0.input(1))
else:
signal_out = Signal(input_op)
# Second-order sections
sos_count = (order - 1) // 2 if odd_order else order // 2
offset1, offset2 = (1, 2) if odd_order else (0, 1)
for n in range(sos_count):
adaptor1 = SymmetricTwoportAdaptor(
coefficients[2 * n + offset1],
signal_out,
latency=latency,
latency_offsets=latency_offsets,
execution_time=execution_time,
)
# Signal(prev_adaptor., adaptor1.input(0), name="Previous-stage to next")
delay1 = Delay(adaptor1.output(1))
delay2 = Delay()
adaptor2 = SymmetricTwoportAdaptor(
coefficients[2 * n + offset2],
delay1,
delay2,
latency=latency,
latency_offsets=latency_offsets,
execution_time=execution_time,
)
Signal(adaptor2.output(1), adaptor1.input(1))
Signal(adaptor2.output(0), delay2)
signal_out = Signal(adaptor1.output(0))
output << signal_out
return SFG([input_op], [output], name=Name(name))
......@@ -21,6 +21,10 @@ class Signal(AbstractGraphComponent):
"""
A connection between two ports.
.. note:: If a Signal is provided as *source* or *destination*, the
connected port is used. Hence, if the argument signal is later
changed, it will not affect the current Signal.
Parameters
==========
......@@ -33,10 +37,6 @@ class Signal(AbstractGraphComponent):
name : Name, default: ""
The signal name.
.. note:: If a Signal is provided as *source* or *destination*, the
connected port is used. Hence, if the argument signal is later
changed, it will not affect the current Signal.
See also
========
set_source, set_destination
......
......@@ -78,10 +78,37 @@ class GraphIDGenerator:
class SFG(AbstractOperation):
"""
Signal flow graph.
Construct an SFG given its inputs and outputs.
Contains a set of connected operations, forming a new operation.
Used as a base for simulation, scheduling, etc.
Inputs/outputs may be specified using either Input/Output operations
directly with the *inputs*/*outputs* parameters, or using signals with the
*input_signals*/*output_signals parameters*. If signals are used, the
corresponding Input/Output operations will be created automatically.
The *id_number_offset* parameter specifies what number graph IDs will be
offset by for each new graph component type. IDs start at 1 by default,
so the default offset of 0 will result in IDs like "c1", "c2", etc.
while an offset of 3 will result in "c4", "c5", etc.
Parameters
----------
inputs : array of Input, optional
outputs : array of Output, optional
input_signals : array of Signal, optional
output_signals : array of Signal, optional
id_number_offset : GraphIDNumber, optional
name : Name, optional
input_sources :
"""
_components_by_id: Dict[GraphID, GraphComponent]
......@@ -110,20 +137,6 @@ class SFG(AbstractOperation):
Sequence[Optional[SignalSourceProvider]]
] = None,
):
"""
Construct an SFG given its inputs and outputs.
Inputs/outputs may be specified using either Input/Output operations
directly with the inputs/outputs parameters, or using signals with the
input_signals/output_signals parameters. If signals are used, the
corresponding Input/Output operations will be created automatically.
The id_number_offset parameter specifies what number graph IDs will be
offset by for each new graph component type. IDs start at 1 by default,
so the default offset of 0 will result in IDs like "c1", "c2", etc.
while an offset of 3 will result in "c4", "c5", etc.
"""
input_signal_count = 0 if input_signals is None else len(input_signals)
input_operation_count = 0 if inputs is None else len(inputs)
output_signal_count = (
......@@ -181,10 +194,11 @@ class SFG(AbstractOperation):
Input, self._add_component_unconnected_copy(input_op)
)
for signal in input_op.output(0).signals:
assert signal not in self._original_components_to_new, (
"Duplicate input signals connected to input ports"
" supplied to SFG constructor."
)
if signal in self._original_components_to_new:
raise ValueError(
"Duplicate input signals connected to input ports"
" supplied to SFG constructor."
)
new_signal = cast(
Signal, self._add_component_unconnected_copy(signal)
)
......@@ -311,7 +325,7 @@ class SFG(AbstractOperation):
)
def __str__(self) -> str:
"""Get a string representation of this SFG."""
"""Return a string representation of this SFG."""
string_io = StringIO()
string_io.write(super().__str__() + "\n")
string_io.write("Internal Operations:\n")
......@@ -329,7 +343,7 @@ class SFG(AbstractOperation):
self, *src: Optional[SignalSourceProvider], name: Name = Name("")
) -> "SFG":
"""
Get a new independent SFG instance that is identical to this SFG
Return a new independent SFG instance that is identical to this SFG
except without any of its external connections.
"""
return SFG(
......@@ -342,6 +356,7 @@ class SFG(AbstractOperation):
@classmethod
def type_name(cls) -> TypeName:
# doc-string inherited.
return TypeName("sfg")
def evaluate(self, *args):
......@@ -359,6 +374,7 @@ class SFG(AbstractOperation):
bits_override: Optional[int] = None,
truncate: bool = True,
) -> Number:
# doc-string inherited
if index < 0 or index >= self.output_count:
raise IndexError(
"Output index out of range (expected"
......@@ -450,7 +466,7 @@ class SFG(AbstractOperation):
):
src = output_operation.input(0).signals[0].source
if src is None:
raise ValueError("Missing soruce in signal.")
raise ValueError("Missing source in signal.")
src.clear()
output_port.signals[0].set_source(src)
return True
......@@ -476,6 +492,18 @@ class SFG(AbstractOperation):
return self
def inputs_required_for_output(self, output_index: int) -> Iterable[int]:
"""
Return which inputs that the output depends on.
Parameters
----------
output_index : int
The output index.
Returns
-------
A list of inputs that are required to compute the output with the given *output_index*.
"""
if output_index < 0 or output_index >= self.output_count:
raise IndexError(
"Output index out of range (expected"
......@@ -521,7 +549,8 @@ class SFG(AbstractOperation):
@property
def id_number_offset(self) -> GraphIDNumber:
"""Get the graph id number offset of the graph id generator for this SFG.
"""
Get the graph id number offset of the graph id generator for this SFG.
"""
return self._graph_id_generator.id_number_offset
......@@ -555,7 +584,8 @@ class SFG(AbstractOperation):
return components
def find_by_id(self, graph_id: GraphID) -> Optional[GraphComponent]:
"""Find the graph component with the specified ID.
"""
Find the graph component with the specified ID.
Returns None if the component was not found.
Parameters
......@@ -567,7 +597,8 @@ class SFG(AbstractOperation):
return self._components_by_id.get(graph_id, None)
def find_by_name(self, name: Name) -> Sequence[GraphComponent]:
"""Find all graph components with the specified name.
"""
Find all graph components with the specified name.
Returns an empty sequence if no components were found.
Parameters
......@@ -581,7 +612,8 @@ class SFG(AbstractOperation):
def find_result_keys_by_name(
self, name: Name, output_index: int = 0
) -> Sequence[ResultKey]:
"""Find all graph components with the specified name and
"""
Find all graph components with the specified name and
return a sequence of the keys to use when fetching their results
from a simulation.
......@@ -609,22 +641,25 @@ class SFG(AbstractOperation):
Parameters
==========
component : The new component(s), e.g. Multiplication
graph_id : The GraphID to match the component to replace.
component : Operation
The new component(s), e.g. Multiplication
graph_id : GraphID
The GraphID to match the component to replace.
"""
sfg_copy = self() # Copy to not mess with this SFG.
component_copy = sfg_copy.find_by_id(graph_id)
assert component_copy is not None and isinstance(
component_copy, Operation
), "No operation matching the criteria found"
assert (
component_copy.output_count == component.output_count
), "The output count may not differ between the operations"
assert (
component_copy.input_count == component.input_count
), "The input count may not differ between the operations"
if component_copy is None or not isinstance(component_copy, Operation):
raise ValueError("No operation matching the criteria found")
if component_copy.output_count != component.output_count:
raise TypeError(
"The output count may not differ between the operations"
)
if component_copy.input_count != component.input_count:
raise TypeError(
"The input count may not differ between the operations"
)
for index_in, inp in enumerate(component_copy.inputs):
for signal in inp.signals:
......@@ -650,8 +685,10 @@ class SFG(AbstractOperation):
Parameters
==========
component : The new component, e.g. Multiplication.
output_comp_id : The source operation GraphID to connect from.
component : Operation
The new component, e.g. Multiplication.
output_comp_id : GraphID
The source operation GraphID to connect from.
"""
# Preserve the original SFG by creating a copy.
......@@ -668,10 +705,11 @@ class SFG(AbstractOperation):
f" ({len(output_comp.output_signals)}) does not match input"
f" count for component ({component.input_count})."
)
assert len(output_comp.output_signals) == component.output_count, (
"Destination operation input count does not match output for"
" component."
)
if len(output_comp.output_signals) != component.output_count:
raise TypeError(
"Destination operation input count does not match output for"
" component."
)
for index, signal_in in enumerate(output_comp.output_signals):
destination = cast(InputPort, signal_in.destination)
......@@ -682,9 +720,17 @@ class SFG(AbstractOperation):
return sfg_copy()
def remove_operation(self, operation_id: GraphID) -> Union["SFG", None]:
"""Returns a version of the SFG where the operation with the specified GraphID removed.
"""
Returns a version of the SFG where the operation with the specified GraphID removed.
The operation has to have the same amount of input- and output ports or a ValueError will
be raised. If no operation with the entered operation_id is found then returns None and does nothing.
Parameters
==========
operation_id : GraphID
The GraphID of the operation to remove.
"""
sfg_copy = self()
operation = cast(Operation, sfg_copy.find_by_id(operation_id))
......@@ -720,9 +766,12 @@ class SFG(AbstractOperation):
return sfg_copy()
def get_precedence_list(self) -> Sequence[Sequence[OutputPort]]:
"""Returns a Precedence list of the SFG where each element in n:th the list consists
of elements that are executed in the n:th step. If the precedence list already has been
calculated for the current SFG then returns the cached version."""
"""
Returns a precedence list of the SFG where each element in n:th the
list consists of elements that are executed in the n:th step. If the
precedence list already has been calculated for the current SFG then
return the cached version.
"""
if self._precedence_list:
return self._precedence_list
......@@ -745,7 +794,7 @@ class SFG(AbstractOperation):
return self._precedence_list
def show_precedence_graph(self) -> None:
def show(self) -> None:
self.precedence_graph().view()
def precedence_graph(self) -> Digraph:
......@@ -793,9 +842,12 @@ class SFG(AbstractOperation):
return pg
def print_precedence_graph(self) -> None:
"""Prints a representation of the SFG's precedence list to the standard out.
If the precedence list already has been calculated then it uses the cached version,
otherwise it calculates the precedence list and then prints it."""
"""
Print a representation of the SFG's precedence list to the standard out.
If the precedence list already has been calculated then it uses the
cached version, otherwise it calculates the precedence list and then
prints it.
"""
precedence_list = self.get_precedence_list()
line = "-" * 120
......@@ -822,9 +874,11 @@ class SFG(AbstractOperation):
print(out_str.getvalue())
def get_operations_topological_order(self) -> Iterable[Operation]:
"""Returns an Iterable of the Operations in the SFG in Topological Order.
Feedback loops makes an absolutely correct Topological order impossible, so an
approximate Topological Order is returned in such cases in this implementation.
"""
Return an Iterable of the Operations in the SFG in topological order.
Feedback loops makes an absolutely correct topological order impossible,
so an approximate topological Order is returned in such cases in this
implementation.
"""
if self._operations_topological_order:
return self._operations_topological_order
......@@ -841,9 +895,8 @@ class SFG(AbstractOperation):
seen = set()
top_order = []
assert (
len(no_inputs_queue) > 0
), "Illegal SFG state, dangling signals in SFG."
if len(no_inputs_queue) == 0:
raise ValueError("Illegal SFG state, dangling signals in SFG.")
first_op = no_inputs_queue.popleft()
visited = {first_op}
......@@ -930,14 +983,32 @@ class SFG(AbstractOperation):
return self._operations_topological_order
def set_latency_of_type(self, type_name: TypeName, latency: int) -> None:
"""Set the latency of all components with the given type name."""
"""
Set the latency of all components with the given type name.
Parameters
----------
type_name : TypeName
The type name of the operation. For example, obtained as ``Addition.type_name()``.
latency : int
The latency of the operation.
"""
for op in self.find_by_type_name(type_name):
cast(Operation, op).set_latency(latency)
def set_execution_time_of_type(
self, type_name: TypeName, execution_time: int
) -> None:
"""Set the execution time of all components with the given type name.
"""
Set the execution time of all operations with the given type name.
Parameters
----------
type_name : TypeName
The type name of the operation. For example, obtained as ``Addition.type_name()``.
execution_time : int
The execution time of the operation.
"""
for op in self.find_by_type_name(type_name):
cast(Operation, op).execution_time = execution_time
......@@ -945,7 +1016,15 @@ class SFG(AbstractOperation):
def set_latency_offsets_of_type(
self, type_name: TypeName, latency_offsets: Dict[str, int]
) -> None:
"""Set the latency offset of all components with the given type name.
"""
Set the latency offsets of all operations with the given type name.
Parameters
----------
type_name : TypeName
The type name of the operation. For example, obtained as ``Addition.type_name()``.
latency_offsets : {"in1": int, ...}
The latency offsets of the inputs and outputs.
"""
for op in self.find_by_type_name(type_name):
cast(Operation, op).set_latency_offsets(latency_offsets)
......@@ -987,9 +1066,8 @@ class SFG(AbstractOperation):
def _add_component_unconnected_copy(
self, original_component: GraphComponent
) -> GraphComponent:
assert (
original_component not in self._original_components_to_new
), "Tried to add duplicate SFG component"
if original_component in self._original_components_to_new:
raise ValueError("Tried to add duplicate SFG component")
new_component = original_component.copy_component()
self._original_components_to_new[original_component] = new_component
if (
......@@ -1141,7 +1219,8 @@ class SFG(AbstractOperation):
):
if original_signal.source is None:
raise ValueError(
"Dangling signal without source in SFG"
"Dangling signal ({original_signal}) without"
" source in SFG"
)
new_signal = cast(
......@@ -1158,10 +1237,17 @@ class SFG(AbstractOperation):
original_destination = cast(
InputPort, original_signal.destination
)
if original_destination is None:
raise ValueError(
f"Signal ({original_signal}) without"
" destination in SFG"
)
original_connected_op = original_destination.operation
if original_connected_op is None:
raise ValueError(
"Signal without destination in SFG"
"Signal with empty destination port"
f" ({original_destination}) in SFG"
)
# Check if connected operation has been added.
if (
......
"""
B-ASIC signal generators
These can be used as input to Simulation to algorithmically provide signal values.
"""
from math import pi, sin
from numbers import Number
from typing import Callable, Sequence
class SignalGenerator:
"""
Base class for signal generators.
Handles operator overloading and defined the ``__call__`` method that should be overridden.
"""
def __call__(self, time: int) -> complex:
raise NotImplementedError
def __add__(self, other) -> "AddGenerator":
if isinstance(other, Number):
return AddGenerator(self, Constant(other))
return AddGenerator(self, other)
def __radd__(self, other) -> "AddGenerator":
if isinstance(other, Number):
return AddGenerator(self, Constant(other))
return AddGenerator(self, other)
def __sub__(self, other) -> "SubGenerator":
if isinstance(other, Number):
return SubGenerator(self, Constant(other))
return SubGenerator(self, other)
def __rsub__(self, other) -> "SubGenerator":
if isinstance(other, Number):
return SubGenerator(Constant(other), self)
return SubGenerator(other, self)
def __mul__(self, other) -> "MulGenerator":
if isinstance(other, Number):
return MultGenerator(self, Constant(other))
return MultGenerator(self, other)
def __rmul__(self, other) -> "MulGenerator":
if isinstance(other, Number):
return MultGenerator(self, Constant(other))
return MultGenerator(self, other)
class Impulse(SignalGenerator):
"""
Signal generator that creates an impulse at a given delay.
Parameters
----------
delay : int, default: 0
The delay before the signal goes to 1 for one sample.
"""
def __init__(self, delay: int = 0) -> Callable[[int], complex]:
self._delay = delay
def __call__(self, time: int) -> complex:
return 1 if time == self._delay else 0
class Step(SignalGenerator):
"""
Signal generator that creates a step at a given delay.
Parameters
----------
delay : int, default: 0
The delay before the signal goes to 1.
"""
def __init__(self, delay: int = 0) -> Callable[[int], complex]:
self._delay = delay
def __call__(self, time: int) -> complex:
return 1 if time >= self._delay else 0
class Constant(SignalGenerator):
"""
Signal generator that outputs a constant value.
Parameters
----------
constant : complex, default: 1.0
The constant.
"""
def __init__(self, constant: complex = 1.0) -> Callable[[int], complex]:
self._constant = constant
def __call__(self, time: int) -> complex:
return self._constant
class ZeroPad(SignalGenerator):
"""
Signal generator that pads a sequence with zeros.
Parameters
----------
data : 1-D array
The data that should be padded.
"""
def __init__(self, data: Sequence[complex]) -> Callable[[int], complex]:
self._data = data
self._len = len(data)
def __call__(self, time: int) -> complex:
if 0 <= time < self._len:
return self._data[time]
return 0.0
class Sinusoid(SignalGenerator):
"""
Signal generator that generates a sinusoid.
Parameters
----------
frequency : float
The normalized frequency of the sinusoid. Should normally be in the
interval [0, 1], where 1 corresponds to half the sample rate.
phase : float, default: 0
The normalized phase offset.
"""
def __init__(
self, frequency: float, phase: float = 0.0
) -> Callable[[int], complex]:
self._frequency = frequency
self._phase = phase
def __call__(self, time: int) -> complex:
return sin(pi * (self._frequency * time + self._phase))
class AddGenerator:
"""
Signal generator that adds two signals.
"""
def __init__(
self, a: SignalGenerator, b: SignalGenerator
) -> Callable[[int], complex]:
self._a = a
self._b = b
def __call__(self, time: int) -> complex:
return self._a(time) + self._b(time)
class SubGenerator:
"""
Signal generator that subtracts two signals.
"""
def __init__(
self, a: SignalGenerator, b: SignalGenerator
) -> Callable[[int], complex]:
self._a = a
self._b = b
def __call__(self, time: int) -> complex:
return self._a(time) - self._b(time)
class MultGenerator:
"""
Signal generator that multiplies two signals.
"""
def __init__(
self, a: SignalGenerator, b: SignalGenerator
) -> Callable[[int], complex]:
self._a = a
self._b = b
def __call__(self, time: int) -> complex:
return self._a(time) * self._b(time)
docs_sphinx/_static/icon_logo.png

2.25 KiB

......@@ -11,7 +11,9 @@ API
port.rst
process.rst
schedule.rst
sfg_generator.rst
signal.rst
signal_flow_graph.rst
signal_generator.rst
simulation.rst
special_operations.rst
************************
``b_asic.sfg_generator``
************************
.. automodule:: b_asic.sfg_generator
:members:
***************************
``b_asic.signal_generator``
***************************
.. automodule:: b_asic.signal_generator
:members:
......@@ -22,7 +22,8 @@ extensions = [
'sphinx.ext.autosummary',
'sphinx.ext.inheritance_diagram',
'sphinx.ext.intersphinx',
'numpydoc',
'sphinx_gallery.gen_gallery',
'numpydoc', # Needs to be loaded *after* autodoc.
]
templates_path = ['_templates']
......@@ -45,8 +46,20 @@ inheritance_node_attrs = dict(fontsize=16)
graphviz_dot = shutil.which('dot')
html_favicon = '_static/icon_logo.png'
# -- Options for HTML output -------------------------------------------------
# https://www.sphinx-doc.org/en/master/usage/configuration.html#options-for-html-output
html_theme = 'furo'
html_static_path = ['_static']
# -- Options for sphinx-gallery --
sphinx_gallery_conf = {
'examples_dirs': '../examples', # path to your example scripts
'gallery_dirs': 'examples', # path to where to save gallery generated output
'plot_gallery': 'True', # sphinx-gallery/913
'filename_pattern': '.',
'doc_module': ('b_asic',),
'reference_url': {'b_asic': None},
}
......@@ -22,9 +22,10 @@ Indices and tables
Table of Contents
^^^^^^^^^^^^^^^^^
.. toctree::
:maxdepth: 2
:maxdepth: 1
self
api/index
GUI
scheduler_gui
examples/index
.. _examples:
===============
B-ASIC Examples
===============
These are examples of how B-ASIC can be used.
"""
======================================
First-order IIR Filter with Simulation
======================================
In this example, a direct form first-order IIR filter is designed.
First, we need to import the operations that will be used in the example:
"""
from b_asic.core_operations import Addition, ConstantMultiplication
from b_asic.special_operations import Delay, Input, Output
# %%
# Then, we continue by defining the input and delay element, which we can optionally name.
input = Input(name="My input")
delay = Delay(name="The only delay")
# %%
# There are a few ways to connect signals. Either explicitly, by instantiating them:
a1 = ConstantMultiplication(0.5, delay)
# %%
# By operator overloading:
first_addition = a1 + input
# %%
# Or by creating them, but connecting the input later. Each operation has a function :func:`~b_asic.operation.Operation.input`
# that is used to access a specific input (or output, by using :func:`~b_asic.operation.Operation.output`).
b1 = ConstantMultiplication(0.7)
b1.input(0).connect(delay)
# %%
# The latter is useful when there is not a single order to create the signal flow graph, e.g., for recursive algorithms.
# In this example, we could not connect the output of the delay as that was not yet available.
#
# There is also a shorthand form to connect signals using the ``<<`` operator:
delay << first_addition
# %%
# Naturally, it is also possible to write expressions when instantiating operations:
output = Output(b1 + first_addition)
# %%
# Now, we should create a signal flow graph, but first it must be imported (normally, this should go at the top of the file).
from b_asic.signal_flow_graph import SFG
# %%
# The signal flow graph is defined by its inputs and outputs, so these must be provided. As, in general, there can be
# multiple inputs and outputs, there should be provided as a list or a tuple.
firstorderiir = SFG([input], [output])
# %%
# If this is executed in an enriched terminal, such as a Jupyter Notebook, Jupyter QtConsole, or Spyder, just typing
# the variable name will return a graphical representation of the signal flow graph.
firstorderiir
# %%
# For now, we can print the precendence relations of the SFG
firstorderiir.print_precedence_graph()
# %%
# As seen, each operation has an id, in addition to the optional name. This can be used to access the operation.
# For example,
firstorderiir.find_by_id('cmul1')
# %%
# Note that this operation differs from ``a1`` defined above as the operations are copied and recreated once inserted
# into a signal flow graph.
#
# The signal flow graph can also be simulated. For this, we must import :class:`.Simulation`.
from b_asic.simulation import Simulation
# %%
# The :class:`.Simulation` class require that we provide inputs. These can either be arrays of values or we can use functions
# that provides the values when provided a time index.
#
# Let us create a simulation that simulates a short impulse response:
sim = Simulation(firstorderiir, [[1, 0, 0, 0, 0]])
# %%
# To run the simulation for all input samples, we do:
sim.run()
# %%
# The returned value is the output after the final iteration. However, we may often be interested in the results from
# the whole simulation.
# The results from the simulation, which is a dictionary of all the nodes in the signal flow graph,
# can be obtained as
sim.results
# %%
# Hence, we can obtain the results that we are interested in and, for example, plot the output and the value after the
# first addition:
import matplotlib.pyplot as plt
plt.plot(sim.results['0'], label="Output")
plt.plot(sim.results['add1'], label="After first addition")
plt.legend()
plt.show()
# %%
# To compute and plot the frequency response, it is possible to use SciPy and NumPy as
import numpy as np
import scipy.signal
w, h = scipy.signal.freqz(sim.results['0'])
plt.plot(w, 20 * np.log10(np.abs(h)))
plt.show()
# %%
# As seen, the output has not converged to zero, leading to that the frequency-response may not be correct, so we want
# to simulate for a longer time.
# Instead of just adding zeros to the input array, we can use a function that generates the impulse response instead.
# There are a number of those defined in B-ASIC for convenience, and the one for an impulse response is called :class:`.Impulse`.
from b_asic.signal_generator import Impulse
sim = Simulation(firstorderiir, [Impulse()])
# %%
# Now, as the functions will not have an end, we must run the simulation for a given number of cycles, say 30.
# This is done using :func:`~b_asic.simulation.Simulation.run_for` instead:
sim.run_for(30)
# %%
# Now, plotting the impulse results gives:
plt.plot(sim.results['0'])
plt.show()
# %%
# And the frequency-response:
w, h = scipy.signal.freqz(sim.results['0'])
plt.plot(w, 20 * np.log10(np.abs(h)))
plt.show()
"""A sfg with delays and interesting layout for precedence list generation.
. .
IN1>--->C0>--->ADD1>----------+--->A0>--->ADD4>--->OUT1
. ^ | ^ .
. | T1 | .
. | | | .
. ADD2<---<B1<---+--->A1>--->ADD3 .
. ^ | ^ .
. | T2 | .
. | | | .
. +-----<B2<---+--->A2>-----+ .
"""
=====================================
Second-order IIR Filter with Schedule
=====================================
"""
from b_asic.core_operations import Addition, ConstantMultiplication
......@@ -37,10 +31,15 @@ sfg = SFG(
inputs=[in1], outputs=[out1], name="Second-order direct form IIR filter"
)
# Set latencies and exection times
# %%
# Set latencies and execution times
sfg.set_latency_of_type(ConstantMultiplication.type_name(), 2)
sfg.set_latency_of_type(Addition.type_name(), 1)
sfg.set_execution_time_of_type(ConstantMultiplication.type_name(), 1)
sfg.set_execution_time_of_type(Addition.type_name(), 1)
# %%
# Create schedule
schedule = Schedule(sfg, cyclic=True)
schedule.plot()
"""
=============================
Third-order Bireciprocal LWDF
=============================
Small bireciprocal lattice wave digital filter.
"""
from b_asic.core_operations import Addition, SymmetricTwoportAdaptor
......
"""Three-point Winograd DFT.
"""
========================
Three-point Winograd DFT
========================
"""
from math import cos, pi, sin
......@@ -38,7 +41,8 @@ sfg = SFG(
name="3-point Winograd DFT",
)
# Set latencies and exection times
# %%
# Set latencies and execution times
sfg.set_latency_of_type(ConstantMultiplication.type_name(), 2)
sfg.set_latency_of_type(Addition.type_name(), 1)
sfg.set_latency_of_type(Subtraction.type_name(), 1)
......@@ -46,4 +50,7 @@ sfg.set_execution_time_of_type(ConstantMultiplication.type_name(), 1)
sfg.set_execution_time_of_type(Addition.type_name(), 1)
sfg.set_execution_time_of_type(Subtraction.type_name(), 1)
# %%
# Generate schedule
schedule = Schedule(sfg, cyclic=True)
schedule.plot()
"""
B-ASIC automatically generated SFG file.
Name: twotapfir
Last saved: 2023-01-24 14:38:17.654639.
==================
Two-tap FIR filter
==================
"""
from b_asic import (
SFG,
......
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<!-- Created with Inkscape (http://www.inkscape.org/) -->
<svg
width="157.537mm"
height="157.537mm"
viewBox="0 0 157.53701 157.537"
version="1.1"
id="svg3487"
inkscape:version="1.2.2 (b0a8486541, 2022-12-01)"
sodipodi:docname="logo.svg"
inkscape:export-filename="icon_logo.png"
inkscape:export-xdpi="5.1594224"
inkscape:export-ydpi="5.1594224"
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
xmlns="http://www.w3.org/2000/svg"
xmlns:svg="http://www.w3.org/2000/svg">
<sodipodi:namedview
id="namedview3489"
pagecolor="#ffffff"
bordercolor="#000000"
borderopacity="0.25"
inkscape:showpageshadow="2"
inkscape:pageopacity="0.0"
inkscape:pagecheckerboard="0"
inkscape:deskcolor="#d1d1d1"
inkscape:document-units="mm"
showgrid="false"
inkscape:zoom="0.4204826"
inkscape:cx="511.31723"
inkscape:cy="709.89857"
inkscape:window-width="1200"
inkscape:window-height="1896"
inkscape:window-x="1200"
inkscape:window-y="0"
inkscape:window-maximized="1"
inkscape:current-layer="layer1" />
<defs
id="defs3484" />
<g
inkscape:label="Lager 1"
inkscape:groupmode="layer"
id="layer1"
transform="translate(-21.895662,-54.322404)">
<path
style="fill:#b0b9ca;fill-opacity:1;stroke-width:0.352777"
d="m 82.14063,206.24136 c -2.498006,-2.15844 -2.668728,-1.68551 2.645854,-7.32951 l 4.780105,-5.0764 -2.388803,-2.19538 c -1.313839,-1.20746 -2.547549,-2.18742 -2.741578,-2.17768 -0.194027,0.01 -1.940277,1.8433 -3.880554,4.07458 -1.94028,2.23129 -3.98757,4.51419 -4.549542,5.0731 -1.018064,1.01253 -1.024845,1.01379 -1.873028,0.34661 -0.468196,-0.36829 -1.163931,-1.0671 -1.546077,-1.55292 l -0.694806,-0.8833 3.432712,-3.63556 c 1.88799,-1.99956 4.070083,-4.31159 4.84909,-5.13786 l 1.416375,-1.5023 -2.627397,-2.64505 c -1.445067,-1.45477 -2.71867,-2.60436 -2.830229,-2.55464 -0.111556,0.0497 -1.677715,1.75728 -3.48035,3.79457 -1.802636,2.03729 -3.914831,4.37648 -4.693764,5.19819 l -1.416246,1.49402 -0.863621,-0.67933 c -0.474991,-0.37362 -1.172626,-1.07216 -1.550294,-1.55229 l -0.686676,-0.87296 3.618039,-3.83206 c 1.989921,-2.10764 4.12573,-4.47511 4.746247,-5.26104 l 1.12821,-1.42897 -2.362931,-2.32345 -2.362935,-2.32344 -3.880554,4.43167 c -2.134306,2.43741 -4.265062,4.79512 -4.735012,5.23935 -0.842283,0.79617 -0.866455,0.79825 -1.696638,0.14522 -0.463206,-0.36435 -1.152724,-1.05724 -1.532263,-1.53975 l -0.690078,-0.87729 3.447351,-3.64157 c 3.840969,-4.05738 5.854218,-6.50591 5.677083,-6.90455 -0.203187,-0.45727 -4.877052,-4.79661 -5.001639,-4.64366 -0.683196,0.83873 -6.983264,7.90587 -8.06582,9.04788 l -1.416246,1.49402 -0.863621,-0.67933 c -0.47499,-0.37363 -1.172625,-1.07216 -1.550294,-1.55229 l -0.686676,-0.87297 3.731728,-3.99867 c 2.05245,-2.19927 4.307163,-4.51879 5.010476,-5.15449 l 1.278742,-1.15581 -2.441308,-2.46016 c -1.342718,-1.35309 -2.612067,-2.46016 -2.820776,-2.46016 -0.401272,0 -5.28383,4.84859 -7.278918,7.22828 -0.648988,0.7741 -1.493927,1.67001 -1.877642,1.99092 -0.651192,0.54459 -0.752456,0.54036 -1.52025,-0.0636 -0.452425,-0.35588 -1.137934,-1.04794 -1.523355,-1.53793 l -0.700762,-0.89087 4.832067,-4.97571 4.832069,-4.97572 -2.237443,-2.25751 -2.237444,-2.25751 -1.78472,1.66496 c -0.981597,0.91573 -2.737221,2.75027 -3.901387,4.07676 -1.164167,1.3265 -2.576463,2.86756 -3.138432,3.42458 -1.017945,1.009 -1.024943,1.01028 -1.873028,0.34317 -0.468196,-0.36828 -1.163069,-1.06599 -1.544161,-1.55048 l -0.692896,-0.88087 3.137955,-3.28521 c 1.725875,-1.80687 3.849698,-4.15685 4.719606,-5.22219 l 1.58165,-1.93698 -2.302359,-2.13878 -2.302362,-2.13879 -3.14865,3.5466 c -1.731759,1.95062 -3.785963,4.2189 -4.564896,5.04062 l -1.416245,1.49402 -0.863621,-0.67933 c -0.474991,-0.37362 -1.170356,-1.06926 -1.545252,-1.54587 l -0.681633,-0.86655 4.581393,-4.88703 c 2.519767,-2.68787 4.582178,-4.97579 4.583133,-5.08427 0.0011,-0.10847 -1.254601,-1.33716 -2.790129,-2.73042 -1.535528,-1.39327 -3.535515,-3.40365 -4.444417,-4.46753 l -1.652548,-1.93433 3.474278,-3.73217 c 1.910855,-2.0527 3.521162,-3.86451 3.578463,-4.02626 0.0573,-0.16175 -0.887725,-1.22501 -2.100056,-2.3628 -2.487343,-2.33439 -7.126674,-7.12273 -7.271893,-7.50544 -0.10654,-0.28078 2.36895,-2.85354 2.745653,-2.85354 0.131704,0 2.413963,2.17451 5.071686,4.83223 l 4.832223,4.83222 2.356318,-2.35632 2.356319,-2.35631 -5.014267,-4.98183 -5.01427,-4.98183 0.681522,-0.86641 c 0.374838,-0.47653 1.067382,-1.16994 1.538991,-1.5409 l 0.857467,-0.67449 5.0858,5.10011 5.085799,5.10011 2.765759,-2.78208 2.765761,-2.78208 -0.800489,-0.65246 c -2.22757,-1.81564 -5.760284,-5.12456 -7.556548,-7.077845 -1.998287,-2.17296 -2.01041,-2.19924 -1.392354,-3.01862 0.342919,-0.45461 0.996008,-1.10757 1.451317,-1.45101 l 0.827831,-0.62443 5.150765,4.99486 5.150768,4.994855 2.252602,-2.23258 c 1.238932,-1.227925 2.208815,-2.417835 2.155301,-2.644245 -0.05351,-0.22642 -1.313813,-1.49695 -2.800665,-2.82339 -1.486847,-1.32645 -3.664347,-3.46214 -4.838888,-4.74598 l -2.135526,-2.33426 1.281713,-1.28172 c 0.704943,-0.70494 1.430372,-1.28171 1.612067,-1.28171 0.181694,0 2.563614,2.15163 5.293156,4.78141 l 4.9628,4.78141 2.409161,-2.3907 c 1.325038,-1.31488 2.409158,-2.5543 2.409158,-2.75425 0,-0.19996 -1.230313,-1.4544 -2.734027,-2.78766 -1.503714,-1.33326 -3.736094,-3.51221 -4.960834,-4.84212 -2.205882,-2.395282 -2.220992,-2.425725 -1.607513,-3.239031 0.340616,-0.451562 0.992452,-1.102492 1.44853,-1.446511 0.825299,-0.622525 0.841274,-0.61413 3.371397,1.771359 1.398194,1.318268 3.645988,3.593123 4.995098,5.055223 1.349111,1.4621 2.542532,2.69899 2.652049,2.74864 0.109519,0.0496 1.423048,-1.14098 2.918957,-2.64584 l 2.719832,-2.7361 -2.902437,-2.614781 c -1.596345,-1.438129 -3.834619,-3.626731 -4.973952,-4.863555 -2.060567,-2.236896 -2.06802,-2.252824 -1.41111,-3.01633 0.967721,-1.124751 2.022189,-2.003807 2.419723,-2.017206 0.191516,-0.0065 2.496719,2.132659 5.122672,4.753586 l 4.774459,4.765323 2.240438,-2.260534 2.240442,-2.260534 -2.247837,-2.057711 c -1.236305,-1.131741 -3.46207,-3.325851 -4.946144,-4.8758 l -2.698311,-2.81809 0.648896,-0.824934 c 0.356891,-0.453715 1.075873,-1.160798 1.597737,-1.571296 l 0.948846,-0.746362 4.874072,4.940307 4.874072,4.940307 2.286664,-2.320916 2.286661,-2.320916 -2.424157,-2.116666 c -1.333288,-1.164167 -3.473725,-3.265928 -4.756528,-4.67058 -2.308305,-2.527564 -2.326005,-2.562346 -1.715733,-3.371399 0.339145,-0.449618 0.993174,-1.101515 1.453398,-1.448662 0.834583,-0.629528 0.842905,-0.625333 3.189208,1.60751 1.293842,1.231277 3.440491,3.403018 4.770327,4.826091 l 2.417884,2.587406 5.069604,-5.026394 5.069606,-5.026395 5.09037,4.820264 5.09036,4.820263 3.07782,-3.439608 c 1.69278,-1.891784 3.71271,-4.111917 4.48873,-4.933629 l 1.41092,-1.49402 0.86362,0.679324 c 0.47498,0.373629 1.17264,1.072159 1.5503,1.55229 l 0.68668,0.872965 -3.73709,3.998676 c -2.05538,2.199272 -4.14477,4.369488 -4.64303,4.822704 l -0.90599,0.82403 2.45949,2.459485 2.45948,2.459486 3.27954,-3.636293 c 1.80374,-1.999961 3.91432,-4.308602 4.69021,-5.130313 l 1.41068,-1.494021 0.86363,0.679325 c 0.47498,0.373628 1.17155,1.070811 1.54792,1.549295 l 0.68432,0.869971 -3.87877,4.121514 c -2.13333,2.266833 -4.18838,4.556314 -4.56679,5.087736 l -0.68802,0.966221 2.56453,2.547417 2.56455,2.547417 3.27695,-3.633481 c 1.80234,-1.998418 3.91178,-4.305793 4.68767,-5.127505 l 1.41068,-1.49402 0.86363,0.679324 c 0.47498,0.373628 1.1726,1.072159 1.55027,1.55229 l 0.68667,0.872965 -3.6576,3.870263 c -2.01168,2.128644 -4.11099,4.464682 -4.6651,5.191196 l -1.00754,1.32094 2.203,2.07067 c 1.21166,1.13887 2.33294,2.07067 2.49174,2.07067 0.15881,0 1.67974,-1.54781 3.37984,-3.43958 1.70008,-1.89177 3.72674,-4.111895 4.50363,-4.933606 l 1.41256,-1.49402 0.86363,0.679325 c 0.47498,0.373627 1.17036,1.069275 1.54524,1.545879 l 0.68165,0.866555 -4.58139,4.887027 c -2.51979,2.68787 -4.58219,4.97067 -4.58314,5.07288 0,0.10222 1.07513,1.25447 2.3913,2.56056 l 2.39303,2.3747 3.04212,-3.08972 c 1.6732,-1.69934 3.57288,-3.72307 4.22156,-4.49717 0.64868,-0.77409 1.49336,-1.67001 1.87706,-1.99091 0.6512,-0.5446 0.75248,-0.54036 1.52027,0.0636 0.45241,0.35587 1.13311,1.04182 1.51265,1.52434 l 0.69009,0.87729 -3.44506,3.66692 c -1.89479,2.01681 -4.04874,4.36505 -4.78658,5.21831 l -1.34152,1.5514 2.72611,2.497705 2.72611,2.4977 3.14748,-3.54528 c 1.73109,-1.949905 3.78476,-4.217595 4.56369,-5.039305 l 1.41627,-1.49402 0.86362,0.67933 c 0.47498,0.37363 1.17261,1.07216 1.55028,1.55229 l 0.68667,0.87296 -3.73576,3.998685 c -2.05465,2.19927 -4.1811,4.41727 -4.72543,4.92889 l -0.9897,0.93022 2.36834,2.35019 2.36834,2.35018 3.27667,-3.63318 c 1.80219,-1.99825 3.9115,-4.30549 4.68739,-5.1272 l 1.41068,-1.49403 0.86363,0.67933 c 0.47498,0.37363 1.17628,1.07681 1.55842,1.56263 l 0.69482,0.88331 -3.27943,3.45916 c -4.41283,4.65473 -5.97704,6.45991 -5.84623,6.74688 0.0602,0.13204 1.08026,1.1567 2.26687,2.27703 l 2.15746,2.03696 3.08547,-3.44807 c 1.69701,-1.89644 3.72038,-4.12038 4.4964,-4.94209 l 1.41092,-1.49402 0.86363,0.67932 c 0.47498,0.37363 1.17036,1.06928 1.54524,1.54588 l 0.68165,0.86656 -4.58526,4.88702 -4.58525,4.88704 3.47819,3.35139 c 5.46674,5.26743 5.3635,4.22202 0.88778,8.98844 -2.10791,2.24484 -3.87945,4.2183 -3.93676,4.38547 -0.0573,0.16718 0.88773,1.23487 2.10007,2.37266 2.48733,2.3344 7.12666,7.12273 7.27189,7.50545 0.10652,0.28078 -2.36895,2.85353 -2.74566,2.85353 -0.13171,0 -2.41242,-2.17297 -5.06828,-4.82881 l -4.8288,-4.82882 -2.28127,2.26099 c -1.2547,1.24354 -2.28126,2.36599 -2.28126,2.49434 0,0.12834 1.06884,1.24418 2.37516,2.47963 1.30636,1.23545 3.5124,3.43278 4.90234,4.88294 l 2.52716,2.63667 -0.64804,0.82387 c -0.35645,0.45312 -1.03362,1.12715 -1.50487,1.49783 l -0.8568,0.67396 -4.95985,-4.97015 -4.95986,-4.97016 -0.99525,0.72003 c -0.5474,0.39601 -1.84812,1.59044 -2.89047,2.65429 l -1.89518,1.93426 0.79856,0.65082 c 2.23189,1.81894 5.76199,5.12682 7.57494,7.09812 2.02846,2.20561 2.03364,2.21688 1.37234,2.98528 -0.97128,1.12862 -2.0252,2.00754 -2.42326,2.02095 -0.19161,0.006 -2.5812,-2.21711 -5.31022,-4.94126 l -4.96186,-4.95299 -2.20776,2.15363 c -1.21428,1.1845 -2.15845,2.36776 -2.09812,2.62947 0.0603,0.26171 1.32617,1.56111 2.81302,2.88756 1.48683,1.32644 3.66435,3.46214 4.83889,4.74598 l 2.1355,2.33426 -1.28169,1.28171 c -0.70496,0.70494 -1.53527,1.28171 -1.84518,1.28171 -0.30991,0 -2.70129,-2.14224 -5.31421,-4.76052 l -4.75073,-4.76054 -2.3881,2.36982 c -1.31347,1.3034 -2.38813,2.53342 -2.38813,2.73338 0,0.19995 1.23032,1.4544 2.73402,2.78766 1.50373,1.33325 3.7361,3.5122 4.96083,4.84211 2.20589,2.39528 2.221,2.42573 1.60753,3.23903 -0.34062,0.45157 -0.9897,1.10041 -1.44237,1.44187 l -0.82307,0.62085 -5.17551,-4.97819 -5.17552,-4.9782 -2.66065,2.66067 -2.66067,2.66067 2.46562,2.1992 c 2.60287,2.32161 7.20151,7.00876 7.21826,7.35715 0.0135,0.28125 -2.51839,2.79282 -2.81541,2.79282 -0.13102,0 -2.36675,-2.13656 -4.96829,-4.74793 l -4.73004,-4.74792 -2.20487,2.18009 c -1.21267,1.19906 -2.20486,2.29102 -2.20486,2.42659 0,0.13556 0.91282,1.09185 2.02848,2.12507 1.11565,1.03322 3.24271,3.14478 4.72679,4.69235 l 2.6983,2.81378 -0.6489,0.82493 c -0.35689,0.45371 -1.03552,1.12906 -1.50807,1.50077 l -0.85921,0.67584 -4.9141,-4.9205 -4.91411,-4.9205 -2.25202,2.2722 -2.252,2.27221 4.65298,4.63497 c 2.55913,2.54924 4.65297,4.75033 4.65297,4.89133 0,0.42982 -2.58006,2.86531 -2.91656,2.75314 -0.17317,-0.0577 -2.36969,-2.15838 -4.88116,-4.66816 l -4.56634,-4.56321 -4.57468,4.56453 -4.57469,4.56454 -2.207858,-2.10687 c -1.214321,-1.15878 -3.330773,-3.18709 -4.703222,-4.50735 l -2.495371,-2.40048 -3.149073,3.46567 c -1.731994,1.90612 -3.553725,3.93807 -4.048292,4.51543 -0.494569,0.57737 -1.208944,1.31429 -1.5875,1.63761 -0.647012,0.5526 -0.741322,0.54202 -1.572754,-0.17639 z"
id="path2031" />
<path
style="fill:#f6ae4c;fill-opacity:1;stroke-width:0.338839"
d="m 30.869962,127.10635 c 1.91738,-1.93045 7.65701,-7.7218 12.75474,-12.86966 5.09772,-5.14787 11.9915,-12.0674 15.3195,-15.376743 6.00034,-5.96669 8.21611,-8.19314 26.45535,-26.58283 9.34029,-9.41735 15.119218,-15.03417 15.468398,-15.03448 0.35926,-2.5e-4 18.49982,17.65229 38.30197,37.27171 11.13387,11.031143 23.56788,23.337933 27.63113,27.348433 4.06324,4.01049 7.4543,7.35956 7.53567,7.44237 0.0814,0.0828 -1.54149,1.84291 -3.60636,3.91133 -2.06487,2.06842 -6.67978,6.69185 -10.25535,10.2743 -8.08571,8.10125 -16.8897,16.88055 -27.14929,27.07307 -4.34978,4.32136 -12.31311,12.29383 -17.69628,17.71666 -10.05033,10.12438 -14.41528,14.376 -14.75066,14.36769 -0.52694,-0.013 -73.215088,-71.07474 -73.420668,-71.77786 -0.0409,-0.13974 1.49447,-1.83354 3.41185,-3.76399 z m 3.01419,5.84984 c 0.37781,0.33278 0.68693,0.52983 0.68693,0.4379 0,-0.0919 -0.30912,-0.4394 -0.68693,-0.77217 -0.37781,-0.33277 -0.68693,-0.52982 -0.68693,-0.4379 0,0.0919 0.30912,0.4394 0.68693,0.77217 z"
id="path2029" />
<path
style="fill:#747982;fill-opacity:1;stroke-width:0.352777"
d="m 97.280673,201.07199 c -2.42535,-2.3785 -9.57247,-9.32206 -15.88251,-15.43013 -6.31003,-6.10807 -19.01003,-18.4117 -28.22222,-27.3414 -9.21219,-8.92971 -18.575055,-17.987 -20.806377,-20.12732 -2.231318,-2.14032 -4.99378,-4.87499 -6.138801,-6.07705 l -2.081858,-2.18554 4.900739,-5.02742 c 2.695406,-2.76507 9.18849,-9.22414 14.429079,-14.35349 5.240588,-5.12934 20.134678,-19.813728 33.097968,-32.631948 12.9633,-12.81823 23.705407,-23.30587 23.871337,-23.30587 0.26886,0 8.32393,7.78921 32.28682,31.22119 10.81754,10.57789 33.23058,32.384818 37.89579,36.870988 2.21602,2.13097 4.73702,4.62747 5.60224,5.54777 l 1.57313,1.67326 -5.5657,5.73507 c -3.06115,3.15429 -9.2416,9.30694 -13.73436,13.67257 -4.49278,4.36562 -19.0064,18.7325 -32.2525,31.92639 -13.24607,13.19389 -24.19163,24.02682 -24.32343,24.07318 -0.13179,0.0464 -2.224001,-1.86176 -4.649347,-4.24025 z m 7.376567,-2.89421 c 1.2082,-1.25822 2.09712,-2.44885 1.97537,-2.64584 -0.24862,-0.40227 -8.732647,-0.50708 -9.126987,-0.11274 -0.23415,0.23415 4.282797,5.04625 4.736747,5.04625 0.11997,0 1.20666,-1.02945 2.41487,-2.28767 z m -0.57766,-29.50442 c 7.19142,-0.50921 10.82473,-1.31116 14.42529,-3.18397 6.25467,-3.25335 10.25199,-8.93672 11.40325,-16.21308 1.046,-6.61111 -0.571,-11.29183 -5.6641,-16.39591 -2.35939,-2.36447 -3.49078,-3.17948 -6.61283,-4.76359 -2.07156,-1.0511 -3.72759,-2.01066 -3.68001,-2.13236 0.0475,-0.1217 1.41718,-1.22098 3.04368,-2.44284 4.52165,-3.39679 6.47846,-7.05265 6.50471,-12.15255 0.0262,-5.10709 -2.47468,-9.68301 -7.46766,-13.663458 -6.33007,-5.04639 -13.39624,-6.68251 -25.419777,-5.88576 -3.02626,0.20054 -5.60877,0.47427 -5.73891,0.6083 -0.75827,0.78092 -0.81366,75.491948 -0.0565,76.267308 0.29466,0.30175 6.82254,0.58165 10.52372,0.45123 1.94027,-0.0684 5.872897,-0.29037 8.739177,-0.49332 z m -7.035157,-11.48329 -1.47098,-0.15409 -0.23576,-2.53874 c -0.12967,-1.39631 -0.0966,-6.63611 0.0734,-11.64401 0.24919,-7.33857 0.40922,-9.1737 0.82479,-9.45793 0.30253,-0.20692 2.0932,-0.28808 4.333107,-0.19637 3.52025,0.14412 4.01956,0.25616 6.41264,1.43889 4.55428,2.25083 6.8647,5.14563 7.72639,9.68055 1.14806,6.04211 -2.34394,11.38792 -8.07876,12.3675 -2.61819,0.44723 -7.618011,0.71023 -9.584857,0.5042 z m -0.98119,-35.86026 c -0.65126,-0.48257 -0.68802,-0.99133 -0.68351,-9.45871 0.002,-4.92179 0.11913,-9.28865 0.25891,-9.70413 0.34702,-1.03148 1.74823,-1.17982 5.658417,-0.599 2.66669,0.39611 3.52576,0.6912 5.03282,1.72875 3.0288,2.08522 4.8054,5.28855 4.81881,8.68864 0.0109,2.71618 -1.69217,6.24427 -3.72448,7.71647 -1.77294,1.2843 -3.0571,1.61927 -7.3213,1.90971 -2.643487,0.18006 -3.496777,0.12055 -4.039667,-0.28173 z m 62.953547,-0.34975 c 0,-0.0607 -0.51594,-0.57665 -1.14652,-1.14653 l -1.14654,-1.03614 1.03616,1.14653 c 0.96581,1.06872 1.2569,1.30868 1.2569,1.03614 z"
id="path2027" />
<path
style="fill:#323740;fill-opacity:1;stroke-width:0.352777"
d="m 86.981226,181.26408 c -18.30762,-17.87367 -38.802529,-37.83992 -41.979675,-40.89683 -1.640697,-1.5786 -3.889973,-3.82279 -4.998389,-4.98709 l -2.015305,-2.1169 0.01765,-3.80223 c 0.0097,-2.09122 0.144259,-4.13328 0.299011,-4.53791 0.154752,-0.40462 1.84745,-2.25564 3.761552,-4.11337 13.944646,-13.53399 43.976356,-42.740064 48.489936,-47.156854 l 5.49865,-5.38073 h 4.831274 4.83126 l 23.0189,22.84236 c 12.66042,12.563294 25.83164,25.595454 29.2694,28.960354 l 6.25047,6.11799 v 3.52789 3.5279 l -19.66497,19.98745 c -21.88785,22.24676 -37.6155,37.84106 -38.78474,38.45588 -0.42899,0.22557 -2.3128,0.40517 -4.24974,0.40517 h -3.479164 z m 19.066404,-12.8041 c 7.88315,-0.76921 11.9667,-2.15326 16.23414,-5.50229 7.27988,-5.71314 10.16479,-17.40149 6.19601,-25.10326 -2.07386,-4.02446 -6.54584,-8.12385 -11.42918,-10.47688 -1.59343,-0.76781 -2.8552,-1.5094 -2.80392,-1.64798 0.0513,-0.13859 1.36321,-1.2261 2.91544,-2.4167 2.96717,-2.27591 5.03725,-5.05141 5.91556,-7.93143 0.69493,-2.27867 0.50824,-7.44661 -0.34716,-9.6104 -1.70656,-4.31684 -6.8526,-9.427384 -11.84535,-11.763644 -4.67951,-2.18969 -7.02208,-2.57278 -15.771644,-2.5792 -4.36563,-0.003 -8.51421,0.1072 -9.21909,0.24536 l -1.28158,0.25119 -0.26111,3.43135 c -0.33972,4.464228 -0.34042,65.536584 -8e-4,69.999274 l 0.26032,3.4207 1.28238,0.1622 c 2.01525,0.2549 16.056714,-0.0783 20.155984,-0.47829 z m -7.231934,-11.54895 c -0.58209,-0.0559 -1.57427,-0.1859 -2.20486,-0.28898 l -1.14654,-0.18741 V 148.568 c 0,-4.32665 0.10305,-9.55073 0.229,-11.60907 l 0.22897,-3.74243 1.79948,-0.10481 c 3.811534,-0.22199 6.760004,0.25132 9.273724,1.48869 4.56184,2.24554 7.09321,5.73279 7.68254,10.58354 0.49607,4.08311 -1.916,8.6184 -5.48174,10.3071 -1.74344,0.82566 -7.8579,1.6621 -10.380574,1.42001 z m -3.15238,-37.60357 c -0.3166,-2.53399 -0.32028,-13.42951 -0.005,-15.94989 0.21124,-1.69078 0.35451,-1.95989 1.14966,-2.15946 1.28876,-0.32346 6.526354,0.43971 8.095754,1.17963 3.24431,1.5296 6.08313,5.86313 6.08313,9.28609 0,1.83522 -1.14149,4.8058 -2.46184,6.40652 -1.78072,2.15889 -3.68894,2.8439 -8.47068,3.04083 l -4.143984,0.17067 z"
id="path2023" />
</g>
</svg>
......@@ -9,11 +9,10 @@ license = { file = "LICENSE" }
requires-python = ">=3.8"
dependencies = [
"numpy",
"pybind11>=2.10.1",
# "pyside2",
"qtpy",
"graphviz>=0.19",
"matplotlib",
"setuptools_scm[toml]>=6.2",
]
classifiers = [
"Intended Audience :: Education",
......@@ -49,7 +48,7 @@ fallback_version = "0.0+UNKNOWN"
[project.urls]
homepage = "https://gitlab.liu.se/da/B-ASIC"
documenation = "https://da.gitlab-pages.liu.se/B-ASIC/"
documentation = "https://da.gitlab-pages.liu.se/B-ASIC/"
[tool.black]
skip-string-normalization = true
......