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])

Linker Module Example

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
AutoUpdater.add_link(CNTRL_V[:2], SLAVE0[1:-1])

# Connecting the last two bits of CNTRL_V to the middle two bits of SLAVE1
AutoUpdater.add_link(CNTRL_V[-2:], SLAVE1[1:-1])

# Impressing 5v and 0v on the SLAVE0 Bus
AutoUpdater.add_link(VCC[0], SLAVE0[0])
AutoUpdater.add_link(VCC[1], SLAVE0[-1])

# Impressing 5v and 0v on the SLAVE1 Bus
AutoUpdater.add_link(VCC[0], SLAVE1[0])
AutoUpdater.add_link(VCC[1], SLAVE1[-1])

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]    
              │                   │
              └───────────────────┘  

Verify with the function table of IC74181 ( Taken from google images )

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]

Demux Block ( from google images )

Full Adder - Using Connectors in Combinational blocks


In [66]:
print(FullAdder.__doc__)


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
fa = FullAdder(a, b, ci)

# 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()