CHAOS Operators

ok cool. i can probably do that quickly. though it’s not quite clear to me how you would select between different functions syntactically, i can just add different states for different ‘modes’ or whatever, and let you figure out how CHAOS.ALG x works


slightly OT, but is it easy to tell me how to repeatedly bang an operator in the simulator? i guess i can just pipe CHAOS\n into stdin over and over, and pipe stdout to plot it, but maybe there is an easier way (and sorry, i’m too lazy to look closely r/n)

also, sorry i’m honestly not really a teletype user. it’s all evolved rather a lot since the last time i even looked at the source code.

1 Like

CTRL-D works, but is less than 20 characters.

Yeah I can do the rest of the code so you can keep your changes to chaos.c/h.

If you want to keep it simple, just make copies of chaos.c/h for each algorithm. Or separate branches and PR them all independently and I’ll handle the merge.

1 Like

i just added an algorithm switch and more functions to chaos.h / chaos.c , and opened a pull request

its incomplete, still need to do cell-aut mode. also more tests. i think i’m out of time for the moment though.

[ed] went ahead and added logic for 1d binary cell-aut. output looks reasonable, though it’s a sort of weird and arbitrary interpretation: the cell states are bits in an 8b value; might be better to just return the sum of bits (rather than the value itself.)

[ed] hm, i keep going back and forth on this. ideally the 1d cell aut output should just be 8 gates. sorry, i don’t even know if TT has bitwise operators…

ok, now i really gotta be done for the night.

4 Likes

I am still missing a somehow comprehensible explanation of what this does. Just tried to install it to see if I can figure it out by myself but it seems to be just a cryptic text file…?

:neutral_face:

New test build: teletype.hex (366.3 KB)

Syntax:

CHAOS              | get next chaotic value
CHAOS 5000         | set current value to half (see below)
CHAOS.R            | get chaos parameter
CHAOS.R 5000       | set chaos parameter to half
CHAOS.ALG          | get current algorithm
CHAOS.ALG 0        | select LOGISTIC
CHAOS.ALG 1        | select CUIBIC
CHAOS.ALG 2        | select HENON
CHAOS.ALG 3        | select CELLULAR AUTOMATA

Algorithm Parameters:

Logistic Map

  • R (0-10000) ranges from 3.2 to 4
  • CHAOS (-10000-10000) ranges from -1 to 1

Cubic Map

  • R (0-10000) ranges from 3.2 to 4
  • CHAOS (-10000-10000) ranges from -1 to 1

Henon Map

  • R (0-10000) ranges from 1 to 1.4
  • CHAOS (-10000-10000) ranges from -1.5 to 1.5

Cellular Automata

  • R (0-255) selects the rule from 0 to 255
  • CHAOS (0-255) ranges from 0-255

When I change CV 3 CHAOS.R X (say from X 5000 to X 0) there seems to be a slew on the CV. Is that expected behaviour?

CHAOS.R 5000 does not return a value. It is a setter.

CV 3 CHAOS.R X is undefined, I think.

Yes, sorry - my fault! What I did was this:

1:
CV 3 CHAOS

Then changing CHAOS.R in live mode from 5000 to 0.

Also what strange stuff is happening when CHAOS.R is exceeding 10000?

I find it a bit hard to guess where on the logistic map (i.e. the Feigenbaum digram) I am. Is there some easy maths to calculate this? I see that the resolution is much higher now but I liked the 275 = 2.75 ratio you first suggested.

It would be nice to have the range starting at 3.0 to include the first branch on the logistic and cubic maps

I understand it a bit better now and I think it is a good idea!

I have to admit I find it confusing and counter-intuitive that the same values for R
and CHAOS seem to produce different output value ranges depending on the chosen algorithm. And why does only the cellular automata offer a 1:1 relationship between input values (0-255) and output values (0-255)?

This is likely just due to my complete lack of understanding of the subject,
but I expect to be able to define an output value range for Chaos,
and be able to change the behavior/type of Chaos while maintaining the output value range I specified.

Of course I can do this scaling after the chaos function, but wouldn’t that be a waste of resources and make finding a suitable chaos type harder, or in other words make things less friendly for experimentation? “Hm, I don’t know if I like this type of chaos function, let me try a different one, wait a sec, that’s not so easy, as I first have to look up which output value ranges the other chaos function produce, and then adopt the scaling function accordingly.”

I guess I am just not getting the point, so please help me understand where my thinking is wrong.

Paging @zebra to the thread to explain!

ok i’ll give it a shot…

logistic, cubic, and henon modes operate internally on bipolar floating point values; the first two use [-1, 1] and henon uses [-1.5, 1.5]. so their output needs to be rescaled to be useful in the fixed-point numerical universe of teletype.

the actual output range at any given time is dependent on the intitial state and the parameter settings. these are chaotic functions and so the whole point is that i can’t easily tell you what a given output range will be for a given configuration. but i can guarantee that as implemented, they will always be in [-10000, 10000].

for cubic/logistic i can prove that this range will never be exceeded, and that there are many orbits that closely approach those bounds. the henon is a tougher analytical nut to crack, and i am sort of eyeballing it and hard-clipping the output if it exceeds those bounds.

if you use low param values for logistic and cubic, you will see pretty steady output values for logistic, and steadily oscillating output values for cubic. cubic will change sign on each iteration; logistic will always have the sign of its initial value ( i think?) ed: no! i was wrong. i think logistic always blows up to -inf if initial state is negative. @sliderule this should be fixed in the implementation; clamp negative initial values to zero.

for henon it’s a bit more complicated (check out that crazy bifurcation map.)

why does only the cellular automata offer a 1:1 relationship between input values (0-255) and output values (0-255)?

because unlike the others, the CA algorithm doesn’t operate on floating point numbers. it actually operates on binary arrays for both the state and the parameter. in this implementation i’ve encoded these as bits in an integer (which is standard practice.) we could of course decide to scale them but i think it’s more useful not to. this way, if you understand how the structure works, you can get specific behaviors by setting known rule and state values.

and if we get bitwise operators, then you will be able to map individual states of the CA (bits in the output) to gates. which IMO is a really awesome musical application of this mathematical structure.

please see here for background on 1d binary CA (also called elementary CA):
http://mathworld.wolfram.com/ElementaryCellularAutomaton.html

It would be nice to have the range starting at 3.0 to include the first branch on the logistic and cubic maps

ok, here’s the line to change:
[ https://github.com/burnsauce/teletype/blob/chaos/src/chaos.c#L50 ]

I find it a bit hard to guess where on the logistic map (i.e. the Feigenbaum digram) I am. Is there some easy maths to calculate this?

i don’t think so. that’s why determining the behaviors of iterative functions like this, directly led to the birth of numerical modelling. analytically, we can show things about the output bounds and the phase space (inductively), but it’s hard to predict a specific orbit without just calculating it.

the equations are simple, so it’s pretty easy to calculate where you end up after N iterations from any given starting configuration, with just a few lines of code in any programming environment. i guess that’s what i’d do.

so given that, i agree that it would be nice to always have a simple relationship between the fixed-point and internal representation of state and parameter.

i should point out that even small differences and errors in floating point implementation will lead to big differences in the orbit results. in numerical modelling work i’ve often seen significant discrepancies between different platforms. i think in this case it might be especially extreme if we are compiling with -mfast-float or such.

which is just to say, you can make a python one-liner to estimate the orbit for a given [state, param] value. but don’t be surprised if the estimate diverges from the TT implementation; it does not necessarily imply a programming error.

I see that the resolution is much higher now but I liked the 275 = 2.75 ratio you first suggested.

in my PR i took the liberty of applying an arbitrary scale to the parameters, as is done to the state. this is necessary if you want multiple algorithms, because they require diferent parameter ranges - setting alpha to 3.5 in a henon map will just blow it up.

and there are many other functions that could be added. a fun one i neglected to mention is the gingerbreadman. also a general LCG might be handy.

if you want the parameters to be literal then i think you have no choice but to split the algorithms into different operators.

i am not really a teletype user or even a eurorack user, so i bow out of the discussion when it gets to fine points of usability and syntactic preferences. that said:

  • i would maybe argue that CA should be a separate op since as pointed out, it’s very different structurally.
  • IMHO, a resolution of 0.01 on the parameter value for the maps, is insufficient to explore the coolness of closely-neihboring orbits.
7 Likes

Could we add getters to the function that return the bounds?

CHAOS.RF | returns the range floor
CHAOS.RC | returns the range ceiling
// I originally thought CHAOS.RMAX CHAOS.RMIN but the line was super long

Which would let you write,

SCALE 0 100 CHAOS.RF CHAOS.RC X 
// still not certain this will fit, I'm not near my TT and don't remember the maximum characters off hand.
// but you get the idea, being able to scale without knowing the allowable ranges by heart or having to
// look them up.

Maybe we need a shorthand symbol for CHAOS?

Actually, given the above we’d also need getters for the return value range. Maybe there’s a better way to do this?

  • CHAOS is really just a 1-argument generator, it could be abstracted to mean any number of things, which is how CA was a natural fit, but I am for spinning it out to its own op given its obvious difference
  • scaling outputs 1.5 to 15000 is possible on 16 bits
  • the problem of parameter precision
    • 2 decimal arguments gets us 7 decimal places:
      • e.g.: CHAOS.R 3000 1001 is 3.0001001
  • currently, pressing the back tick key makes a pound symbol. I could replace that with any bitmap.

Exploring CHAOS

  • tracking min and max of generated values allows for dynamic scaling
  • you can get a windowed average using Q
1 Like

feel like i should just state this again as clearly as possible:

for LOGISTIC, the output range will always be in [0, 1], given initial state in [0, 1]. (i think negative initial state will blow it up.)

for CUBIC, the output will always be in [-1, 1], given initial state in [-1, 1].

for both of these, the state is trivially mapped to [-10k, 10k], and the parameter is arbitrarily mapped. (if you’d prefer it to be literal, i guess i’d recommand [3000, 3999] -> [3.0, 3.9]. but i don’t really see what you gain from this; you just lose resolution and require anyone using the operator to also have knowledge of the underlying algorithm.)

it is not easy to say for any given initial configuration, what range that specific sequence will cover. (that is kind of the point.) but generally, for these two maps: as you increase the parameter, it will be increasingly likely that any given initial state will eventually hit any given output value in the range.

this applies more or less to the henon map, and to other iterative maps that we haven’t added yet (gbman, twisted logistic, lcg, &c.) they also have provably bounded ranges, and likewise it is futile to ask the TT to calculate, in advance, the specific range for a given configuration.

so i basically don’t think a getter for the range seems very useful. unless you take this, as @sliderule does (?), to mean an analysis feature that dynamically tracks the actual output range.


i think having a windowed average sounds interesting. but with a long window the output would tend to be boring (0 or 1/2.) with a short window it could get pretty funky. from a design perspective i’d tend towards making “windowed average” its own operator (as we did in aleph BEES.)

Actually, I was suggesting that doing things like tracking the minimum and maximum values could be a useful function of some patch, e.g.:

X CHAOS
Y MIN Y X
Z MAX Z X
X SCALE Y Z N 24 N 48 X
CV 1 X
1 Like

that sounds like a very useful thing to have

Do you mean a useful thing to have built-in or a useful code snippet?

i mean just to support the idea that analyzing the range / mean of an input is a generally useful functionality (not just for CHAOS.) but its possible that i don’t quite get what you’re doing in this snippet

1 Like

The script keeps track of the range of chaos values by storing the minimum in Y and the maximum in Z.

Then it scales the chaos value to a 2-octave voltage range mapped from Y to Z and sends it to a CV output.