Angled walls in Lego

Introduction

Most Lego instructions put bricks aligned with the grid, but a few of them uses bricks at angles, for example the Corner Garage. If we look at a Lego board as a coordinate system, and assume that the brick we want to put at an angle has one end in (0,0), then it is possible to end it at a stud at (a,b) if there is an integer c such that a^2 + b^2 = c^2. This is known as a Pythagorean triple, and it is known that there are infinitely many of these. The smallest one, which can also be used in Lego is (3,4,5), so a 6 stud piece can be put at an angle from a stud to the stud 4 studs to the right and 3 studs above. Note that we need a 6 stud piece to cover a distance of 5.

Near Pythagorean triples

There are only a few small Pythagorean triples usable in Lego construction, where the longest brick is 16 studs long. However, in the Corner Garage mentioned earlier, they use a triple (12, 12, 17) to produce a 45° angle, but this is not a Pythagorean triple since \sqrt{12^2 + 12^2} = 16,9706 \neq 17. The relative error for this Lego approved triple is 0.17%, so we use this as an upper bound on the triples computed here.

We may extend the list of triples further because there are Lego pieces which allow us to put a brick half-way between studs, so we do not need to restrict ourselves to integers but may include half-integers too. If we restrict the coordinates to be at most 15 units long, there are 44 triples. Sorted by angle they are:

\begin{align*}
1.91°&: (15, 0.5, 15),\newline
1.97°&: (14.5, 0.5, 14.5),\newline
2.05°&: (14, 0.5, 14),\newline
2.12°&: (13.5, 0.5, 13.5),\newline
2.2°&: (13, 0.5, 13),\newline
2.29°&: (12.5, 0.5, 12.5),\newline
2.39°&: (12, 0.5, 12),\newline
2.6°&: (11, 0.5, 11),\newline
2.86°&: (10, 0.5, 10),\newline
3.18°&: (9, 0.5, 9),\newline
15.64°&: (12.5, 3.5, 13),\newline
16.26°&: (12, 3.5, 12.5),\newline
16.93°&: (11.5, 3.5, 12),\newline
19.44°&: (8.5, 3, 9),\newline
20.14°&: (15, 5.5, 16),\newline
20.77°&: (14.5, 5.5, 15.5),\newline
22.62°&: (6, 2.5, 6.5),\newline
22.62°&: (12, 5, 13),\newline
25.71°&: (13.5, 6.5, 15),\newline
28.07°&: (7.5, 4, 8.5),\newline
28.07°&: (15, 8, 17),\newline
29.98°&: (13, 7.5, 15),\newline
30.96°&: (15, 9, 17.5),\newline
33.69°&: (7.5, 5, 9),\newline
33.69°&: (15, 10, 18),\newline
34.82°&: (11.5, 8, 14),\newline
35.13°&: (13.5, 9.5, 16.5),\newline
36.87°&: (2, 1.5, 2.5),\newline
36.87°&: (4, 3, 5),\newline
36.87°&: (6, 4.5, 7.5),\newline
36.87°&: (8, 6, 10),\newline
36.87°&: (10, 7.5, 12.5),\newline
36.87°&: (12, 9, 15),\newline
36.87°&: (14, 10.5, 17.5),\newline
38.42°&: (14.5, 11.5, 18.5),\newline
38.66°&: (12.5, 10, 16),\newline
38.99°&: (10.5, 8.5, 13.5),\newline
39.47°&: (8.5, 7, 11),\newline
40.24°&: (13, 11, 17),\newline
42.61°&: (12.5, 11.5, 17),\newline
43.6°&: (10.5, 10, 14.5),\newline
45°&: (8.5, 8.5, 12),\newline
45°&: (12, 12, 17),\newline
45°&: (14.5, 14.5, 20.5)
\end{align*}

Note that only angles up to 45 degrees are included here, since larger angles can be constructed from symmetry. Below are pictures of two examples of the triples (7.5, 4, 8.5) (left) and (6, 2.5, 6.5) .

Vertical angles

The above example is for putting bricks horizontally on a plate. However, some bricks, like Lego Technic bricks or the “light holder” bricks, allows you to build vertical angles as well, because you can put a brick on the side of it.

The height of a brick and the with of one stud is, however, not equal, so the Pythagorean triples have to be computed differently. We still allow the horizontal axis to be integers and half-integers, as above, but for the vertical axis, we use the unit size of one place. If you’ve ever built with Legos, you probably know that three plates equals one brick, but it is also true that that five plates equal two studs. So the if we keep using one horizontal stud as a unit, the vertical coordinate must be a multiple of \frac{2}{5}. This gives the following list of 11 near Pythagorean triples:

\begin{align*}
2.3°&: (10, 0.4, 10),\newline
2.5°&: (9, 0.4, 9),\newline
2.9°&: (8, 0.4, 8),\newline
3.3°&: (7, 0.4, 7),\newline
17.7°&: (10, 3.2, 10.5),\newline
20.5°&: (7.5, 2.8, 8),\newline
23.6°&: (5.5, 2.4, 6),\newline
28.1°&: (7.5, 4, 8.5),\newline
31°&: (6, 3.6, 7),\newline
36.9°&: (8, 6, 10),\newline
40.4°&: (8, 6.8, 10.5),\newline
\end{align*}

Below is a picture of a usage of the triples (6, 3.6, 7) and (7.5, 2.8, 8). Recall that 0.4 on the vertical axis corresponds to one plate and 1.2 is the full height of a brick.

Source code

The source code used to compute the triples is available here.

Dynamically Adaptive Tuning

Background

It has been known since Pythagoras that musical intervals correspond to a whole-number ratio of frequencies between the notes. The ratios for the 12 intervals in a chromatic scale are given below.

IntervalRatio
Unison1
Semitone\frac{16}{15}
Major second\frac{9}{8}
Minor third\frac{6}{5}
Major third\frac{5}{4}
Fourth\frac{4}{3}
Tritone\frac{45}{32}
Fifth\frac{3}{2}
Minor sixth\frac{8}{5}
Major sixth\frac{5}{3}
Minor seventh\frac{9}{5}
Major seventh\frac{15}{8}
Octave2

The problem is that these cannot be used as basis for for tuning an instrument because the intervals do not add up to what you would expect. As an example, you would expect that two major seconds, which is (\frac{9}{8})^2 = \frac{81}{64} would give the same ratio as a major third, but this is clearly not the case. Famously, the difference between 12 fifths and 7 octaves, which should be the same, is known as the Pythagorean comma:

\frac{(\frac{3}{2})^{12}}{2^7} \approx 1.01364.

One could fix a base note and then use the intervals from the table above to tune all keys on a piano, but because the notes are not evenly spaces, this will not allow transposition – a melody will sound different depending on what key it is played in. The most common solution to this problem is to use equal temperament which divides the octave into 12 equally sized ratios. This permits transposition but has the caveat that all intervals will only be approximately equal to their ideal ratio.

The equal temperament has been the most commonly used tuning system for centuries, but there have been some suggestions on how to improve the intonation of instruments, especially after the invention of electronic instruments. A recent example is presented in [1], where a method to compute just tuning in real-time using the method of least-squares is presented, and there is also a brief historical overview of other approaches.

Below, I present a method for optimal tunings which is very similar to the one in [1], but it is a lot simpler to understand and implement and I believe the resulting tuning is very similar. The idea behind this method is simply to use just tuning from a based on the lead/melody line. To describe it, we first need to define some formalism about tuning systems.

Tuning systems

A tuning system may be described as a strictly increasing function \tau: \mathbb{Z} \to (0, \infty) such that \tau(0) = 1. The equal tuning can, for example, be described by the relative tuning function

\tau_{\text{12-ET}}(n) = 2^{\frac{n}{12}}.

As an example of how to use this function, we first pick a base, for example that note n = 0 corresponds to A4, so it has frequency 440 Hz. The note a fifth (seven semi-tones) above then has frequency 440 Hz \times \tau_{\text{12-ET}}(7) = 659.255 Hz.

Given a base note, the just intervals in the table above defines a tuning \tau_{\text{Just}} because they define the tuning of the notes 0, \ldots, 12, and all other values may then be derived by the moving up and down in octaves, e.g. \tau_{\text{Just}}(n + 12) = 2 \tau_{\text{Just}}(n) .

We represent a score with v monophonic parts as a matrix of size v \times l with integer entries. The first row is assumed to be the leading part and l is the length of the score. The score is discretized such that a single column corresponds to the shortest note duration in the score and longer notes are represented by spanning multiple columns. This formalism cannot capture neither repeated notes nor rests, but since we are only interested in harmony, it will suffice for our purpose.

As an example, consider the following arrangement of the first four bars of Air on the G String by J. S. Bach / August Willhelmj.

Using standard MIDI numbers for notes where A4 corresponds to 69, this may be represented by the following matrix:

\left(\begin{matrix}
76, 76, 76, 76, 76, 76, 76, 76, 76, 76, 76, 76, 76, 76, 76, 76, 76, 76, 81, 77, \cdots \\
67, 67, 67, 67, 67, 67, 67, 67, 72, 72, 72, 72, 72, 72, 72, 72, 69, 69, 72, 72, \ldots \\
60, 60, 60, 60, 59, 59, 59, 59, 57, 57, 57, 57, 55, 55, 55, 55, 53, 53, 53, 53, \ldots \\
\end{matrix}\right)

which we will denote A = (a_{ij}). The goal of the tuning is to translate each of these notes a_{ij} into a frequency f_{ij} \in (0, \infty). This can be done using the equal tuning by setting f_{ij} = 440 \times \tau_{\text{12-ET}}(a_{ij} - 69) for all i, j. This will result in the following:

Dynamically adaptive tuning system

To get pure intervals we instead use the following method: Assume that frequencies f_{1,1}, \ldots, f_{1,L} for the first row has been determined. Now, the frequencies for row i is defined by

f_{ij} = f_{1j} \tau_{\text{Just}}(a_{ij} - a_{1j}).

This ensures that all intervals between the first and the j‘th row are just.

In order to tune the first row we can either use equal tuning, but to ensure just step intervals in the lead we instead pick a frequency for the first note, in this case f_{1,1} = 660 because the first note in the lead is A5, and define

f_{1,j} = f_{1,j-1} \tau_{\text{Just}}(a_{1,j} - a_{1,j-1}).

for j > 1. The resulting arrangement with dynamically adaptive just tuning as described above sounds like this.

The tuning is dynamical, meaning that the same note played in different places in the score may be tuned to different frequencies. This may even be true for sustained notes, if the melody changes in the duration of the sustained note. As an example, the F# half-note played by the third voice in the second half of the third bar changes frequency for each 8th note duration, and is tuned as 183.33, 182.52, 183.33 and 182.52 Hz resp. in the duration of the half note.

As it is presented here, the method may be applied to a fixed score where all notes are known in advance, but it could also be used in real-time assuming the program performing the tuning has a well-defined way of determining the lead, for example the highest played note, and then use this as the base.

The code used to generate the sound clips is available on GitHub.

Literature

[1] K. Stange, C. Wick and H. Hinrichsen, “Playing Music in Just Intonation: A Dynamically Adaptive Tuning Scheme,” in Computer Music Journal, vol. 42, no. 3, pp. 47-62, Oct. 2018, doi: 10.1162/comj_a_00478.

Turtle graphics

Turtle graphics is a method for generating images from integer sequences using very simple rules. The drawing is done by a “turtle” which moves and draws on a plane according to some rules. At any point in time, the turtle has a position and a direction, but no other state.

For example, consider the Thue-Morse sequence defined by

a_0 = 0, \\ a_{2n} = a_n, \\ a_{2n + 1} = 1 – a_n.

Now define a turtle by the following rules. For each 0 in the sequence, the turtle rotates by \pi and for each 1, the turtle moves ahead one unit and then rotate by \frac{\pi}{3}. This gives the Koch snowflake:

Hans Zantema has written a very nice paper on turtle graphics, including criteria for rules to ensure that the picture drawn by a turtle is either finite or self-similar. The paper also includes a number of examples, including the so-called rosettes which are defined over a binary sequence defined by the morphisms

0 \mapsto 011, 1 \mapsto 0

starting with 0. One example of a rosette is the turtle which for each 0 rotates 7 \pi / 9 and then moves, and for each 1 it rotates -2\pi / 9 and moves. This gives the following picture.

Below is a 6-minute animation of how the turtle moved while drawing the rosette.

The method can also produce more fractal-like images, like the one below which is also from Zantemas paper. Here the sequence is defined by

0 \mapsto 001100, 1 \mapsto 001101

where 0 rotates the turtle by 7\pi / 18 and 1 rotates the turtle -7 \pi / 12.

The code used to generate the pictures and video are available here.