Septimal Harmony Again

:: Roughly six rambling paragraphs of motivation for 7-limit just intonation

We mostly play instruments that are harmonic, meaning that sounded notes have strong identifiable base frequencies in addition to strongly present spectral spikes, or "partials", at frequencies which are integer multiples of the base frequency - so called harmonic partials or harmonics. We can sound multiple notes against each other that are related by simple frequency ratios ("just intonation") to produce nice combination-sounds because of this. If you have instruments whose partials are inharmonic, then just intonation stops being the right framework for producing euphonious polyphony among them.

In just intonation, you can get a fairly good scale using frequency ratios with prime factors of just 2 and 3. The interval system that abstracts this frequency ratio space is called rank-2 interval space and it's what almost all western musicians learn - it has intervals like the perfect fourth, the minor second, the augmented sixth, and the diminished seventh. Purely tuning rank-2 intervals is also called "Pythagorean tuning". The major, minor, and chromatic scales you get by purely tuning rank-2 intervals are fairly good, but not great. Most tuning systems you're familiar with, like 12-tone equal temperament and quarter comma meantone, are a patch for this: by mistuning rank-2 interval space a little, you can get some notes to sound like they have simpler and prettier ratios with factors of (2, 3, 5) instead of more complex ratios with just factors of (2, 3). For example, if you tune the rank-2 major seventh purely, you get a frequency ratio of 243/128, whereas the rank-3 major seventh is more simply 15/8. In addition to being have a smaller numerator and denominator, 15/8 does in fact sound better when sounded against the unison. Quarter comma meantone and 12-TET slide the major seventh toward its 5-limit value.

I contend that major, minor, and chromatic scales of western music theory are fundamentally rank-3, in that they're correctly abstracted from frequency ratios with factors of 5. Our music is most naturally represented with rank-3 intervals. There are many reasons why we use mistuned rank-2 intervals instead of purely tuned rank-3 intervals to represent western music - some of which are convenience of mental representation, convenience of symbolic representation on written scores, convenience of instrument construction, and convenience of performance. And at this point, people are so used to mistuned rank-2 intervals, that lots of people don't even like the sound of purely tuned rank-3 intervals as much, so called 5-limit just intonation.

But I believe western music is fundamentally rank-3, and I'm committed to rewriting music theory to reflect this. We've already got the convenient theory written, now it's time to do it right.

If harmony sounds better when we consider prime factors of 5 in our frequency ratios, what about higher primes? Is there a use for factors of 7?

The seventh harmonic sounds pretty good sounded against unison. It's definitely not a piano note, but it's not offensive. If anything it's kind of too pure? Like if you're used to 12-TET you'll be like, "Wait a second, why isn't this beating slightly? I'm use to slight beating." Also, barbershop quartets often use the seventh harmonic, and let's be honest, barbershop quartet music is sometimes technically impressive, but it's not really good. Some instruments are designed to suppress reduce spectral content near the 7th harmonic and its multiples: piano hammers are placed along the string that way. But despite the fact that some instruments suppress it, and that barbershop quartets aren't transcendently beautiful, I think think the 7th harmonic and other septimal intervals are pretty cool and valuable/useful in just intonation. "Blue notes" in blues which fall between the usual piano keys are often analyzed as being septimal. Like blues guitarists don't  just bend their strings to make ornamental variations in their melodies - they can be observed bending reliably to the same non-12-TET notes, and septimal frequency ratios are one framework for understanding the function of those notes. I've also used septimal intervals productively in analyzing middle eastern microtonal music. As we go to higher primes, they definitely become less relevant: you can't really pluck a 13th harmonic on a string, for example. Higher harmonics also get weaker in magnitude/volume as you go higher, so it gradually becomes unlikely that they're contributing perceptually to the timbre of instruments or the timbre of harmonies. Also people have imperfect pitch discrimination, so I think it stops making much sense to analyze pitches past a certain granularity - like even if it were loud enough to hear, is the 29th harmonic different enough from intervals available with harmonics up to 23 that we should name it that way? Or more concretely, trained people can only hear like 3 to 5 cents of frequency difference in a quiet laboratory setting, but my guess is that most people in noisy environments don't do much better than 20 cents. If an octave is 1200 cents, and there are perhaps 12 simple frequency ratios within an octave that are associated with each prime, then we can cover all the perceptually distinguishable frequencies with 1200 / 20 / 12 = 5 primes; [2, 3, 5, 7, 11]. Even if allow finer discrimination of frequency ratios in this model, it's not obvious to me that people will use frequency ratios differently just because they can notice a difference - a 5 cent sharp perfect fourth is still just going to be used like a perfect fourth. The fact that different tuning systems in wide use (or former/historic wide use) will place intervals more than 5-cents away from their pure values proves that our functional-assignments aren't as fine as our pitch discrimination.

Anyway, I recognize that the 11th harmonic contributs audibly to musical timbre. You can use audio filters to amplify or diminish the magnitude of a the 11th harmonic of a sound to experience its contribution and train yourself to recognize it - and it is fairly present and important, I'd say, having done a little of this training. So there's logical room for a theory of how to use 11-limit frequency ratios harmonically. But also the 11th harmonic sounded against the unison sounds pretty bad to my ear, while the 7th harmonic sounds quite good. So I myself am strongly motivated to understand septimal harmony, while the 11th harmonic and higher I mostly leave for other people to theorize about. The 7th harmonic, which sounds good/cool/interesting, and is also definitely useful for analyzing microtones beyond 5-limit just intonation, which are not uncommon in human music, even if they're not in the core of major/minor/chromatic notes that we use for most daily music in the west.

: Investigating 7-limit Just Intonation 

...

I started by making a little scale with septimal intervals and finer divisions than the chromatic. And then I picked three random distinct intervals from the scale to make a chord and listened to them to judge their consonance. I also removed the lowest note from all the intervals of the chord, so that below they're all have P1 in the bass. This made for a lot more intervals in my chord space than were in my original scale. Which is fine. It means I did a more thorough investigation of septimal intervals. Anyway, then I rated the chords as {"good", "okay", or "bad"} in terms of consonance. And I did that at least four times for each chord below and many others that were too ugly to include. Then I associated those categories with {3, 2, 1} so I could take an average and sort numerically. And here below we have, a bunch of chords with septimal intervals sorted by how consonant I thought they were. Higher values for higher consonance.

...

3.0 : ('P1', 'm3', 'SpM6')

3.0 : ('P1', 'SpGrA5', 'SpA9')

3.0 : ('P1', 'SpA6', 'M10')

3.0 : ('P1', 'SpA4', 'SpM6')

3.0 : ('P1', 'SpA3', 'M6')

3.0 : ('P1', 'Sbd4', 'Sbd6')

3.0 : ('P1', 'SbAcd4', 'AcM6')

3.0 : ('P1', 'P5', 'SbAcd11')

3.0 : ('P1', 'M6', 'SbAc11')

2.8333333333333335 : ('P1', 'SpGrA5', 'M10')

2.8333333333333335 : ('P1', 'P4', 'Sbd7')

2.8 : ('P1', 'Sbm3', 'Gr5')

2.8 : ('P1', 'Sbd5', 'M6')

2.8 : ('P1', 'Sbd3', 'Sbd5')

2.8 : ('P1', 'SbSb4', 'SbSbm6')

2.8 : ('P1', 'AcM2', 'Sbd5')

2.75 : ('P1', 'SpGrM3', 'SpM6')

2.75 : ('P1', 'SpA6', 'P8')

2.75 : ('P1', 'SpA3', 'SpA6')

2.75 : ('P1', 'SpA2', 'SpGrA5')

2.75 : ('P1', 'Sbd5', 'Sbd7')

2.75 : ('P1', 'SbAcd4', 'SbAcm6')

2.75 : ('P1', 'SbAcd4', 'AcM9')

2.7142857142857144 : ('P1', 'm7', 'SbAcd11')

2.7142857142857144 : ('P1', 'SpM6', 'SpA11')

2.7142857142857144 : ('P1', 'Grm3', 'Sbd6')

2.6666666666666665 : ('P1', 'm3', 'SpA4')

2.6666666666666665 : ('P1', 'm10', 'SpA11')

2.6666666666666665 : ('P1', 'm10', 'Sbd12')

2.6666666666666665 : ('P1', 'SpGr5', 'SpM6')

2.6666666666666665 : ('P1', 'SpA3', 'SpM6')

2.6666666666666665 : ('P1', 'Sbm7', 'M13')

2.6666666666666665 : ('P1', 'Grm7', 'Sbd10')

2.6 : ('P1', 'SpM6', 'SpA9')

2.6 : ('P1', 'SpGrM3', 'm6')

2.6 : ('P1', 'Sbm3', 'M6')

2.5 : ('P1', 'm3', 'Sbd5')

2.5 : ('P1', 'SpSpM3', 'M6')

2.5 : ('P1', 'SpA4', 'm6')

2.5 : ('P1', 'Sbd7', 'AcM9')

2.5 : ('P1', 'SbAcd4', 'P5')

2.5 : ('P1', 'SbAcd11', 'AcM13')

2.5 : ('P1', 'M3', 'SpGrA5')

2.5 : ('P1', 'AcA2', 'Sbm7')

2.4285714285714284 : ('P1', 'SpA2', 'SpA4')

2.4 : ('P1', 'm3', 'Sp5')

2.4 : ('P1', 'd8', 'SbAcd11')

2.4 : ('P1', 'SpGrm3', 'SpGr5')

2.4 : ('P1', 'SpA2', 'M6')

2.4 : ('P1', 'Sbd4', 'Grm7')

2.4 : ('P1', 'SbAcd4', 'm7')

2.3333333333333335 : ('P1', 'm3', 'SpA5')

2.3333333333333335 : ('P1', 'd4', 'Sbd6')

2.3333333333333335 : ('P1', 'SpM2', 'SpA4')

2.3333333333333335 : ('P1', 'SpM2', 'SpA3')

2.3333333333333335 : ('P1', 'SpA5', 'P8')

2.3333333333333335 : ('P1', 'SpA3', 'P8')

2.3333333333333335 : ('P1', 'Sbm7', 'Sbm10')

2.3333333333333335 : ('P1', 'Sbm7', 'M10')

2.3333333333333335 : ('P1', 'Sbd8', 'P11')

2.3333333333333335 : ('P1', 'Sbd5', 'Grd7')

2.3333333333333335 : ('P1', 'Sbd12', 'M13')

2.3333333333333335 : ('P1', 'SbSbm7', 'SbSbAc11')

2.3333333333333335 : ('P1', 'SbAc4', 'Sbm7')

2.3333333333333335 : ('P1', 'P4', 'Sbm6')

2.3333333333333335 : ('P1', 'AcM6', 'SbAcd8')

2.2857142857142856 : ('P1', 'SpA4', 'SpM9')

2.25 : ('P1', 'm7', 'SpA8')

2.25 : ('P1', 'SpGrm7', 'SpM9')

2.25 : ('P1', 'SpGr5', 'M10')

2.25 : ('P1', 'SpA4', 'SpGrA5')

2.25 : ('P1', 'SpA2', 'SpGr5')

2.25 : ('P1', 'Sbd7', 'P8')

2.25 : ('P1', 'SbAc11', 'SbAcM13')

2.25 : ('P1', 'Sb4', 'Sbm6')

2.25 : ('P1', 'P5', 'Sbd7')

2.2 : ('P1', 'm3', 'SbAcm6')

2.2 : ('P1', 'SpGrm3', 'SpGrm7')

2.2 : ('P1', 'SpGrM3', 'SpA4')

2.2 : ('P1', 'Sp5', 'SpGrm7')

2.2 : ('P1', 'Sbm3', 'P5')

2.2 : ('P1', 'Sbm3', 'A5')

2.1666666666666665 : ('P1', 'm3', 'SpGrm7')

2.1666666666666665 : ('P1', 'Grd5', 'Sbd8')

2.0 : ('P1', 'm6', 'SpGrM7')

2.0 : ('P1', 'SpSpA2', 'SpSpGrA5')

2.0 : ('P1', 'SpM6', 'SpM9')

2.0 : ('P1', 'SpM3', 'SpGrm7')

2.0 : ('P1', 'SpM3', 'SpGrA5')

2.0 : ('P1', 'SpM3', 'SpA5')

2.0 : ('P1', 'SpM3', 'P5')

2.0 : ('P1', 'SpM2', 'SpGrM7')

2.0 : ('P1', 'SpGrm3', 'SpA4')

2.0 : ('P1', 'SpGrM7', 'SpA9')

2.0 : ('P1', 'SpGrM7', 'M10')

2.0 : ('P1', 'SpGrM3', 'SbGrm7')

2.0 : ('P1', 'SpGr5', 'SpA9')

2.0 : ('P1', 'SpGr5', 'P8')

2.0 : ('P1', 'SpA5', 'SpA11')

2.0 : ('P1', 'SpA3', 'SpA9')

2.0 : ('P1', 'Sp4', 'SpM6')

2.0 : ('P1', 'Sbm7', 'SbAcd11')

2.0 : ('P1', 'Sbm7', 'P8')

2.0 : ('P1', 'Sbm6', 'M9')

2.0 : ('P1', 'Sbd8', 'Sbd10')

2.0 : ('P1', 'Sbd5', 'Sbm7')

2.0 : ('P1', 'Sbd5', 'Grm7')

2.0 : ('P1', 'Sbd4', 'Sbd10')

2.0 : ('P1', 'Sbd3', 'Grm7')

2.0 : ('P1', 'SbSbd5', 'SbGrd7')

2.0 : ('P1', 'SbSbAcd4', 'Sbm6')

2.0 : ('P1', 'SbAcd4', 'P12')

2.0 : ('P1', 'SbAcd4', 'Acm6')

2.0 : ('P1', 'SbAc4', 'SbAcM6')

2.0 : ('P1', 'SbAc11', 'AcA13')

2.0 : ('P1', 'P8', 'SpA10')

2.0 : ('P1', 'P8', 'Sbd10')

2.0 : ('P1', 'M3', 'Sbm7')

2.0 : ('P1', 'Grm7', 'Sbm10')

2.0 : ('P1', 'Grm3', 'Sbd8')

2.0 : ('P1', 'Grd5', 'Sbd10')

2.0 : ('P1', 'Acd4', 'SbAcm6')

2.0 : ('P1', 'AcM6', 'SbAc11')

2.0 : ('P1', 'AcM3', 'SbAcd8')

2.0 : ('P1', 'AcM2', 'SpAcA4')

2.0 : ('P1', 'Ac5', 'SbAcm10')

2.0 : ('P1', 'A4', 'Sbm6')

2.0 : ('P1', 'A2', 'SbGrm7')

1.8571428571428572 : ('P1', 'SpM3', 'SpA4')

1.8333333333333333 : ('P1', 'SpGr5', 'SpGrM7')

1.8333333333333333 : ('P1', 'Sb5', 'AcA9')

1.8 : ('P1', 'm3', 'SpA11')

1.8 : ('P1', 'SpGrM3', 'SpA8')

1.8 : ('P1', 'SpA2', 'SpA3')

1.8 : ('P1', 'Sbd4', 'SbGrm7')

1.8 : ('P1', 'Sbd4', 'Grd5')

1.8 : ('P1', 'Sb4', 'M6')

1.8 : ('P1', 'P8', 'SpA11')

1.8 : ('P1', 'P5', 'SpM6')

1.8 : ('P1', 'M3', 'SpGrM7')

1.75 : ('P1', 'Spm6', 'Sp11')

1.75 : ('P1', 'SpM3', 'SpSpGrA5')

1.75 : ('P1', 'SpM3', 'SpGrM7')

1.75 : ('P1', 'SpM2', 'SpM6')

1.75 : ('P1', 'SpGrm7', 'SpM10')

1.75 : ('P1', 'Sp4', 'Spm6')

1.75 : ('P1', 'Sbm3', 'SbAc11')

1.75 : ('P1', 'Sbd8', 'm10')

1.75 : ('P1', 'Sbd5', 'm10')

1.75 : ('P1', 'Sbd3', 'd5')

1.75 : ('P1', 'SbAc4', 'P8')

1.75 : ('P1', 'Sb5', 'SbSbm10')

1.75 : ('P1', 'M2', 'Sbm7')

1.7142857142857142 : ('P1', 'SbAcm2', 'Ac4')

1.6666666666666667 : ('P1', 'm6', 'SbAc11')

1.6666666666666667 : ('P1', 'm3', 'Sbm6')

1.6666666666666667 : ('P1', 'm3', 'SbSbAcm6')

1.6666666666666667 : ('P1', 'SpM3', 'd5')

1.6666666666666667 : ('P1', 'SpM2', 'SpGr5')

1.6666666666666667 : ('P1', 'SpM2', 'SpA5')

1.6666666666666667 : ('P1', 'SpA4', 'SpA5')

1.6666666666666667 : ('P1', 'SpA3', 'SpM7')

1.6666666666666667 : ('P1', 'SpA3', 'SpA8')

1.6666666666666667 : ('P1', 'SpA2', 'SpA8')

1.6666666666666667 : ('P1', 'Sbm6', 'Sb8')

1.6666666666666667 : ('P1', 'Sbm3', 'P8')

1.6666666666666667 : ('P1', 'SbAcm3', 'SbAc4')

1.6666666666666667 : ('P1', 'SbAcM2', 'AcA4')

1.6666666666666667 : ('P1', 'SbAc4', 'AcA9')

1.6666666666666667 : ('P1', 'P5', 'SpGrM7')

1.6666666666666667 : ('P1', 'P5', 'Sbd10')

1.6666666666666667 : ('P1', 'M3', 'Sbm6')

1.6666666666666667 : ('P1', 'M2', 'SpA10')

1.6666666666666667 : ('P1', 'Gr5', 'Sbm10')

1.6666666666666667 : ('P1', 'AcA2', 'SbAcM6')

1.6666666666666667 : ('P1', 'AcA2', 'SbAc4')

1.6 : ('P1', 'm7', 'SbAcm9')

1.6 : ('P1', 'SpM2', 'Sbd5')

1.6 : ('P1', 'SpA4', 'SpGrm7')

1.6 : ('P1', 'SpA3', 'SpGr5')

1.6 : ('P1', 'Sbm7', 'AcM9')

1.6 : ('P1', 'Sbm3', 'A4')

1.6 : ('P1', 'Sbd3', 'm6')

1.6 : ('P1', 'P4', 'Sbm7')

1.5 : ('P1', 'm3', 'Sbm7')

1.5 : ('P1', 'm3', 'Sb5')

1.5 : ('P1', 'SpM6', 'Sp11')

1.5 : ('P1', 'SpM3', 'SpM9')

1.5 : ('P1', 'SpM3', 'SpA6')

1.5 : ('P1', 'SpGrm7', 'SpA11')

1.5 : ('P1', 'SpGrM3', 'Spm6')

1.5 : ('P1', 'SpGrM3', 'SpGrm7')

1.5 : ('P1', 'SpAcM6', 'Ac11')

1.5 : ('P1', 'SpAcA2', 'Ac4')

1.5 : ('P1', 'SpA5', 'SpM9')

1.5 : ('P1', 'SpA5', 'SpGrM7')

1.5 : ('P1', 'SpA2', 'SpA10')

1.5 : ('P1', 'Sp4', 'SpGrM7')

1.5 : ('P1', 'Sbm2', 'Sb4')

1.5 : ('P1', 'Sbd5', 'SbSbd7')

1.5 : ('P1', 'Sbd4', 'Sbd11')

1.5 : ('P1', 'SbSbm3', 'Sbm6')

1.5 : ('P1', 'SbAcm2', 'SbSbd5')

1.5 : ('P1', 'SbAc4', 'P5')

1.5 : ('P1', 'SbAc4', 'AcM9')

1.5 : ('P1', 'Sb5', 'Grm7')

1.5 : ('P1', 'Sb4', 'GrM10')

1.5 : ('P1', 'M6', 'Sb8')

1.5 : ('P1', 'M3', 'Sb5')

1.5 : ('P1', 'Grm3', 'Sb4')

1.5 : ('P1', 'Acm6', 'SbAcd11')

1.5 : ('P1', 'AcA1', 'SbAcm6')

1.5 : ('P1', 'A5', 'Sb8')

1.4 : ('P1', 'SpA4', 'SpA8')

1.4 : ('P1', 'Sbm3', 'P4')

1.4 : ('P1', 'Sbd5', 'M7')

1.4 : ('P1', 'SbAcM6', 'P12')

1.3333333333333333 : ('P1', 'd4', 'Sbd10')

1.3333333333333333 : ('P1', 'SpSpA2', 'SpM6')

1.3333333333333333 : ('P1', 'SpM6', 'SpA8')

1.3333333333333333 : ('P1', 'SpM6', 'P12')

1.3333333333333333 : ('P1', 'SpM3', 'SpA3')

1.3333333333333333 : ('P1', 'SpM3', 'SpA11')

1.3333333333333333 : ('P1', 'SpM3', 'SbAcm13')

1.3333333333333333 : ('P1', 'SpGrm7', 'SpA8')

1.3333333333333333 : ('P1', 'SpGrm3', 'm6')

1.3333333333333333 : ('P1', 'SpGrm3', 'SpGrM7')

1.3333333333333333 : ('P1', 'SpGrm3', 'Sp8')

1.3333333333333333 : ('P1', 'SpGrM7', 'SpM10')

1.3333333333333333 : ('P1', 'SpGrA5', 'SpA6')

1.3333333333333333 : ('P1', 'SpGr5', 'SpM10')

1.3333333333333333 : ('P1', 'SpA4', 'SpA12')

1.3333333333333333 : ('P1', 'Sp5', 'SpGrM7')

1.3333333333333333 : ('P1', 'Sbm6', 'SpGrM10')

1.3333333333333333 : ('P1', 'Sbm3', 'Sb5')

1.3333333333333333 : ('P1', 'Sbm10', 'm13')

1.3333333333333333 : ('P1', 'Sbd5', 'Sbd12')

1.3333333333333333 : ('P1', 'Sbd4', 'Grd7')

1.3333333333333333 : ('P1', 'SbSbm6', 'SbSbd8')

1.3333333333333333 : ('P1', 'SbAcm9', 'SbAc11')

1.3333333333333333 : ('P1', 'SbAc4', 'AcA6')

1.3333333333333333 : ('P1', 'Sb5', 'M7')

1.3333333333333333 : ('P1', 'P5', 'SbAc11')

1.3333333333333333 : ('P1', 'P4', 'SbM10')

1.3333333333333333 : ('P1', 'M6', 'SpM9')

1.3333333333333333 : ('P1', 'M6', 'Sbd8')

1.3333333333333333 : ('P1', 'M3', 'SpM9')

1.3333333333333333 : ('P1', 'M10', 'SbAcM13')

1.3333333333333333 : ('P1', 'Grd3', 'Sbd6')

1.3333333333333333 : ('P1', 'AcA2', 'Sb5')

1.3333333333333333 : ('P1', 'Ac4', 'SbAcm10')

1.3333333333333333 : ('P1', 'A4', 'Sbm10')

1.25 : ('P1', 'SpSpGrA5', 'P8')

1.25 : ('P1', 'SpM9', 'Sbd11')

1.25 : ('P1', 'SpM2', 'SpGrm7')

1.25 : ('P1', 'SpGrM3', 'Sp8')

1.25 : ('P1', 'SpA3', 'SpGrM7')

1.25 : ('P1', 'SpA1', 'SpGrm7')

1.25 : ('P1', 'SpA1', 'SpGr5')

1.25 : ('P1', 'Sbm6', 'SbSbd7')

1.25 : ('P1', 'SbSbAcd4', 'SbAcM13')

1.25 : ('P1', 'SbAcd4', 'd5')

1.25 : ('P1', 'Sb5', 'A11')

1.25 : ('P1', 'M3', 'Sbd5')

1.25 : ('P1', 'GrM6', 'SbGrm7')

1.2 : ('P1', 'SpA1', 'SpA3')

1.2 : ('P1', 'Sbd3', 'm3')

...

A bunch of these intervals I find pretty suspicious; I think they're probably not representing simple septimal sounds. Rather they're consonant to my ear because they're approximating other frequency ratios, like 3-limit ratios or 5-limit ratios or even irrational 12-EDO frequency ratios, which my ear is unfortunately also accustomed to and sometimes picks out as consonant.

The next step of my investigation is to go through the more consonant chords and try to figure out which ones are actually septimal in character, and then I can piece together some heuristics for building consonant septimal chords, which can then be used as constraints in composing counterpoint and other polyphony.

There are other options for judging chordal consonance programmatically - I could use a Sethares-inspired psychoacoustic model of polyphonic audition (which I think would work fairly well but is overkill as a thing to include in a program for composing) or I could look at complexity of the chord's otonal representation (which I think is nonsense psychoacoustically but it would be easy). But my program of reverse engineering chords that I like worked well when I learned/invented heuristics for composing in 5-limit just intonation and I think it will continue to serve me well in 7-limit.

...

When I look through all the internal intervals within the harmonious-rated chords above, a lot of the frequency ratios of internal intervals are close to 5-limit ratios - off by a factor of 225/224, which is like 7 cents. The interval justly associated with 225/224 is called the septimal super augmented zeroth, SpA0. I'm going to use this fact to figure out which of the chords are not really septimal.

First I define the basis for a tunings system

    (SpA0, Sbm7, P8, M3)

In the rank-4 Lilley Johnston comma basis, this basis is written

    ((0, 0, -1, 1), (3, 10, 6, -1), (3, 12, 7, 0), (1, 4, 2, 0))

This has a determinant of 2, which will be important shortly. The basis intervals are justly tuned to (225/224, 7/4, 2/1, 5/4), but I'm going to define a tuning system that tempers out the first interval, SpA0.

    (SpA0, Sbm7, P8, M3) -> (1/1, 7/4, 2/1, 5/4)

Now we have the pieces we need to tune arbitrary rank-4 intervals in a system that tempers out SpA0, and therefore assigns equal frequency ratios to two intervals that differ by SpA0. I can go through chords and look at their intervals and say for each one, "Is there an interval with these same tempered coordinates / the same frequency ratio that has a shorter name? If  so, let's make a new chord where the intervals are simplified and we'll see that some of these harmonious chords with complex rank-4 intervals were functioning as harmonious chords with only rank-3 intervals, as far as someone with pitch discrimination around 7 cents can discern."

I am also interested in using this temperament procedure to replace complex intervals with simpler intervals of a different kind - those with lower prime-rank, rather than shorter/simpler names. And I suppose I could combine these two: like if Grm7 and Sbm7 happened to have the same tempered coordinates, then I could prefer to spell by chords with Grm7 on account of it being 5-limit. I think that's worth exploring at some point, but first I'm just going to use short interval names as my measure of complexity, and given two interval names of equal length, I'm going to prefer ones which come earlier in the list of intervals I added to a list as they became relevant when I was playing around with septimal chords. This is kind of arbitrary, but I don't think it's exactly wrong to say "these intervals are in practice more important, so I'm going to use them in my future analyses".

We could also use a measure of just-frequency-ratio complexity to judge which of two intervals is simpler when they have the same tempered coordinates. Lots of options. For another time.

...

Okay, so the super augmented third, SpA3 showed up a few times in my harmonious septimal chords. This differs from P4 by SpA0, and P4 is way simpler, so I'm going to reinterpret all the SpA3s as being not really septimal. Like [P1, SpA3, M6] should be called [P1, P4, M6], which is an inversion of [P4, M6, P8] which is a major chord rooted on P4, like F.maj in they key of C major. Not septimal.

Likewise our temperament maps Sbd6 to P5. Not septimal. I'm replacing SpGrA5 with Grm6. I'm replacing SpSpM3 with Spd4. And SbAcd4 becomes AcM3. And Sbd3 becomes AcM2. And SbAcd11 is AcM10. And SpA6 becomes Grm7.

Using the tempering procedure, SbSb4 becomes SbA3. But neither one of these are particularly useful/functional/interpretable intervals. But they're both within 6 cents of AcM3. And that's how I'll treat them. This is like tempering out the intervals justly associated with 19683/19600 or 4375/4374 (a schisma off from SpA0), respectively. I think I'd also like to push SpGrM3 and Grd4 to AcM3.

My tempering procedure would turn SpGr5 into Grd6, which is like {32/21 -> 1024/675}. Neither one makes much sense to me. I think I'll stick with the first one. There really isn't much nearby that's simpler for frequency ratios other than P5. I suppose I should listen to the chord with P5 instead of SpGr5 to see which is better.

Due to my kind of arbitrary preference ordering of intervals that have the same length names, the temperament procedure actually introduced a septimal interval where it hadn't been before: I stand by AcA2 being re-interpreted as Sbm3, so now the harmonious chord [P1, AcA2, Sbm7] has an interpretation that' seven more septimal, [P1, Sbm3, Sbm7]. And {AcA2 -> Sbm3} looks like {75/64 -> 7/6} in frequency space, so that's attractive. Sbd10 tempers the same as the simpler AcM9, which is {56/25 -> 9/4}. And an octave down, Sbd3 goes to AcM2, which looks like {28/25 -> 9/8}.

These tempered substitutions look at a little suspicious to me:

    SbSb4 -> SbA3

    SbSbm6 -> SbA5

    SpGrM3 -> Grd4

    SpGr5 -> Grd6

I'll probably go through the frequency ratios and cent values for each substitution to see what's going on there / whether there are better options.

The more I look at this, the more I think that I should only use complexity of frequency ratios as my determining factor in choosing tempered interpretations.

The substitution SbAcm6 -> AcA5 is like {63/40 -> 405/256} which is suspicious for its increasing numerical complexity and for the fact that neither of those are simple intervals with standard harmonic functions relative to P1. Their cent values are 786 -> 794. Since Grm6, justly tuned to128/81, is a 3-limit interval with a standard harmonic function and its about as numerically simple as 63/40, I think that's the substitution I'm going to make instead. This is like tempering out the interval justly associated with (128/81) / (63/40) = 5120/5103, which is about 5 cents. This differs from SpA0 by a schisma, and I'd been seriously considering tempering out the schisma in addition to SpA0 in order to simplify interval names, so this is great.

...

So close. Three more intervals to decide about, and then I'll have septimal chords with simplified names, and I can go through and figure out if the simplified ones are more consonant. And then I can compare all the most consonant chords and decide which I like best among e.g.
    [P1, m3, Sbd5]
    [P1, m3, SpA4]
    [P1, m3, SpM6]

And pretty soon I'll have strong opinions about the best septimal chords. And then I can codify them with programmatic constraints and use them to compose and generate septimal music with really good harmony.

...

Here's a thought: if a chord is harmonious, then its inversions should be harmonious too. So if I can find any triad that is unambiguously nice and septimal, then I get two more triads for free that are nice and septimal. And if I have ratings for one chord, and four for another, and I find out that they're inversions of one another, then I've now got 8 ratings for the inversion family, which hopefully means greater precision or accuracy or something in my catalogue of how good these chords are.

...

Oh, super interesting. I was going through a new set of chords, giving them ratings. And I tried changing the instrument. And my ratings changed! Broadly, more chords sound consonant/harmonious/euphonious when played on a (software) clarinet ensemble than on a (software) set of guitar strings.

...

Here's are some summaries of a new round of ratings I did for a new batch of chords: Higher score mean greater consonance.

1.1666666666666667 : ('P1', 'M3', 'SpGr5')
1.1666666666666667 : ('P1', 'Sb5', 'M6')
1.1666666666666667 : ('P1', 'Sbd3', 'Grd7')
1.2 : ('P1', 'SpM3', 'Sbm7')
1.2857142857142858 : ('P1', 'SpM2', 'SpA5')
1.3333333333333333 : ('P1', 'P5', 'SpM6')
1.3333333333333333 : ('P1', 'Sbd3', 'Grm7')
1.4 : ('P1', 'SpM2', 'SpAcA4')
1.4285714285714286 : ('P1', 'GrM3', 'Sbm6')
1.4285714285714286 : ('P1', 'SbAc4', 'AcM6')
1.5 : ('P1', 'SbAcm6', 'm7')
1.5 : ('P1', 'SbGrd4', 'Grm6')
1.5 : ('P1', 'SpGrA5', 'SpA6')
1.5 : ('P1', 'SpM2', 'SpGr5')
1.5714285714285714 : ('P1', 'M2', 'Sbd5')
1.5714285714285714 : ('P1', 'SpM3', 'P5')
1.6 : ('P1', 'Sbm3', 'SbGrd6')
1.6 : ('P1', 'SpM3', 'SpAcA5')
1.6666666666666667 : ('P1', 'AcM3', 'SpM6')
1.6666666666666667 : ('P1', 'M3', 'Sbm7')
1.6666666666666667 : ('P1', 'M3', 'SpA6')
1.6666666666666667 : ('P1', 'Sbd4', 'Grd7')
1.6666666666666667 : ('P1', 'm3', 'SpGrm7')
1.7142857142857142 : ('P1', 'AcA2', 'SbAcM6')
1.7142857142857142 : ('P1', 'SbAc4', 'SbAcM6')
1.8 : ('P1', 'Sbm3', 'A5')
1.8 : ('P1', 'Sbm3', 'P4')
1.8 : ('P1', 'Sp5', 'SpGrM7')
1.8 : ('P1', 'SpA2', 'SpA10')
1.8 : ('P1', 'SpA3', 'SpGr5')
1.8 : ('P1', 'SpGrM3', 'SpGrm7')
1.8 : ('P1', 'SpGrm3', 'SpGrm7')
1.8 : ('P1', 'SpGrm3', 'm6')
1.8 : ('P1', 'SpSpM3', 'M6')
1.8 : ('P1', 'm3', 'Sbd5')
1.8333333333333333 : ('P1', 'A4', 'Sbm6')
1.8333333333333333 : ('P1', 'AcA4', 'Sbm7')
1.8333333333333333 : ('P1', 'Grd4', 'SpM6')
1.8333333333333333 : ('P1', 'Grm3', 'Sbd8')
1.8333333333333333 : ('P1', 'M3', 'SpGrA5')
1.8333333333333333 : ('P1', 'M3', 'SpM6')
1.8333333333333333 : ('P1', 'P4', 'Sbm7')
1.8333333333333333 : ('P1', 'P4', 'SpM6')
1.8333333333333333 : ('P1', 'SbA3', 'SbA5')
1.8333333333333333 : ('P1', 'Sp4', 'SpA5')
1.8333333333333333 : ('P1', 'SpA4', 'SpGrm7')
1.8333333333333333 : ('P1', 'SpM6', 'SpM13')
1.8571428571428572 : ('P1', 'Sbm3', 'A11')
1.8571428571428572 : ('P1', 'SpA2', 'SpM6')
2.0 : ('P1', 'AcM2', 'Sbd5')
2.0 : ('P1', 'AcM3', 'Sbm7')
2.0 : ('P1', 'Grd7', 'Sbd13')
2.0 : ('P1', 'Grm3', 'Sbm6')
2.0 : ('P1', 'M3', 'Sbm6')
2.0 : ('P1', 'Sb5', 'M7')
2.0 : ('P1', 'SbAcd4', 'd8')
2.0 : ('P1', 'SbGrM3', 'Grm6')
2.0 : ('P1', 'Sbm10', 'P11')
2.0 : ('P1', 'Sbm3', 'Grm7')
2.0 : ('P1', 'Sbm6', 'Sbm10')
2.0 : ('P1', 'SpA4', 'M6')
2.0 : ('P1', 'SpA4', 'SpGrA5')
2.0 : ('P1', 'SpA4', 'SpM6')
2.0 : ('P1', 'SpA4', 'SpM9')
2.0 : ('P1', 'SpA4', 'm6')
2.0 : ('P1', 'SpA5', 'SpM9')
2.0 : ('P1', 'SpGr4', 'Grm6')
2.0 : ('P1', 'SpGr5', 'M10')
2.0 : ('P1', 'SpGr5', 'P8')
2.0 : ('P1', 'SpGr5', 'SpM6')
2.0 : ('P1', 'SpGrM3', 'SpM6')
2.0 : ('P1', 'SpM3', 'SpA6')
2.0 : ('P1', 'SpM3', 'SpGrM7')
2.0 : ('P1', 'SpM3', 'SpGrm7')
2.0 : ('P1', 'd4', 'Sbd7')
2.0 : ('P1', 'm10', 'Sbd12')
2.0 : ('P1', 'm10', 'SpA11')
2.0 : ('P1', 'm3', 'Sbd7')
2.0 : ('P1', 'm3', 'SpM6')
2.0 : ('P1', 'm3', 'SpSp5')
2.142857142857143 : ('P1', 'Sbd6', 'Grm7')
2.142857142857143 : ('P1', 'Sbm3', 'P8')
2.142857142857143 : ('P1', 'Sbm6', 'M9')
2.142857142857143 : ('P1', 'SpGrA5', 'M10')
2.142857142857143 : ('P1', 'm3', 'SbAcm6')
2.1666666666666665 : ('P1', 'Grm3', 'Sbd13')
2.1666666666666665 : ('P1', 'M3', 'SpGrM7')
2.1666666666666665 : ('P1', 'SbAcd4', 'm7')
2.1666666666666665 : ('P1', 'Sbd5', 'M7')
2.1666666666666665 : ('P1', 'Sbd5', 'Sbd7')
2.1666666666666665 : ('P1', 'SpGr5', 'SpM9')
2.1666666666666665 : ('P1', 'SpM6', 'SpA9')
2.1666666666666665 : ('P1', 'm3', 'SpA4')
2.2 : ('P1', 'Sbm3', 'Gr5')
2.2 : ('P1', 'Sbm3', 'Sbd5')
2.2 : ('P1', 'Sbm3', 'Sbm6')
2.2 : ('P1', 'SpA10', 'SpM13')
2.2 : ('P1', 'SpA3', 'SpA9')
2.2 : ('P1', 'SpA4', 'SpA5')
2.2 : ('P1', 'SpA5', 'SpA11')
2.2 : ('P1', 'SpGr5', 'SpM10')
2.2 : ('P1', 'SpGrM3', 'SpA5')
2.2 : ('P1', 'SpGrM3', 'm6')
2.2 : ('P1', 'SpGrM7', 'M10')
2.2 : ('P1', 'SpM3', 'SpA5')
2.2 : ('P1', 'SpM3', 'SpGrA5')
2.2 : ('P1', 'SpSpM3', 'SpSpAcA5')
2.2 : ('P1', 'm3', 'SpA5')
2.2 : ('P1', 'm3', 'Spd6')
2.2857142857142856 : ('P1', 'M6', 'SpA9')
2.2857142857142856 : ('P1', 'SbAcd4', 'SbAcm6')
2.2857142857142856 : ('P1', 'SpA2', 'Grm6')
2.2857142857142856 : ('P1', 'SpA2', 'SpGrA5')
2.3333333333333335 : ('P1', 'AcA9', 'SbAcM13')
2.3333333333333335 : ('P1', 'Grm3', 'Sbm7')
2.3333333333333335 : ('P1', 'P5', 'Sbm10')
2.3333333333333335 : ('P1', 'SbAc4', 'A5')
2.3333333333333335 : ('P1', 'SbAcd4', 'Acm6')
2.4 : ('P1', 'Sbm3', 'P5')
2.4 : ('P1', 'Sbm3', 'Sbm7')
2.4 : ('P1', 'Sbm7', 'Sbm10')
2.4 : ('P1', 'Sp4', 'SpM6')
2.4 : ('P1', 'Sp4', 'm6')
2.4 : ('P1', 'SpA2', 'SpGr5')
2.4 : ('P1', 'SpA3', 'SpGrA5')
2.4 : ('P1', 'SpA9', 'SpA11')
2.4 : ('P1', 'SpGr5', 'SpA10')
2.4 : ('P1', 'SpM2', 'SpGr4')
2.4 : ('P1', 'SpM3', 'SpGr5')
2.4 : ('P1', 'SpM3', 'SpM6')
2.4 : ('P1', 'Spd4', 'M6')
2.4 : ('P1', 'd8', 'SbAcd11')
2.4 : ('P1', 'm7', 'SbAcd11')
2.4285714285714284 : ('P1', 'AcM6', 'SbAcd11')
2.4285714285714284 : ('P1', 'Grm3', 'Sbd6')
2.4285714285714284 : ('P1', 'Sbd4', 'Grm7')
2.5 : ('P1', 'AcM3', 'SbA5')
2.5 : ('P1', 'AcM3', 'Sbm6')
2.5 : ('P1', 'Gr5', 'Sbm10')
2.5 : ('P1', 'SbAcd4', 'AcM6')
2.5 : ('P1', 'SbAcd4', 'SbAcm13')
2.5 : ('P1', 'SbGrdd5', 'Grm6')
2.5 : ('P1', 'SbSbGrd4', 'Grm6')
2.5 : ('P1', 'Sbd5', 'M6')
2.5 : ('P1', 'SpGrA5', 'SpA9')
2.6 : ('P1', 'SpA3', 'SpM6')
2.6 : ('P1', 'SpA9', 'M13')
2.6 : ('P1', 'SpA9', 'SpA10')
2.6 : ('P1', 'SpGrM3', 'SpGr5')
2.6 : ('P1', 'Spd4', 'SpAcm6')
2.6666666666666665 : ('P1', 'A4', 'Sbm10')
2.6666666666666665 : ('P1', 'AcM3', 'SbAcm6')
2.6666666666666665 : ('P1', 'SbAcd4', 'P12')
2.6666666666666665 : ('P1', 'Sbd4', 'Grm6')
2.6666666666666665 : ('P1', 'Sbd4', 'm6')
2.7142857142857144 : ('P1', 'Sbd7', 'AcM9')
2.8 : ('P1', 'Sbm7', 'M10')
2.8 : ('P1', 'SpA2', 'SpAcAA4')
2.8 : ('P1', 'SpA3', 'M6')
2.8 : ('P1', 'SpA6', 'M10')
2.8 : ('P1', 'SpA6', 'P8')
2.8333333333333335 : ('P1', 'A5', 'Sbm10')
2.8333333333333335 : ('P1', 'AcM3', 'SbSbm6')
2.8333333333333335 : ('P1', 'Grm6', 'SpA9')
2.8333333333333335 : ('P1', 'Grm7', 'Sbd10')
2.8333333333333335 : ('P1', 'M6', 'SbAc11')
2.8333333333333335 : ('P1', 'SbAc4', 'M6')
2.8333333333333335 : ('P1', 'SbAcd11', 'AcM13')
2.8333333333333335 : ('P1', 'SbAcd4', 'AcM9')
2.8333333333333335 : ('P1', 'Sbd4', 'Sbd6')
2.857142857142857 : ('P1', 'AcM3', 'SpAcAA4')
2.857142857142857 : ('P1', 'P4', 'Sbm6')
2.857142857142857 : ('P1', 'SbAcd4', 'P5')
3.0 : ('P1', 'AcM3', 'Sbd7')
3.0 : ('P1', 'P4', 'Sbd7')
3.0 : ('P1', 'P5', 'SbAcd11')
3.0 : ('P1', 'SbGrdd5', 'Sbd7')
3.0 : ('P1', 'SbSb4', 'SbSbm6')
3.0 : ('P1', 'Sbd7', 'P8')
3.0 : ('P1', 'Sbm7', 'M13')

...

I had the idea of using some math I used to use for document retrieval and word clouds and things like that. Basically find out which internal intervals are more likely to be in good chords and which are more likely to be in bad chords. And make allowances that only one bad interval needs to appear for a chord to sound bad, whereas all of the intervals in a chord need to be good or okay for the whole thing to sound good or okay.

...

Okay! Good news and bad news. The good news is I think I'm almost done analyzing septimal harmony. The bad news is that I don't like septimal harmony and I'm probably just going to give up on it soon. I figured out what most most of the septimal chords with [1, 3, 5] or [1, 3, 6] or [1, 4, 6] intervals were - I looked at triads with intervals of lower ordinal than 7ths. Aaaaand .... they're all just 5-limit chords in disguise.

I'm pretty sure (P1, SpSpM3, SpSpAcA5) was just functioning as (P1, P4, M6) to my ear. This is an inversion of [P1, M3, P5], along with [P1, m3, m6].

And (P1, SbGrdd5, Grm6) was just functioning as (P1, P4, Grm6). This is an inversion of [P1, Grm3, P5] along with [P1, AcM3, AcM6].

These three
(P1, SpA2, Grm6)
(P1, SpA2, SpGrA5)
(P1, m3, SpSp5)
were all functioning as (P1, m3, Grm6). This one looks weirder as an inversion: [P1, AcM3, Ac5] in root position, and [P1, Gr4, M6] for the (1, 4, 6) option. Did you know that those sounded decent? Its news to me. I should add them as chords to my 5-limit just intonation composition suite.

These three 
(P1, AcM3, SpAcAA4)
(P1, SbAcd4, P5)
(P1, SpGrM3, SpGr5)
were all functioning as
(P1, AcM3, P5)
That's already in root position, but its inversions are [P1, P4, AcM6] and [P1, Grm3, Grm6] if you were curious.

This guy
(P1, SpA2, SpAcAA4),
was functioning as
(P1, m3, P5)
which has inversions of [P1, P4, m6]  and [P1, M3, M6].

And (P1, Sbm3, P5) is pretty much the only simple septimal triad that might have a unique sound to my ear, but its sound is pretty close to (P1, m3, P5) also, and not necessarily better than (P1, m3, P5). So what am I even doing here? Its inversions are [P1, P4, Sbm6] and [P1, SpM3, SpM6].

From those chord equivalences above, it seems my ear doesn't particularly notice any of these commas:

225/224 x5, "marvel"
126/125 x2, "starling"
19683/19600 x2, "cataharry"
245/243 x1, "sensamagic"
5120/5103 x1, "hemifamity"
64/63 x1, "Archytas"

I've got "x5" because there were 5 different intervals among the chords that differed from 5-limit ones by factors of 225/224 in their just tunings. That's 7-cents and I already knew that I have a little bit of a hard time choosing among intervals that differ by 22 cents, so no surprise here, but it's ...  it's a little disheartening to do so much math and coding and chord rating investigation, just to have it all be useless because I'm so tone deaf.

...

Anyway! We've got one root position septimal triad that might be worth using: [P1, Sbm3, P5]. And also there might be septimal intervals that are useful to put on top of triads, old and new. So septimal harmony might not be a total dud. But I need to stop looking at the whole chord space and start looking at like, "which seventh do I like best on top of  [P1, Sbm3, P5]". Or "what root positions triads work well with the harmonic seventh". And I think I'd like to know if there's any use for these intervals: [Sbm7, SpM7, Sbm9, SpM9, Sbm10, SpM10] which is noticeably different in sound/function from simple 5-limit intervals. Like if you flatten a minor interval by 36/35 instead of 81/80, or if you raise a major interval by 36/35 instead of sharpening it by 81/80, are the septimal intervals recognizably septimal in sound, or are they just close to Pythagorean intervals? My ear mostly ignored 225/224, not (36/35) / (81/80) = 64/63, and that guy is a whole 1200 * log_2(64/63) = 27 cents, so I should be able to hear it and make judgements about it. And hopefully I can find some harmonies that are both nice and recognizably septimal.

...

I already did some of that back in February of this year. 

...

Closed form expressions for matrix entries generated by iterative proportional fitting

Inspired by this.

If we start with a matrix [[1, 1], [1, 1]] and we perform iterative proportional fitting with real-valued non-zero growth factors [a, b], I've found that the equilibrium matrix has the form:

    [2a^2 / (a + b), 2ab / (a + b)]

    [2ab / (a + b), 2b^2 / (a + b)]

By growth factors, I mean the desired row and column sums are given by the original ones times those factors.

What if we have a different initial matrix?

If your initial matrix is all 5s instead of all 1s, then all the entries in the equilibrium matrix are 5 times larger.

If you scale the initial matrix columns by positive integers (m, n), then in the equilibrium matrix, the columns are scaled by (m, n). 

If you scale the initial rows by constants, you don't get anything like that though. Which is weird, because the iterative-proportional-fitting procedure is pretty symmetric between rows and columns. I guess in my code I take turns scaling rows (first) and columns (second) over and over, so that's one source of asymmetry.

Anyway, let's say we have an initial matrix [[m, m], [n, n]]. What's the equilibrium matrix for different growth factors (a, b)? Weirdly it only converges when the growth factors are equal, {a = b}. Otherwise, for example, the top left matrix entry alternates between two small rational values. When the growth factors are equal, the equilibrium matrix is the initial matrix scaled by the growth factor, i.e. [[am, am], [an, an]].

Okay, we've seen fully-constant initial matrices, and matrices with constant columns, and matrices with constant rows. Now for something spicier. Let's investigate a matrix that has all 1s except for the top left entry. Let's have a small change of notation: [a, b] no longer refer to growth factors. Instead our initial matrix is [[a, b], [c, d]], so that we can say {b=c=d=1}.

I've figured out symbolic expressions for the equilibrium matrix when we have growth factors [1/p, 1] for {p} a positive integer. I don't know of any reason why these formulas wouldn't work with {p} drawn from a more general classes of numbers, but I figured out the formulas using {p} over positive integers, and that's the only place where I've checked the formulas, and that's the only place where I'll assert their correctness now.

All the entries can be written as solutions of quadratic equations with leading terms {px^2} and rational coefficients. For given values of {a} and {p}, all the quadratic equations associated with the four entries of the equilibrium matrix have the same discriminant.

The top left entry of the equilibrium matrix is

    ((p + a^2 + a/2 - 1/2) - sqrt(D)) / (p(a - 1))

for discriminant

    D = p^2 + (2a^2 + a - 1)p + ((a+1)/2)^2

The anti-diagonal of the equilibrium matrix is constant. Both values are given by

    (-(p + (a+1)/2) + sqrt(D)) / (p(a -1))

The bottom right entry of the equilibrium matrix is

    ((2ap + a/2 - p + 1/2) - sqrt(D)) / (p(a - 1))

My method for figuring out these formulas mostly amounted to finding symbolic forms for entries of equilibrium matrices with defined {a} and {p}, and gradually noticing linear and quadratic patterns in constants, generalizing repeatedly from special cases. All pattern recognition, no proofs. But the formulas are correct. And if you can explain why, that'd be cool to see.

Next I'd like to try finding symbolic expressions for the equilibrium matrix terms when we have independent growth rates, or perhaps when we have non-unitary values for both {a} and {d} in the initial matrix, but those sound pretty hard, and I'm just going to savor the accomplishment of finding the above formulas for a while.

Oh! I can figure out growth rates [1, 1/p] instead of [1/p, 1]. That sounds like a manageable challenge. Please hold!

...

For growth rates [1, 1/p] and initial matrix [[a, 1], [1, 1]], IPF gives us an equilibrium matrix with top left entry

    ((a^2 + a/2 - 1/2)p + 1 - sqrt(D)) / ((a - 1)p)

for discriminant 

    D = ((a + 1)/2)^2 p^2 + (2a^2 + a - 1) p + 1

The antidiagonal is constant, and both values are given by

    (-1 * (((a + 1)/2)p + 1) + sqrt(D)) / ((a - 1)p)

and the bottom right entry of the equilibrium matrix is
    (p(a + 1)/2 + (2a - 1) - sqrt(D)) / ((a - 1)p)

Nice.

I just checked, and these formulas still work if your second growth rate isn't the reciprocal of an integer. You can use a growth rates of [1, 6/1] or [1, 5/8] or whatever. Just set {p} equal to the reciprocal of your second growth rate and they'll still predict correctly. And the case is likewise the set of formulas before these, for growth rates [1/p, 1]. You can use positive reals in the first slot, just set {p} to the reciprocal of the first growth rate.

...

I want to take small steps to generalize from here. I'm thinking that I could either look at initial matrices of the form [[a, 1], [1, a]] or I could look at growth rates {c * [1/p, 1]} and {c * [1, 1/p]}. And then eventually I'll get to independent diagonal values and independent growth rates. Or maybe that's already equivalent to independent growth rates? Because two real numbers will be related by a multiplicative constant {c}, namely their ratio. And {p} will be the inverse of one of them. I think that might be everything. Welp.

Let's start with an initial matrix of the form [[a, 1], [1, a]] and growth factors [1/p, 1], for {p} a positive integer. I fully expect that the formulas will continue to generalize to {1/p} being any positive real number.

For a=3, the discriminant term of entries in the equilibrium matrices has the form
D = p^2 + 34p + 1

The top left entry is given by 
    (p + 17 - sqrt(D)) / 4p

The anti-diagonal is constant with both values given by
    (-p  - 1 + sqrt(D)) / 4p

And the bottom right entry is given by
    (17p + 1 - sqrt(D)) / 4p

.

For a = 5, my first guess was that the discriminant was
    D = 1/4 p^2 + 49/2 p + 1/4

but that looks a little funny, and you can move a constant between the discriminant and the rest of the expression. So let's also consider four times the previous expression: 
    D = p^2 + 98p + 1

If we use that 4x discriminant, then the upper left entry of the equilibrium matrix has the form
    (p + 49 - sqrt(D)) / 8p

which isn't so bad. Let's stick with this discriminant. The anti-diagonal is constant, with values of the form
    (-p + -1 + sqrt(D)) / 8p

and the bottom right entry looks like
     (49p + 1 - sqrt(D)) / 8p

Smashing. Let's do {a = 7} and then we'll guess and check the full form for general {a} and then move on to something more challenging.

For {a = 7}, the discriminant term in the equilibrium matrix entries is
    D = p^2 + 194p + 1

The top left entry is
    (p + 97 - sqrt(D)) / 12p

the anti-diagonal is
    (-p - 1 + sqrt(D)) / 12p

and the bottom right entry is
    (97p + 1 - sqrt(D)) / 12p
.

So, generalizing over a=(3, 5, 7), it looks like the general determinant is
    p^2 + (4a^2 - 2)p + 1

We'll check that of course, but I've heard of crazier things.

The top left entry generalized to depend on {a} looks like
    (p + (2a^2 - 1) - sqrt(D)) / (2(a - 1)p)

The anti-diagonal is
    (-p - 1 + sqrt(D)) / ((a - 1)p)

and the bottom right entry is
    ((2a^2 - 1)p + 1 - sqrt(D)) / (2(a - 1)p)

...

I had the thought that if I do analyze initial matrix 
    [[a, 1], [1, a]]
and the
    [[a, 1], [1, 2a]]
and then
    [[a, 1], [1, 3a]]
and maybe a few more, then I could try to generalize over those formulas and hopefully get a formula that's free in the coefficient in front of {a} on the bottom left, and then if that generalizes past the positive integers, then I've basically got independent upper-left and bottom-right entries. And then hopefully the simple patterns continue where you can multiply columns or rows by constants. And then we've got the whole damn thing solved. For one growth factor at least.

I'm starting to think that this problem is too boring to solve.

...