Course Home

 

Course Information

 

Schedule and Assignments

Lab 3: Software Modem

Introduction

In this lab, you will build a software modem using the SHARC. This lab will concentrate on detecting bits and will ignore all the signaling functions required for a real modem. You will build both transmitter and receiver components which must operate concurrently.

Our modem will use a simple technique to transmit bits known as frequency-shift keying. Keying here refers to Morse code-style keying. Since we cannot send DC over a phone line, we will assign separate sinusoidal frequencies to zero and one. The transmitter will continuously generate sinusoids, with the frequency depending on whether a zero or one is to be transmitted as the current bit. The receiver section uses a pair of digital filters tuned to the two frequencies---each filter tunes in one sinusoid and tunes out the other. If the signal output from the zero filter, for example, is sufficiently large, the receiver section determines that a zero is being transmitted.

Your modem will be used in loopback mode---you will connect your transmitter to your own receiver. However, in practice, modems are widely separated and cannot be synchronized by a single clock. The modems must therefore use an initialization sequence to make sure that they know where bits start and end. We generally assume that the transmission time of a bit is long relative to the clock rate, so that the transmitter and receiver remain synchronized throughout the transmission. The transmitter and receiver agree on the transmission time for a bit by setting themselves to the same baud rate.

Generating a waveform

The first step is to generate appropriate waveforms. You can start with the bandpass demo (bp.c) for this program. Your code will primarily go into the routine spr0_asserted(), which handles the timer interrupt.

Table lookup is a good way to generate many types of signals. You should first add a table for a sine wave. You should generate output values for the sine wave every 9 degrees, or a total of 11 points from 0 degrees to 90 degrees inclusive. A good maximum output value to use is 25,000.

Modify spr0_asserted() to generate a sine wave at the outputs. You can test the result both by listening over the speaker and by hooking an oscilloscope to the speaker plug. (How smooth is your waveform?) This should generate a signal with a frequency of about 110 Hz.

You can use the 110 Hz tone as one of your bit frequencies. To keep things simple, you want to choose the other frequency far enough away that it the two tones easily separable. To generate your other tone, generate a sine wave using only every third entry of your original table, giving you a tone of about 330 Hz.

So that your modem will be compatible with others, generate 100 samples per bit.

Detecting a bit

You can put the code for bit detection in spr0_asserted() as well. You can connect your transmitter to your receiver in one of two ways: you can connect a stereo cable from the speaker output to the microphone input, or you can use a C assignment to copy the generated signal to the detection code.

You can use the FIR filter routine called by bp.c to perform the filtering required for 0/1 detection. The function fir() is part of the SHARC C runtime library and a manual page is available on the SHARC CD-ROM. The first argument to the routine is the current sample. The second argument is a set of coefficients for the filter called coeffs in bp.c---more on these in a moment. The third argument is an array holding the filter state (called state in bp.c) and the fourth argument is the number of taps in the filter. You need to run two filters concurrently, so you need to modify the bp.c file to have two state arrays, one for the 0 filter and another for the 1 filter. In addition to modifying the variable declarations, you will need to modify main() to initialize both arrays. The coeffs[] array is actually a two-dimensional array, with the first dimension to select the filter pass band and the second indexing the coefficients. You should use &coeffs[1][0] to detect the 110 Hz signal and &coeffs[4][0] to detect the 330 Hz signal.

After filtering, you need to measure the energy in each signal. Fir() will give you one floating-point value for the filtered magnitude at that point. You can take the average of the last ten (or more) samples (either taking the absolute magnitude or square to avoid negatives and positives cancelling). A good threshold to use for the average filter output is 6000 (assuming a maximum generated signal of 25000).

Write code that detects whether the current input signal is 0 or 1. You can use LEDs 1 and 2 to display the results in real time. (Remember that CLR_FLAG turns on the LED and SET_FLAG turns it off.)

System organization

You can assume that the transmitter gets the data to transmit from an internal text string. You need to scan through each character in the string and send each bit in every character.

You must select a baud rate for transmission and receiving. The baud rate is related to the length of time used to transmit a bit. That rate should be at least as long as one wavelength for the lowest-frequency signal generated (110 Hz) but longer bit rates increase the reliability of detection.

Before transmitting the string, you should transmit a fixed pattern (use "01") to tell the receiver that transmission is beginning.

Turn in

* UML diagrams that document the design:

-         class diagrams for major classes

-         state diagrams for the transmitter and receiver

-         any useful sequence diagrams

* A listing of your (well-commented) program.

Copyright ã 1998, 2000 Wayne Wolf