cog/Frameworks/libsidplay/sidplay-residfp-code/combined-waveforms/old/combined.cs

384 lines
12 KiB
C#
Raw Normal View History

2014-12-08 06:26:31 +00:00
using System;
using System.Diagnostics;
using System.Globalization;
using System.IO;
namespace sidwaveforms {
class Parameters {
public float bias, pulsestrength, topbit, distance, stmix;
public int Score(int wave, int[] reference, bool print, int bestscore) {
var score = 0;
var wa = new float[12 + 12 + 1];
for (var i = 0; i <= 12; i ++) {
wa[12-i] = wa[12+i] = 1.0f / (1.0f + i * i * distance);
}
for (var j = 4095; j >= 0; j --) {
/* S */
var bitarray = new float[12];
for (var i = 0; i < 12; i ++)
bitarray[i] = (j & (1 << i)) != 0 ? 1f : 0f;
/* T */
if ((wave & 3) == 1) {
var top = (j & 2048) != 0;
for (var i = 11; i > 0; i --) {
if (top) {
bitarray[i] = 1f - bitarray[i-1];
} else {
bitarray[i] = bitarray[i-1];
}
}
bitarray[0] = 0;
}
/* ST */
if ((wave & 3) == 3) {
bitarray[0] *= stmix;
for (var i = 1; i < 12; i ++) {
bitarray[i] = bitarray[i-1] * (1f - stmix) + bitarray[i] * stmix;
}
}
bitarray[11] *= topbit;
SimulateMix(bitarray, wa, wave > 4);
var simval = GetScore8(bitarray);
var refval = reference[j];
score += ScoreResult(simval, refval);
if (print) {
float analogval = 0;
for (int i = 0; i < 12; i ++) {
float val = (bitarray[i] - bias) * 512 + 0.5f;
if (val < 0)
val = 0;
if (val > 1)
val = 1;
analogval += val * (1 << i);
}
analogval /= 16f;
Console.WriteLine(string.Format(CultureInfo.InvariantCulture, "{0} {1} {2} {3}", j, refval, simval, analogval));
}
if (score > bestscore) {
return score;
}
}
return score;
}
private void SimulateMix(float[] bitarray, float[] wa, bool HasPulse) {
var tmp = new float[12];
for (int sb = 0; sb < 12; sb ++) {
var n = 0f;
var avg = 0f;
for (var cb = 0; cb < 12; cb ++) {
var weight = wa[sb - cb + 12];
avg += bitarray[cb] * weight;
n += weight;
}
if (HasPulse) {
var weight = wa[sb - 12 + 12];
avg += pulsestrength * weight;
n += weight;
}
tmp[sb] = bitarray[sb] * 0.50f + avg / n * 0.50f;
}
for (var i = 0; i < 12; i ++)
bitarray[i] = tmp[i];
}
private int GetScore8(float[] bitarray) {
var result = 0;
for (var cb = 0; cb < 8; cb ++) {
if (bitarray[4+cb] > bias)
result |= 1 << cb;
}
return result;
}
private static int ScoreResult(int a, int b) {
var v = a ^ b;
return v;
/* var c = 0;
while (v != 0) {
v &= v - 1;
c ++;
}
return c;
*/
}
public override string ToString() {
return string.Format(CultureInfo.InvariantCulture,
@"bestparams.bias = {0}f;
bestparams.pulsestrength = {1}f;
bestparams.topbit = {2}f;
bestparams.distance = {3}f;
bestparams.stmix = {4}f;
new waveformconfig_t({0}f, {1}f, {2}f, {3}f, {4}f)",
bias, pulsestrength, topbit, distance, stmix
);
}
}
class Optimizer {
static readonly Random random = new Random();
private static float GetRandomValue() {
var t = 1f - (float) random.NextDouble() * 0.9f;
if (random.NextDouble() > 0.5) {
return 1f / t;
} else {
return t;
}
}
private static void Optimize(int[] reference, int wave, char chip)
{
var bestparams = new Parameters();
if (chip == 'D') {
switch (wave) {
case 3:
// current score 240
bestparams.bias = 0.9634957f;
bestparams.pulsestrength = 0f;
bestparams.topbit = 0f;
bestparams.distance = 4.165269f;
bestparams.stmix = 0.8020396f;
break;
case 5:
// current score 600
bestparams.bias = 0.8931507f;
bestparams.pulsestrength = 2.483499f;
bestparams.topbit = 1.0f;
bestparams.distance = 0.03339716f;
bestparams.stmix = 0f;
break;
case 6:
// current score 613
bestparams.bias = 0.8869214f;
bestparams.pulsestrength = 2.440879f;
bestparams.topbit = 1.680824f;
bestparams.distance = 0.02267573f;
bestparams.stmix = 0f;
break;
case 7:
// current score 32
bestparams.bias = 0.9842906f;
bestparams.pulsestrength = 2.772751f;
bestparams.topbit = 0f;
bestparams.distance = 0.4342486f;
bestparams.stmix = 1f;
break;
}
}
if (chip == 'E') {
switch (wave) {
case 3:
// current score 112
bestparams.bias = 0.9689716f;
bestparams.pulsestrength = 0f;
bestparams.topbit = 0f;
bestparams.distance = 3.088513f;
bestparams.stmix = 0.7588146f;
break;
case 5:
// current score 166
bestparams.bias = 0.9161022f;
bestparams.pulsestrength = 1.879311f;
bestparams.topbit = 1.0f;
bestparams.distance = 0.02331964f;
bestparams.stmix = 0f;
break;
case 6:
// current score 10
bestparams.bias = 0.879145f;
bestparams.pulsestrength = 1.30156f;
bestparams.topbit = 0f;
bestparams.distance = 0.006426161f;
bestparams.stmix = 0f;
break;
case 7:
// current score 8
bestparams.bias = 0.911324f;
bestparams.pulsestrength = 2.959469E-07f;
bestparams.topbit = 0f;
bestparams.distance = 4.148929E-06f;
bestparams.stmix = 1f;
break;
}
}
if (chip == 'G') {
switch (wave) {
case 3:
// current score 188
bestparams.bias = 0.9506974f;
bestparams.pulsestrength = 0f;
bestparams.topbit = 0f;
bestparams.distance = 2.104169f;
bestparams.stmix = 0.7887034f;
break;
case 5:
// current score 360
bestparams.bias = 0.8924618f;
bestparams.pulsestrength = 2.01122f;
bestparams.topbit = 1.0f;
bestparams.distance = 0.03133072f;
bestparams.stmix = 0f;
break;
case 6:
// current score 668
bestparams.bias = 0.8952018f;
bestparams.pulsestrength = 2.213601f;
bestparams.topbit = 1.705941f;
bestparams.distance = 0.01260567f;
bestparams.stmix = 0f;
break;
case 7:
// current score 12
bestparams.bias = 0.9527834f;
bestparams.pulsestrength = 1.794777f;
bestparams.topbit = 0f;
bestparams.distance = 0.09806272f;
bestparams.stmix = 0.7752482f;
break;
}
}
if (chip == 'V') {
switch (wave) {
case 3:
// current score 5546
bestparams.bias = 0.9781665f;
bestparams.pulsestrength = 0f;
bestparams.topbit = 0.9899469f;
bestparams.distance = 8.077209f;
bestparams.stmix = 0.8226412f;
break;
case 5:
// current score 628
bestparams.bias = 0.9236207f;
bestparams.pulsestrength = 2.19129f;
bestparams.topbit = 1f;
bestparams.distance = 0.1108298f;
bestparams.stmix = 0f;
break;
case 6:
// current score 593
bestparams.bias = 0.9248214f;
bestparams.pulsestrength = 2.232846f;
bestparams.topbit = 0.9491023f;
bestparams.distance = 0.1313893f;
bestparams.stmix = 0f;
break;
case 7:
// current score 168
bestparams.bias = 0.9845552f;
bestparams.pulsestrength = 1.381085f;
bestparams.topbit = 0.9621315f;
bestparams.distance = 1.699522f;
bestparams.stmix = 1f;
break;
}
}
if (chip == 'W') {
switch (wave) {
case 3:
// current score 315
bestparams.bias = 0.9686383f;
bestparams.pulsestrength = 0f;
bestparams.topbit = 0.9955494f;
bestparams.distance = 2.141501f;
bestparams.stmix = 0.9635284f;
break;
case 5:
// current score 784
bestparams.bias = 0.9069195f;
bestparams.pulsestrength = 2.203437f;
bestparams.topbit = 1f;
bestparams.distance = 0.129717f;
bestparams.stmix = 0f;
break;
case 6:
// current score 757
bestparams.bias = 0.9075199f;
bestparams.pulsestrength = 2.180424f;
bestparams.topbit = 0.9760311f;
bestparams.distance = 0.1208313f;
bestparams.stmix = 0f;
break;
case 7:
// current score 211
bestparams.bias = 0.9882526f;
bestparams.pulsestrength = 1.736355f;
bestparams.topbit = 0.9395381f;
bestparams.distance = 2.698372f;
bestparams.stmix = 1f;
break;
}
}
var bestscore = bestparams.Score(wave, reference, true, 4096 * 255);
Console.Write("# initial score {0}\n\n", bestscore);
var p = new Parameters();
while (true) {
var changed = false;
while (! changed) {
foreach (var el in new string[] { "bias", "pulsestrength", "topbit", "distance", "stmix" }) {
var field = typeof(Parameters).GetField(el);
var oldValue = (float) field.GetValue(bestparams);
var newValue = oldValue;
if (random.NextDouble() > 0.5) {
newValue *= GetRandomValue();
if (el == "stmix") {
if (newValue > 1f)
newValue = 1f;
}
}
field.SetValue(p, newValue);
changed = changed || oldValue != newValue;
}
}
var score = p.Score(wave, reference, false, bestscore);
/* accept if improvement */
if (score <= bestscore) {
bestparams = p;
p = new Parameters();
bestscore = score;
Console.Write("# current score {0}\n{1}\n\n", score, bestparams);
}
}
}
private static int[] ReadChip(int wave, char chip) {
Console.WriteLine("Reading chip: {0}", chip);
var result = new int[4096];
var i = 0;
foreach (var line in
File.ReadAllLines(string.Format("sidwaves/WAVE{0:X}.CSV", wave))
) {
var values = line.Split(',');
result[i ++] = Convert.ToInt32(values[chip - 'A']);
}
return result;
}
public static void Main(string[] args) {
var wave = int.Parse(args[0]);
Debug.Assert(wave == 3 || wave == 5 || wave == 6 || wave == 7);
var chip = char.Parse(args[1]);
Debug.Assert(chip >= 'A' && chip <= 'Z');
var reference = ReadChip(wave, chip);
Optimize(reference, wave, chip);
}
}
}