Ok, here the all code and the library
//MANAGE SOUND
import ddf.minim.*;
import ddf.minim.ugens.*;
// MANAGE ARDUINO
import processing.serial.*;
Serial arduinoport;
int networkSize;
// MANAGE data TO SEND to ARDUINO
float speed0, speed1, speed2, speed3, speed4;
int VirtualPosition, VirtualPosition1;
float[] pos;
// MANAGE SOUND
Minim minim;
AudioOutput out;
AudioOutput out1;
AudioOutput out2;
MoogFilter moog;
MoogFilter moog1;
MoogFilter moog2;
//MANAGE VARIABLE TO MODULATE SOUND
float phaz, freq;
float rez;
float[] phazi;
// MANAGE PERSPECTIVE
import peasy.*;
PeasyCam cam;
// change these for screen size
float fov = 45; // degrees
float w = 1000;
float h = 800;
// don't change these
float cameraZ, zNear, zFar;
float w2 = w / 2;
float h2 = h / 2;
// MAANGE MOVEMENT
import sync.*;
PNetwork net;
float side;
float displacement;
float NaturalF;
float coupling;
float noiseScale= 1;
void setup() {
//perspective setting
size(1000, 800, P3D);
//********to send value to Arduino
String[] ports = Serial.list();
// printArray(ports);
printArray(Serial.list());
// arduinoport = new Serial(this,ports[6],115200);
//***************
// initialize the minim and out objects
minim = new Minim(this);
out = minim.getLineOut();
// construct a law pass MoogFilter with a
// cutoff frequency of 1200 Hz and a resonance of 0.5
moog = new MoogFilter( 1200, 0.5 );
moog1 = new MoogFilter( 1200*4, 0.5 );
moog2 = new MoogFilter( 1200*8, 0.5 );
// we will filter a white noise source,
// which will allow us to hear the result of filtering
Noise noize = new Noise( 0.5f );
// send the noise through the filter
noize.patch( moog ).patch( out );
noize.patch( moog1 ).patch( out );
phazi= new float[networkSize];
/* to manage later reflection on sphere
colorMode(RGB, 1);
// fill(0.4);
*/
cam = new PeasyCam(this, 1000);
cameraZ = (h / 2.0) / tan(radians(fov) / 2.0);
zNear = cameraZ / 10.0;
zFar = cameraZ * 10.0;
println("CamZ: " + cameraZ);
rectMode(CENTER);
//
int networkSize = 12; // To modulate sound of 12 note (one octave) Later!!!
coupling = 1;// How modulate this?
float noiseLevel = 0 ; // Usefull only with case Q?
net = new PNetwork(this, networkSize, coupling, noiseLevel);
side = height*0.15*1/networkSize;
displacement = width/2;
frameRate(20);
}
void draw() {
// MODULATE COUPLING with MouseX
coupling = mouseX/80;
net.setCoupling(coupling);
// println(coupling);
// MODULATE the noise in Q and q case
noiseDetail(4, mouseY/(height*1/1.2));//mouseX/(width/20), mouseY/(height*1/1.2)
background(220);
// Calculate the overall order (cohesion) in the network
PVector order = net.getOrderVector();
float orderParameter = net.getOrderParameter();
stroke(100);
fill(100);
String ordometer = String.format("Order: %.2f", orderParameter);
text(ordometer, 10, 20);
// net.setCoupling(coupling);
String couplingFormat = String.format("Coupling: %.2f", coupling);
text(coupling, 200, 20);
translate(width/2, height/2);
/* to manage later the direction of the light
lightSpecular(1, 1, 1);
directionalLight(0.8, 0.8, 0.8, 0, 0, -1);
float s = mouseX / float(width);
specular(s, s, s);
*/
// Draw spheres corresponding to the phase of each oscillator
stroke(75, 190, 70);
for (int i = 0; i < net.size; i++) {
pushMatrix();
float x = displacement*cos(net.phase[i]);
float y = displacement*sin(net.phase[i]);
// ***************************************DATA TO MANAGE SOUND
if (net.naturalFrequency[i] < 0) {
freq = constrain( map( net.naturalFrequency[i], 0, -5, 200, 12000 ), 200, 12000 );
}
else {
freq = constrain( map( net.naturalFrequency[i], 0, 5, 200, 12000 ), 200, 12000 );
}
if (net.phase[i] < 0) {
// phaz = constrain( map( net.phase[i], 0, -2*PI, 200, 12000 ), 200, 12000 );
phazi[i]= constrain( map( net.phase[i], 0, -2*PI, 200, 12000 ), 200, 12000 );
}
else {
// phaz = constrain( map( net.phase[i], 0, 2*PI, 200, 12000 ), 200, 12000 );
phazi[i]= constrain( map( net.phase[i], 0, -2*PI, 200, 12000 ), 200, 12000 );
}
println ( phazi[i]);
float freq = constrain( map( net.naturalFrequency[i], 0, 5, 200, 12000 ), 200, 16000 );/// adjust frequency between 200 and 16000
// moog.frequency.setLastValue( freq ); // modulate the cutoff or the moog filter with frequency
// moog1.frequency.setLastValue( phaz ); // modulate the cutoff or the moog filter with phase
rez= constrain( map( orderParameter, 0, 1, 0, 1), 1, 0 );
// moog.resonance.setLastValue( rez); //rez
//
// ************** PRINT DATA TO SEE COHERENCE BETWEEN MOVEMENT AND SOUND
/*
print ("phase "); print (i); print (" ");
print (net.phase[i]); print (" ");
print ("phaz "); print (i); print (" "); println (phaz );
print ("frequency "); print (i); print (" ");
print (net.naturalFrequency[i]); print (" ");
print ("freq "); print (i); print (" "); println (freq );
print ("rez"); print (i); print (" "); println (rez );
*/
translate(-w2, -h2, -1000); // Set the perspective 3D with two fingers on the trackpad
line (250,250, 250, 250); // line showing how ball will behang by the motor's axe.
// line (0,0,0,0,0, 11*250+200+250); //axe helping the 3D representation. axe qui relie les pendules
fill (0);
sphere(side*3); // this sphere serves as a reference
sphereDetail( 4*5);
// Draw sphere
fill(25*(net.size-i), 11*(net.size-i), (i+net.size)*11 );
noStroke(); //
translate (x*1,y*1, 200+(50*5*i)); //*-1 go in clockwise, *1 go in CCW
sphere(side*3);
// Draw axe of each sphere
rotate(net.phase[i]);
stroke(120);
line(0, 0, displacement*-1, 0 ); // * opposite / translate
noStroke();
popMatrix();
}
//********* AESTHETIC PROPOSITION to HAVE the same movement at the OPPOSITE SIDE
/*
noiseDetail(4, mouseY/(height*1/1.2));//mouseX/(width/20), mouseY/(height*1/1.2)
// background(0);
translate(-(width/2), -(height/2), -1000);
stroke(75, 190, 70);
for (int i = 0; i < net.size; i++) {
pushMatrix();
float x = displacement*cos(net.phase[i]);
float y = displacement*sin(net.phase[i]);
/*
rotate(net.phase[i]);
stroke(120);
line(0, 0, displacement*1, 0 );
rotate(-net.averagePhase); // draw a line pointing to the average phase of the network
color (12);
stroke (255);
line(0, 0, displacement*net.orderParameter, 0);
*/
/*
// Draw sphere
fill(25*(net.size-i), 11*(net.size-i), (i+net.size)*11 );
noStroke(); //
translate (x*-1,y*-1, 200+(50*5*i)); //*-1 go in clockwise, *1 go in CCW
sphere(side*3);
// Draw axe of each sphere
rotate(net.phase[i]);
stroke(120);
line(0, 0, displacement*1, 0 ); // * opposite / translate
noStroke();
popMatrix();
}
*/
net.step();
for (int i = 0; i < net.size; i++) {
//******************************* ASSIGN MOTOR WITH SPEED (former solution but to much expensive for now, maybe latter)
String speed= (nf (net.velocity[i], 0, 2)+"*"); // keep only 2 digit after the coma
// print (" speedMeasureLess: "); print (speed); // speed without measure
//******************************* ASSIGN MOTOR WITH POSITION
// RESOUDRE L'ERREUR // ASSIGN MOTOR WITH POSITION IN A SIMPLER MANNER ( WITH A AN ARRAY)
// pos[i]= map ((net.phase[i]), 0, TWO_PI, 0, 2048);
float pos0 = map ((net.phase[0]), 0, TWO_PI, 0, 2048); // Put the position at the good scale for a step motor with 2048 step.
float pos1 = map ((net.phase[1]), 0, TWO_PI, 0, 2048); // Put the position at the good scale for a step motor with 2048 step.
int Pos0= int (pos0);
int Pos1= int (pos1);
// CHANGE DATA TO HAVE THEM ON A CIRCLE BETWEEN 0 and 2048
if ( Pos0 <2049 ) {
VirtualPosition = Pos0;
}
if ( Pos0 < 0) {
VirtualPosition = 2048+ Pos0;
}
if ( Pos1 <2049 ) {
VirtualPosition1 = Pos1;
}
if ( Pos1 < 0) {
VirtualPosition1 = 2048+ Pos1;
}
// //Specify int DATA values, in order Arduino understand it's int DATA.
// And split them with "*"
String pos = (10)+"*"+(10) +"*"+(10)+"*"+(int (VirtualPosition1))+"*"+(int (VirtualPosition)) +"*";
// print (" pos ");println (pos);
// arduinoport.write(pos); // Send data to Arduino.
}
}
void keyPressed() {//**** faire position de base à l'arret avec ecrart equidistant qui s'incrementent entre G et le chiffre
if ( key == '5' ) moog.type = MoogFilter.Type.LP;
if ( key == '6' ) moog.type = MoogFilter.Type.HP;
if ( key == '7' ) moog.type = MoogFilter.Type.BP;
if (key == 'S') {println ("Add noise in last Frequencies. Vary it with mouse y");
background (255);
for (int i = 0; i < net.size; i++) {
// net.naturalFrequency[i] = TWO_PI * noise(i*0.1); //0.01 to begin slower
net.naturalFrequency[i] = net.naturalFrequency[i] + noise(i*0.1); // pas mal
// net.naturalFrequency[i] = net.naturalFrequency[i] * noise(i*0.5); // trop aleatoire
print ("phase "); print (i); print (" ");
print (net.phase[i]); print (" ");
print ("frequency "); print (i); print (" ");
println (net.naturalFrequency[i]);
}
}
//************* To modulate the parameters of the middle sphere
if (key == 'e') {
net.phase[net.size-net.size/2] +=0.1;
for (int i = 0; i < net.size; i++) {
print ("phase "); print (i); print (" ");
print (net.phase[i]); print (" ");
print ("frequency "); print (i); print (" ");
println (net.naturalFrequency[i]);
}
}
if (key == 'd') {
net.phase[net.size-net.size/2] -=0.1;
for (int i = 0; i < net.size; i++) {
print ("phase "); print (i); print (" ");
print (net.phase[i]); print (" ");
print ("frequency "); print (i); print (" ");
println (net.naturalFrequency[i]);
}
}
else if (key == 'r') {
net.naturalFrequency[net.size-net.size/2] +=0.1;
for (int i = 0; i < net.size; i++) {
printSummary(i);
}
}
else if (key == 'f') {
net.naturalFrequency[net.size-net.size/2] -=0.1;
for (int i = 0; i < net.size; i++) {
printSummary(i);
}
}
///****************************** MODULATE SPEED of ALL FREQUENCIE MORE OR LESS FASTLY
/// **************************** How could i modulate the couple?
else if (key == 'y') {
println("y= Increase last frequencies + 0.05*i ");
for (int i = 0; i < net.size; i++) {
net.naturalFrequency[i] = net.naturalFrequency[i]+(0.05*i);
println(coupling);
printSummary(i);
}
}
/*
}
/*
if (key == 'i') { // Shift frequencies one by one.
for (int i = 0; i < net.size; i++) {
if (i+1 < net.size) {
net.naturalFrequency[i]= net.naturalFrequency[i+1];
//* or something else but it doesn't work
net.naturalFrequency[11]= net.naturalFrequency[0];
net.naturalFrequency[10]= net.naturalFrequency[11];
net.naturalFrequency[9]= net.naturalFrequency[10];
net.naturalFrequency[8]= net.naturalFrequency[9];
net.naturalFrequency[7]= net.naturalFrequency[8];
net.naturalFrequency[6]= net.naturalFrequency[7];
net.naturalFrequency[5]= net.naturalFrequency[6];
net.naturalFrequency[4]= net.naturalFrequency[5];
net.naturalFrequency[3]= net.naturalFrequency[4];
net.naturalFrequency[2]= net.naturalFrequency[3];
net.naturalFrequency[1]= net.naturalFrequency[2];
net.naturalFrequency[0]= net.naturalFrequency[1];
printSummary(i);
}
else {
// net.naturalFrequency[0]= net.naturalFrequency[net.size];
}
}
}
///****************************** MODULATE SPEED of ALL FREQUENCIE MORE OR LESS FASTLY
/// **************************** How could i modulate the couple?
else if (key == 'y') { println("y= Increase last frequencies + 0.05*i ");
float coupling = mouseY/80; // Why it doesn't change the coupling
for (int i = 0; i < net.size; i++) {
net.naturalFrequency[i] = net.naturalFrequency[i]+(0.05*i);
print ("coupling : "); println (coupling);
printSummary(i);
}
}
*/
else if (key == 'h') { println(" Decrease last frequencies - 0.05*i");
for (int i = 0; i < net.size; i++) {
net.naturalFrequency[i] = net.naturalFrequency[i]-(0.05*i);
printSummary(i);
}
}
if (key == 'w') { println(" Increase with 0.1 ");
for (int i = 0; i < net.size; i++) {
net.naturalFrequency[i]= net.naturalFrequency[i]+(i*0.1);
printSummary(i);
}
}
if (key == 'v') { println(" Decrease with 0.1 "); //
for (int i = 0; i < net.size; i++) {
net.naturalFrequency[i]= net.naturalFrequency[i]-(i*0.1); ;
printSummary(i);
}
}
if (keyCode == UP) { //println( "Increase with 0.01 "); // Incremente together without changing phases
for (int i = 0; i < net.size; i++) {
// net.naturalFrequency[i] = net.naturalFrequency[i]+0.01*i;
net.naturalFrequency[i] = net.naturalFrequency[i]+0.1;
printSummary(i);
}
}
if (keyCode == DOWN) {// println(" Decrease all last frequencies proportionnaly to i "); // Incremente together without changing phases
for (int i = 0; i < net.size; i++) {
// net.naturalFrequency[i] = net.naturalFrequency[i]-0.01*i;
net.naturalFrequency[i] = net.naturalFrequency[i]-0.1;
printSummary(i);
}
}
//************************** CHANGE THE WAY OF ROTATION
else if (key == 'o') {// println(" Opposite frequencies without changing phases ");
for (int i = 0; i < net.size; i++) {
net.naturalFrequency[i] = -1* net.naturalFrequency[i];
printSummary(i);
}
}
//************************** SET HARMONIC MOVEMENT
else if (key == 'c') { println("c = Harmonic Frequencies in ClockWiseWay ");
for (int i = 0; i < net.size; i++) {
net.naturalFrequency[i]= i*-0.1;
printSummary(i);
}
}
else if (key == 'C') { println(" C = Reset frequency positively in harmonic way. "); //
for (int i = 0; i < net.size; i++) {
net.naturalFrequency[i]= i*0.1;
printSummary(i);
}
}
else if (key == '0') { println("Set Frequencies to 0 ");
for (int i = 0; i < net.size; i++) {
net.naturalFrequency[i]=1;
printSummary(i);
}
}
else if (key == '1') { println("Set Frequencies to 1+ harmonic distance ");
for (int i = 0; i < net.size; i++) {
float coupling = mouseY/(height/10); // No effect
print ("coupling :"); println (coupling);
net.naturalFrequency[i]=1-i*0.05;
printSummary(i);
}
}
// ****************** ALIGNEMENT of PHASES --- thus, phases alignement depend of coupling.
else if (key == '9') { println(" Set Phases to 0 "); //
for (int i = 0; i < net.size; i++) {
net.phase[i]=0;
printSummary(i);
}
}
else if (key == '8') { println(" Add 180° to all oscillator ");
for (int i = 0; i < net.size; i++) {
net.phase[i]=PI;
printSummary(i);
}
}
// MAKE A SORT OF FOLLOW MODE
}
void printSummary(int i) {
print("phase "); print(i); print(" ");
print(net.phase[i]); print(" ");
print("frequency "); print(i); print(" ");
println(net.naturalFrequency[i]);
}
package sync;
import java.util.Arrays;
import processing.core.*;
/**
* Sync for Processing
* Simulate oscillator synchronization with Processing
* https://github.com/nickmcintyre/processing-synchronization
*
*
* @author Nick McIntyre https://mcintyre.io
* @modified 03/01/2020
* @version 0.2.1 (14)
*
* @example BrainExample
* @example FireflyExample
* @example OrderExample
* @example PhaseExample
*/
public class PNetwork implements PConstants {
public PApplet parent;
public int size;
public float time;
public float stepSize;
public float[][] coupling;
public float noiseLevel;
public float[] naturalFrequency;
public float[] phase;
public float[] velocity;
public float[] acceleration;
private float[] oldPhase;
/**
* Initialize the PNetwork object.
*
* @param parent The parent PApplet object.
* @param size The number of oscillators in the network.
* @param coupling The global level of coupling in the network.
* @param noiseLevel The level of noise.
* @param stepSize The size of the time step.
*/
public PNetwork(PApplet parent, int size, float coupling, float noiseLevel, float stepSize) {
this.parent = parent;
this.parent.registerMethod("dispose", this);
time = 0.0f;
this.stepSize = stepSize;
this.noiseLevel = noiseLevel;
this.size = size;
this.oldPhase = new float[size];
initializeCoupling(coupling);
initializeFrequency();
initializePhase();
initializeVelocity();
initializeAcceleration();
}
/**
* Initialize the PNetwork object.
*
* @param parent The parent PApplet object.
* @param size The number of oscillators in the network.
* @param coupling The global level of coupling in the network.
* @param noiseLevel The level of noise.
*/
public PNetwork(PApplet parent, int size, float coupling, float noiseLevel) {
this(parent, size, coupling, noiseLevel, 0.05f);
}
/**
* Initialize the PNetwork object.
*
* @param parent The parent PApplet object.
* @param size The number of oscillators in the network.
* @param coupling The global level of coupling in the network.
*/
public PNetwork(PApplet parent, int size, float coupling) {
this(parent, size, coupling, 0.0f);
}
/**
* Initialize the PNetwork object.
*
* @param parent The parent PApplet object.
* @param phase The phase of each oscillator.
* @param naturalFrequency The natural frequency of each oscillator.
* @param coupling The level of coupling between each pair of oscillators.
* @param noiseLevel The level of noise.
* @param stepSize The size of the time step.
*/
public PNetwork(PApplet parent, float[] phase, float[] naturalFrequency, float[][] coupling, float noiseLevel, float stepSize) {
this.parent = parent;
parent.registerMethod("dispose", this);
time = 0.0f;
this.naturalFrequency = naturalFrequency;
size = naturalFrequency.length;
this.coupling = coupling;
this.stepSize = stepSize;
this.noiseLevel = noiseLevel;
this.phase = phase;
this.oldPhase = new float[size];
initializeVelocity();
initializeAcceleration();
}
/**
* Initialize the PNetwork object.
*
* @param parent The parent PApplet object.
* @param phase The phase of each oscillator.
* @param naturalFrequency The natural frequency of each oscillator.
* @param coupling The level of coupling between each pair of oscillators.
* @param noiseLevel The level of noise.
*/
public PNetwork(PApplet parent, float[] phase, float[] naturalFrequency, float[][] coupling, float noiseLevel) {
this(parent, phase, naturalFrequency, coupling, noiseLevel, 0.05f);
}
/**
* Initialize the PNetwork object.
*
* @param parent The parent PApplet object.
* @param phase The phase of each oscillator.
* @param naturalFrequency The natural frequency of each oscillator.
* @param coupling The level of coupling between each pair of oscillators.
*/
public PNetwork(PApplet parent, float[] phase, float[] naturalFrequency, float[][] coupling) {
this(parent, phase, naturalFrequency, coupling, 0.0f);
}
/**
* Initialize the coupling matrix for the case of uniform, global coupling.
*
* @param coupling The level of coupling between all oscillators.
*/
private void initializeCoupling(float coupling) {
this.coupling = new float[size][size];
setCoupling(coupling);
}
/**
* Set natural frequencies of oscillators using Perlin noise.
*/
private void initializeFrequency() {
naturalFrequency = new float[size];
float t = 0.0f;
float dt = 0.1f;
for (int i = 0; i < size; i++) {
naturalFrequency[i] = TWO_PI * parent.noise(t);
t += dt;
}
}
/**
* Set initial phases of oscillators using Perlin noise.
*/
private void initializePhase() {
phase = new float[size];
float t = 0.0f;
float dt = 0.1f;
for (int i = 0; i < size; i++) {
phase[i] = TWO_PI * parent.noise(t);
t += dt;
}
}
/**
* Set initial angular velocity of oscillators to 0.
*/
private void initializeVelocity() {
velocity = new float[size];
Arrays.fill(velocity, 0);
}
/**
* Set initial angular acceleration of oscillators to 0.
*/
private void initializeAcceleration() {
acceleration = new float[size];
Arrays.fill(acceleration, 0);
}
/**
* Shift the natural frequency of each oscillator to that of a
* neighbor's.
*
* @param n The number of indices to shift.
*/
public void shiftFrequencies(int n) {
shiftArray(naturalFrequency, n);
}
/**
* Shift the phase of each oscillator to that of a neighbor's.
*
* @param n The number of indices to shift.
*/
public void shiftPhases(int n) {
shiftArray(phase, n);
shiftArray(oldPhase, n);
}
/**
* Shift the elements of an array to the left or right.
*
* @param a The array to be shifted.
* @param n The number of indices to shift.
*/
private void shiftArray(float[] a, int n) {
float[] b = Arrays.copyOf(a, a.length);
if (n > 0) { // shift right
System.arraycopy(b, 0, a, n, a.length - n);
System.arraycopy(b, a.length - n, a, 0, n);
} else { // shift left
System.arraycopy(b, -n, a, 0, a.length + n);
System.arraycopy(b, 0, a, a.length + n, -n);
}
}
/**
* Set the coupling strength within the network.
*
* @param coupling The level of coupling.
*/
public void setCoupling(float coupling) {
setCoupling("A2A", coupling);
}
/**
* Set the connective arrangement and coupling strength within the network.
*
* @param arrangement The connective arrangement of the network.
* @param coupling The level of coupling.
*/
public void setCoupling(String arrangement, float coupling) {
if (arrangement.equals("A2A")) {
/**
* All-to-all
*
* {{0, X, X, X},
* {X, 0, X, X},
* {X, X, 0, X},
* {X, X, X, 0}}
*/
for (int i = 0; i < size; i++) {
for (int j = 0; j < size; j++) {
this.coupling[i][j] = coupling;
}
}
} else if (arrangement.equals("LU")) {
/**
* Linear Unidirectional
*
* {{0, X, 0, 0},
* {0, 0, X, 0},
* {0, 0, 0, X},
* {0, 0, 0, 0}}
*/
for (int i = 0; i < size; i++) {
for (int j = 0; j < size; j++) {
if (j == i + 1) {
this.coupling[i][j] = coupling;
} else {
this.coupling[i][j] = 0;
}
}
}
} else if (arrangement.equals("LB")) {
/**
* Linear Bidirectional
*
* {{0, X, 0, 0},
* {X, 0, X, 0},
* {0, X, 0, X},
* {0, 0, X, 0}}
*/
for (int i = 0; i < size; i++) {
for (int j = 0; j < size; j++) {
if (j == i + 1) {
this.coupling[i][j] = coupling;
} else if (i == j + 1) {
this.coupling[i][j] = coupling;
} else {
this.coupling[i][j] = 0;
}
}
}
} else if (arrangement.equals("BU")) {
/**
* Box Unidirectional
*
* {{0, X, 0, 0},
* {0, 0, X, 0},
* {0, 0, 0, X},
* {X, 0, 0, 0}}
*/
for (int i = 0; i < size; i++) {
for (int j = 0; j < size; j++) {
if (j == i + 1) {
this.coupling[i][j] = coupling;
} else if (j == 0 && i == size - 1) {
this.coupling[i][j] = coupling;
} else {
this.coupling[i][j] = 0;
}
}
}
} else if (arrangement.equals("BB")) {
/**
* Box Bidirectional
*
* {{0, X, 0, X},
* {X, 0, X, 0},
* {0, X, 0, X},
* {X, 0, X, 0}}
*/
for (int i = 0; i < size; i++) {
for (int j = 0; j < size; j++) {
if (j == i + 1) {
this.coupling[i][j] = coupling;
} else if (i == j + 1) {
this.coupling[i][j] = coupling;
} else if (j == 0 && i == size - 1) {
this.coupling[i][j] = coupling;
} else if (i == 0 && j == size - 1) {
this.coupling[i][j] = coupling;
} else {
this.coupling[i][j] = 0;
}
}
}
}
}
/**
* Advance the simulation forward one time step.
*/
public void step() {
step(1);
}
/**
* Advance the simulation forward a given number of time steps.
*
* @param numSteps The number of time steps to take.
*/
public void step(int numSteps) {
for (int i = 0; i < numSteps; i++) {
solveRK4();
}
}
/**
* Calculate the next phase of the oscillator network by solving the governing
* equation with the classical Runge-Kutta method.
*
* https://en.wikipedia.org/wiki/Runge-Kutta_methods
*/
private void solveRK4() {
float noise = noiseLevel * parent.noise(time);
oldPhase = Arrays.copyOf(phase, size);
float[] oldVelocity = Arrays.copyOf(velocity, size);
for (int i = 0; i < size; i++) {
// Calculate increments
float k1 = stepSize * differentiate(0.0f, i, noise);
float k2 = stepSize * differentiate(k1/2, i, noise);
float k3 = stepSize * differentiate(k2/2, i, noise);
float k4 = stepSize * differentiate(k3, i, noise);
// Update phase
phase[i] = (phase[i] + (k1 + 2*k2 + 2*k3 + k4)/6);
// Update velocity
velocity[i] = (phase[i] - oldPhase[i]) / stepSize;
// Update acceleration
acceleration[i] = (velocity[i] - oldVelocity[i]) / stepSize;
// Keep phase within TWO_PI
phase[i] %= TWO_PI;
}
time += stepSize;
}
/**
* Calculate the time derivative of an oscillator's phase using the Kuramoto model.
*
* https://en.wikipedia.org/wiki/Kuramoto_model
*
* @param increment The last increment calculated.
* @param oscIndex The index of the oscillator being updated.
* @param noise The amount of noise.
*
* @return {@code float} time derivative
*/
private float differentiate(float increment, int oscIndex, float noise) {
float derivative = naturalFrequency[oscIndex] + noise;
for (int j = 0; j < size; j++) {
derivative += (coupling[oscIndex][j] / size) * PApplet.sin(oldPhase[j] - increment);
}
return derivative;
}
/**
* Calculate the complex "order" of the network.
*
* @return {@code PVector} x-real y-imaginary
*/
public PVector getOrderVector() {
PVector orderVector = new PVector();
for (int i = 0; i < size; i++) {
PVector phaseVector = new PVector(PApplet.cos(phase[i]), PApplet.sin(phase[i]));
orderVector.add(phaseVector);
}
orderVector.div(size);
return orderVector;
}
/**
* Calculate the order parameter of the network (0-1).
*
* @return {@code float} order parameter
*/
public float getOrderParameter() {
PVector orderVector = getOrderVector();
return orderVector.mag();
}
/**
* Dispose of the PNetwork object.
*/
public void dispose() {
}
}