Tuesday, May 3, 2011

How to test TCP/IP sockets delays on a single machine

Problem Statement:

How much time delay does a socket introduce when used to communicate between two processes on a machine?

Solution:

To estimate the delay, build a small test program to act as a server and a client. Measure the total time required for multiple data transfers.

Server.py

import socket

HOST = '127.0.0.1'
PORT = 50006

s = socket.socket(socket.AF_INET,socket.SOCK_STREAM)
s.bind((HOST,PORT))
s.listen(1)
conn,addr = s.accept()
print 'Connected by',addr
while 1:
    data = conn.recv(1024)
    if not data: break
    conn.send(data)
conn.close()

 

Client.py

import socket
import time

HOST = '127.0.0.1'
PORT = 50006

s = socket.socket(socket.AF_INET,socket.SOCK_STREAM)
s.connect((HOST,PORT))
t0 = time.time()
for i in range(0,1000):
    s.send('Hello World!')
    data = s.recv(1024)
delta_time = time.time()-t0
s.close()
print 'Received ',data
print 'Average Time ',delta_time/1000.0

 

Start Server.py at the command line. Run Client.py.  For my machine, the results were:

Received  Hello World!
Average Time  5.5999994278e-05

 

Discussion:

This test created a reliable socket between two independent processes by using the SOCK_STREAM socket which uses TCP/IP as a transport layer protocol.

Test Conditions:

  • Python 2.6
  • win7 with Intel i7 CPU
This work is licensed under a Creative Commons Attribution By license.

Friday, April 8, 2011

Installing JModelica after PythonXY

To get JModelica 1.5 to work with PythonXY 2.6.5.6 on win7 Professional, the following steps will work:
  1. Install PythonXY using default options.
  2. Start the JModelica install. When given a choice on where install, choose C:\.
  3. Add a path file to the site-packages directory in python. In a default install of PythonXY, the location is “C:\Python26\Lib\site-packages”. The name of the file should be “jmodelica.pth”. The contents of the file is a single line “C:\JModelica.org-1.5\Python”. To understand how Python paths work, see this reference.
  4. Open “C:\JModelica.org-1.5\setenv.bat” with a text editor. Manually set all of the environment variables in your system to match the environment variables defined in this file.
  5. Start a python interpreter in PythonXY.
  6. Follow the direction for testing in “C:\JModelica.org-1.5\README.TXT”. The tests should complete successfully.
Addendum:
   This approach also works with JModelica 1.6 and PythonXY 2.7.2.
   Simply substitute "JModelica.org-1.6" for "JModelica.org-1.5" in the above steps.
This work is licensed under a Creative Commons Attribution By license.

Monday, March 21, 2011

First Draft: A Script to Display Multicolor Voronoi Diagrams in Matplotlib

reference_plot

Code Sample

'''
This module generates 2D voronoi diagrams from a list of points.
The vornoi cells can be colored by supplying a value associated with 
   each node.
'''

__author__ = 'Ed Tate'
__email__  = 'edtate<at>gmail-dot-com'
__website__ = 'exnumerus.blogspot.com'
__license__ = 'Creative Commons Attribute By - http://creativecommons.org/licenses/by/3.0/us/'''

from matplotlib.pyplot import cm

def voronoi2D(xpt,ypt,cpt=None,cmap=None):
    '''
    This function returns a list of line segments which describe the voronoi
        cells formed by the points in zip(xpt,ypt).
    
    If cpt is provided, it identifies which cells should be returned.
        The boundary of the cell about (xpt[i],ypt[i]) is returned 
            if cpt[i]<=threshold.
            
    This function requires qvoronoi.exe in the working directory. 
    The working directory must have permissions for read and write access.
    This function will leave 2 files in the working directory:
        data.txt
        results.txt
    This function will overwrite these files if they already exist.
    '''
    
    if cpt is None:
        # assign a value to cpt for later use
        cpt = [0 for x in xpt]
        
    if cmap is None:
        cmap = cm.gray
    
    # write the data file
    pts_filename = 'data.txt'
    pts_F = open(pts_filename,'w')
    pts_F.write('2 # this is a 2-D input set\n')
    pts_F.write('%i # number of points\n' % len(xpt))
    for i,(x,y) in enumerate(zip(xpt,ypt)):
        pts_F.write('%f %f # data point %i\n' % (x,y,i))
    pts_F.close()

    # trigger the shell command
    import subprocess
    p = subprocess.Popen('qvoronoi TI data.txt TO results.txt p FN Fv QJ', shell=True)
    p.wait()

    # open the results file and parse results
    results = open('results.txt','r')

    # get 'p' results - the vertices of the voronoi diagram
    data = results.readline()
    voronoi_x_list = []
    voronoi_y_list = []
    data = results.readline()
    for i in range(0,int(data)):
        data = results.readline()
        xx,yy,dummy = data.split(' ')    
        voronoi_x_list.append(float(xx))
        voronoi_y_list.append(float(yy))
        
    # get 'FN' results - the voronoi edges
    data = results.readline()
    voronoi_idx_list = []
    for i in range(0,int(data)):
        data = results.readline()
        this_list = data.split(' ')[:-1]
        for j in range(len(this_list)):
            this_list[j]=int(this_list[j])-1
        voronoi_idx_list.append(this_list[1:])
        
    # get 'FV' results - pairs of points which define a voronoi edge
    # combine these results to build a complete representation of the 
    data = results.readline()
    voronoi_dict = {}
    for i in range(0,int(data)):
        data = results.readline().split(' ')

        pair_idx_1 = int(data[1])
        pair_idx_2 = int(data[2])

        vertex_idx_1 = int(data[3])-1
        vertex_idx_2 = int(data[4])-1

        try:
            voronoi_dict[pair_idx_1].append({ 'edge_vertices':[vertex_idx_1,vertex_idx_2],
                                      'neighbor': pair_idx_2 })
        except KeyError:
            voronoi_dict[pair_idx_1] = [{ 'edge_vertices':[vertex_idx_1,vertex_idx_2],
                                      'neighbor': pair_idx_2 } ]

        try:
            voronoi_dict[pair_idx_2].append({ 'edge_vertices':[vertex_idx_1,vertex_idx_2],
                                      'neighbor': pair_idx_1 })
        except KeyError:
            voronoi_dict[pair_idx_2] = [{ 'edge_vertices':[vertex_idx_1,vertex_idx_2],
                                      'neighbor': pair_idx_1 } ]    

                    
    #################
    # generate a collection of voronoi cells
    result_list = []
    for point_idx in voronoi_dict.keys():
        # determine cell color
        this_color = cmap(cpt[point_idx])
        
        # display this cell, so add the data to the edge list
        e_list = []
        for edge in voronoi_dict[point_idx]:
            p1_idx = edge['edge_vertices'][0]
            p2_idx = edge['edge_vertices'][1]
            e_list.append((p1_idx,p2_idx))
        
        # put the vertices points in order so they
        #   walk around the voronoi cells
        p_list = [p1_idx]
        while True:
            p=p_list[-1]
            for e in e_list:
                if p==e[0]:
                    next_p = e[1]
                    break
                elif p==e[1]:
                    next_p = e[0]
                    break
            p_list.append(next_p)
            e_list.remove(e)
            if p_list[0]==p_list[-1]:
                # the cell is closed
                break
            
        # build point list
        this_x_list = []
        this_y_list = []
        if all([p>=0 for p in p_list]):
            for p in p_list:
                if p>=0:
                    this_x_list.append(voronoi_x_list[p])
                    this_y_list.append(voronoi_y_list[p])     
                    
        result_list.append([this_x_list,this_y_list,this_color])
        
    return result_list

if __name__=='__main__':
    
    import random
    
    xpt = [random.random()-0.5 for i in range(0,100)]
    ypt = [random.random()-0.5 for i in range(0,100)]
    cpt = [int(random.random()*255) for i in range(0,100)]

    import matplotlib.pyplot as pp
    
    result_list = voronoi2D(xpt,ypt,cpt,cmap=pp.cm.copper)
    
    pp.figure()
    for item in result_list:
        x_list = item[0]
        y_list = item[1]
        this_color = item[2]
        pp.fill(x_list,y_list,color=this_color,edgecolor='none')
    
   
    pp.axis([-0.5,0.5,-0.5,0.5])

    pp.show()
    
    
    
This work is licensed under a Creative Commons Attribution By license.

Sunday, March 20, 2011

Using Mathjax CDN to Embed Equations (Formulas) in a Web Page

$$ \begin{aligned} \nabla \times \vec{\mathbf{B}} -\, \frac1c\, \frac{\partial\vec{\mathbf{E}}}{\partial t} & = \frac{4\pi}{c}\vec{\mathbf{j}} \\ \nabla \cdot \vec{\mathbf{E}} & = 4 \pi \rho \\ \nabla \times \vec{\mathbf{E}}\, +\, \frac1c\, \frac{\partial\vec{\mathbf{B}}}{\partial t} & = \vec{\mathbf{0}} \\ \nabla \cdot \vec{\mathbf{B}} & = 0 \end{aligned} $$

Summary

Using Mathjax Content Delivery Network (CDN) equations and formulas can be added to a webpage with a few simple steps. This solution eliminates the need to setup and maintain a server. It is freely available for low bandwidth users. For some work flows, a document can be created offline and uploaded with little or no modification. This article summaries how to setup a webpage for use with Mathjax. The article provides a few examples of use.

Discussion

If you want to include equations in a blog, there are a few basic approaches. The simplest is to create pictures of the equations and embed those pictures in the web page. If you use MS Word to create HTML pages, this is how it embeds equations. Most of the standard options in Lyx for exporting to HTML use the same technique.  Alternatively, you can use some approach to render the equations at display time. The Google Chart API works like this. An image is embedded in a web page and the URL for the image contains a definition of the equation to display. Elyxer is a tool which converts a document written in Lyx into an HTML document which uses MathJax, jsMath, Google Chart API, or plain HTML to display the equations. This article shows how to manually use MathJax with a webpage.

Step 1: Add the MathJax scripts to the webpage.

You accomplish the first step by putting something like

<script type="text/javascript"
  src="http://cdn.mathjax.org/mathjax/latest/MathJax.js?config=TeX-AMS-MML_HTMLorMML">
</script>

into the <head> block of your document. This statement can be place in other locations like the <body>, but the <head> block is preferred. Since MathJax can be customized in many ways, there are many different ways to link MathJax to the webpage. The sample above works, but other configurations are possible. See the getting started guide for a detailed description of some of the options.

Step 2: Write your equations inside escape character sequences.

To add an equation, an escape sequence is entered. There is one escape sequence for inline equations and another for equations which appear on a line by themselves. For example, using the scrip method above, the sequence

$$…$$
and
\[ …\]
indicates that an equation is to appear by itself. The sequence
\(…\)

indicate that an equation should appear inline.

Below is a sample HTML page which includes MathJax.

<html>
  <head>
    <script type="text/javascript" src="/MathJax/MathJax.js?config=TeX-AMS-MML_HTMLorMML"></script>
  </head>
  <body>
    <p> Acceleration, \(a\), is a function of force, \(F\), and mass, \(m\). The relationship is usually written as \[F=m\cdot a\].<\p> However, by manipulating the equation, acceleration can be solved for as shown in equation (1).</p>
    <table border="0" cellspacing="0" cellpadding="2" width="100%">
      <tbody><
        <tr>
        <td valign="top" width="10%"></td>
        <td valign="top" width="80%"><p align="center">$$a=\frac{f}{m}$$</p></td>
        <td valign="top" width="10%">(1)</td>
        </tr>
    </tbody>
    </table>
  </body>
</html>

 

This code will result in a display like shown below:


Acceleration, \(a\), is a function of force, \(F\), and mass, \(m\). The relationship is usually written as \[F=m\cdot a\]. However, by manipulating the equation, acceleration can be solved for as shown in equation (1).

 

$$a=\frac{f}{m}$$

(1)

 

Conclusion

Thanks to the MathJax team and their sponsors. This is a fantastic service that really simplifies the maintenance and upkeep required to add equations to almost anything.


References:

This work is licensed under a Creative Commons Attribution By license.

Notes on installing a 2nd wireless router

image

Problem Statement

Given a 2wire 2701HG-B DSL modem with wireless router connected to the AT&T network and a Netgear N600 Dualband Router WNDR3400. The goal is to connect the two routers into a single network. All machines that are configured to work with the 2wire model should still work once the installation is complete. Ideally, no changes are required to the installed settings in the 2wire router. Both routers should behave like a single network, so regardless of where a device or computer connects, it can see all other devices on the local network. All devices should be able to see the internet regardless of where they connect.

Discussion

WARNING: I am not an network engineer. This discussion and the advice may have issues which result in network security performance issues. This configuration works to the extent it was tested. Use the advice with discretion.

The initial installation consisted of a 2wire 2701HG-B DSL modem with wireless router. This was configured per AT&T instructions using the out-of-the-box installation software. This provided a wireless access point for the internet and local area network capable of about 50Mbps with 4 hard wired access points. The network initially supported b/g wireless connections. Several devices in the home were connected to the network. The setup panels for the 2wire gateway are accessible from  http://gateway.2wire.net .

Original Network and Gateway Configuration

image

 

A Netgear N600 Dualband Router, model WNDR3400 was obtained for faster local area network access. It supports a/b/g/n wireless access and had two channels so it can devices can connect to either the a/n channel on 5GHz or the b/g/n channel on 2.4 GHz.  In an optimal setting, both channels should be capable of 300Mbs. This router also has a USB port which can be configured as network storage: a drive which can be mapped in for use by any device on the network.

There was a fair amount of advice available on how to configure a second router. The key decision is on how the 2nd router should behave. One configuration is to establish a subnet. The 2nd router creates its own local area network which is isolated from the primary router. By opening firewall protections in the 2nd router, misc services like printing and device discover is possible between the primary local area network and the secondary local area network. The key disadvantage to this approach is that if you reconfigure the network in the future, the 2nd router has so many configuration changes it can be difficult to get the network working as expected. Another configuration is to have one router act as a master for the network and services in the other router partially disabled. This is necessary because each router is configured by default to do tasks which will conflict if they are connected together. Specifically, the DHCP services, which assign network addresses to connected devices, can only be performed by one router. So the DHCP services in the second router are disabled so only one router is assigning network addresses.

One last thing is that most routers are themselves devices which require an IP address. So if the second router shares a local area with another router, the IP addresses need to properly configures outside of any automatic address assignments.

The solution works through three network configurations. The first configuration allows devices connected to the second router to see the internet, but the two independent networks exist: devices can only see devices which are connected to the same local area network (LAN). The second configuration partially disables the firewall in the N600. This enables some printers on the primary LAN to be used by devices on the secondary LAN. Finally, both routers are connected together to form a single LAN and all devices can see each other regardless of which router they access.

Solution

Step 1: Configure the N600

The first step in setting up the network is to install the N600 and configure it. The image below shows how the N600 is wired to the 2wire router. Once this is completed, the computer connected to the N600 is used to configure the N600 using the software disc which was provided. When this is complete, any device connected to the N600 should be able to see the internet through the 2wire gateway. If there is a problem, verify that the internet can be seen by connecting a device to the 2wire gateway. At this step, things like the wireless configuration for the N600 and wireless security can be configured.

Network Setup to configure N600 Router

image

In this configuration, each router assigned IP addresses to the components which connect to it. The firewall in the N600 prevents services like device discovery and printing from working across the network.

At this point, a device connected to the N600 can access the router configurations by connecting to http://www.routerlogin.net. This will bring up the administration page. It can be a good idea to change the admin password to prevent unwanted network changes.

Step 2: Disable NAT Filtering (optional).

With a device connected to the N600, log into the administration pages at http://www.routerlogin.net. On the left had side of the screen, select ‘WAN Setup’. This let you modify what the N600 allows to pass between the two LANs. On the page that appears, set ‘NAT Filtering’ to ‘Open’. Click ‘Apply’ to save the change.

image

With this change, it should now be possible to access the internet and print to devices connected to the 2wire gateway from devices which are connected to the N600. This configuration can be useable and has a few advantages for situations where high traffic might be present. There are basically two independent networks and the only sharing between them is internet traffic.

Additional changes can probably configure the LAN on the N600 to allow devices on both LANs to see each other, but the testing for that was not done.

Step 3: Reconfigure N600 to share same LAN

This step requires a few things to be done before any testing can be done to confirm the job was done correctly. So there are a few places where things can go wrong.

Step 3a: Identify where the 2wire gateway assigns addresses.

With a device connected to the 2wire gateway, log into http://gateway.2wire.net. Select ‘Home Networking’ and ‘Advanced Settings’. The ‘Private Network’ panel should show where the 2wire gateway assigns IP addresses. In the example below, the base address is 192.168.1.0. By looking at the ‘Current Settings’ the range of assigned addresses can be seen. In this case, the range of assigned addresses are 192.168.1.64 through 192.168.1.253. Keep this range in mind.

image

Step 3b: Disconnect the N600 from the 2Wire gateway.

image

Step 3c: Reconfigure the N600.

To reconfigure the N600, the DHCP services will be turned off and the IP address of the N600 will be set in address range of the 2wire gateway but outside of the DHCP range for the 2wire gateway. For this system, an address of 192.168.1.10 will work.

With a computer connected to the N600, connect to http://www.routerlogin.net and go to the LAN Setup page. On that page enter 192.168.1.10 as the IP address and unselect ‘Use Router as DHCP Server’. This sets up the address the N600 will appear at in the future and prevents the N600 from assigning network addresses.  Click ‘Apply’. The N600 will reset and you may lose communication because the network addresses will no longer be valid. If this happens everything is fine. However you will not be able to do anything with this setup until you do the next step.

image

Step 3d: Reconnect the N600 to the 2wire.

Connect one of the LAN ports on the N600 to a LAN port on the 2wire. Do NOT connect anything to the WAN port of the N600. Do NOT use a cross-over cable (If you do not know what this is, do not worry about it).

image

Step 4: Testing

To test this system, connect a device to the N600. Try to log into the 2wire at http://gateway.2wire.net. If the setup is working, you should be able to log into the 2wire gateway. This proves the N600 and the 2wire are sharing the same LAN. Next log into the N600. Unfortunately, the convenient login address will no longer work since the DHCP services in the N600 were disables. So you have to log in using the IP address: http://192.168.1.10. If you can do this, chances are things are now correctly configured.

Conclusion:

You should have 6 wired ports available (3 on the 2wire, 3 on the N600) and 3 wireless connection options: a b/g wireless connection on the 2wire, a b/g/n connection on the N600, and an a/n connection on the N600.  All devices on these connects should be able to see each other and the internet.

This work is licensed under a Creative Commons Attribution By license.