Second Spiral Example

While the model in the section First Spiral Example generates a nice looking square spiral, the model may not be one of the standard spiral models that would have simulation data to go with it. This section takes the first spiral example another step and modifies it to generate a more useful model.

The basic premise of the first model is that the vertex points computed along the spiral are the vertex (corners) of the resulting square spiral, but a little adjustment is needed to square things up. While this worked well, the model does have a couple of failings when we try to use it for a real-world model. First, the adjustment math is rather complex. Second, it is very hard to make adjustments to the end-points so that these line up on edges or adhere to other model constraints.

To address this concern, a different geometry definition is explored. Instead of the computed spiral points being the vertex points, the computed points are defined as points on the sides of the square spiral. Then the vertex points are the perpendicular intersection of two sides lying on two successive compute points.

A Second Geometry Lesson

Once again we must consider geometry. We will start with two vectors of a given radius and angle ( r1,a1 and r2,a2 ). These vectors correspond to two of the computed points on the spiral. We know the angle and radius of each one. The end of each line lies on one leg of the final spiral, and the ends meet the leg at an angle of 90°. What we need to compute is the vector r3,a3 to where these two sides intersect, and then the actual x,y point. For a square spiral, several more of these angles will also be 90°, but we will not assume that in this example, so we can create a general case that could be used to generate a spiral of any number of sides.

Now we'll take this general case geometry and formalize it a bit so it is easier to see the relationships between the various angles and sides. Note that even though it has been drawn such that the r1,a1 vector is on the X-axis, this will not be true for the general case, so we must take care in the assumptions that we make.

We can start with the known values and work to a solution for the r3,a3 vector and then the values for ( x,y ):

  1. The first given vector is of length and angle: r1,a1 .
    The second given vector is of length and angle: r2,a2 .
  2. This makes the angle between them
    .
  3. The definition of cos() says that
    ,
    .
  4. The definition of sin() says that
    , so
    .
  5. B is part of a right triangle, so
    .

  6. , so
    . Substitute for j and we get
    .
  7. The definition of tan() says that
    , so
    , which, substituting for k expands to
    .

  8. . Substitute for a and n , and
    . Substitute for A , and
  9. We now have the two sides of the triangle that will give us the r3,a3 vector: r1 and m . The definition of a triangle says that
    , so
    (using m from step 8).
  10. And again,
    ,
    (again using m from step 8). But that's only the angle between vector 1 and vector 3, the actual angle will be
    .
    So, for any given r1,a1 and r2,a2 we can use the calculations above ( m from step 8, r3 from step 9, and a3 from step 10) to generate an r3,a3 to the point of intersection. There will need to be some special case handling for the end-points, for example, making the final spiral start and stop on the first and last vectors of the spiral (rather than being a point on the side).

Using the Equations

The next question is how to represent all this in the polar control. We have rather long equations based on the current and previous radius/angle vectors (implying the need to save the current vector for the next iteration) as well as special case processing for the first and last points. While it may be possible to do all this within the limits of the fields in the polar control, it is much easier to do it as new functions defined in AEL and called from within the polar control.

Define Controls

We start by defining the initial controls needed to create the shape. Define a width control to operate on the initial path:

Control: Width
Change: Absolute
Width: width

Next, define a polar control with the function calls in place. In the next section we will define the actual functions in AEL. Define the polar control as:

Control: Polar
Delete Ends: True
Units: Radians
Start: 0.0
Stop: PI*2*turns
Step: PI/(sides/2); set_angle_info(0.0,PI*2*turns,PI/(sides/2))
Radius: init_radius + (width + space) * _angle / (2*PI)
X Offset: compute_x(_angle_i, _radius, _angle)
Y Offset: compute_y(_angle_i, _radius, _angle)

We set the variables start , stop , and step the same way they were set in the spiral example in the section First Spiral Example The one addition to the angle definition section is the call to the function set_angle_info() . The purpose of this function is to pass these three values to the AEL code so they can be saved for use in future calculations.

Create an AEL File

We must create an AEL file to hold the function definitions that we need. The AEL file begins with some global variables and the definition of set_angle_info() .

decl angle_start, angle_stop, angle_step;
 decl angle_n; 
 decl r1;        // last saved radius 
 decl a1;        // last saved angle 
 //   r2         // current radius from the polar controller 
 //   a2         // current angle from the polar controller 
 decl r3;        // new radius 
 decl a3;        // new angle  
 ******************************************************************************************
******************************************************************************************
 defun set_angle_info(start, stop, step)
 { 
 angle_start = start; 
 angle_stop  = stop; 
 angle_step  = step; 
 angle_n     = (angle_stop - angle_start) / angle_step; 
 r1 = a1     = 0; 
 }

The function saves the three value, computes the number of angle steps, and clears the last radius/angle values (which will be used later). We add to this AEL file later.

Calculate the Radius

The radius calculation is basically the same as used in the previous example. Since the radius points lie on the sides rather than on the vertex points (corners) we do not need to do the adjustments that were required in the previous example (starting at A Short Geometry Lesson). In addition, we have added a new variable ( init_radius ) so we can control the radius of the first turn and therefore the overall size. Also note that in order for the init_radius variable to work as intended, the original graphics must be centered on the origin (0,0) which is the center of rotation for the polar control. This way, any value for init_radius is in effect moving the initial shape off the origin before starting to sweep it in the spiral form.

Enter the X and Y Offsets

We now have a computed radius and angle ( r2,a2 ) so we can proceed with the adjustments defined by the equations above. We will use the X Offset and Y Offset fields to make the needed function calls. Of course, since the offset fields provide a delta to apply to the computed radius and angle, we will actually have to return the difference between the r2,a2 and r3,a3 vectors in the function calls. We will also have to convert from polar to cartesian coordinates since the vectors are in polar coordinates but the X and Y Offset are in cartesian coordinates. Given a radius and angle the basic conversion formulas are:

But since we want the difference between the two vectors, we get:

As shown above in the polar control, we call two functions: compute_x() and compute_y() . As parameters we pass the angle count (which iteration we are on) and the r2,a2 vector. The support code that we will now add to our AEL file appears on the following page.

******************************************************************************************
******************************************************************************************

defun compute_x(idx, r2, a2)
{
decl x;
decl m;
if (idx == 0)           // first point
        return(0);
if (idx == angle_n + 1) // last point
        return(r1*cos(a1) - r2*cos(a2));

m = r2*sin(a2-a1)-(r1-r2*cos(a2-a1))*tan(PI/2-a2+a1);
r3 = sqrt(r1*r1+m*m);
a3 = atan(m/r1)+a1;

x = r3*cos(a3) - r2*cos(a2);

return(x);
}

******************************************************************************************
******************************************************************************************

defun compute_y(idx, r2, a2)
{

decl y;

if (idx == 0) {         // first point

        r1 = r2;
        a1 = a2;
        return(0);
        }

if (idx == angle_n + 1) // last point

        return(r1*sin(a1) - r2*sin(a2));
r1 = r2;
a1 = a2;
y = r3*sin(a3) - r2*sin(a2);
return(y);
}

The compute_x() function is called first. It handles the special case code for the first and last points, and then computes m , which is then used to compute the r3,a3 vector. We then convert to a delta-X for return to the polar control. The compute_y() is called next. It, too, checks for the first and last points, then saves r2,a2 as r1,a1 (previous vector) for the next iteration. Finally, it converts the delta-Y for return to the polar controller.

Place the AEL file containing the code for the three defined functions ( set_angle_info() , compute_x() , and compute_y() ) in the file user_defined_fun.ael in the $HOME/hpeesof/de/ael or $HPEESOF_DIR/custom/de/ael directory so that these functions are loaded at run-time and are available when the model is inserted. Placing the ael file in either of these directories will require an additional configuration var setting:

The Results

Here is an example inserted with the following parameters:

init_radius = 20.0 mil
sides = 4
turns = 3
width = 25.0 mil
space = 15.0 mil

Two additional polar controls were added to this model to help demonstrate how the geometry works. The first addition is a simple smooth spiral:

Control: Polar
Delete Ends: True
Units: Radians
Start: 0.0
Stop: PI*2*turns
Step: PI/16.0
Radius: init_radius + (width+space) * _angle / (2*PI)
X Offset: 0.0 mil
Y Offset: 0.0 mil

The second is the same simple spiral but with only four sides, which was the basis of the model in the section First Spiral Example.

Control: Polar
Delete Ends: True
Units: Radians
Start: 0.0
Stop: PI*2*turns
Step: PI/(sides/2)
Radius: init_radius + (width + space) * _angle / (2*PI)
X Offset: 0.0 mil
Y Offset: 0.0 mil

Create a Rectangular Spiral

Suppose we do not want a square spiral, but rather a rectangular spiral where we can control the size of both the major and minor axis. The previous examples use the basic idea of making the radius a function of angle so that as the angle increases so does the radius. In other words, if
r = (constant) produces a circle, then
r = f(angle) produces a spiral.

We added additional math to normalize the angle, provide control over the size of the spiral (as a function of width and space), and control the initial size of the spiral (by using init_radius ).

But if instead of a circle as the basic fundamental shape, what if we used an ellipse? We could then modify it to increase its two axis as a function of angle as we did with the circle.

The polar definition for an ellipse is:

where t = theta (an angle)

Create an Ellipse

Start by simply implementing the above to create a simple ellipse.

Control: Polar
Delete Ends: True
Units: Radians
Start: 0.0
Stop: PI*2*turns
Step: PI/16.0
Radius: sqrt(a*a*b*
b/(a*a*sin(_angle)*sin(_angle)+b
*b*cos(_angle)*cos(_angle)))
X Offset: 0.0 mil
Y Offset: 0.0 mil


where:

turns = 1
a = 100.0 mil
b = 50.0 mil

Make an Elliptical Spiral

As we said above, a circle is:
r = (init_radius)
or
r = f(init_radius)
Where the function f does not actually modify the constant. Next we modified the constant so that it would increase in size as a function of the angle:

As stated above an ellipse is a more complicated function in terms of a and b :
r = f(a, b)
Where a and b serve the same purpose as init_radius . So, if we increase them as a function of angle in the same way, we should get the elliptical spiral we want:

,

where f() is the above definition of an ellipse.
So now we have:

Control: Polar
Delete Ends: True
Units: Radians
Start: 0.0
Stop: PI*2*turns
Step: PI/16.0
Radius: sqrt(pow(a+(width+space)*_angle/(2*PI),2)*
pow(b+(width+space)*_angle/(2*PI),2)/
(pow(a+(width+space)*_angle/(2*PI),2)*
pow(sin(_angle),2)+
pow(b+(width+space)*_angle/(2*PI),2)*
pow(cos(_angle),2)))
X Offset: 0.0 mil
Y Offset: 0.0 mil


where:

turns = 1
a = 100.0 mil
b = 50.0 mil
width = 25.0 mil
space = 25.0 mil

Reduce the Number of Sides

Next we reduce the number of sides to four, and we have our points on the sides of the spiral.

Add Function Calls

Control: Polar
Delete Ends: True
Units: Radians
Start: 0.0
Stop: PI*2*turns
Step: PI/2.0; set_angle_info(0.0, PI*2*turns, PI/2)
Radius: sqrt(pow(a+(width+space)*_angle/(2*PI),2)*
pow(b+(width+space)*_angle/(2*PI),2)/
(pow(a+(width+space)*_angle/(2*PI),2)*
pow(sin(_angle),2)+
pow(b+(width+space)*_angle/(2*PI),2)*
pow(cos(_angle),2)))
X Offset: compute_x(_angle_i, _radius, _angle)
Y Offset: compute_y(_angle_i, _radius, _angle)

 

Privacy Statement  | Terms of Use  | Legal | Contact Us  | © Agilent 2000-2008 

Contents
Additional Resources