There is an effort in the College of Engineering to
improve the freshman engineering course (EE 10111-10112)
and make the course more interesting and educational. One
of the problems relevant to EE senior design is that there
is not an adequate introduction to the fun side of
electrical engineering that teaches fundamental concepts of
what electrical engineers do.
Our goal is to create an engaging module for the freshman
engineering course representative of the different
applications of EE in the real world. There is presently
little exposure to EE concepts in the freshman course. In
addition to emphasizing civil engineering, computer
science, and robotics, the freshman course should contain a
module that focuses on circuits and signal processing,
clearly expresses what EE entails, and sparks interest in
the field among the freshmen. The concepts fundamental to
EE are also transferrable skills among different
engineering disciplines, such as familiarity with
microcontrollers, filters, and circuits. The proposed
solution is a new EE learning module, using an EE Toolbox
that will contain components to allow students to gain an
introduction to the different aspects of EE. The Toolbox
will be an interactive learning environment designed to
cover the basics of the audio applications of signal
processing and, in the process, of basic circuit-building.
The main concerns for the power source are the microcontroller, the speakers, and supply voltages for amplifier circuits. The microcontroller operates at a range of 2.3-3.6V, and while many amplifiers operate at 9V, some can use lower voltages. Speakers also have some flexibility, depending on the model chosen. Taking these into consideration, it was decided that the system will be powered through USB, which would allow the user to operate it while connected to a computer or to a wall adapter. Because data will be transferred from the module to a computer through USB, it makes sense to use this as the power source, while minimizing the number of external connections to the system. The USB connection will supply a DC voltage of 5V, which will suffice for the microcontroller, which operates at a maximum of 3.6V, and for the amplifiers and filters on the breadboard. Because USB was selected as the power source, USB-powered speakers will be used.
The most basic functions of the audio effects board do not require a graphical user interface; instructions for operation will be provided as a part of the curriculum materials. By default, the audio signal is passed through the effects board to the speaker or output audio jack. When desired, the user flips a switch or presses a button, which relays the audio signal to the microcontroller. Meanwhile, a MATLAB graphical user interface on the computer will wait to accept the incoming data from the USB. When the data is finished exporting and processed, it will be displayed on a graph. The user can observe the output in either time or frequency domain, and will have the option to change the scale and other parameters of the plot. On the mobile phone, a simple signal generator application will be used to send out the signal. The app will have adjustable amplitude and frequency controls, and the tones generated will be in the audible range.
One of the main foci of this system is to allow the user to apply filters and amplifiers to an audio signal and observe the chances caused by these components. The analog audio input signal will connect to a breadboard, where the user adds on the various sound effects. Most of the filters will be pre-built and pre-packaged on small PCB’s made ready to be inserted on the breadboard. These circuits will be rather complex, so the freshmen will not be expected to build them on their own. Nonetheless, the components of the circuits will be made visible so that they can be explained briefly and observed by the students. Additionally, having these circuits pre-built will significantly reduce the likelihood of making a lethal connection that could damage the microcontroller, while facilitating the whole process in general. There will also be other small boards for students to build their own simpler circuits on. For example, a basic passive wave rectifier can be built using only a resistor and diodes and would be relatively simple to assemble, even for inexperienced engineers. These boards will have small labels and drawings to make the placement of the components clear. Thus, students will be able to observe the effects that filters have on a signal and gain a basic understanding of some circuit design.
Because a major component of the module is to allow the user to observe the effects of filters on a signal, it will allow the user to experience this first hand through sound. The module will accept an analog audio input from an external device, most likely a smartphone, through a 3.5mm audio jack. A mobile application on the smartphone will be used to generate sinusoidal signals (and other types of signals) with adjustable frequency and amplitude controls. Music files can also be played from the phone. The analog audio signal will be sent to the breadboard, where it is passed through pre-built filter boards and output through the speakers. The speakers will be USB-operated and produce an output at a reasonably audible range. The user can adjust the volume. Alternatively, the output signal can be relayed to an output audio jack, where the user can connect headphones or other speakers.
The system must be presented in a clear and portable manner, giving the user convenient access to all subsystems and components. It will be reasonably compact, about the size of a large laptop, and close securely for storage of loose components and cables. A likely manifestation of this would be a toolbox-like kit, which will have the breadboard, speakers, and LCD screen all on the same plane. Underneath these components in the “box” part of the kit will be the microcontroller and other interfaces between the subsystems. The input and output audio jacks and the USB port will be clearly visible on the outer surface of the product for easy connection. A drawer or small box-like compartment will contain the filters and other loose components. The goal is to make the system appear as simple as possible so as to minimize the risk of error and not overwhelm the freshmen.
The user will begin operation of the system by first connecting selected filters to the breadboard and assembling any filters as needed. Next, the user will turn on the system and connect the audio source to the input audio jack using a 3.5mm cable. The input signal will be connected to the speakers or output audio jack by default. Sound transmission will begin when the user turns on the signal on the mobile application on the phone. Volume can be adjusted. The user may toggle between the speakers or the output audio jack, using a button or a switch. When the data is ready to be recorded, the user presses a “Send” button, and the screen will update to show that the audio signal is being sampled. The audio signal will be relayed to the analog to digital converter of the microcontroller unit, where it will be converted into digital data and sent out of the microcontroller to the computer through the USB cable. An appropriate limit will be set on the sample size, depending on the frequency and nature of the signal. The data is then processed by the MATLAB program on the computer and plotted on a graph in either time or frequency domain. Here the user will be able to make adjustments to the plot and visually observe the effects created by the filters on the audio signal. If desired, the user may record multiple sets of data and overlay their graphs to allow the comparison of different effects.
The speakers are essential to the EE Toolbox. They allow a direct method of interaction with the user without a need for interfacing with the computer. There were certain requirements that the speakers did have to meet. Namely, the speakers had to:
With these requirements in mind, the group did some initial research into speaker systems. Initial results yielded speakers activated by microcontrollers or driven by external circuits which demanded high power consumption. Neither of these systems would work due to the system requirements.
With these parameters in mind, we met with Doug Hall to discuss speaker design and how to select appropriate speakers for the system. Doug Hall offered a few things to note with regards to the system. The first is that the audio quality will be largely determined by our D/A and sampling. Having a high resolution and using many bits is critical for our interface with the speakers. Given our need for high quality audio and audible tones, he suggested we look into acquiring speakers with good drivers. Second, high audio quality also requires the acquisition of full-range speakers. In order to notice the effects of low pass filter or high pass filtering, speakers which have a broader spectral response are more adequate. Full-Range speakers have a frequency response of 60-20000Hz, covering the vast majority of sounds within the audible range of humans.
With these considerations in mind, the group initially conceived acquiring full range speakers with a driving circuit separately. However, this could lead to a lot of error, and given our time constraints, it was not feasible to purchase parts in an attempt to optimize the audio output from the speakers. For the design, high-fidelity speakers will not be necessary. The board will have an audio jack which the user can use to connect their own speakers if they wish to obtain sound at a higher quality.
In addition, it would also require the use of a lot of power to drive the amplifier. Purchasing an Objective-2 headphone amplifier was under consideration, but due to budgetary constraints and system requirements, it was deemed unnecessary.
The final design settled upon is the X-Mini MAX XAM15-GM Portable Capsule Speakers. The speakers are designed as small capsules with a 2-inch diameter, thus fitting the first requirement. The speakers have batteries which are recharged through a micro-USB port, are simple to interact with—a standard audio jack—, and have a full-range frequency response. The battery lasts up to 18 hours, and each speaker can be used individually such that the unaltered output and filtered output can be heard at the same time. Thus, the speakers fit the whole set of system requirements and additional features which make the experience user-friendly.
The speakers have ceramic drivers. Ceramic drivers are used to deal with the high frequencies which neodymium drivers are not geared to handle. The ceramic tweeters are highly corrosion resistant and have a higher resistance to demagnetization (IKE 2012), producing less distortion at high frequencies. The speakers are also better designed to deal with bass, as they have a Bass Xpansion System which serves as a digital subwoofer system. To complement the digital system, the speakers can also decompress to expand the area for the bass to work with, as follows:
As seen above, the speaker has the ability to expand to increase its bass capabilities.
The subsystem was tested under two different conditions:
Full Range capabilities were tested using a frequency generator application[1] on a mobile phone. The speakers were driven from 50-100Hz for low frequency testing and from 19000-21000Hz for high frequency testing. The main factor looked for was whether the speakers were audible at such ranges. After running continuous tests with the frequency generator, the speakers were determined to be able to reproduce frequencies at such levels, even going so far as to shaking on the table when driving the bass.
The driving power was then placed to the test. The speakers were pushed to very high volumes using a personal computer. Under such driving, the speakers were able to provide audio well above normal conversation range, thus demonstrating that they are powerful enough to satisfy the audio needs of the EE Toolbox.
2. Driving Power
Full Range capabilities were tested using a frequency generator application[1] on a mobile phone. The speakers were driven from 50-100Hz for low frequency testing and from 19000-21000Hz for high frequency testing. The main factor looked for was whether the speakers were audible at such ranges. After running continuous tests with the frequency generator, the speakers were determined to be able to reproduce frequencies at such levels, even going so far as to shaking on the table when driving the bass.
The driving power was then placed to the test. The speakers were pushed to very high volumes using a personal computer. Under such driving, the speakers were able to provide audio well above normal conversation range, thus demonstrating that they are powerful enough to satisfy the audio needs of the EE Toolbox.
Subsystem Description: Screen
Requirements:
Must send a line of text to the LCD screen, describing the actions taking place (i.e reading data, exporting data, etc.)
Flow Chart:
Functionality Description:
After the LCD screen has been initialized, the software sends a line of code to the screen. It then waits for an arbitrary amount of time (for the moment), 3 sec, and then switches to a new line of text. The lines of code we used for this demonstration were ÒSampling dataÉÓ and ÒExporting dataÉÓ.
Design Decisions:
The text for the sampling and exporting data will be sent to the screen when a button is pressed on our box. This will then set a flag. When the flag is set, the data is sent to the screen. When the flag goes back to being low, the text is no longer sent to the screen.
Due to time constraints, the LCD screen subsystem was abandoned for the sake of other subsystems.
System Integration:
In the future the LCD screen will also be used to show the volume of the speaker, when the data is actually being sampled, and when the data is actually exporting to the computer. These attributes will be implemented when the connections between the different subsystems are made. The volume of the speaker will also be on an arbitrary scale that the group decides and is dependent on the other subsystems. The actual amount of time the text Òsampling dataÓ and Òexporting dataÓ will be on the screen is dependent on how fast we are actually doing these actions and will reflect those actions in real time. For code refer to Appendix A
Remove code below:
Code:
/*
* File: newmain.c
* Author: jweisenb
*
* Created on February 18, 2015,
3:54 PM
*/
#include <stdio.h>
#include <stdlib.h>
#include <xc.h>
#include "SDlib.h"
#include "SDlib_LCD.h"
#include "SDlib_delay.h"
#include "configbitsrev2014vC.h"
#define BUTTONFLAG PORTFbits.RF0
/*
*
*/
int main(int argc, char** argv) {
IEC0bits.T2IE=1; //
interrupt enabled
IFS0bits.T2IF=0;
//Interrupt flag off
LCD_init(); //
Initialize LCD
serial_init(57600);
set_output_device(2);
//LCD screen
LCD_clear();
while (1)
{
LCD_setpos(0,0);
printf("Device Ready"); //Home Screen
// if (IFS0bits.T2IF){
//if(BUTTONFLAG){
// IFS0bits.T2IF=1; //Interrupt flag on
LCD_clear(); // Make
sure nothing on screen
LCD_setpos(0,0);
printf("Sampling data..."); //Written to screen
delay_ms(3000); //Arbitrary 10 sec
LCD_clear();LCD_setpos(0,0);
printf("Exporting data...");
delay_ms(3000); //Arbitrary 10 sec
LCD_clear();LCD_setpos(0,0);
printf("Speakers on...");
LCD_clear();
IFS0bits.T2IF=0; //Interrupt flag off
// }
}
return (EXIT_SUCCESS);
}
Subsystem Description: SPI
Requirements:
The SPI needed to write to memory using an interrupt-driven scheme so that the write would be fast enough, in conjunction with the analog to digital conversion, to sample at a fast enough rate to analyze audio signals.
Functionality Description:
Upon initialization, the SPI would set up for the page write, which could write up to 256 bytes of data without having to change the chip enable bit or send more address bytes or commands to start the write. This would speed up the write process by up to five bytes per byte of data to be written, compared to the byte-program protocol.
Design Decisions:
In order to have enough memory to store up to 30 seconds for two tracks (filtered and unfiltered) of data, we decided to use a 64Mbit SPI. However, due to time constraints, this subsystem was ultimately not incorporated into the final design.
Subsystem Description: USB
Requirements:
Must deliver a stream of data from the microcontroller to the computer in a
format that the computer can save as a data file.
- open a connection to the USB port
- set attributes to properly read USB port
- read USB stream to a pipe
- find stop delimiter
- write all data up to the stop delimiter to the file
Flow chart:
Functionality description:
Given an incoming stream of data from the microcontroller, this software opens
a pipe from the USB port to which the microcontroller is connected. The
software checks chunks of the data for a stop delimiter. If the target file
does not exist, the program creates it. The program then appends the newly
read data to the end of the file and closes the file.
Design decisions:
Overview: This program was written in C for consistency's sake. That is the
language that has been used to program the microcontroller, and the libraries
are easy to use. The initial development took place on a Linux (Ubuntu)
operating system due to the ease of use of the compiler, system calls, etc.
Now that the code has been written and shown to work in a programmer-friendly
environment, adding functionality for Windows and Mac will only require changes
to one function and the makefile. Additionally, MATLAB has some compatibility
with C, so using C should facilitate the integration of this program into the
computer sid of the user interface.
Testing:
Linux: At this point, some information is printed to the terminal to show the
user that the data have been read properly. A test string of characters (a
known quantity) was sent from the microcontroller in a loop via USB. The
program read in the data, and upon finding a "0" stopped reading, wrote the
data to a file. After calling the "cat" command in the shell, it was visually
confirmed that the file contained the expected characters.
System integration:
The protocol on the microcontroller needed to read data from the analog to digital conversion output and send it to the USB. This was tested in a similar manner to the subsystem testing, using many samples from the ADC subsystem. Once these connections were confirmed to work, continuous samples were taken by plugging in a phone and using that as input.
Subsystem Description: Filters
The filters subsystem was the base of the educational curriculum. Each filter was intended to show another aspect of the relationship between the frequency and time domains. The following filters were attempted during the design process. A diode distortion filter was the first built and tested. In the first implementation it consisted of two diodes facing in opposite directions. 1N4148 fast switching silicon diodes were used because that was the part that was available at the time of testing. A resistance value of 330 Ohms was arbitrarily selected for R1. The signal sine wave was supplied by signal generator mobile application from the ¼ inch headphones jack. A Tektronix oscilloscope was used to observe the waveform characteristics of the filter. In the time domain, when a waveform has a voltage amplitude greater than the turn on voltage of the diode the voltage clips. Additional harmonic frequencies which are integer multiples of the original sine tone frequency are observed in the frequency domain.
The second filter built and tested was a treble booster. This filter was tested qualitatively by playing music from a phone as the input. The most audible artifact from the filtering was the high frequencies of the cymbal sounds on the drum set.
The following filters were designed and built using eagle without prior breadboard implementation and testing. The filters seemed simple enough that they would certainly work. The components were selected so that the time constant, R*C, value would filter frequencies within the audible range, less that 20kHz. Once the components were mounted on the boards the circuits were tested by measuring the signal response in the time domain. The results showed that the filters didnÕt work. There were floating voltages at unexpected pins. The output showed an unexpected DC voltage without any input signal. There may have been inconsistencies with the pinout on the board and the pinout of the device itself. Comparison of these two factors were not taken into consideration prior to sending the boards to be printed.
Subsystem Description: Audio Input
The audio input subsystem is required to take the analog audio signal from the mobile phone source and appropriately read in the signal so it is able to be modified by various filter/audio effects circuits.
The analog output of the mobile device audio signal is a quickly changing audio voltage signal that varies from roughly -440mV to 450mV at its maximum amplitude and is centered on zero volts. That is, without any amplification, the maximum audio signal amplitude is roughly 0.9 volts peak to peak (Vpp). This is simply read in with an audio jack to stereo wire connector, which then is connected directly into the breadboard so that the students can access the input signal. We chose this connector so that the students can see the audio signal being sent from the phone to the breadboard and get a better grasp on the idea that audio signals are voltages. This also gives the students flexibility in setting up the input signal on the breadboard in a way that lets them connect filters most effectively for them.
This subsystem was tested by connecting a 3.5mm audio cable to the audio jack and reading the signal on the scope when connected to the other subsystems (namely the ADC level shifter and the audio out speaker).The input signal from the Samsung Galaxy S3 device was a simple sine wave generated from the mobile app Signal Generator[3]. The amplitude of sine wave was set to its maximum value on the app, and the volume on the phone was also set to its highest setting to produce the highest amplitude audio signal for testing. All voltage readings were made on a Tectronix MSO 3011 mixed signal oscilloscope.
Subsystem Description: ADC
The analog-to-digital converter subsystem is required to sample the audio signal either right after the audio-in subsystem prepares the signal for the audio effects subsystem, or after the audio effects subsystem itself. This way, students will be able to compare and contrast audio signals before and after the effects circuits are applied, and they can view the effects in both the time and frequency domain. This subsystem is also responsible for centering the audio signal around 1.65V to adjust for the signal range on the microcontroller ADC. Thus, this subsystem has both hardware and software components to convert the analog audio signal data into a digital signal that can be sent to a separate device.
The following DC bias circuit is what shifts the audio signal voltage offset from 0V to 1.65 volts.
Figure XX – DC biasing circuit
We chose this circuit because it effectively produces a signal whose range can be fully sampled by the microcontroller ADC and also takes full advantage of the microcontroller ADC range given the maximum audio levels from our phone. Also, this circuit has very minimal frequency response, so the sampled audio should faithfully characterize the frequency components from the phone generated audio signal.
This circuit operates by setting a DC reference voltage of 1.65V using a voltage divider and unity gain amplifier to set the DC bias. This is done by resistors R10 and R11 in the above schematic. The purpose of the unity gain circuit (IC2B op amp) is to separate the 1.65V from being affected by any resistive/capacitive elements in the rest of the circuit. Once the reference voltage is set, the rest of the circuit forms an op amp level shifter centered about 1.65V and with a maximum AC component of 3.3Vpp. This gain is set by resistors R12, R13, R14, R15, with the gain calculated by the following:
A(gain) = R15 / R14 = 1.2kohms / 0.33kohms = 3.64 V / V.
Therefore, when a 0.9Vpp AC signal is sent from the phone to the circuit, the signal is first shifted up to 1.65V DC bias, then amplified by 3.64 V / V to yield an AC signal of 3.3Vpp.
We can easily obtain the 3.3V, 5V, and gnd sources aspects of the circuit from the microcontroller and USB power, which is ideal because these are also the reference voltages we are using for the microcontroller ADC.
Once the signal is set to take full advantage of the microcontroller ADC, the signal needs to be sampled by the microcontroller. This is done by running a C-program to set specific microcontroller pins to read in an analog signal, then setting reference voltages, sample times, and conversion times to appropriately sample the audio signal at a high enough rate in order to capture the frequency components we need. Because most music is sampled at 44.1 kHz, we want our circuit to complete its sampling and conversion at least a couple times faster than this. This will leave time to possibly send each sample individually during each sample period while still retaining the frequency components we want to show.
The following flow chart shows the process of our ADC microcontroller program:
Figure XX – ADC code flow chart.
Initializing the ADC involves setting the configuration bits to set sample/conversion time, reference voltages, buffer size, and multiplexer mode. First, we select manual sampling in order to easily control our sample speed and monitor the process for other tasks (such as sending out the data serially). We set the AD1CON3bits.ADCS bit to 3 in order to set the conversion time from the peripheral clock bus to 200 nanoseconds, which gives the microcontroller time to do the analog-digital conversion, but is also fast enough to capture all of our spectrum. The AVdd and AVss pins on the microcontroller are set as our reference voltages in order to give the ADC a consistent reference voltage from the board directly without worrying about any other external voltage sources. We also select the program to start conversion when the sample bit is cleared, and format the data as an unsigned integer.
The actual conversion process in the block diagram occurs by first selecting a microcontroller pin for the analog input. Then, the sample bit is set high and the program delays for 1 microsecond. This gives the microcontroller time to sample, but we are still well above our minimum sample rate of 44.1 kHz. Then the sample bit is cleared, thus starting the conversion process and outputting to the next block.
The output of the conversion needs to be scaled from quantized bits to a relevant voltage level, so we multiply the output of the ADC by 3.3V / 1024 bits to scale to the reference voltage of 3.3 volts. Lastly, this unsigned integer is sent serially to a computer and then the process repeats until all the data is collected.
We test the ACD system by first setting the proper gain on the audio-in subsystem to produce an audio signal of 3.3Vpp. This inputs into the DC bias circuit and we then run the ADC program while displaying the ADC scaled value on the LCD screen. First, we input no signal through the amplifier, and the screen reads 1.65 volts, which we expect as there is only the DC bias signal. When we increase the amplifier gain and output an audio signal, the screen value starts rapidly oscillating between values around 0.5 and 2.8. This shows that the signal is successfully DC biased and the ADC rapidly converting the analog signal to a digital signal.
System Integration Testing
Hardware integration:
The first part of testing our subsystem integration involved getting the audio in subsystem, ADC op amp level shifter circuit, analog filters, and audio output circuit/speakers all functioning properly together. Originally, all of this was tested on breadboard circuits reprsenting what we would eventually place on our board. The signals were viewed on the oscilloscope, and power signals were produced by either an external power source (+5V) or from the senior design kit board (+3.3V, Vdd).
First, we tested reading in an audio signal from the phone and running the signal through the op amp level shifter in the ADC subsystem. Originally, this proved difficult, as the audio signal fro m the phone would disappear when connected directly to the op amp level shifter. Thus, we connected the phone audio signal to a unity gain amplfier (IC5A op amp) in order to ensure that the signal was consistently being fed into the op amp level shifter. The resulting level shifter output, when the phone output signal was the maximum 0.9Vpp AC signal, was a 3.3Vpp signal with a 1.65V DC bias. This is what we expected, but there was also top end clipping on the signal at a voltage below 3.3V. This seemed strange, as the Vcc pin on the op amp was set to 3.3V, so clipping below this level is not something we expected. However, raising the the Vcc top end range to 5V fixed this problem, for whatever reason.
After the audio input and op amp level shifter were successfully integrated, the next step was to introduce the audio output circuit/speakers. Originally, we tried connecting the audio input straight into the speaker output while the op amp level shifter was still connected, which sometimes worked but sometimes, as with the level shifter testing, the audio signal went away. To combat this, we placed another unity gain amplifier before the signal went to the speaker. This also proved useful when connecting filters to the speaker, as we did not need to worry about the effect the filter elements would have on the speaker. The unity gain was actually an inverting amplfier set with a gain of 1. This was done so that the gain could easily be changed if the speaker volume range is too high or too soft. As it turned out, the unity gain provided an acceptable audio range, as the signal could be heard easily, but it was not disturbingly loud.
So far, the system was able to read in a signal from the phone, play the sound at a reasonable volume through the speaker, and shift the signal to the ADC range, all at the same time. The last hardware integration process was to insert a filter after the audio input, create another op amp level shifter for the filtered signal (in addition to the original input signal), and insert a switch that can direct either the original audio or the filtered signal to the speaker output.
This integration involved adding yet another unity gain for between the filter output and a duplicated op amp level circuit that performs the same function as the oringal level shifter. Thus, a total of three new op amps were added to the system. Next, we added a three-way switch between the speaker output unity gain amplifier and the original/filtered signals, so that we could easily switch the speaker output between the two signals.
To test this, we constructed a simple RC lowpass filter circuit and fed the original audio signal into the filter. When we played music through the phone, we were able to hear the higher frequency components (such as cymbal crash noises) at a distinctly lower volume when we switched the speaker circuit to play the filtered output. By switching quickly between the original signal and the filtered signal, we were able to actually hear the differences in the frequency components of the two signals. We confirmed this by viewing both signals on the scope and playing a sine wave through the phone. At high frequencies, the filtered signal is significantly smaller amplitude, while the two signals were very similar in amplitude at low frequencies. Thus, we confirmed that both the filter worked and the switch was successfully integrated into the system.
Lastly, we tested the op amp level shifter signals. While the original shifted audio signal was the same as we had observed when originally testing the level shifter, the filtered signal showed a lower amplitude, but the same DC bias as the original signal. This confirms that the two op amp level shifter circuits were effective at preparing both signals for the microcontroller ADC. Thus, from a hardware standpoint, all of our system requirements were met before designing our board.
Software
The software components that needed to be put together were the timer, and making the analog to digital conversion interrupt-driven. Originally, the plan was to have memory on the board, as well, so the SPI protocols were initially part of the integration testing, but due to time constraints this part of the code was abandoned. To test the timer initially, the kit boardÕs LEDÕs were used. The kit board was the testing board, because for the most part, any bugs in the code would manifest themselves using the kit board, and we could isolate those bugs to software issues rather than wondering if whatever problem arose was rather a hardware problem. Once the code was working, we could test it on our board, knowing that any bugs would be due to the interface between the software and hardware.
Software and Hardware
Once the timer was working, the next step was to make the ADC interrupt-driven. On each timer interrupt, a new ADC conversion was triggered. Upon completion of that conversion, the data was sent to the USB. After printing that data out in the terminal (using the cat command), the values that displayed were compared to the values expected. Since we did not know exactly how fast we were sampling (there was an active wait in the case that the previous ADC conversion was not finished), the initial tests were with the input grounded and connected to VDD. Ultimately, when an audio signal was the input, the values did oscillate as expected.
Users Manual/Installation Manual
PC Software Setup:
This program must be run on Linux. (A terminal emulator may work as well, but performance is not guaranteed.) Put the software in a working directory (call it Work/). In Work/, enter the command ÒmakeÓ. Then, enter the command Òsudo ./readSerialPortÓ.
Troubleshooting:
Alternatively, if you do not want to worry about which directory you are in, simply enter the command Òsudo cat <serial device> >> <output file name>Ó. <serial device> is how the computer recognizes the USB device plugged in.
Hardware setup:
1.) Plug in
both USB connectors to computer with Linux operating system
a.) Both board
power LEDs should light up if on
2.) Verify that
the +5V, -5V, and GND pins are properly connected to their corresponding
labeled pins on the breadboard
a.) Use DMM to
test if necessary
How to test if system is working:
1.) Connect
phone to breadboard via the provided audio cable
2.) Using
ÒSignal GeneratorÓ phone app, play a 1kHz sine wave with maximum amplitude and
the volume turned to maximum
a.) Turn off
speaker if too loud
3.) Using the
grey buttons, set the Òrecording timeÓ on the LCD display to 2 seconds
4.) Press the
red record button
5.) On your
computer, locate the newly created .dat file in your local directory
6.) Move the
the .dat file to your working MATLAB directory and rename it to Òsine.datÓ
7.) With the
Òsine.datÓ file in your MATLAB working directory, run the following MATLAB
script:
clear all;
load sine.dat;
sine = transpose(sine);
plot(t,sine) %Plot time domain signal
axis([0 4/tone_freq -1.2 1.2]); %Only view 4 periods of time domain
title('Time domain signal');
xlabel('Time (s)');
sound(sine,fs); %Listen to the audio of the signal
y=fft(sine,length(t)); %Compute the FFT
f=fs/length(y)*(1:length(y)); %scaling frequency axis by fs
figure;
plot(f,real(y)) %Plot frequency domain signal
axis([0.95*tone_freq tone_freq*1.05 0 3500])
title('Frequency domain spectrum');
xlabel('Frequency (Hz)');
8.) After
running the script, you should see the following charts:
To-Market Design Changes
In order to take the Freshman Module and bring it to a point where it could be successfully implemented as a module for the First Year Engineering Course, there need to be several design changes implemented. The first design change which must be implemented is to have the device be detected by the computer. Currently, the microcontroller is not detected by the Serial Port of the computer. Instead, the USB port is only able to provide power through the USB cable for the device. For the device to be programmable, the device needs to be recognized by the computer. This detection must also be implemented cross-platform, meaning it must occur in Windows, Mac OS, and Linux.
The next step in our design change is to develop an external casing for the microcontroller which is user-friendly for the student. This will serve a dual function. First, the microcontroller will be black-boxed for the user such that the user is not intimidated by the array of wires and devices sticking out of the board for them to interface with without any previous experience using microcontrollers. This will make the experience more pleasant for end users while preventing a fear factor from settling into students. Second, the casing will allow the design to evolve from a rudimentary packaging of a pizza box to a durable structure which will protect the microcontroller from basic, wear and tear damage to dropping.
The way in which the casing is envisioned the microcontroller board will have three buttons to interface with: an up button and down button to change the length of recording to more or less in one-second units from a base of ten seconds; and a red record/export button which will initiate the recording process and then export the information through the USB to the computer for analysis once the recording process has finished. Pins from the microcontroller will be brought up to the surface of the casing to allow for interaction with the microcontroller, and the casing will cold the microcontroller in place while having slots for the programmer and the USB port plugin, which serves the dual-feature of powering the device and serving as the information export pathway for the recorded information.
There will also be a slot in the casing for a headphone jack to plug in a speaker or a headphone, and another slot in the top in which the volume control slider is visible. Next to the volume control the case will have a breadboard attached to it so the user can set up their own personal filters and interact with the boardÕs input pins. In this way, the user can compare the effects of their distorted signal from the original signal, outputting the audio of the distorted signal through the audio jack or sampling the distorted signal.
The third change made in our design would be universalize the method of interaction with the active filters made in addition to the breadboard. Having the method of interaction with those boards be connecting wires to the appropriate pins allows more room for error for the user, and to minimize that error we suggest having a universal port which would connect ground to ground, Vdd to Vdd, and other corresponding pins to the appropriate spots between the actual microcontroller and the active filter boards. This port would consist of having a pre made wire which plugs into the pins in the microcontroller and the filter boards only one way, thus preventing errors when using the port and making the experience much more user friendly.
The last design change to implement would be adding more methods of interaction with the microcontroller. During the presentation, we added a Fortune Teller which had copper tape on the sides such that when the Fortune Teller was used it closed switches. If we attached the leads of the device to sound-producing devices we could generate sounds and have the student use this more fun method of interaction to engage with the microcontroller. Developing other methods of interaction such as origami with copper tape on it to close switches or drums which switched the filter being actively used would allow the user to have a more pleasant and fun experience interacting with the microcontroller.
Conclusions
Overall, there were a number of issues that prevented us from ever fully meeting all of our requirements. First, the computer was never able to recognize the serial USB driver on our board. This prevented us from ever reading in the serial data from the USB on our custom board and made it impossible for us to export ADC digital data from our board. Also, we were never able to get the op amp level shifter circuit on our board to function correctly, whether it was because of schematic flaw or soldering issues. Finally, we were never able to get the microcontroller ADC running anywhere near the 44.1 kHz that we need to sample the audio signal when integrated with the USB protocol. Because of these three issues, our system was never able to export audio data to a computer that could then further analyze the data in MATLAB or solely rely on our custom board design. These were important features that we were never able to fully realize.
However, our system still had features that freshman engineering students could use to engage with electrical engineering concepts. Our system allows students to plug in there phone/media device, connect to a breadboard, experiment with analog filters using either basic circuit elements or our provided filters, and actually hear the difference in the audio signal when the effect is applied. While they may have some experience with electrical components, our system shows them a useful and accessible application (audio) for these ideas. From here, they can easily experiment with and become more interested in electrical engineering ideas.
If we were to go back and change our approach to this project, the key difference would be the timing of creating our board design. Because we waited so long to get our first design done, we only had one chance to get one board version built. This made it extremely difficult to correct any errors with the board (USB, op amps), and we didnÕt have the option of building another board at that point. Also, we would have looked into the SPI protocol much earlier in order to give ourselves more time in figuring out ADC system integration. In the end, we wound up just running out of time.
As far as continuing our project, the next key steps would be
to fix the ADC protocol to get it sampling at 44.1 kHz (probably involves
integrating SPI protocol), fix up any board design issues, and make the overall
presentation much more neater and accessible. While we were able to lay the
groundwork for the students interaction with audio technology, there is still
the potential to create an even more immersive and accessible experience for
freshman engineering students interested in electrical engineering.


Features?
- simplicity: CREATE, READ, WRITE, APPEND
- handling of arbitrary POD type through clang++ based compiler
- position independent named arguments
- compile time evaluation
- H5CPP handles are binary compatible with CAPI handles/id-s
RAII,
exception policy,
conversion policy between CAPI and H5CPP


Newtonian Gravity: Black and White
Sorry, your browser does not support HTML5 Canvas. May I suggest Google Chrome or Mozilla Firefox?
Click and fling to add new particles. Hold-click and scroll to increase/decrease mass. Press 't' to toggle trails, 'p' to pause, 'c' to clear, and 'r' reset to the initial settings.
© 2013 C.J. Campo


Lesson 1 March 14 2015 (Pi day! Let's go!!')
Technological Empathy
Systems thinking
Breaking big problem into small ordered discrete instructions
Coding is about learning to instruct the computer to complete tasks for you
Experienced coders often say that the benefits of thinking like a programmer often spills into other facets of their life
Anyone can learn any thing therefore anyone can learn to code!
Instructions to the web
WWW – collection of HyperText Marker Language (HTML) pages
Browser makes requests through internet to servers in a protocol called HTTP
Servers respond with files. Optimized for hosting files.
HTML
HTML is the heart of the web
Text – what we see
Markup – what it looks like
References – to other documents
Links –to other pages
HTML Markup is set up like " Contents "
Also learned some basic commands like BOLD and ITALIICS as well as being introduced to "inline" versus "block" commands.
Block commands build a box around the content whereas inline commands like IMG will display in the line of the text.


@link
is not a tag, but something like keyword. GenDoc.exe replaces the "@link:"
occurrences to the
documentation path from the site corner, e.g. "/jsgui-doc/content/doc"
. Please don't forget the tailing ":" after "@link".
For example, Data_Object.dobj()
will produce the following result: Data_Object.dobj()


| About Dailyrotten |
|
Feedback
If you like this page, hate it, or would like to suggest changes,
<EMAIL_ADDRESS>is listening. This page
is experimental and somewhat different from what we usually offer, so please
do send your feedback.
Adding Stories
If you are a rotten newshound and you would like to suggest a story,
visit our submit page to
send us the URL. Stories that are accepted will have your name credited.
Viewership
On the first full day this page went live, 100,000 people visited this Rotten
News page. Of course that was the day after the WTC attacks, so that number is
somewhat distorted. Right now this page gets between 50,000 and 75,000 people
every day.
Linking
We encourage everyone to link to this page; if you like it, others probably
will as well.
Other Rotten
Rotten
Gaping Maw
Celebrity Morgue
Mugshots
Rotten Store
Shockumentary
Rate My Poo
Rate My Kitten
Rate My Finger
Penny Postcards
Phallic
Dr. Sputnik
Boners
Dead Pool
NNDB
Home
Make Dailyrotten your start page
|
|
|
December 11, 2003
Babykiller gets 8 years
News Corporation | Submitted by: Draz-Nova
"Baby Jordan had his tiny toes crushed one by one, was hit so hard his bottom teeth went through the roof of his mouth, and was subjected to repeated punches to the stomach. The seven-month-old's torture and suffering ended only when he choked to death on his own vomit. Yesterday the man responsible for the brutal killing of the baby boy was sentenced to a minimum term of just eight years and three months. With time already served, Christopher Hoerler could be free in January 2010, at the age of 32... nobody heard Jordan scream during the attack because it was believed the first punch to his jaw, which drove his bottom teeth into the roof of his mouth, knocked him unconscious. His extensive facial injuries and fractured ribs suggested he had been dragged face down over carpet or a sofa and punched hard in the abdomen. Hoerler then set about crushing Jordan's little toes - one by one - with a fan clamp."
|
|
Read article...
|
|
Policemen nailed for on-the-job hijinks
BBC | Submitted by: Soylent
"Two policemen are facing the sack after they were caught on camera speeding and wearing Ku Klux Klan-style white hoods in Western Australia. The incident happened in August 2001, and at the time police were unable to identify the suspects, who were pictured travelling at twice the speed limit in Bunbury, 180 kilometres south of Perth... The investigation has now revealed that the car involved was an unmarked police car, and its two occupants officers from Bunbury Police Station."
 The gin hadn't been used in more than 30 years and inside the pit was a thick combination of water, oil, diesel fuel, hydraulic fluid, and dirt. As the son looked into the eight to ten foot pit, he slipped and fell in. The cousin ran for help and called 9-1-1. That's when the father, 42-year-old Eugene Weston Senior, jumped into the pit after his son... The pit bull is still alive and unharmed."
|
|
Read article...
|
|
Tard allegedly kills, incinerates newborn
winfieldcourier.com | Submitted by: Pickmy Seaton
"Rebecca Lynn Gregory was taken into custody over the weekend and remains in jail on $50,000 bond... Investigators searched the farm until late Monday and recovered 'some bone fragments' from an area of the farm known as the 'dead hole' where trash and animal carcasses are incinerated... Sheriff's officers were allowed to search the single-story residence for 'the body of a deceased human infant, remains of said infant, trace evidence of said infant or trace evidence of the birth of said infant, blood evidence, D.N.A., large dog food bag, plastic trash bag, towels, sweat pants, and other clothing items, any written indicia of the pregnancy of Rebecca Gregory, and any photographic evidence of the pregnancy of Rebecca Gregory.'"
|
|
Read article...
|
|
Secret Service admits they sent Mohamad home
Washington Post | Submitted by: optional
"While expressing regret over the incident, the Secret Service also stopped short of offering the apology that the waiter, Mohamad I. Pharoan, 58, has sought. He had expected to help serve lunch to 550 people at a banquet at which President Bush raised $1 million for his reelection campaign. Instead, he says, he was given a few minutes to change clothes and was escorted off the premises after a manager asked him one question: 'Is your name Mohamad?' Last week, the Secret Service denied that it had requested the hotel's management to dismiss Pharoan for the day. But a spokesman said yesterday that after further review, the Secret Service found it was responsible."
|
|
Read article...
|
|
Official Iraqi civilian death count halted
Atlanta Journal-Constitution | Submitted by: A. P. Palled
"The Associated Press conducted a major investigation of Iraq's wartime civilian casualties, documenting the deaths of 3,240 civilians between March 20 and April 20. That investigation, conducted in May and June, surveyed about half of Iraq's hospitals and reported that the real number of civilian deaths was sure to be much higher. The Health Ministry's count, which was to be based on the records of all Iraq's hospitals, promised to be more complete. The ministry began its survey at the end of July, when shaky nationwide communication links began to improve. It sent letters to all hospitals and clinics in Iraq, asking them to send back details of civilians killed or wounded in the war, ministry officials said then. Many hospitals responded, [Dr. Nagham Mohsen] said, but last month, Shabandar told her that [Iraqi health minister Dr. Khodeir Abbas] wanted the count halted. He also told her not to release the information she already had collected, she said."
|
|
Read article...
|
|
Mayor embarrassed over naked photos
Globe and Mail | Submitted by: TAZZY8JAZZY
"As the first female mayor of the northern B.C. town of Houston, Sharon Smith was proud of her accomplishments. So was her husband. So proud that he snapped photos of Her Worship wearing the chain of office - and nothing else. Everything was fine until photos of a smiling Ms. Smith were allegedly copied from her home computer during a house party her kids threw, then circulated around the mill town of 4,300... 'My privacy has been violated in every sense,' Ms. Smith wrote in her letter earlier this month to Houston Today. 'These photos are private property belonging to my husband and me. I am very hurt and embarrassed.'"
|
|
Read article... and
This... and
This...
|
|
Russian anti-kidnapping official jailed for kidnapping
Toronto Star | Submitted by: Lydia
"The 11-year-old son of a slain politician was freed after 3-1/2 years in captivity in southern Russia, and the head of the regional anti-kidnapping unit was a suspect in the case, police said today... among those arrested Wednesday in the case was Imamutdin Temirbulatov, head of the regional police unit charged with fighting kidnapping... Rossiya reported that two high-ranking officials from the kidnapping unit were arrested, but gave no further details. Countless victims have been kidnapped for ransom in the southern Russian region of Dagestan in recent years."
|
|
Read article...
|
|
Atmosphere reeling from 8,000 years of human activity
CNN | Submitted by: Mean Gene
"Beginning 8,000 years ago, atmospheric levels of carbon dioxide began to rise as humans started clearing forests, planting crops and raising livestock, a scientist said Tuesday. Methane levels started increasing 3,000 years later... Previously, scientists widely assumed it was only with the onset of the factory age that human activity had any significant effect on the global climate. The prehistoric changes in carbon dioxide and methane levels have been noted before but were attributed to natural causes, Ruddiman said."
|
|
Read article...
|
|
|
|
|


--- title: blobster keywords: fastai sidebar: home_sidebar summary: "API details." ---
azure_blob_storage = AzureBlobStorage(account='your_account_string', key='your_key_string')
Once the credentials have been loaded with load_credentials
a connection can be established by calling the connect
method.
azure_blob_storage.connect()
azure_blob_storage.list_all_containers()
azure_blob_storage.delete_container(container_that_shall_be_deleted)


Array Methods
Problem 3.


Date of birth
The Adobe family of companies Adobe family of compaines may keep me informed with personalized personalized emails about products and services. See our Privacy Policy Privacy Policy for more details or to opt-out at any time.
By clicking Create account, I agree that I have read and accepted the Terms of Use Terms of Use and Privacy Policy.Privacy Policy


Document contains Header/Footer, Footnote/Endnote, Comment, Frame, TextBox
Frame story[W丫¥ل云玗İαЂ1]
[i][1][W丫¥ل云玗İαЂ2]
[1] Footnote story
[i] Endnote story
[W丫¥ل云玗İαЂ1]Trying to add a comment
[W丫¥ل云玗İαЂ2]Comment story


public class RabbitsGrassSimulationAgent
extends java.lang.Object
implements uchicago.src.sim.gui.Drawable
| Modifier and Type | Field and Description |
|---|---|
private int |
energy |
private int |
ID |
private static int |
IDNumber |
private static java.awt.image.BufferedImage |
rabbitIcon |
private RabbitsGrassSimulationSpace |
rgsSpace |
private int |
vX |
private int |
vY |
private int |
x |
private int |
y |
| Constructor and Description |
|---|
RabbitsGrassSimulationAgent(int energyInit)
Constructor that takes the initial energy of the agent
|
| Modifier and Type | Method and Description |
|---|---|
void |
draw(uchicago.src.sim.gui.SimGraphics G)
Draw this agent to the RePast graphics
object.
|
int |
getEnergy()
Get the amount of energy held by this agent
|
java.lang.String |
getID()
Get this agent's internal unique ID
|
int |
getX()
Get this agent's X position
|
int |
getY()
Get this agent's Y position
|
void |
report()
Prints a report on this agent's status variables to
the System output
|
void |
setEnergy(int e)
Set the amount of energy to the agent
|
void |
setRabbitGrassSimulationSpace(RabbitsGrassSimulationSpace rgss)
Set this agent's pointer to the space object
in which it resides.
|
static void |
setRabbitImg(java.awt.image.BufferedImage img)
Set the visual representation of the agents.
|
void |
setVxVy()
Set this agent's velocity in the X and Y direction
Actually chooses a new velocity randomly; velocity
will be one of the 8 possible variations where
X and Y are -1, 0, or 1 and Y but both are not zero
|
void |
setXY(int newX,
int newY)
Set a new X and Y position for the agent.
|
void |
step()
A basic 'step' for this agent- the actions it
takes when it is the agent's 'turn' in the simulation
|
private boolean |
tryMove(int newX,
int newY)
Attempt a move to a new location.
|
private int x
private int y
private int vX
private int vY
private int energy
private static int IDNumber
private int ID
private RabbitsGrassSimulationSpace rgsSpace
private static java.awt.image.BufferedImage rabbitIcon
public RabbitsGrassSimulationAgent(int energyInit)
energyInit
- Initial rabbit energypublic void setXY(int newX, int newY)
newX
- newY
- public void setVxVy()
public void setRabbitGrassSimulationSpace(RabbitsGrassSimulationSpace rgss)
rgss
- The space object into which the agent is
being placedpublic java.lang.String getID()
public int getEnergy()
public void setEnergy(int e)
e
- New energy that will be given to the agentpublic void report()
public int getX()
getX
in interface uchicago.src.sim.gui.Drawable
public int getY()
getY
in interface uchicago.src.sim.gui.Drawable
public void draw(uchicago.src.sim.gui.SimGraphics G)
draw
in interface uchicago.src.sim.gui.Drawable
G
- the graphics object to which this agent
will be drawnpublic void step()
private boolean tryMove(int newX, int newY)
newX
- the intended destination's X coordinatenewY
- the intended destination's Y coordinatepublic static void setRabbitImg(java.awt.image.BufferedImage img)
img
- the graphical image that represents the agent


2 Corinthians 12:3
And I knew such a man, (whether in the body, or out of the body, I cannot tell: God knoweth;)


WITNESS LIST Judicial Affairs Committee April 14, 2003-12:00A HB 3274 Against: Scholl, Shirley (112th District Attorney)


I'm in column 1 of 1. I stretch the entire width and keep going.
I'm in column 1 of 2
I'm in column 2 of 2


Five Myths and Misfortunes
i.
:: foliage
summer is long gone
winter is yet to come
let alone the spring but
let me come to think of it;
about the brown fall for
it can be a perfect lesson
about how death, of leaves
and living things, at the very
least, is beautiful and
ephemeral and beautiful and
ephemeral and be—
ii.
:: apollo
exploding tanks, wasted oxygen,
choked throats, dry lungs, almost lost
forever in foreign space and home;
but home was the last thing we recalled
because the suits that allowed us to walk
inside this zero gravity cubicle
needed to call a small station in that
rotting blue planet, first of all
we were almost forever lost
yet home was calling us home
iii.
:: postman
he gazes through the window
and mumbles about loneliness;
of himself, stamp and airmail,
an old office he will someday leave
for retirement but then he checks his
phone and giggles and stops mumbling
iv.
:: astral
look at the girl in sweater
and brunette milk braids
crying while knotting the
dead dots beyond the skies
we can hear you, little girl
don’t hope for silly things like
getting new band merch for
christmas or losing weight
to the constellations because
even when we have lived here
for million years, we are still
unseen, our hopes are crashing
and burned like one of those dead
dots, again, but we are also one of
the dead dots, again, just in the
other side of galaxy you don’t see
v.
:: feast
my name is toothpick
but nobody picks me before
dinner or in the middle of dinner
or after dinner; whenever


Application Name:
Application Nick Name:
ip Address of Service
Port of Service (Optional):
Type of Application:
Collaboration: This is app that allows users to collaborate.
Community: This is a app that supports community building or services.
Circumvention: This application increases the security or Privacy of users.

URL of application Icon:


Management Utilities is happy to bring you a brand new simulaton of the SR products market!
Market simulation is an easy to play simulation. You have only 3 tabs to consider:
Market info to analyze the market, Order to make your decision, Balance sheet to see your results!


Deep Learning Programming Paradigm
Deep Learning Programming Paradigm
However much we might ultimately care about performance, we first need working code before we can start worrying about optimization. Writing clear, intuitive deep learning code can be challenging, and the first thing any practitioner must deal with is the language syntax itself. Complicating matters, of the many deep learning libraries out there, each has its own approach to programming style.
In this document, we focus on two of the most important high-level design decisions: 1. Whether to embrace the symbolic or imperative paradigm for mathematical computation. 2. Whether to build networks with bigger (more abstract) or more atomic operations.
Throughout, we'll focus on the programming models themselves. When programming style decisions may impact performance, we point this out, but we don't dwell on specific implementation details.
Symbolic vs. Imperative Programs
If you are a Python or C++ programmer, then you're already familiar with imperative programs. Imperative-style programs perform computation as you run them. Most code you write in Python is imperative, as is the following NumPy snippet.
import numpy as np
a = np.ones(10)
b = np.ones(10) * 2
c = b * a
d = c + 1
When the program executes c = b * a
, it runs the actual numerical computation.
Symbolic programs are a bit different. With symbolic-style programs, we first define a (potentially complex) function abstractly. When defining the function, no actual numerical computation takes place. We define the abstract function in terms of placeholder values. Then we can compile the function, and evaluate it given real inputs. In the following example, we rewrite the imperative program from above as a symbolic-style program:
A = Variable('A')
B = Variable('B')
C = B * A
D = C + Constant(1)
# compiles the function
f = compile(D)
d = f(A=np.ones(10), B=np.ones(10)*2)
As you can see, in the symbolic version, when C = B * A
is executed, no computation occurs.
Instead, this operation generates a computation graph (also called a symbolic graph)
that represents the computation.
The following figure shows a computation graph to compute D
.
Most symbolic-style programs contain, either explicitly or implicitly, a compile step. This converts the computation graph into a function that we can later call. In the above example, numerical computation only occurs in the last line of code. The defining characteristic of symbolic programs is their clear separation between building the computation graph and executing it. For neural networks, we typically define the entire model as a single compute graph.
Among other popular deep learning libraries, Torch, Chainer, and Minerva embrace the imperative style. Examples of symbolic-style deep learning libraries include Theano, CGT, and TensorFlow. We might also view libraries like CXXNet and Caffe, which rely on configuration files, as symbolic-style libraries. In this interpretation, we'd consider the content of the configuration file as defining the computation graph.
Now that you understand the difference between these two programming models, let's compare the advantages of each.
Imperative Programs Tend to be More Flexible
When you're using an imperative-style library from Python, you are writing in Python. Nearly anything that would be intuitive to write in Python, you could accelerate by calling down in the appropriate places to the imperative deep learning library. On the other hand, when you write a symbolic program, you may not have access to all the familiar Python constructs, like iteration. Consider the following imperative program, and think about how you can translate this into a symbolic program.
a = 2
b = a + 1
d = np.zeros(10)
for i in range(d):
d += np.zeros(10)
This wouldn't be so easy if the Python for-loop weren't supported by the symbolic API. When you write a symbolic program in Python, you're not writing in Python. Instead, you're writing in a domain-specific language (DSL) defined by the symbolic API. The symbolic APIs found in deep learning libraries are powerful DSLs that generate callable computation graphs for neural networks. <!-- In that sense, config-file input libraries are all symbolic. -->
Intuitively, you might say that imperative programs are more native than symbolic programs. It's easier to use native language features. For example, it's straightforward to print out the values in the middle of computation or to use native control flow and loops at any point in the flow of computation.
Symbolic Programs Tend to be More Efficient
As we've seen, imperative programs tend to be flexible and fit nicely into the programming flow of a host language. So you might wonder, why do so many deep learning libraries embrace the symbolic paradigm? The main reason is efficiency, both in terms of memory and speed. Let's revisit our toy example from before.
import numpy as np
a = np.ones(10)
b = np.ones(10) * 2
c = b * a
d = c + 1
...
Assume that each cell in the array occupies 8 bytes of memory. How much memory do you need to execute this program in the Python console?
As an imperative program we need to allocate memory at each line.
That leaves us allocating 4 arrays of size 10.
So we'll need 4 * 10 * 8 = 320
bytes.
On the other hand, if we built a computation graph,
and knew in advance that we only needed d
,
we could reuse the memory originally allocated for intermediate values.
For example, by performing computations in-place,
we might recycle the bits allocated for b
to store c
.
And we might recycle the bits allocated for c
to store d
.
In the end we could cut our memory requirement in half,
requiring just 2 * 10 * 8 = 160
bytes.
Symbolic programs are more restricted.
When we call compile
on D, we tell the system
that only the value of d
is needed.
The intermediate values of the computation,
in this case c
, is then invisible to us.
We benefit because the symbolic programs
can then safely reuse the memory for in-place computation.
But on the other hand, if we later decide that we need to access c
, we're out of luck.
So imperative programs are better prepared to encounter all possible demands.
If we ran the imperative version of the code in a Python console,
we could inspect any of the intermediate variables in the future.
Symbolic programs can also perform another kind of optimization, called operation folding. Returning to our toy example, the multiplication and addition operations can be folded into one operation, as shown in the following graph. If the computation runs on a GPU processor, one GPU kernel will be executed, instead of two. In fact, this is one way we hand-craft operations in optimized libraries, such as CXXNet and Caffe. Operation folding improves computation efficiency.
Note, you can't perform operation folding in imperative programs, because the intermediate values might be referenced in the future. Operation folding is possible in symbolic programs because you get the entire computation graph, and a clear specification of which values will be needed and which are not.
Case Study: Backprop and AutoDiff
In this section, we compare the two programming models on the problem of auto differentiation, or backpropagation. Differentiation is of vital importance in deep learning because it's the mechanism by which we train our models. In any deep learning model, we define a loss function. A loss function measures how far the model is from the desired output. We then typically pass over training examples (pairs of inputs and ground-truth outputs). At each step we update the model's parameters to minimize the loss. To determine the direction in which to update the parameters, we need to take the derivative of the loss function with respect to the parameters.
In the past, whenever someone defined a new model, they had to work out the derivative calculations by hand. While the math is reasonably straightforward, for complex models, it can be time-consuming and tedious work. All modern deep learning libraries make the practitioner/researcher's job much easier, by automatically solving the problem of gradient calculation.
Both imperative and symbolic programs can perform gradient calculation. So let's take a look at how you might perform automatic differentiation with each.
Let's start with imperative programs. The following example Python code performs automatic differentiation using our toy example:
class array(object) :
"""Simple Array object that support autodiff."""
def __init__(self, value, name=None):
self.value = value
if name:
self.grad = lambda g : {name : g}
def __add__(self, other):
assert isinstance(other, int)
ret = array(self.value + other)
ret.grad = lambda g : self.grad(g)
return ret
def __mul__(self, other):
assert isinstance(other, array)
ret = array(self.value * other.value)
def grad(g):
x = self.grad(g * other.value)
x.update(other.grad(g * self.value))
return x
ret.grad = grad
return ret
# some examples
a = array(1, 'a')
b = array(2, 'b')
c = b * a
d = c + 1
print d.value
print d.grad(1)
# Results
# 3
# {'a': 2, 'b': 1}
In this code, each array object contains a grad function (it is actually a closure).
When you run d.grad
, it recursively invokes the grad function of its inputs,
backprops the gradient value back, and
returns the gradient value of each input.
This might look a bit complicated, so let's consider the gradient calculation for symbolic programs. The following program performs symbolic gradient calculation for the same task.
A = Variable('A')
B = Variable('B')
C = B * A
D = C + Constant(1)
# get gradient node.
gA, gB = D.grad(wrt=[A, B])
# compiles the gradient function.
f = compile([gA, gB])
grad_a, grad_b = f(A=np.ones(10), B=np.ones(10)*2)
The grad function of D
generates a backward computation graph,
and returns a gradient node, gA, gB
,
which correspond to the red nodes in the following figure.
The imperative program actually does the same thing as the symbolic program.
It implicitly saves a backward computation graph in the grad closure.
When you invoked d.grad
, you start from d(D)
,
backtrack through the graph to compute the gradient, and collect the results.
The gradient calculations in both symbolic
and imperative programming follow the same pattern.
What's the difference then?
Recall the be prepared to encounter all possible demands requirement of imperative programs.
If you are creating an array library that supports automatic differentiation,
you have to keep the grad closure along with the computation.
This means that none of the history variables can be
garbage-collected because they are referenced by variable d
by way of function closure.
What if you want to compute only the value of d
,
and don't want the gradient value?
In symbolic programming, you declare this with f=compiled([D])
.
This also declares the boundary of computation,
telling the system that you want to compute only the forward pass.
As a result, the system can free the memory of previous results,
and share the memory between inputs and outputs.
Imagine running a deep neural network with n
layers.
If you are running only the forward pass,
not the backward(gradient) pass,
you need to allocate only two copies of
temporal space to store the values of the intermediate layers,
instead of n
copies of them.
However, because imperative programs need to be prepared
to encounter all possible demands of getting the gradient,
they have to store the intermediate values,
which requires n
copies of temporal space.
As you can see, the level of optimization depends on the restrictions on what you can do. Symbolic programs ask you to clearly specify these restrictions when you compile the graph. One the other hand, imperative programs must be prepared for a wider range of demands. Symbolic programs have a natural advantage because they know more about what you do and don't want.
There are ways in which we can modify imperative programs to incorporate similar restrictions. For example, one solution to the preceding problem is to introduce a context variable. You can introduce a no-gradient context variable to turn gradient calculation off.
with context.NoGradient():
a = array(1, 'a')
b = array(2, 'b')
c = b * a
d = c + 1
However, this example still must be prepared to encounter all possible demands, which means that you can't perform the in-place calculation to reuse memory in the forward pass (a trick commonly used to reduce GPU memory usage). The techniques we've discussed generate an explicit backward pass. Some of the libraries such as Caffe and CXXNet perform backprop implicitly on the same graph. The approach we've discussed in this section also applies to them.
Most configuration-file-based libraries, such as CXXNet and Caffe are designed to meet one or two generic requirements: get the activation of each layer, or get the gradient of all of the weights. These libraries have the same problem: the more generic operations the library has to support, the less optimization (memory sharing) you can do, based on the same data structure.
As you can see, the trade-off between restriction and flexibility is the same for most cases.
Model Checkpoint
It's important to able to save a model and load it back later. There are different ways to save your work. Normally, to save a neural network, you need to save two things: a net configuration for the structure of the neural network and the weights of the neural network.
The ability to check the configuration is a plus for symbolic programs. Because the symbolic construction phase does not perform computation, you can directly serialize the computation graph, and load it back later. This solves the problem of saving the configuration without introducing an additional layer.
A = Variable('A')
B = Variable('B')
C = B * A
D = C + Constant(1)
D.save('mygraph')
...
D2 = load('mygraph')
f = compile([D2])
# more operations
...
Because an imperative program executes as it describes the computation,
you have to save the code itself as the configuration
,
or build another configuration layer on top of the imperative language.
Parameter Updates
Most symbolic programs are data flow (computation) graphs. Data flow graphs describe computation. But it's not obvious how to use graphs to describe parameter updates. That's because parameter updates introduce mutation, which is not a data flow concept. Most symbolic programs introduce a special update statement to update persistent state in the programs.
It's usually easier to write parameter updates in an imperative style, especially when you need multiple updates that relate to each other. For symbolic programs, the update statement is also executed as you call it. So in that sense, most symbolic deep learning libraries fall back on the imperative approach to perform updates, while using the symbolic approach to perform gradient calculation.
There Is No Strict Boundary
In comparing the two programming styles, some of our arguments might not be strictly true, i.e., it's possible to make an imperative program more like a traditional symbolic program or vice versa. However, the two archetypes are useful abstractions, especially for understanding the differences between deep learning libraries. We might reasonably conclude that there is no clear boundary between programming styles. For example, you can create a just-in-time (JIT) compiler in Python to compile imperative Python programs, which provides some of the advantages of global information held in symbolic programs.
Big vs. Small Operations
When designing a deep learning library, another important programming model decision is precisely what operations to support. In general, there are two families of operations supported by most deep learning libraries:
- Big operations - typically for computing neural network layers (e.g. FullyConnected and BatchNormalize).
- Small operations - mathematical functions like matrix multiplication and element-wise addition.
Libraries like CXXNet and Caffe support layer-level operations. Libraries like Theano and Minerva support fine-grained operations.
Smaller Operations Can Be More Flexible
It's quite natural to use smaller operations to compose bigger operations. For example, the sigmoid unit can simply be composed of division, addition and an exponentiation:
sigmoid(x) = 1.0 / (1.0 + exp(-x))
Using smaller operations as building blocks, you can express nearly anything you want. If you're more familiar with CXXNet- or Caffe-style layers, note that these operations don't differ from a layer, except that they are smaller.
SigmoidLayer(x) = EWiseDivisionLayer(1.0, AddScalarLayer(ExpLayer(-x), 1.0))
This expression composes three layers, with each defining its forward and backward (gradient) function. Using smaller operations gives you the advantage of building new layers quickly, because you only need to compose the components.
Big Operations Are More Efficient
Directly composing sigmoid layers requires three layers of operation, instead of one.
SigmoidLayer(x) = EWiseDivisionLayer(1.0, AddScalarLayer(ExpLayer(-x), 1.0))
This code creates overhead for computation and memory (which could be optimized, with cost).
Libraries like CXXNet and Caffe take a different approach. To support coarse-grained operations, such as BatchNormalization and the SigmoidLayer directly, in each layer, the calculation kernel is hand crafted with one or only some CUDA kernel launches. This makes these implementations more efficient.
Compilation and Optimization
Can small operations be optimized? Of course, they can. Let's look at the system optimization part of the compilation engine. Two types of optimization can be performed on the computation graph:
- Memory allocation optimization, to reuse the memory of the intermediate computations.
- Operator fusion, to detect sub-graph patterns, such as the sigmoid, and fuse them into a bigger operation kernel.
Memory allocation optimization isn't restricted to small operations graphs.
You can use it with bigger operations graph, too.
However, optimization might not be essential
for bigger operation libraries like CXXNet and Caffe,
because you can't find the compilation step in them.
However, there's a (dumb) compilation step
in these libraries,
that basically translates the layers into a fixed forward,
backprop execution plan, by running each operation one by one.
For computation graphs with smaller operations, these optimizations are crucial to performance. Because the operations are small, there are many sub-graph patterns that can be matched. Also, because the final, generated operations might not be enumerable, an explicit recompilation of the kernels is required, as opposed to the fixed amount of precompiled kernels in the big operation libraries. This creates compilation overhead for the symbolic libraries that support small operations. Requiring compilation optimization also creates engineering overhead for the libraries that solely support smaller operations.
As in the case of symbolic vs. imperative, the bigger operation libraries "cheat" by asking you to provide restrictions (to the common layer), so that you actually perform the sub-graph matching. This moves the compilation overhead to the real brain, which is usually not too bad.
Expression Template and Statically Typed Language
You always have a need to write small operations and compose them. Libraries like Caffe use hand-crafted kernels to build these bigger blocks. Otherwise, you would have to compose smaller operations using Python.
There's a third choice that works pretty well. This is called the expression template. Basically, you use template programming to generate generic kernels from an expression tree at compile time. For details, see Expression Template Tutorial. CXXNet makes extensive use of an expression template, which enables creating much shorter and more readable code that matches the performance of hand-crafted kernels.
The difference between using an expression template and Python kernel generation is that expression evaluation is done at compile time for C++ with an existing type, so there is no additional runtime overhead. In principle, this is also possible with other statically typed languages that support templates, but we've seen this trick used only in C++.
Expression template libraries create a middle ground between Python operations and hand-crafted big kernels by allowing C++ users to craft efficient big operations by composing smaller operations. It's an option worth considering.
Mix the Approaches
Now that we've compared the programming models, which one should you choose? Before delving into that, we should emphasize that depending on the problems you're trying to solve, our comparison might not necessarily have a big impact.

As you've seen, there usually is a trade-off between efficiency, flexibility, and engineering complexity. The more suitable programming style depends on the problem you are trying to solve. For example, imperative programs are better for parameter updates, and symbolic programs for gradient calculation.
We advocate mixing the approaches. Sometimes the part that we want to be flexible isn't crucial to performance. In these cases, it's okay to leave some efficiency on the table to support more flexible interfaces. In machine learning, combining methods usually works better than using just one.
If you can combine the programming models correctly, you can get better results than when using a single programming model. In this section, we discuss how to do so.
Symbolic and Imperative Programs
There are two ways to mix symbolic and imperative programs:
- Use imperative programs within symbolic programs as callbacks
- Use symbolic programs as part of imperative programs
We've observed that it's usually helpful to write parameter updates imperatively, and perform gradient calculations in symbolic programs.
Symbolic libraries already mix programs because Python itself is imperative. For example, the following program mixes the symbolic approach with NumPy, which is imperative.
A = Variable('A')
B = Variable('B')
C = B * A
D = C + Constant(1)
# compiles the function
f = compile(D)
d = f(A=np.ones(10), B=np.ones(10)*2)
d = d + 1.0
The symbolic graphs are compiled into a function that can be executed imperatively. The internals are a black box to the user. This is exactly like writing C++ programs and exposing them to Python, which we commonly do.
Because parameter memory resides on the GPU, you might not want to use NumPy as an imperative component. Supporting a GPU-compatible imperative library that interacts with symbolic compiled functions or provides a limited amount of updating syntax in the update statement in symbolic program execution might be a better choice.
Small and Big Operations
There might be a good reason to combine small and big operations. Consider applications that perform tasks such as changing a loss function or adding a few customized layers to an existing structure. Usually, you can use big operations to compose existing components, and use smaller operations to build the new parts.
Recall Amdahl's law. Often, the new components are not the cause of the computation bottleneck. Because the performance-critical part is already optimized by the bigger operations, it's okay to forego optimizing the additional small operations, or to do a limited amount of memory optimization instead of operation fusion and directly running them.
Choose Your Own Approach
In this document, we compared multiple approaches to developing programming environments for deep learning. We compared both the usability and efficiency implications of each, finding that many of these trade-offs (like imperative vs symbolic aren't necessarily black and white). You can choose your approach, or combine the approaches to create more interesting and intelligent deep learning libraries.
Contribute to MXNet
This document is part of our effort to provide open-source system design notes for deep learning libraries. If you're interested in contributing to MXNet or its documentation, fork us on GitHub.


1990’s
In 1990 the multimedia PC is developed. Schools are beginning to use CD-ROMs with educational programs and databases.
The 1990’s brought on the era of the Computer Lab, with increased computer usage by students and teachers; The computer lab was developed, to house the growing number of computers.
1995 is the begging of the world wide web as being a popular place to communicate. The internet in classroom, allowed for students to send emails, research information, and have more freedom to discover and learn on their own.
1995-1999 the Internet becomes widely used and accepted in schools, with most schools having their own web servers, as well as faculty creating instructional web pages.
The 1990’s allowed students to access all forms of multimedia, much like were able to today. The internet and new programs, allowed for video, animation, audio, and images to be accessible easily.
Email also allowed for students around the globe to readily communicate with each other. As well it allowed student to get answers to their questions directly from scientists. A web site that existed in 1993 called: Ask a scientist. The site allowed students to email experts in all areas of study any questions they had.