コード例 #1
0
 public override string FormatNodeValue(DynamicalNode node)
 {
     if (node is NeuralOscillatorNode)
     {
         double averageMagnitude = node.AverageMagnitude;
         return(averageMagnitude.ToString("F4"));
     }
     else
     {
         return(base.FormatNodeValue(node));
     }
 }
コード例 #2
0
        public GFNN2LayerSystem(
            IIntegrator integrator,
            ToneNode soundSource,
            bool enableLearning,
            double middleFrequency = ToneNode.MiddleC,
            int octaves            = 2,
            int nodesPerOctave     = 120)
            : base(integrator)
        {
            this.EnableLearning = enableLearning;

            // Initialize SIRs
            this.SIRs = new double[]
            {
                // Sub harmonics.
                1.0 * 1 / 1,
                1.0 * 1 / 2,
                //1.0 * 1 / 3,
                //1.0 * 2 / 3,
                //1.0 * 1 / 4,
                //1.0 * 3 / 4,
                //1.0 * 1 / 5,
                //1.0 * 2 / 5,
                //1.0 * 3 / 5,
                //1.0 * 4 / 5,

                // 12-tone ET.
                1.0 * 16 / 15,
                1.0 * 9 / 8,
                1.0 * 6 / 5,
                1.0 * 5 / 4,
                1.0 * 4 / 3,
                1.0 * 17 / 12,
                1.0 * 3 / 2,
                1.0 * 8 / 5,
                1.0 * 5 / 3,
                1.0 * 16 / 9,
                1.0 * 15 / 8,
                1.0 * 2 / 1,
            };


            _soundSource = soundSource;
            _layers      = new List <List <NeuralOscillatorNode> >();

            var layer1 = GenerateLayer(
                "COC",
                middleFrequency,
                octaves,
                nodesPerOctave,
                -0.01,
                // omega=2 pi
                -1,
                -1,
                0,
                0.1,
                2.0 * Math.PI);

            var layer2 = GenerateLayer(
                "DCN",
                middleFrequency,
                octaves,
                nodesPerOctave,
                -0.4,
                1.2,
                -1,
                -0.01,
                0.75,
                0);


            // Connect sound source to layer 1.
            foreach (var node in layer1)
            {
                node.AddIncomingNode(soundSource);
            }

            // Afferent layer 1 to layer 2.
            // Connect each node in layer 1 to its corresponding node in layer 2.
            double afferentWeightPlasticity = 0;
            double afferentWeightDecay      = 0;

            foreach (var pair in layer1.Zip(layer2, (n1, n2) => new { L1N = n1, L2N = n2 }))
            {
                Debug.Assert(pair.L1N.CenterFrequency == pair.L2N.CenterFrequency);

                pair.L2N.AddIncomingNode(pair.L1N, 1.0, afferentWeightDecay, afferentWeightPlasticity);
            }

            // Internal layer 2 to layer 2.
            double internalWeight    = 0.005;
            double sirMatchThreshold = 0.005;

            double internalWeightDecay      = 1.0;
            double internalWeightPlasticity = 1.0;

            int connectionsAdded = 0;
            int iteration        = -1;

            var outerJoin = layer2
                            .Join(layer2, n => true, n => true, (n1, n2) => new { N1 = n1, N2 = n2 })
                            .OrderBy(n => n.N1.CenterFrequency)
                            .ThenBy(n => n.N2.CenterFrequency);

            foreach (var pair in outerJoin)
            {
                iteration++;

                if (pair.N1 == pair.N2)
                {
                    continue;
                }

                // Learn weights.
                if (this.EnableLearning)
                {
                    //if (iteration % 2 != 0)
                    //{
                    //    continue;
                    //}

                    pair.N1.AddIncomingNode(pair.N2, internalWeight, internalWeightDecay, internalWeightPlasticity);
                    pair.N2.AddIncomingNode(pair.N1, internalWeight, internalWeightDecay, internalWeightPlasticity);

                    connectionsAdded += 2;
                }
                // Hardcoded weights.
                else
                {
                    // Connect layer 2 nodes to each other when they
                    // match a (probably) learned SIR/eigenmultiple frequency.
                    double frequencyRatio    = pair.N1.CenterFrequency / pair.N2.CenterFrequency;
                    double frequencyRatioAlt = 1.0 / frequencyRatio;

                    foreach (double sir in this.SIRs)
                    {
                        bool isMatch = MathHelpers.ApproximatelyEqual(frequencyRatio, sir, sirMatchThreshold) ||
                                       MathHelpers.ApproximatelyEqual(frequencyRatioAlt, sir, sirMatchThreshold);

                        if (!isMatch)
                        {
                            continue;
                        }

                        pair.N1.AddIncomingNode(pair.N2, internalWeight, 0, 0);
                        pair.N2.AddIncomingNode(pair.N1, internalWeight, 0, 0);

                        connectionsAdded += 2;

                        goto NextPair;
                    }
                }

NextPair:
                continue;
            }


            // Assign layers to system.
            var allNodes = new DynamicalNode[] { soundSource }.Concat(layer1).Concat(layer2);

            this.Nodes = allNodes;

            // Remember layers.
            _layers.Add(layer1);
            _layers.Add(layer2);

            // Create hebbian learning system.
            if (this.EnableLearning)
            {
                _hebbianSystem = new ConnectionWeightSystem(new RungeKuttaIntegrator(), this);
            }
        }