Lab 1: Understanding Baseband Modulation Techniques in Digital Communications
Introduction
In this lab, you will explore the fundamental concepts of baseband modulation techniques used in digital communications, focusing specifically on Manchester encoding and Non-Return-to-Zero Inverted (NRZI) encoding. These techniques are crucial for understanding how data is physically represented and transmitted over communication channels. Even though these specific methods are not used in modern 5G technologies, they provide a foundational understanding that is applicable to more advanced digital communication systems.
Objectives
Understand the principles behind Manchester and NRZI encoding.
Generate a random binary data stream and apply these encoding techniques.
Visualize the encoded data to analyze the bit patterns and their transitions.
Discuss the implications of each encoding type in terms of signal integrity and error resilience.
Required Tools
Python 3.x
NumPy library
Matplotlib library
Ensure that you have a Python environment ready, with the necessary libraries installed. You can install these libraries using pip if they are not already installed:
pip install numpy matplotlib
Setup Instructions
Before you begin the experiments, make sure to set up your Python environment correctly. This lab assumes you have basic knowledge of running Python scripts and are familiar with using plotting libraries to visualize data.
Open your Python IDE or Jupyter notebook: Prepare your environment where you will execute the Python scripts.
Create a new Python script or notebook: Name it Baseband_Modulation_Experiment.py or create a new notebook named Baseband_Modulation_Experiment.ipynb.
Import the necessary libraries: Ensure that NumPy and Matplotlib are imported, and set up your plotting environment with the following lines of code:
import numpy as np
import matplotlib.pyplot as plt
Note
Make sure to configure your matplotlib inline if you are using Jupyter notebooks by adding the line %matplotlib inline at the beginning of your notebook.
Generating Random Binary Data
This part of the experiment involves generating a random binary sequence which we will use as input for the encoding techniques.
Generate the Data: Add the following function to your script to generate a binary data sequence. This function uses NumPy to create a random array of 0s and 1s.
def generate_random_data(length): """Generate a random binary data stream.""" np.random.seed(0) # Seed for reproducibility return np.random.choice([0, 1], size=length)
Call the Function: Now, call the generate_random_data function with a desired length. In this example, we generate 20 bits.
data_length = 20 data = generate_random_data(data_length)
Visualize Encoded Data: Define a function to visualize the encoded data, that will be called in the main function and referred to in the sections that talk about Manchester and NRZI encoding
def plot_encoded_data(time_slots, encoded_data, title, ylabel): """Plot encoded data as a step function with annotations.""" plt.figure(figsize=(12, 2)) plt.step(time_slots, encoded_data + 0.5, where='post', linewidth=1.5) # Offset for visibility plt.ylim(0, 2) plt.title(title) plt.xlabel('Time Slots') plt.ylabel(ylabel) plt.grid(True) plt.yticks([0.5, 1.5], ['0', '1']) # Annotating transitions for i, value in enumerate(encoded_data[:-1]): if encoded_data[i] != encoded_data[i+1]: plt.annotate('', xy=(i+1, 1.5 if encoded_data[i+1] > encoded_data[i] else 0.5), xytext=(i+1, 0.5 if encoded_data[i+1] > encoded_data[i] else 1.5), arrowprops=dict(facecolor='red', shrink=0.05, width=1.5, headwidth=8)) plt.show()
Visualize the Original Data: To better understand what your raw input data looks like, plot it using Matplotlib.
plt.figure(figsize=(12, 2)) plt.step(np.arange(len(data)), data + 0.5, where='post', linewidth=1.5) plt.ylim(0, 2) plt.title('Original Binary Data') plt.xlabel('Bit Index') plt.ylabel('Binary Value') plt.grid(True) plt.yticks([0.5, 1.5], ['0', '1']) plt.show()
The plot of the original binary data.
The plot above shows the original binary data generated for the experiment. Each bit in the sequence is represented as either a ‘0’ or ‘1’. This binary sequence serves as the input for the subsequent encoding processes. Notice how each bit is distinctly represented, which will contrast with the transformation seen in the encoding techniques.
Manchester Encoding
Manchester encoding is a method of encoding where each bit of data is represented by two levels, making it easier to synchronize the clock.
Implement the Encoding: Add a Manchester encoding function to your script. This function doubles the length of the input bitstream, where ‘0’ is encoded as ‘10’ and ‘1’ as ‘01’.
def manchester_encode(bitstream): encoded = np.empty(2 * len(bitstream), dtype=int) for i, bit in enumerate(bitstream): encoded[2*i:2*i+2] = [1 - bit, bit] return encoded
Encode the Data: Encode the generated binary data using your Manchester encoding function.
manchester_encoded = manchester_encode(data)
Visualize the Encoded Data: Plot the Manchester encoded data to observe how each bit is represented.
plot_encoded_data(np.arange(len(manchester_encoded)), manchester_encoded, 'Manchester Encoding', 'Encoded Signal')
The plot of the Manchester encoded data showing how each original bit is split into two parts.
This figure illustrates the Manchester encoding of the initial binary data. In Manchester encoding, each bit from the original data is transformed into two bits. A ‘0’ is represented as high-to-low (10) and a ‘1’ as low-to-high (01). Observe the transitions at the midpoint of each bit period, which are critical for clock synchronization in digital communication systems, ensuring that the timing of the transmission is maintained accurately.
NRZI Encoding
Non-Return-to-Zero Inverted (NRZI) is a method of encoding that signifies a bit value at the transition between signal levels.
Implement the Encoding: Define a function for NRZI encoding, where a ‘1’ results in a level change and ‘0’ means maintaining the current level.
def nrzi_encode(bitstream, initial_level=0): encoded = np.empty(len(bitstream), dtype=int) current_level = initial_level for i, bit in enumerate(bitstream): if bit == 1: current_level = 1 - current_level encoded[i] = current_level return encoded
Encode the Data: Use the NRZI encoding function on the same binary data.
nrzi_encoded = nrzi_encode(data)
Visualize the Encoded Data: Display the NRZI encoded signal to analyze how bits are represented by the presence or absence of transitions.
plot_encoded_data(np.arange(len(nrzi_encoded)), nrzi_encoded, 'NRZI Encoding', 'Encoded Signal')
The plot of the NRZI encoded data highlighting the transitions.
The NRZI (Non-Return-to-Zero Inverted) encoding plot shown here represents ‘1’ by a transition at the beginning of the bit period and ‘0’ by no transition. Unlike Manchester encoding, NRZI maintains the previous level for a ‘0’, which can lead to long sequences without transitions if there are consecutive zeros. This characteristic makes it crucial for NRZI to be used with data sequences that are expected to have frequent ones, reducing the likelihood of synchronization issues.
Simulating Encoding Techniques
In this part of the lab, you will run a Python script that simulates various digital encoding techniques. This script allows you to generate plots for different encoding schemes such as Unipolar NRZ, Polar NRZ-L, Polar NRZ-I, Polar RZ, Manchester, Differential Manchester, and Alternate Mark Inversion. By visualizing these schemes, you will gain a better understanding of how data is represented in different formats.
Python Script for Encoding Techniques
This section provides a complete Python script that simulates various digital encoding techniques. The script allows you to visualize different encoding schemes, helping you understand the transformation of binary data into encoded signals. Simply copy the entire script, paste it into your Python environment, and run it to see the effects of each encoding method.
Copy and Run the Script
Open your Python IDE or a Jupyter notebook.
Copy the Python script below:
import matplotlib.pyplot as plt def unipolar(inp): inp1=list(inp) inp1.insert(0,0) return inp1 def polar_nrz_l(inp): inp1=list(inp) inp1.insert(0,0) inp1=[-1 if i==0 else 1 for i in inp1] return inp1 def polar_nrz_i(inp): inp2=list(inp) lock=False for i in range(len(inp2)): if inp2[i]==1 and not lock: lock=True continue if lock and inp2[i]==1: if inp2[i-1]==0: inp2[i]=1 continue else : inp2[i]=0 continue if lock: inp2[i]=inp2[i-1] inp2=[-1 if i==0 else 1 for i in inp2] return inp2 def polar_rz(inp): inp1=list(inp) inp1=[-1 if i==0 else 1 for i in inp1] li=[] for i in range(len(inp1)): li.append(inp1[i]) li.append(0) return li def Biphase_manchester(inp): inp1=list(inp) li,init=[],False for i in range(len(inp1)): if inp1[i]==0: li.append(-1) if not init: li.append(-1) init=True li.append(1) elif inp1[i]==1 : li.append(1) li.append(-1) return li def Differential_manchester(inp): inp1=list(inp) li,lock,pre=[],False,'' for i in range(len(inp1)): if inp1[i]==0 and not lock: li.append(-1) li.append(-1) li.append(1) lock=True pre='S' elif inp1[i]==1 and not lock : li.append(1) li.append(1) li.append(-1) lock=True pre='Z' else: if inp1[i]==0: if pre=='S': li.append(-1);li.append(1) else: li.append(1);li.append(-1) else: if pre=='Z': pre='S' li.append(-1);li.append(1) else: pre='Z' li.append(1);li.append(-1) return li def AMI(inp): inp1=list(inp) inp1.insert(0,0) lock=False for i in range(len(inp1)): if inp1[i]==1 and not lock: lock=True continue elif lock and inp1[i]==1: inp1[i]=-1 lock=False return inp1 def plotall(li): plt.subplot(7,1,1) plt.ylabel("Unipolar-NRZ") plt.title("Unipolar -NRZ") plt.plot(unipolar(li),color='red',drawstyle='steps-pre',marker='>') plt.subplot(7,1,2) plt.ylabel("P-NRZ-L") plt.title("NRZ-L") plt.plot(polar_nrz_l(li),color='blue',drawstyle='steps-pre',marker='>') plt.subplot(7,1,3) plt.ylabel("P-NRZ-I") plt.title("NRZ-I") plt.plot(polar_nrz_i(li),color='green',drawstyle='steps-pre',marker='>') plt.subplot(7,1,4) plt.ylabel("Polar-RZ") plt.title("Polar RZ") plt.plot(polar_rz(li),color='red',drawstyle='steps-pre',marker='>') plt.subplot(7,1,5) plt.ylabel("B_Man") plt.title("Manchester") plt.plot(Biphase_manchester(li),color='violet',drawstyle='steps-pre',marker='>') plt.subplot(7,1,6) plt.ylabel("Dif_Man") plt.title("Differential Manchester") plt.plot(Differential_manchester(li),color='red',drawstyle='steps-pre',marker='>') plt.subplot(7,1,7) plt.ylabel("A-M-I") plt.title("Alternate Mark Inversion") plt.plot(AMI(li),color='blue',drawstyle='steps-pre',marker='>') plt.show() def plotunrz(li): plt.ylabel("Unipolar-NRZ") plt.plot(unipolar(li),color='red',drawstyle='steps-pre',marker='>') plt.title("Unipolar -NRZ") plt.show() def plotpnrzl(li): plt.ylabel("P-NRZ-L") plt.plot(polar_nrz_l(li),color='blue',drawstyle='steps-pre',marker='>') plt.title("NRZ-L") plt.show() def plotnrzi(li): plt.ylabel("P-NRZ-I") plt.plot(polar_nrz_i(li),color='green',drawstyle='steps-pre',marker='>') plt.title("NRZ-I") plt.show() def plotprz(li): plt.ylabel("Polar-RZ") plt.plot(polar_rz(li),color='red',drawstyle='steps-pre',marker='>') plt.title("Polar RZ") plt.show() def plotbman(li): plt.ylabel("B_Man") plt.plot(Biphase_manchester(li),color='violet',drawstyle='steps-pre',marker='>') plt.title("Manchester") plt.show() def plotdifman(li): plt.ylabel("Dif_Man") plt.plot(Differential_manchester(li),color='red',drawstyle='steps-pre',marker='>') plt.title("Differential Manchester") plt.show() def plotami(li): plt.ylabel("A-M-I") plt.plot(AMI(li),color='blue',drawstyle='steps-pre',marker='>') plt.title("Alternate Mark Inversion") plt.show() if __name__=='__main__': try: print("Enter the size of Encoded Data : ") size=int(input()) except: print("The size must be an integer value") exit() l =0 flag=0 li=[] print("\n =================================================================================================") selection=int(input("\n Enter your selection of encoding scheme. Press the following \n 1. Unipolar NRZ \n 2. Polar NRZ-l \n 3. Polar NRZ-I \n 4. Polar RZ \n 5. Manchester \n 6. Differential Manchester \n 7. Alternate Mark Inversion \n 8. All \n============================================================================================== \n Enter your selection : ")) print("==================================================================================================") if(1<=selection<=8): print("Select Success") print('Enter the binary bits sequnece of length one bit at a time ',size,' bits : \n') for i in range(size): if((l==0) or (l==1)): try: l=int(input()) li.append(l) except: print("\n Data stream must have only binary values") else: print("\n Invalid Input") flag=1 break if(flag==0): if(selection==1): plotunrz(li) elif(selection==2): plotpnrzl(li) elif(selection==3): plotnrzi(li) elif(selection==4): plotprz(li) elif(selection==5): plotbman(li) elif(selection==6): plotdifman(li) elif(selection==7): plotami(li) elif(selection==8): plotall(li) print("\n Encoding Success") else: print("\n Enter only binary inputs. Try Again!") else: print("\n Enter a valid selection")
Run the Script: After pasting, execute the script in your Python environment. You will be prompted to input the length of the binary data sequence and the specific encoding schemes you wish to visualize.
Analyze the Output: The script will generate plots for the selected encoding techniques, displaying how each bit of the original data is transformed according to the specified encoding rules. These visualizations are crucial for understanding the practical applications of these techniques in digital communication systems.
Understanding the Outputs
Each encoding method visualized by the script has distinct characteristics:
Unipolar NRZ: Represents bits without inversion, maintaining a high signal for ‘1’ and low for ‘0’.
Polar NRZ-L: Uses two levels with ‘1’ represented by a positive level and ‘0’ by a negative level.
Polar NRZ-I: Indicates a ‘1’ by a transition at the beginning of the bit period, with ‘0’ represented by no change.
Polar RZ: Similar to Polar NRZ but includes a return to zero midway through each bit period.
Manchester Encoding: Encodes each bit as either a high followed by a low or a low followed by a high, depending on the bit value.
Differential Manchester: Combines differential encoding and Manchester encoding to ensure synchronization.
Alternate Mark Inversion (AMI): Uses three levels, representing ‘0’ as zero voltage and alternating ‘1’s between positive and negative levels to maintain no DC bias.
Each figure produced by the script will be labeled accordingly, and the transitions or lack thereof will be clearly marked to illustrate how each encoding scheme handles the binary input data. Use these visualizations to compare and contrast the effectiveness and complexity of each method in different communication scenarios.
This composite figure illustrates all the encoding techniques applied to the same binary data sequence, providing a side-by-side comparison of each method’s impact on the signal format.
Conclusion
In this lab, you explored two fundamental digital encoding techniques, Manchester encoding and Non-Return-to-Zero Inverted (NRZI) encoding. These methods are essential for ensuring reliable data transmission by providing synchronization and reducing error rates. Through the practical simulations, you were able to visualize how binary data is transformed into different signal forms, preparing you for more complex communication system studies.
Review Questions
To further your understanding and assess what you have learned in this lab, consider the following questions:
What are the main advantages of Manchester encoding in terms of transmission reliability?
In what scenario might NRZI encoding be preferred over other types of encoding?
Explain how the presence of transitions in NRZI encoding helps in maintaining synchronization with the receiver.
Describe a situation where Manchester encoding could cause issues in a communication system. How might these be mitigated?
What role do encoding schemes play in error detection and correction within digital communications?
Further Exploration
Experiment with different noise levels in the channel simulation to observe the robustness of each encoding scheme under various signal-to-noise ratios.
Implement other encoding techniques such as 4B/5B or 8B/10B encoding and compare their performance to Manchester and NRZI.
Use these encoding techniques to simulate a simple data link layer protocol and analyze the performance in terms of throughput and data integrity.