Piston-Driven Wheel Simulation

Edit: I noticed a small mistake in the formulas below. I’ll try to get it fixed this week.

I visited a railroad museum today, and I saw a display showing how the piston is linked to the train wheel. For fun and learning I wanted to model the basic mathematics of how the linkage moves with the wheel and the piston, without looking up the answer on the Internet. That part seemed very simple:

Since l and p are fixed length, it was a matter of simple trigonometry, as seen above. Then I threw the math into a simple Racket program to simulate the movement. That part not hard, but it took an hour or two to add enough lines and circles to make the graphic look half-way decent. Here is a video recording of it running (about 10 seconds):

Here is the source code packaged with the video:


One interesting part of the math is the connection point of l and p (see the diagram above). Until you get very long lengths of l, you get something close to the cosine function but not quite the same.

Emacs Calc: Matrix Mapping “Close Enough” Keyboard Macro

In Emacs Calculator, frequently I come up with results that that are algebraically supposed to be a whole number, but instead because of precision error they end up as some annoying value that is very close. For example, I’m expecting a 0 but get “3.69600000004e-11” which is an extremely small value close to zero. For matrices, I defined this shortcut which maps over the elements, rounding them if they are “close enough” to the whole number.

After defining the macro I inserted it into ~/.emacs.d/calc.el:

(fset 'calc-ce
   (lambda (&optional arg) "Keyboard macro." (interactive "p") (kmacro-exec-ring-item (quote ([86 77 39 105 102 40 97 98 115 40 114 111 117 110 100 40 120 41 45 120 41 32 60 32 48 46 48 48 48 48 48 48 49 44 114 111 117 110 100 40 120 41 44 120 41 return return] 0 "%d")) arg)))

In calc, press ‘x c e’.

So, this


This is not the same thing as simply rounding as it only rounds if the value is very close (under 0.0000001 difference). The formula mapped over the matrix is

if(abs(round(x)-x) < 0.0000001,round(x),x)

A different approach I tried was to multiply, truncate, and reverse the multiplication, but this doesn’t work for values like 0.9999999999.

More Emacs Calculator Functionality

The first video demonstrates algebraic formulas and live evaluation in Emacs Calculator:

The second video covers two subjects: (1) mapping functions over vectors, and (2) using emacs to display algebraic formulas as math LaTeX (to paste into a WordPress post, for example). Please forgive the improper pronunciation of “LaTeX”, which I remembered afterwards.

Emacs Calc: Angle Between Vectors

In my geometry studies, I learned that one can get the angle between two vectors with this formula:

cos \theta = \frac{V_1 \cdot V_2}{| V_1 | | V_2 |}

I.e., the cosine of the angle equals the dot product of the two vectors over the product of their magnitudes.

Here we get about 1.05 radians or about 60.26 degrees. A cool thing about this formula is it works for vectors of any (matching) dimension, i.e., 3-D coordinates, 4-D coordinates, etc.

This is definitely doable in Emacs Calc, since we have a dot product function, called inner-product (press ‘x inner product’), But doing the angle formula involves a lot of steps, with either stack rotation or storing the vectors in variables. So I wanted to get the angle formula stored as a calc formula. Unfortunately, inner-product itself is only an interactive function, so this was problematic. However, inner-product actual calls another function, inner. So, this formula is possible:

arccos(inner(mul, add, v1, v2) / (abs(v1) abs(v2)))

How do you store this formula in Emacs? I could walk you through the steps described in section 18.4 of the Emacs Calc info manual, but the end result is that this code is stored in your ~/.emacs.d/calc.el:

(put 'calc-define 'calc-vectorsangle '(progn
 (defun calc-vectorsangle nil (interactive) (calc-wrapper (calc-enter-result 2 "vect" (cons (quote calcFunc-vectorsangle) (calc-top-list-n 2)))))
 (put 'calc-vectorsangle 'calc-user-defn 't)
 (defun calcFunc-vectorsangle (v1 v2) (math-normalize (list (quote
  calcFunc-arccos) (list (quote /) (list (quote calcFunc-inner) (quote
  (var mul var-mul)) (quote (var add var-add)) v1 v2) (list (quote *)
  (list (quote calcFunc-abs) v1) (list (quote calcFunc-abs) v2))))))
 (put 'calcFunc-vectorsangle 'calc-user-defn '(calcFunc-arccos (/
  (calcFunc-inner (var mul var-mul) (var add var-add) (var v1 var-v1)
  (var v2 var-v2)) (* (calcFunc-abs (var v1 var-v1)) (calcFunc-abs (var
  v2 var-v2))))))
 (define-key calc-mode-map "zA" 'calc-vectorsangle)

Then when you start calc, you can put two vectors on the stack, and enter command ‘x vectorsangle’ or ‘z A’ for short:

This will work for vectors with as many more coordinates as you want, so long as there are the same number in each vector.