Reproducing A Clever Animation Product, Part 2

Today I did some experiments to try to figure out why the animations I’ve created seem to hitch and hiccup slightly from time to time. Again, this work is based on recreating the basic functionality of the Greensock animation product described here and especially here.

The first thing I thought of was that the drawing operations themselves might be taking long enough that they don’t complete during every animation step (about 16 ms at 60 frames per second). I therefore set the update loop to only draw the items every other scan. This approach didn’t relieve the hitching and updating at 30 fps left the animation looking slightly choppy.

The next thing I tried was recording the elapsed time for every drawing loop and displaying the value if it was greater than 16 ms. However, the value was never displayed, so it appears that the speed of the drawing isn’t an issue.

Next it occurred to me that if an element has to travel far enough and in fine enough increments that the difference between traveling three or four pixels in an update, particularly when advancing by the smaller number doesn’t happen often, might be enough to look like a hitch. I therefore set the durations of the transitions to be shorter so each increment is larger, and I also incorporated a fade-in by ramping up the opacity. The combination of these two changes made things look pretty smooth.

I also observe that the example animation in the second Greensock link, above, involves transitions that are relatively short, so there isn’t time for anything to hitch. That may be the key to the whole enterprise. That said, there’s an animation in the first link that shows a fountain of green balls. I will try to reproduce something like that and see how it looks. Most of the effects can be replicated (though perhaps not as well as the originals), and I’ll be working through duplicating some of them over the next few posts.

In the meantime, I found it necessary to add an initialization capability so rerunning the animation starts from a good place. Here’s the basic code in its entirety.

Posted in Tools and methods | Tagged , , | Leave a comment

Reproducing A Clever Animation Product, Part 1

I’ve been working on an introductory animation for my soon-to-be-released landing page (what, stumbling into a random WordPress post and a tiny resume link isn’t the pithiest possible introduction?), and I was looking around and playing with various ideas when I stumbled across this site and this video. This company makes what look to be a very impressive set of products with even more impressive licensing terms. However, since the point of this website, for now, is to help me learn new things when I’m not describing and recreating some of the work I’ve done from earlier in my career, I used the information presented as inspiration for creating my own basic animation framework.

The first thing I want to point out as I begin this week of related posts is that I haven’t looked at the company’s and product’s code at all. I’m just trying to recreate some basic functionality and use what I see as inspiration for my own explorations. The things I found helpful were the ideas embodied in the animation product. I would not assume that I’ve figured out exactly how they did what they did but I’ve definitely been able to recreate some of the same functionality in my own way. This is in keeping with my goal of ensuring that all the running code on this site is my own.

If you check out the linked video you see a tool that uses a very terse JavaScript syntax that produces very nice, very controllable effects. The key thing is that the animations produced run quickly and smoothly. I a) needed an animation and b) like to build tools so this was a natural thing to tackle.

I spent some of the past weekend building up a rather cumbersome first attempt at an animation framework. It was big and it was kludgy and it was slow and it sometimes hiccuped. I recognized that I needed a system that carried out the following steps:

  1. specify element
  2. specify initial properties
  3. specify final properties
  4. specify duration
  5. specify start time
  6. build list of commands that run for every animation call

What I originally came up with was a way to create an array with links bunch of elements, create arrays with transformation objects that describe what to do with each element, and a way to cycle through the lists of elements and transformations to see what needs to be done… during every animation step. Since the animation steps might be happening every 60th of a second on a modern device (possibly less often on an older machine… like a Palm Pre like maybe), you can imagine there’s quite a bit of overhead. I also made the original animation space rather large which involved long traversals that took up a decent amount of time. The original animations worked but they took a lot of code to express and like I said, they weren’t always very smooth. Then I noticed a couple of things that helped.

One was that the example animation shown in the linked video was comparatively small, and the transitions all happened rather quickly. I therefore resolved to make my intro animation much smaller. I chose a 400-by-400 pixel space for the animation, which fits my page and should look respectable on any modern device. I don’t promise that any example I develop during these experiments will run well (or even at all) on every device, in every browser, and on every OS, but it should work and look reasonable on anything current. I’m also assuming a 60 frames-per-second refresh rate. I’ll explain why tomorrow.

The other thing I noticed is that the verbiage on the company’s site spoke of creating tweens for each animation step. This suggested that the product wasn’t figuring out what to do during every animation step, but was probably pre-calculating the actions up front. I ended up rewriting something that was much, much more succinct in terms of code and ran a heck of a lot more smoothly.

It takes a certain amount of information to describe the actions to be taken, and the incredibly terse JavaScript that does so in the linked video seems to leave some of it out. Or, rather, it makes certain assumptions about where things begin and end. I created a function that linked to elements in the animation div (I made them all divs themselves but they could be anything and it would probably be more efficient if most of them weren’t divs) and another set of functions that calculate tweens and load them into a list of commands to be executed as the animation proceeds. It occurred to me that the JavaScript files written by the company probably do something similar, and the impossibly pithy code the users write is actually something that gets peeled apart, interpreted, and fed to a series of functions similar to what I wrote. I don’t know that to be true, I just feel like it might be.

The thing that ultimately makes the thing go, and go smoothly, is the list of commands to be processed during each animation step. Remember from a recent post that the basic animation loop works something like this:

What you want, therefore, is the pithiest possible set of commands to run in the doSomeStuff call. I use the animationStep variable as an index into the array of animation commands I set up prior to kicking off the animation loop. The array of animation commands has two dimensions, one for each animation step, and one for each command issued during that step. (I happened to reserve element zero in each secondary array for holding the number of commands to be issued but that isn’t strictly necessary.) When the animation runs for each time step all it has to do is cycle through the list of activities that has to be performed during that animation step.

So, how do you–pithily–tell the program how to manipulate some aspect of an HTML element? Wouldn’t it be nice if we had access to something simple like:

…where we could refer to a known JavaScript handle, a specific property, and a specific value? Well, using the concept of automatic code generation it’s a simple matter to generate a bit of text like the following, which represents a valid line of JavaScript code that can be stored in the second dimension of the array of animation commands.

“handle001.style.left = ‘117px’;”

I also happened to be reading through some advice on JavaScript programming, which says to NOT use the eval() command, but this seemed almost too good to be true. If we feed the generated string to the eval command we can do just about anything. There may be some overhead from using this method, but it certainly gets the job done.

It is entirely possible that the good people at Greensock came up with a better way to do this, and I’m sure that there are, in fact, many ways to accomplish this sort of thing. This method does have the virtue of being compact and straightforward, and, most importantly, it more or less works.

I’ll go into more detail in subsequent posts but here is a very simple example of the process in action.

The red line slides in from the left over one second starting from time zero. The blue line drops down from the bottom over two seconds starting from the 0.5-second mark. All parameters are settable.

As I look at this I see that the process keeps hitching and hiccuping, so it’s very likely that I’m missing something. It’s possible that the eval() function is not the best way to do things, and it’s also possible that the problem lies elsewhere. The elements I’m moving are divs, which require more overhead to move than just raw HTML elements, and I’m also updating every element during every animation step (60 fps on modern devices). It’s possible that I can skip animation steps and still get decent effects.

Posted in Tools and methods | Tagged , , | Leave a comment

Prettying Up the 3D Graph Output

Here I’ve prettied the graph up so the lines change color every 100 degrees F, and I’ve added a legend. I suppose I could choose consecutive colors with a bit more contrast.

Posted in Tools and methods | Tagged , , , , , | Leave a comment

Graphing the Matrix Output

Here I continually run the heating routine for a piece with an initial temperature of 70 degrees in a furnace set to 2300 degrees. The temperature scale, expressed vertically, runs from 0-2500 degrees. The bottom of the piece, which sits on a solid hearth through which no heat is transferred, is to the lower right.

The graph is rendered using a shortcut isometric technique which obviates the need for matrix multiplications and perspective transformations.

Posted in Tools and methods | Tagged , , , , , | Leave a comment

How Quickly Can the Matrix Be Solved On Different Machines?

Today I ran 2750 iterations of the matrix on some additional machines.

My 64GB iPad 3 runs a 1 GHz, dual-core, 32-bit, ARM Cortex-A9 and ran the test in 1.308 seconds on load and about 1.15 seconds on rerun.

My MacBook Pro from 2013 runs a 2.7 GHz Core i7 and did the initial run in 0.09-0.130 seconds and re-runs in as little as 0.070 seconds. That’s almost as fast as my 2015 notebook PC.

I wasn’t kidding about digging up my old Palm Pre, either. I finally got it charged up and running but found it would only run up to 500 iterations before it would hang. I therefore created another version of the test which runs only 500 iterations, as shown below.

The Pre Plus, a 500 MHz ARM Cortex-A8, managed to grind through 500 iterations in 4.77 seconds. At that rate it would take 25.85 seconds to do 2750 iterations. That is slower than what a good desktop machine from the late 1990s could do. A couple of thoughts occur to me, however. The Palm Pre was introduced to great fanfare but had numerous problems from the beginning. What was left of Palm didn’t have the resources to get the software into the best shape when it was released (the ability to record video was only enabled after a handful of OS updates). I would not be surprised if the code for the browser or JavaScript implementation were less than optimal. The company was acquired by HP, which then managed to drive the final nails into Palm’s coffin.

Still, the matrix code doesn’t make use of any special or new features of HTML, CSS, or JavaScript and did manage to run to completion, so I guess that’s an interesting finding on its own. It’s kind of like the poodles in tutus that used to walk on their hind legs on the old Ed Sullivan Show. You weren’t impressed that they did it well, what was impressive is that they could do it at all.

Posted in Tools and methods | Tagged , , , , | Leave a comment

How Quickly Can the Matrix Be Solved?

The solution was finally made to run last week. Today the question is how fast the thing runs. My feel for the answer to this question has to do with the context in which I first asked it.

From 1994 to 2000 the fastest desktop computers I worked with maxed out at 400 MHz. That was true for PCs and the more expensive DEC Vax and Alpha machines we were running. By contrast the laptop I’m working on uses an Intel Core i7-4510U CPU with a base speed of 2.00 GHz. That would be five times faster on its own. However, that number is the base speed of each core, and depending on the number running the speed can theoretically be boosted to as much as 3.1 GHz. The Windows system page indicates that the fastest core may be running at 2.6 GHz.

After that we can consider that each core in a current CPU is likely to be further optimized in terms of its internal architecture, the number of clock cycles it takes to perform each operation, the amount of available cache memory, the speed at which data can be moved in and out of RAM, and other considerations. The current chip and OS is also 64 bits while the older ones were only 32 bits, though that consideration may not have much effect on the speed of calculations.

I don’t know how to evaluate the overhead incurred by the operating system itself, but running JavaScript in a browser at least carries the overhead of the browser.

Next we can consider the number of times the matrix code had to be run for every model iteration. The matrix had to be run at least once to update the current temperature of each piece in the furnace during each time step. The number of pieces in a furnace could range from, say, 8 to 144 depending on the application, so lets pick 50 for giggles. This number doesn’t really matter because the bulk of the work is done when trying to predict what happens in the future.

Control systems based on model-predictive simulation work by starting from current conditions and calculating what will happen in the future. If the results obtained by the simulation match the desired results then the control settings need not be changed. However, if the predicted results do not match the desired results the program has to figure out what control inputs to change. Without going into detail, the furnace Level 2 systems I wrote would march the pieces out of the furnace at the current average pace of movement through the furnace, figure out what the discharge average and differential temperatures (the difference between the temperatures of the hottest and coldest nodes in a particular piece, which value had to be below a specified threshold) would be, compare the predicted result with the desired result, and adjust the control settings.

The control settings adjusted by the Level 2 system were the temperature setpoints for each zone in the furnace. A furnace might have anywhere from one to six (or more) independently controlled zones. It was up to the Level 1 systems to do the detailed work necessary to make this happen. They used PLCs to control gas flows, fuel-air ratios, pressures, movements, cooling, opening and closing of doors, operation of exhaust flues, safety systems, and so on. They were a whole world of their own and I was always thoroughly impressed with the people who built those systems.

For this example I’ve assumed that there are three effective zones of control in the furnace, and the predicted temperature of at least one piece has to be calculated for each zone. The “critical” piece in each zone was the one that was logically identified to be the hardest to heat. Pieces could be a bit over temperature of more thoroughly soaked (lower than target differential temperature, but if they were too cold or not sufficiently soaked they could break a mill stand, which would slow the operation down). As the pieces are being marched out of the furnace the prediction code assumes that the Level 1 system will move the furnace temperatures to their setpoints for each zone if they are not already there. I ran successive iterations of the prediction code until I either got the discharge temperatures to within a few degrees of their targets or until the number of iterations gets up to five. Greater accuracy could be achieved during later time steps but the model could never be allowed to run longer than its designated time step.

Next I considered the pace of movement through the furnace. If the furnace was running slowly it might take two hours for a piece to get through the furnace, and that would mean 180 40-seecond time steps. So, at 3 pieces times 5 iterations times 180 steps we have 2700 matrix calculations. More are certainly possible.

I’ve set the example up to run 2750 iterations, which would be enough to update 50 pieces plus predict three as described. The code runs when the page is first loaded and again whenever the button is clicked. I noticed that clicking the button to repeat the test yields notably better results, so there must be some overhead associated with the initial load of the page.

I would have expected the code to take 5-10 seconds to run, but on my laptop, with the file served from local disk, the initial result was 0.08 seconds and about 0.05 when the button is clicked to rerun. This represents a performance improvement of at least 100, which is kind of mind-blowing to me.

Served over a fast connection from the website I get results of about 0.085 seconds on load and 0.052 seconds on rerun.

On my iPhone 5S I get 0.352 seconds on load and 0.230 seconds on rerun. That may be even more mind-blowing.

Tomorrow I’ll try this on a few other systems to see how it feels. What results are you getting on your setup?

Posted in Tools and methods | Tagged , , , , , , | Leave a comment

Finally Solving the Matrix

Once we get all the parameters calculated and the matrix loaded, then we can finally solve the thing. Here’s how the code looks:

We start with a 7×7-node workpiece where the interior nodes are two inches wide and two inches high. The surface nodes are half as wide or high, meaning the cross-section area of each node is four square inches in the interior of the piece, one square inch on the four corners of the piece, and two square inches for the other surface nodes. The length of the surface exposed to the furnace is zero for interior nodes, zero for the bottom middle nodes (the piece is sitting on a solid hearth through which it is assumed no heat transfer occurs), one inch for the bottom nodes on each side, and two inches for the remaining surface nodes (the two corner nodes include one inch across the top surface and one inch down the side surface). The center of each interior node is assumed to be in the middle of the node, one inch from each side. The “center” of each surface node is assumed to be on the middle of the outer surface of the node. The “center” of the outer corner nodes is assumed to be on the outermost corner. This way there are always exactly two inches between the centers of each node, so the heat conduction terms make sense and the radiation can “see” the “center” of each node.

I have done it this way from the beginning and found that the readings of surface temperature on pieces which were actually heated in furnace matched the predicted values with impressive accuracy.

If all nodes are initialized to 70 degrees F, then exposed to a furnace at 1800 degrees F for successive 40-second time steps, we get the following results:

Posted in Tools and methods | Tagged , , | Leave a comment

Dimensions and Other Considerations Before We Solve the Matrix

Yesterday’s post showed how some of the constants and parameters are initialized or calculated. Today we’ll describe a few more.

This exercise defines a cross-section of a steel billet that is 8 inches by 8 inches and divided into five nodes high and five nodes wide. I found it convenient to assume the surface nodes were only half the height or width of the middle nodes, and to assume the center of surface nodes is on the outer edge or corner of the node, or in the middle of the node for central nodes. This means that the centers are always equidistant both across and up. The surface nodes also receive conducted heat and radiated heat at the same location. Nodes on the corners have one quarter the cross-sectional area of the fully central nodes, and nodes on the surface but not on the corner have one half the area of the fully central nodes.

Posted in Tools and methods | Tagged , , | Leave a comment

Static and Dynamic Coefficients in Matrix Thermal Solutions

Recalling yesterday’s initial heat balance equation for each node:

it should be noted that the values of both the specific heat and the thermal conductivity of steel are themselves functions of temperature. That means that these values need to be calculated for every node, every time a temperature matrix is loaded and solved. Finding those values means interpolating from a table of values as a function of temperature (English units). The values of the other constants are shown as well.

The values for view factors are affected by shadowing caused by the structures the workpieces are sitting on (typically beams, a solid hearth, or rollers) and the workpieces each piece is sitting beside, if there is a gap between them. The values for the bottom and side views assume a solid hearth and notional effects of shading from neighboring pieces. I have written systems that considered a changing configuration of support structure over the length of a furnace and variable-width gaps between workpieces.

Posted in Tools and methods | Tagged , , , | Leave a comment

A Specific Example of Equations To Be Solved By Matrix

Dividing a cross-section of a steel billet into nodes, we can start by looking at the energy balance for each node:

All this equation is saying is that the change in the quantity of energy in a given node per unit time is equal to the sum of the energy flows into and out of the node. The quantity to the left is the accumulation terms while the quantities on the right side of the equation are terms for radiative heat transfer from the environment to the surface of the steel, conductive heat transfer between nodes within the steel, convective heat transfer between the external atmosphere and the steel, and inductive heat transfer into the steel.

Let’s start by breaking the mass in the accumulator term down as follows:

We continue by eliminating the convection and induction terms because they are comparatively small or nonexistent, and then by dividing all the remaining terms by the unit area:

Next we can expand terms:

Steal a first order dependent variable from the fourth order term:

Substituting back into the previous equation yields:

Gathering terms we get:

The coefficients for the Tn terms and the Tc terms on the left side of the equation fill the initialized coefficient matrix while the terms on the right side of the equation fill the initialized source matrix. There is one T term for each node. The radiation transfer terms drop out for any node that isn’t on the surface of the piece of steel being heated. The conduction terms drop out between any two nodes that aren’t internally connected.

This equation gets written for each node individually and then the system of equations gets solved. All of the Tn terms for the new time step end up in the source matrix at the end. Note that the temperatures are all represented in absolute degrees.

Posted in Tools and methods | Tagged , , | Leave a comment