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); } } }