I think I fixed the precision loss in this fractal, at least for some of the locations which were broken. Was pretty hard. Not sure if there's a generally applicable solution.

It needed a couple of case analyses similar to the diffabs() function (which evaluates |X+x|-|X| without catastrophic precision loss when x is small compared to X) but specific to this fractal.

Show thread

Separated Perpendicular fractal formula is not working for deep zooms with perturbation techniques as intended.

around the outside, inside looks more reasonable. In other locations (more often) the opposite happens. Other locations are perfectly fine to 1e50 zoom level and beyond. Some kind of precision loss somewhere...

Formula:
```
a, b = coordinates of pixel
xn = (abs(x) - 7/2) * abs(x) - y * y + a;
yn = 2 * (7/4 - abs(x)) * y + b;
x = xn;
y = yn;
```

Perturbation techniques applied to give iterations of low-precision deltas vs high-precision reference. This goes wrong somewhere and too much information is lost from the low-precision numbers, causing pixelation

```
// mathr - 2021-10-11 -

typedef double sample;
SR 48000
"dsp.h"
R sample

typedef struct
{
int reloaded;
double t;
R note[2][3];
BIQUAD env[2][3];
PHASOR osc[2][3][2];
} S;

int go(S *s, int inchannels, const float *in, int outchannels, float *out)
{
if (s->reloaded)
{
s->reloaded = 0;
panic(s);
}
R bpm = 138 * 4./6;
R hz = 35;
R cps = bpm / 60 / 4;
R t = (s->t += cps / SR);
R fade = pow
( envL(slow(4, t))
* envLR(rotL(4, slow(4, t))
), 2);
pair chords[3][4] =
{ { { 4, 4 }, { 2, 4 }, { 2, 5 }, { 4, 3 } }
, { { 2, 5 }, { 4, 6 }, { 3, 6 }, { 3, 4 } }
, { { 4, 6 }, { 2, 8 }, { 4, 8 }, { 2, 5 } }
};
R chord[2] = { 0, 0 };
for (int c = 0; c < 2; ++c)
{
for (int i = 0; i < 3; ++i)
{
R stereo = rotL(sine2(slow(4, t + (c - 0.5))) / 64, t);
R note = timeCat(chords[i], stereo);
R trig = (s->note[c][i] != note) * 500 * fade;
s->note[c][i] = note;
R q = mix(flatq, 5, envL(slow(8, t)));
R env = sine2(biquad(highpass(&s->env[c][i], cps * note, q), trig));
R osc = sine2(phasor(&s->osc[c][i][0], hz * (1 + (c - 0.5)/16) + (i - 1) / 30.0 + 1000 * env * sine2(phasor(&s->osc[c][i][1], hz * note))));
chord[c] += osc;
}
}
for (int c = 0; c < outchannels; ++c) {
out[c] = c < 2 ? 0.2 * chord[c] * fade : 0;
}
return 0;
}
```

Show thread

```
// mathr - 2021-10-06 -
typedef double R;
SR 48000
"dsp.h"
R sample
typedef struct
{
int reloaded;
double t;
R note[2][3];
BIQUAD env[2][3];
PHASOR osc[2][3],bosc[2][3];
}S;
int go(S *s,int nin,const float *in,int nout,float *out)
{
if (s->reloaded)
{
s->reloaded=0;
panic(s);
}
R bpm=138*4./3;
R hz=35;
R cps=bpm/60/4;
R t=(s->t+=cps/SR);
R fade=pow(envL(slow(4,t))*envLR(rotL(4,slow(4,t))),2);
pair chords[3][4]=
{{{4,4},{2,4},{2,5},{4,3}}
,{{2,5},{4,6},{3,6},{3,4}}
,{{4,6},{2,8},{4,8},{2,5}}};
R chord[2]={0,0};
R bass=0;
for(int c=0;c<2;++c){
for(int i=0;i<3;++i){
R stereo=rotL(sine2(slow(4,t+(c-0.5)))/64,t);
R note=timeCat(chords[i],stereo);
R trig=(s->note[c][i]!=note)*500*fade;
s->note[c][i]=note;
R q=mix(flatq,5,envL(slow(8,t)));
R env=sine2(biquad(highpass(&s->env[c][i],cps*note/3,q),trig));
R osc=square2(phasor(&s->osc[c][i],hz*note*3));
R pulse=exp2(square(fast(3,t)))/4;
R bosc=trisaw2(saw(slow(2,t)),phasor(&s->bosc[c][i],hz*note*3*pulse));
bass+=bosc;
chord[c]+=env*osc;
}
}
bass*=fade;
for (int c=0;c<nout;++c) {
out[c]=c<2?0.2*mix(chord[c],bass,0.5):0;
}
return 0;
}
```

Show thread

```
// mathr - 2021-10-01 -
typedef double sample;
SR 48000
"dsp.h"
R sample

typedef struct
{
int reloaded;
double t;
R note[2][3];
BIQUAD env[2][3];
PHASOR osc[2][3], bosc[2][3];
} S;

int go(S *s, int nin, const float *in, int nout, float *out)
{
if (s->reloaded)
{
s->reloaded = 0;
panic(s);
}
R bpm = 138;
R hz = 35;
R cps = bpm / 60 / 4;
R t = (s->t += cps / SR);
R fade = pow
( envL(slow(4, t))
* envLR(rotL(4, slow(4, t))
), 2);
pair chords[3][4] =
{ { { 2, 4 }, { 1, 4 }, { 1, 5 }, { 4, 3 } }
, { { 1, 5 }, { 2, 6 }, { 2, 6 }, { 3, 4 } }
, { { 2, 6 }, { 1, 8 }, { 3, 8 }, { 2, 5 } }
};
R chord[2] = { 0, 0 };
R bass = 0;
for (int c = 0; c < 2; ++c)
{
for (int i = 0; i < 3; ++i)
{
R stereo = rotL(sine2(slow(4, t + (c - 0.5))) / 64, t);
R note = timeCat(chords[i], stereo);
R trig = (s->note[c][i] != note) * 500 * fade;
s->note[c][i] = note;
R q = mix(flatq, 5, envL(slow(8, t)));
R env = sine2(biquad(highpass(&s->env[c][i], cps * note, q), trig));
R osc = sine2(phasor(&s->osc[c][i], hz * note * 3));
R pulse = exp2(square(fast(4, t))) / 4;
R bosc = sine2(phasor(&s->bosc[c][i], hz * note * 3 * pulse));
bass += bosc;
chord[c] += env * osc;
}
}
bass *= fade;
for (int c = 0; c < nout; ++c) {
out[c] = c < 2 ? 0.2 * mix(chord[c], bass, 0.5) : 0;
}
return 0;
}
```

This week I have mostly been working on 's , making it so that it can control uniform variables declared in the colouring .

In the example attached, the interior colour jumps from black to red when passing near to a particular minibrot.

Some bugs to fix:
- zoom speed display is inaccurate (scaled incorrectly by duration)
- the timeline table should not expand so much horizontally to fill the window
- the timeline table should have scrollbars when the window is smaller than the table
- when the windows are hidden (with Ctrl-F10) the timeline sequencing is disabled
- the initial values should be populated from the KFP palette if one is used
- it crashes when the number of columns is too big for Dear ImGui (upstream ImGui has a limit of 64, I applied a patch from the issue tracker to raise it to 1000 which is hopefully enough, unfortunately it seems harder to patch ImGUI to have no fixed limit at all...)

Found a solvent that worked nicely for removing the sticky remains of label glue residue.

Have 12 floppy disks all installed with my software and clean and ready for new labels.

Getting labels seems to be harder than expected, the required size is about 70mm square with rounded corners. Most custom print jobs are minimum 200 stickers and I don't need anywhere near that many, so I'm thinking of getting plain white labels (also minimum pack size 200...) designed for inkjet/laser printing at home, and doing potato prints with acrylic paint, with finer details by hand.

Show thread

This is more like what I had imagined - just needed some settings adjusted, and an extra thing for preferring to continue in the same direction.

Show thread

an experiment with agent simulation (each leaves a trail when it goes from A to B, and prefers using existing trails even if the route is a bit longer)

didn't quite turn out as I had expected / hoped (was going for "emergent city plan")

Got detached key working in both PNG (an extra image file with extension ".key.png" in place of ".png") and PDF (a second page in the same file) export. Overlay on image is another option, as is having no key at all (the default mode).

I adjusted the dashing patterns for each ray by hand in the GUI, this would be something nice to automate because it's very tedious mouse clickery.

The way I'm showing the text makes it non-selectable in the PDF, need to fix that too... hopefully it's something simple in my use of the Cairo API.

Show thread

Added an in-image key with labels for external rays to my Mandelbrot Perturbator GTK project.

Need to make it optional and/or detachable to a second page in PDF export because some images might have long ray labels (100s-1000s of characters) and having them all on the image will be distracting.

I tried counting the number of clockwise-oriented triples of (period 4 iteration N, period 11 iteration N, period 11 iteration N + 4) for N in 1, 2, 3, and it allowed me to distinguish them.

But those filaments spiralled only a little, and the method fails with more curly locations like the one attached with angled internal address 1 2 3 1/8 23.

Colour is blue vs orange depending on the proportion of clockwise triples for (period 23 N, pixel N, pixel N+23) for N in 1,2...22.

Show thread

Trying to figure out how to distinguish between numerators in angled internal addresses, from just the complex points C and its iterates Z (the marked points on the Hubbard trees). The angled internal addresses of the period 11 islands are 1 1/3 3 1/2 4 k/3 11 for k = 1, 2. If I can get an O(N) algorithm (here N is 11) to determine k from C then I will be very happy.

These images were made knowing the angles of the rays; finding the angles starting from C seems to be O(N^2) which is much too slow when N gets large.

sorry no image descriptions 

other cases did not do so well, the new algorithms failed for pre-periodic rays, and another periodic case had other problems

Show thread

It works well in some cases.

I found the nearest point algorithm (black line, previous implementation) is stable down to sharpness 2 in most cases (sharpness 1 fails immediately, unsurprisingly). This was a bit of a surprise, albeit a pleasant one.

The other pleasant surprise is that the new algorithm is ~2x faster for the same sharpness, presumably fewer iterations of Newton's method are needed to converge as the initial guess is better.

But they don't work for very low sharpness, and the linear approximation $r_{n+1} = r_n + (r_n - r_{n-1})$ fails often.

Caveat: I traced to dwell 1000 with low period rays, so the end result will be deep in a cusp: this is not a typical use case. Typical would be to trace to dwell 1000 with a period 500 ray, hopefully far enough for Newton's method to find the minibrot's nucleus.

Show thread
Show older
post.lurk.org

Welcome to post.lurk.org, an instance for discussions around cultural freedom, experimental, new media art, net and computational culture, and things like that.