``````

In [1]:

# Imports
from BinPy import *

``````

### Logic Gates Example - 2 Input / Multi Input Logic Gates

BinPy has basic logic gates like AND, OR, XOR, XNOR, NAND and NOR which accepts both numeric inputs as well as connector inputs.

``````

In [2]:

# XOR GATE in BinPy

# Create a gate instance
xor1 = XOR(1, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1)

xor1.output()

``````
``````

Out[2]:

0

``````
``````

In [3]:

# Using a Connector in BinPy

A = Connector(1) # input 1
B = Connector(0) # input 2
C = Connector()  # output

xor1.set_inputs(A, B)  # Overrides previous inputs
xor1.set_output(C)

``````
``````

In [4]:

C.get_logic() # or use C.state

``````
``````

Out[4]:

1

``````
``````

In [5]:

A.set_logic(0);
C.get_logic()

``````
``````

Out[5]:

0

``````

### Usage of Bus object in BinPy

``````

In [6]:

# Using Bus in BinPy

``````
``````

In [7]:

# Initiating the Bus with connectors

bit_1 = Connector(0)
bit_2 = Connector(1)
bit_3 = Connector(0)
bit_4 = Connector(0)

bus_a = Bus(bit_1, bit_2, bit_3, bit_4)

``````
``````

In [8]:

# Probing the logic of the Bus

bus_a.get_logic_all(as_list=False)

``````
``````

Out[8]:

'0b0100'

``````
``````

In [9]:

# Probing the voltage of the Bus -- The logic states can be represented by a 5v logic
# To get another logic family edit the binpy.config file to set the desired logic HIGH and logic LOW parameters

bus_a.get_voltage_all()

``````
``````

Out[9]:

[0.0, 5.0, 0.0, 0.0]

``````
``````

In [10]:

# Creating another Bus from an existing Bus

bus_b = Bus(bus_a)

bus_b.get_voltage_all()

``````
``````

Out[10]:

[0.0, 5.0, 0.0, 0.0]

``````
``````

In [11]:

# Concatenating the two Bus-es

bus_c = bus_a + bus_b

bus_c

``````
``````

Out[11]:

[0, 1, 0, 0, 0, 1, 0, 0]

``````
``````

In [12]:

# Copying values between buses

bus_d = Bus(8) # 8 indicates the length of the Bus. By default all busses will be digital in type

print (bus_d)

``````
``````

[None, None, None, None, None, None, None, None]

``````
``````

In [13]:

bus_d.copy_values_from(bus_c)
print (bus_d)

``````
``````

[0, 1, 0, 0, 0, 1, 0, 0]

``````
``````

In [14]:

# Iterating through a bus and setting names ( TAG's ) for connectors
i = 7
for connector in bus_d:
connector.set_name("B"+str(i))
print ( connector )
i -= 1

``````
``````

Connector; Name: B7; Index: 41; State: 0
Connector; Name: B6; Index: 42; State: 1
Connector; Name: B5; Index: 43; State: 0
Connector; Name: B4; Index: 44; State: 0
Connector; Name: B3; Index: 45; State: 0
Connector; Name: B2; Index: 46; State: 1
Connector; Name: B1; Index: 47; State: 0
Connector; Name: B0; Index: 48; State: 0

``````
``````

In [15]:

# Probing the connector tags of each bus

print (" ".join( [ connector.name for connector in bus_d ]))

``````
``````

B7 B6 B5 B4 B3 B2 B1 B0

``````
``````

In [16]:

# Analog Bus

PWR = Bus(Connector(voltage=5.2), Connector(voltage=0))

print (PWR)

``````
``````

[5.2, 0.0]

``````
``````

In [17]:

# Bus is an abstraction over the python lists, so you can do all list operations on it

# Slicing Bus-es

bus_e = Bus(bus_d[:-4])

print (bus_e == bus_b)

``````
``````

True

``````
``````

In [18]:

# Circulary rotating the bits of the Bus-es

print ("Before rotation, bus_e : ", bus_e)

print ("After circularly rotating right by 3 positions, bits of bus_e: ", bus_e >> 3)

# Note that this returns a list of the Connectors and not a bus object. Use Bus(bus_e>>2) to return a Bus object

print ("After circularly rotating left by 3 positions, bits of bus_e: ", bus_e << 3)

``````
``````

('Before rotation, bus_e : ', [0, 1, 0, 0])
('After circularly rotating right by 3 positions, bits of bus_e: ', [1, 0, 0, 0])
('After circularly rotating left by 3 positions, bits of bus_e: ', [0, 0, 1, 0])

``````

BinPy's linker modules stores all the connection in a NetworkX Graph data structure and traverses trought it iteratively in the background to reflect changes to the outputs / inputs of the ports.

Simulating the below connection ( drawn using KiCAD ) using BinPy's Linker module.

``````

In [19]:

# Using the linker module to connect two Bus-es
CNTRL_V = Bus(4)

CNTRL_V.set_voltage_all(5.0,5.0,2.0,2.5)

VCC = Bus(Connector(voltage = 5.2), Connector(voltage=0))

``````
``````

In [20]:

SLAVE0, SLAVE1 = Bus(4), Bus(4)

SLAVE0.set_type(analog = True)
SLAVE1.set_type(analog = True)

# Connecting the first two bits of CNTRL_V to the middle two bits of SLAVE0

# Connecting the last two bits of CNTRL_V to the middle two bits of SLAVE1

# Impressing 5v and 0v on the SLAVE0 Bus

# Impressing 5v and 0v on the SLAVE1 Bus

``````
``````

In [21]:

print (SLAVE0.get_voltage_all())

``````
``````

[5.2, 5.0, 5.0, 0.0]

``````
``````

In [22]:

print (SLAVE1.get_voltage_all())

``````
``````

[5.2, 2.0, 2.5, 0.0]

``````
``````

In [23]:

CNTRL_V.set_voltage_all(5.0, 6.0, 2.0, 1.1)

``````
``````

In [24]:

# The Slave Bus-es have been updated with the updated voltage in CNTRL_V

print (SLAVE0.get_voltage_all())

``````
``````

[5.2, 5.0, 6.0, 0.0]

``````
``````

In [25]:

print (SLAVE1.get_voltage_all())

``````
``````

[5.2, 2.0, 1.1, 0.0]

``````
``````

In [26]:

# Unlinking the SLAVE0 from CNTRL_V

AutoUpdater.remove_link(SLAVE0[1:-1]) # Only the middle 2 ports are connected to CNTRL_V
# VCC is still connected to SLAVE0

``````
``````

In [27]:

CNTRL_V.set_voltage_all(3.0, 2, 1, 6.2)

``````
``````

In [28]:

# SLAVE0 Retains the last held value

print (SLAVE0.get_voltage_all())

``````
``````

[5.2, 5.0, 6.0, 0.0]

``````
``````

In [29]:

# SLAVE1 however is updated

print (SLAVE1.get_voltage_all())

``````
``````

[5.2, 1.0, 6.2, 0.0]

``````
``````

In [30]:

# Change in VCC is reflected to both SLAVE0 and SLAVE1

VCC[0].set_voltage(5.5)

print (SLAVE0[0].get_voltage())

``````
``````

5.2

``````
``````

In [31]:

print (SLAVE1[0].get_voltage())

``````
``````

5.5

``````

### Example to illustrate the usage of bittools

`BinPyBits` is a class inheriting from the `bitstring.BitArray` class. It will be used for efficient manipulation / handling of Bit vectors.

``````

In [32]:

from BinPy import *

# Initializing a BinPyBits object

bit_vector = BinPyBits(5)

``````
``````

In [33]:

# By default all BinPyBits objects are not signed

bit_vector.signed

``````
``````

Out[33]:

False

``````
``````

In [34]:

# Getting the decimal value

bit_vector.uint

``````
``````

Out[34]:

5

``````
``````

In [35]:

# Getting the binary string

bit_vector.bin

``````
``````

Out[35]:

'101'

``````
``````

In [36]:

# Do not use int with unsigned BinPyBits objects

bit_vector.int

``````
``````

Out[36]:

-3

``````
``````

In [37]:

# This returns -3 since '101' ==> -3 ( 2's Complement representation )

# You could use :

int_value = bit_vector.int if bit_vector.signed else bit_vector.uint

print int_value

``````
``````

5

``````
``````

In [38]:

# Creating a BinPyBits object using binary string

bit_vector = BinPyBits('1111', signed=False)

# Converting to decimal

int_value = bit_vector.int if bit_vector.signed else bit_vector.uint

print int_value

``````
``````

15

``````
``````

In [39]:

# Creating a signed BinPyBits

bit_vector = BinPyBits('1111', signed=True)

# Converting to decimal

int_value = bit_vector.int if bit_vector.signed else bit_vector.uint

print int_value

``````
``````

-1

``````
``````

In [40]:

# Converting to hex

bit_vector.hex

``````
``````

Out[40]:

'f'

``````

Refer the documentation of bittstring to discover additional functionality.

``````

In [41]:

# The speciality of BinPyBits lies in the fact that it can be initialized from various types of inputs
# Except for the initialization, the rest of the functionalities remain similar to that of the bitstring.BitArray

# Initializing a signed value using - sign

bit_vector = BinPyBits('-1111', signed=True)

print bit_vector.int

``````
``````

-15

``````

### Multiplication algorithms in BinPy

#### Roberson's Multiplication algorithm

``````

In [42]:

product = robertsons_multiply('111111', '111111', 7)
print product

``````
``````

00111110000001

``````
``````

In [43]:

to_unsigned_int(product)

``````
``````

Out[43]:

3969

``````
``````

In [44]:

product = robertsons_multiply('111111', '000001', 7, signed=True)
print product

``````
``````

11111111111111

``````
``````

In [45]:

to_signed_int(product)

``````
``````

Out[45]:

-1

``````

#### Booth's Multiplication alogrithm

``````

In [46]:

product = booths_multiply('110011', '111001')
print product

``````
``````

000001011011

``````
``````

In [47]:

to_unsigned_int(product)

``````
``````

Out[47]:

91

``````
``````

In [48]:

product = booths_multiply(bin(-5), bin(-5), signed=True)
print product

``````
``````

00011001

``````
``````

In [49]:

to_signed_int(product)

``````
``````

Out[49]:

25

``````

#### Karatsuba's Multiplication algorithm

``````

In [50]:

product = karatsuba_multiply('1010', '1001')
print product

``````
``````

01011010

``````
``````

In [51]:

print  to_unsigned_int(product)

``````
``````

90

``````
``````

In [52]:

product = karatsuba_multiply('1010', '1001', signed=True) # --6  *  -7  = 42
print product

``````
``````

00101010

``````
``````

In [53]:

print to_unsigned_int(product)

``````
``````

42

``````

### IC's - Using Integrated Circuits in BinPy

``````

In [54]:

# Usage of IC 7400:

ic1 = IC_7400()

print(ic.__doc__)

``````
``````

None

``````
``````

In [55]:

ic1.draw_IC()

``````
``````

┌─────────◡─────────┐
│                   │
[0]    ──┤  1            14  ├──    [0]
│                   │
│                   │
[0]    ──┤  2      7     13  ├──    [0]
│                   │
│                   │
[Z]    ──┤  3      4     12  ├──    [0]
│                   │
│                   │
[0]    ──┤  4      0     11  ├──    [Z]
│                   │
│                   │
[0]    ──┤  5      0     10  ├──    [0]
│                   │
│                   │
[Z]    ──┤  6             9  ├──    [0]
│                   │
│                   │
[0]    ──┤  7             8  ├──    [Z]
│                   │
└───────────────────┘

``````
``````

In [56]:

pin_dict = {1: 1, 2: 0, 4: 0, 5: 0, 7: 0, 9: 1, 10: 1, 12: 0, 13: 0, 14: 1}
ic1.set_IC(pin_dict)
ic1.run()

``````
``````

Out[56]:

{3: 1, 6: 1, 8: 0, 11: 1}

``````
``````

In [57]:

ic1.draw_IC()

``````
``````

┌─────────◡─────────┐
│                   │
[1]    ──┤  1            14  ├──    [1]
│                   │
│                   │
[0]    ──┤  2      7     13  ├──    [0]
│                   │
│                   │
[1]    ──┤  3      4     12  ├──    [0]
│                   │
│                   │
[0]    ──┤  4      0     11  ├──    [1]
│                   │
│                   │
[0]    ──┤  5      0     10  ├──    [1]
│                   │
│                   │
[1]    ──┤  6             9  ├──    [1]
│                   │
│                   │
[0]    ──┤  7             8  ├──    [0]
│                   │
└───────────────────┘

``````
``````

In [58]:

alu = IC_74181()

``````
``````

In [59]:

print alu.__doc__

``````
``````

This is a 4-bit Arithmetic Logic Unit which performs 16 diff functions.
It has two modes active high input mode and active low input mode(Active high mode is used here)

Pin Number  Description
1       Input - B0
2       Input - A0
3       Input - Select Line - S3
4       Input - Select Line - S2
5       Input - Select Line - S1
6       Input - Select Line - S0
7       Input - Carry
8       Input - Mode Input(M)
9       Output- F0
10      Output- F1
11      Output- F2
12      Ground
13      Output- F3
14      Output- A=B
15      Output- P
16      Output- NOT(C(n+4))
17      Output- G
18      Input - B3
19      Input - A3
20      Input - B2
21      Input - A2
22      Input - B1
23      Input - A1
24      VCC

Mode and Select Lines are used to select the function to be performed by the ALU on
the two 4-bit input data A3 A2 A1 A0 & B3 B2 B1 B0(Inputs A0-A3 and
B0-B3 have to be complemented and given).

``````
``````

In [60]:

alu.draw_IC()

``````
``````

┌─────────◡─────────┐
│                   │
[0]    ──┤  1            24  ├──    [0]
│                   │
│                   │
[0]    ──┤  2      7     23  ├──    [0]
│                   │
│                   │
[0]    ──┤  3      4     22  ├──    [0]
│                   │
│                   │
[0]    ──┤  4      1     21  ├──    [0]
│                   │
│                   │
[0]    ──┤  5      8     20  ├──    [0]
│                   │
│                   │
[0]    ──┤  6      1     19  ├──    [0]
│                   │
│                   │
[0]    ──┤  7            18  ├──    [0]
│                   │
│                   │
[0]    ──┤  8            17  ├──    [Z]
│                   │
│                   │
[Z]    ──┤  9            16  ├──    [Z]
│                   │
│                   │
[Z]    ──┤ 10            15  ├──    [Z]
│                   │
│                   │
[Z]    ──┤ 11            14  ├──    [Z]
│                   │
│                   │
[0]    ──┤ 12            13  ├──    [Z]
│                   │
└───────────────────┘

``````
``````

In [61]:

# Complementing A Bus and B Bus
#_ = [ ( NOT(A[i]).set_output(A_Compl[i]), NOT(B[i]).set_output(B_Compl[i]) ) for i in range(4) ]

``````
``````

In [62]:

# Input Bus A and B
A, B = Bus(4), Bus(4)

# Power supply of VCC 5v / GND 0v
PWR = Bus(Connector(voltage=0), Connector(voltage=5.0))

MOD = 1
SEL = list(reversed([1, 1, 1, 0]))
CAR = 1

``````
``````

In [63]:

A.set_logic_all('1000') # 8
B.set_logic_all('0001') # 1

A_ = A.get_logic_all() # I might as well store A_ directly as a list of logic bits ...
B_ = B.get_logic_all()

alu.set_IC({   1:B_[0],
2:A_[0],
3:SEL[3],
4:SEL[2],
5:SEL[1],
6:SEL[0],
7:CAR,
8:MOD,
12:int(PWR[0]),
18:B_[3],
19:A_[3],
20:B_[2],
21:A_[2],
22:B_[1],
23:A_[1],
24:int(PWR[1])
})

alu.run()

``````
``````

Out[63]:

{9: 1, 10: 0, 11: 0, 13: 1, 14: 0, 15: 1, 16: 1, 17: 0}

``````
``````

In [64]:

alu.draw_IC()

``````
``````

┌─────────◡─────────┐
│                   │
[0]    ──┤  1            24  ├──    [1]
│                   │
│                   │
[1]    ──┤  2      7     23  ├──    [0]
│                   │
│                   │
[1]    ──┤  3      4     22  ├──    [0]
│                   │
│                   │
[1]    ──┤  4      1     21  ├──    [0]
│                   │
│                   │
[1]    ──┤  5      8     20  ├──    [0]
│                   │
│                   │
[0]    ──┤  6      1     19  ├──    [0]
│                   │
│                   │
[1]    ──┤  7            18  ├──    [1]
│                   │
│                   │
[1]    ──┤  8            17  ├──    [0]
│                   │
│                   │
[1]    ──┤  9            16  ├──    [1]
│                   │
│                   │
[0]    ──┤ 10            15  ├──    [1]
│                   │
│                   │
[0]    ──┤ 11            14  ├──    [0]
│                   │
│                   │
[0]    ──┤ 12            13  ├──    [1]
│                   │
└───────────────────┘

``````

### Combinational circuits

#### DEMUX

``````

In [65]:

# Initializing the DEMUX class

# Must be a single input

demux = DEMUX(1)

# Put select lines

# Select Lines must be power of 2

demux.select_lines(0, 1) # a, b

# Output of demux

print (demux.output())  # D0, D1, D2, D3

``````
``````

[0, 1, 0, 0]

``````

### Full Adder - Using Connectors in Combinational blocks

``````

In [66]:

``````
``````

This Class implements Full Adder, Arithmetic sum of three bits and
return its Sum and Carry
Output: [CARRY, SUM]
Example:
>>> from BinPy import *
>>> fa = FullAdder(0, 1, 1)
>>> fa.output()
[1, 0]

``````
``````

In [67]:

a, b, ci, s, co = Connector(1), Connector(0), Connector(1), Connector(), Connector()

# Initializing full adder using connectors

# Connect outputs
fa.set_output(0, co)
fa.set_output(1, s)

``````
``````

In [68]:

print (co.get_logic(), s.get_logic())

``````
``````

(1, 0)

``````

### MUX

``````

In [69]:

# Initializing the MUX class

mux = MUX(0, 1, 1, 0)

# Put select lines

mux.select_lines(0, 0)

# Output of mux

print (mux.output())

``````
``````

0

``````

### Sequential Circuits - Introducing the clock object.

#### JK Flip Flop and the The ASCII Art based Oscilloscope of BinPy

``````

In [70]:

j, k, p, q = Connector(1), Connector(0), Connector(0), Connector(1)

# A clock of 4 hertz frequency initialized to 1
clock = Clock(0, 4)

jkff = JKFlipFlop(j, k, Connector(1), clock.A, clear=Connector(1))

# To connect outputs use s.set_outputs(op1,op2)
jkff.set_outputs(A=p, B=q)

# Initiating the oscilloscope
o = Oscilloscope((clock.A, 'CLK'), (j, 'J'), (
k, 'k'), (p, 'OUT'), (q, 'OUT!'), (Connector(1), 'ENABLE'))

o.start()
o.set_scale(0.02)  # Set scale by trial and error.
o.set_width(100)
o.unhold()

# For each j,k in 0,0 / 0,1 / 1,0 / 1,1 Trigger ( Send a Falling edge clock pulse to the jkff module )

from time import sleep

for j.state, k.state in zip([0, 0, 1, 0, 1], [0, 0, 0, 1, 1]):

print "j,k = ", ( j.state, k.state )
# Sending One Clock Pulse

# The same thing can also be done by --> jkff.setInputs(j = 1, k = 0)
while True:
if clock.A.state == 0:
# Falling edge will trigger the FF
jkff.trigger()
break
print (jkff.state())

# Sending a positive edge to jkff
while True:
if clock.A.state == 1:
# Falling edge will trigger the FF
jkff.trigger()
break

o.display()

``````
``````

j,k =  (0, 0)
[0, 1]
j,k =  (0, 0)
[0, 1]
j,k =  (1, 0)
[1, 0]
j,k =  (0, 1)
[0, 1]
j,k =  (1, 1)
[1, 0]
===================================================================================================================
BinPy - Oscilloscope
===================================================================================================================
SCALE - X-AXIS : 1 UNIT WIDTH = 0.02
===================================================================================================================
│
│
│          ┌──────────┐          ┌───────────┐          ┌──────────┐           ┌──────────┐
CLK  │          │          │          │           │          │          │           │          │
─ ─────────┘          └──────────┘           └──────────┘          └───────────┘          └───────────
│
│
│
│
│                                ┌──────────────────────┐                      ┌─────────────────────┐
J  │                                │                      │                      │                     │
─ ───────────────────────────────┘                      └──────────────────────┘                     └
│
│
│
│
│                                                       ┌────────────────────────────────────────────┐
k  │                                                       │                                            │
─ ──────────────────────────────────────────────────────┘                                            └
│
│
│
│
│                                            ┌──────────────────────┐                     ┌──────────┐
OUT  │                                            │                      │                     │          │
─ ───────────────────────────────────────────┘                      └─────────────────────┘          └
│
│
│
│
│ ┌──────────────────────────────────────────┐                      ┌─────────────────────┐
OUT!  │ │                                          │                      │                     │
─ ┘                                          └──────────────────────┘                     └───────────
│
│
│
│
│ ┌──────────────────────────────────────────────────────────────────────────────────────────────────┐
ENABL  │ │                                                                                                  │
─ ┘                                                                                                  └
│
│
│││││││││││││││││││││││││││││││││││││││││││││││││││││││││││││││││││││││││││││││││││││││││││││││││││││││││││││││││││
───────────────────────────────────────────────────────────────────────────────────────────────────────────────────

``````

### Multivibrator

``````

In [71]:

# MODE selects the mode of operation of the multivibrator.

# Mode No. :  Description
#   1          Monostable
#   2          Astable
#   3          Bistable

out = Connector()

``````

#### Multivibrator in mode 1 - Monostable mode

``````

In [72]:

# Initialize mutivibrator in MODE 1

m = Multivibrator(0, mode=1, time_period=1)
m.set_output(out)

# Initialize the oscilloscope
o = Oscilloscope((out, 'OUT'))
o.set_scale(0.005)  # Set scale by trial and error.
o.set_width(100)
o.unhold()
time.sleep(0.1)
m.trigger()  # Also works with m()
time.sleep(0.1)

# Display the oscilloscope
o.display()
m.kill()
o.kill()

``````
``````

===================================================================================================================
BinPy - Oscilloscope
===================================================================================================================
SCALE - X-AXIS : 1 UNIT WIDTH = 0.005
===================================================================================================================
│
│
│                      ┌─────────────────┐
OUT  │                      │                 │
─ ─────────────────────┘                 └────────────────────────────────────────────────────────────
│
│
│││││││││││││││││││││││││││││││││││││││││││││││││││││││││││││││││││││││││││││││││││││││││││││││││││││││││││││││││││
───────────────────────────────────────────────────────────────────────────────────────────────────────────────────

``````

### Analog Buffer

``````

In [73]:

# Source Bus
a = Bus(4)
a.set_type(analog=True)
a.set_voltage_all(3.5, 6.7, 2.2, 1.1)

# Ouput Bus
b = Bus(4)
b.set_type(analog=True)

# Enable input
e = Bus(1)
e.set_logic_all(1)

``````
``````

In [74]:

# Initializing an analog Buffer
buff1 = AnalogBuffer(a, b, e, 0.8) # With an attenuation of 0.8, relay the input to the output

``````
``````

In [75]:

print b.get_voltage_all()

``````
``````

[3.1920379377456842, 6.110472623684595, 2.0064238465830018, 1.0032119232915009]

``````
``````

In [76]:

# BinPy automatically converts the voltage to logic state based on 5v-0v logic
print b.get_logic_all()

``````
``````

[1, 1, 0, 0]

``````
``````

In [77]:

print b.get_voltage_all()

``````
``````

[3.1920379377456842, 6.110472623684595, 2.0064238465830018, 1.0032119232915009]

``````
``````

In [78]:

# Changing the input

a.set_voltage_all(1,1,1,1)

``````
``````

In [79]:

b.get_voltage_all()

``````
``````

Out[79]:

[0.9120108393559098,
0.9120108393559098,
0.9120108393559098,
0.9120108393559098]

``````
``````

In [80]:

# Changing the attenuation level

buff1.set_attenuation(0)

``````
``````

In [81]:

b.get_voltage_all()

``````
``````

Out[81]:

[1.0, 1.0, 1.0, 1.0]

``````

### Analog Signal Generator - Amplitude Modulation using 2 Analog Signal Generators

``````

In [82]:

# AM Signal generation using 2 intances of Signal Generator modules.

import numpy as np
%matplotlib inline
import matplotlib.pyplot as plt
import math, time

# Message sine signal generator of frequency 10 Hz and 1 Vpp amplitude
m_t = SignalGenerator(typ = 0, freq = 10, ampl = 1)
m_t.set_offset(-0.5)

# Carrier sine signal generator of frequency 100 Hz and 10 Vpp amplitude
c_t = SignalGenerator(typ = 0, freq = 100, ampl = 10)
c_t.set_offset(-5) # To make the range as [-5, 5]
c_t.set_modulation_input(m_t.outputs)
c_t.set_modulation_type(1)

time.sleep(0.5) # To allow setup time

c_t.last_updated_time, (c_t.outputs[0].voltage - c_t.outputs[1].voltage)

# Populate the plot points to data array

data = np.zeros(shape = (2, math.ceil(m_t.time_period / c_t.sampling_time_interval)))

for i in range(data.shape[1]):
data[0][i] = m_t.last_updated_time + m_t.time_period * i
data[1][i] = c_t.outputs[0].voltage
time.sleep(c_t.sampling_time_interval)

# Plot the modulated signal for the given timeframe
fig, ax = plt.subplots()
ax.plot(data[0], data[1])
plt.show()

# Kill the signal generator threads after use
m_t.kill()
c_t.kill()

``````
``````

``````