/* dpc.js Direct Power Control requires - numeric.js requires - seedrandom.js requires - d3.js */ var dpc = {}; // Define User Inputs ************************** // ********************************************* dpc.randomSeed = d3.select("body").append("div") .attr("class", "randomSeed"); dpc.randomSeed.append("h4") .text("Random Seed:"); dpc.randomSeed.append("input") .attr("type","text") .attr("id", "seedValue") .attr("value", "1934"); dpc.MS = d3.select("body").append("div") .attr("class", "MS"); dpc.MS.append("h4") .text("Mobile Stations:"); dpc.MS.append("select") .attr("id", "selectbox") .selectAll("option") .data([3,4,5,6,7,8,9]) .enter() .append("option") .text(function(d){return d;}); dpc.NS = d3.select("body").append("div") .attr("class", "Noise"); dpc.NS.append("h4") .text("Receiver Noise (mW):"); dpc.NS.append("select") .attr("id", "selectboxNoise") .selectAll("option") .data([0.1,0.2,0.3,0.4,0.5]) .enter() .append("option") .text(function(d){return d;}); dpc.Steps = d3.select("body").append("div") .attr("class", "Steps"); dpc.Steps.append("h4") .text("Iterations:"); dpc.Steps.append("select") .attr("id", "selectboxSteps") .selectAll("option") .data([10,20,30,40,50]) .enter() .append("option") .text(function(d){return d;}); d3.select("body").append("div") .attr("class", "clear"); // Create Divs to Hold HTML Tables ***************** // ************************************************* dpc.gain = d3.select("body") .append("div") .attr("class","tables gain"); dpc.gain.append("h4").text("Channel Gain Matrix:"); dpc.targetSIRs = d3.select("body") .append("div") .attr("class", "tables SIRs"); dpc.targetSIRs.append("h4").text("Target SIRs:"); dpc.power = d3.select("body") .append("div") .attr("class", "tables power"); dpc.power.append("h4").text("Initial Power Settings (mW):"); dpc.results = d3.select("body") .append("div") .attr("class","tables Results"); dpc.results.append("h4").text("Results...").attr("id","resultsH4"); // D3 SVG Plotting ********************************* // ************************************************* dpc.colors = ['rgb(228,26,28)','rgb(55,126,184)','rgb(77,175,74)','rgb(152,78,163)','rgb(255,127,0)','rgb(255,255,51)','rgb(166,86,40)','rgb(247,129,191)','rgb(153,153,153)']; dpc.colorsHex = ["#e41a1c","#377eb8","#4daf4a","#984ea3","#ff7f00","#ffff33","#a65628","#f781bf","#999999"]; dpc.margin = {top: 20, right:20, bottom:50, left:50}; dpc.height = 400 - dpc.margin.top - dpc.margin.bottom; dpc.width = 700 - dpc.margin.left - dpc.margin.right; dpc.x = d3.scale.linear() .range([0,dpc.width]); dpc.y = d3.scale.linear() .range([dpc.height, 0]); dpc.xAxis = d3.svg.axis() .scale(dpc.x) .orient("bottom") .ticks(10); dpc.yAxis = d3.svg.axis() .scale(dpc.y) .orient("left") .ticks(5); dpc.line = d3.svg.line() .x(function(d,i){return dpc.x(i);}) .y(function(d){return dpc.y(d);}); dpc.svg = d3.select("body") .append("svg") .attr("width", dpc.width + dpc.margin.left + dpc.margin.right) .attr("height", dpc.height + dpc.margin.bottom + dpc.margin.top) .append("g") .attr("transform", "translate(" + dpc.margin.left + "," + dpc.margin.top + ")"); // text format functions dpc.formatNumber = d3.format("<.2f"); dpc.formatGain = d3.format("<.3f"); // Display setting for bl.ocks.org d3.select(self.frameElement).style("height", (2.3*dpc.height) + "px"); // HTML Table Display Function ********************** // ************************************************** dpc.displayTables = function (tableClass, divName, dataVector, formatFunc) { d3.selectAll("." + tableClass).remove(); dpc[divName].append("table") .attr("class",tableClass) .append("tbody") .selectAll("tr") .data(dataVector) .enter() .append("tr") .attr("bgcolor", function(d,i){return dpc.colorsHex[i];}) .selectAll("td") .data(function(row){return row;}) .enter() .append("td") .html(function(d){return formatFunc(d)}); }; // Directed Power Control Algorithm ****************** // *************************************************** dpc.algorithm = function (params) { // initialize ******************************** // ******************************************* /* MSs = number of mobile stations t = number of time steps powerRange = uniform range for initial power settings sirRange = uniform range for target SIRs gainRange = uniform range for interference channel gains noise = receiver noise, assumed to be the same across receivers seed = seed for random number generator */ var seed = params.seed; var MSs = params.MSs; var noise = params.ns; var t = params.t; var powerRange = params.powerRange; var sirRange = params.sirRange; var gainRange = params.gainRange; Math.seedrandom(seed); function getRandomArbitrary(minmax) { var min = minmax[0]; var max = minmax[1]; return Math.random() * (max - min) + min; }; // loop over channelGain matrix and set gains for // interference channels by taking random samples // from gainRange var i; var j; var channelGain = numeric.identity(MSs); for (i = 0; i < MSs; i += 1){ for (j = 0; j < MSs; j +=1){ if (i != j){ channelGain[i][j] = getRandomArbitrary(gainRange); }; }; }; // display gain table as html table dpc.displayTables("gainTable","gain",channelGain, dpc.formatGain); // create SIR targets by taking random // samples from sirRange, store in D matrix // create constant vector v var sd = numeric.rep([MSs,1],0); // SIR Targets, for table display only var D = numeric.rep([MSs, MSs], 0); // SIR targets var V = numeric.rep([MSs, 1], 0); // constant vector for (i = 0; i < MSs; i += 1){ D[i][i] = getRandomArbitrary(sirRange); sd[i][0] = D[i][i]; V[i][0] = D[i][i] * noise / channelGain[i][i]; }; // display Target SIRs as html table dpc.displayTables("sirTable","targetSIRs",sd, dpc.formatNumber); // create F matrix to store channel conditions var F = numeric.rep([MSs, MSs], 0); for (i = 0; i < MSs; i+=1){ for (j = 0; j < MSs; j += 1){ if (i != j){ F[i][j] = channelGain[i][j]/channelGain[i][i]; }; }; }; // create initial power vector by taking random // samples from powerRange var powerT0 = numeric.rep([MSs,1], 0); for (i = 0; i < MSs; i += 1){ powerT0[i][0] = getRandomArbitrary(powerRange); }; // display initial power settings as html table dpc.displayTables("powerTable","power",powerT0,dpc.formatNumber); // Algorithm ********************************* // ******************************************* // feasibility check var DF = numeric.dot(D,F); var eigs = numeric.eig(DF).lambda.x; var isFeasible = d3.max(eigs) < 1; // power minimal solution if (isFeasible) { var solution = numeric.dot(numeric.inv(numeric.sub(numeric.identity(MSs),DF)),V); }; // if feasible display power minimal solution // else display "no solution" in red if (isFeasible){ d3.selectAll("#resultsH4").remove(); // remove old header dpc.results.append("h4").text("Minimal Power Solution (mW):").attr("id","resultsH4"); dpc.displayTables("resultsTable","results",solution,dpc.formatNumber); } else { d3.selectAll("#resultsH4").remove(); // remove old header d3.selectAll(".resultsTable").remove(); dpc.results.append("h4").text("No Solution").style("color","red").attr("id","resultsH4"); }; // create empty matrix to store power var powerM = numeric.rep([MSs, t], 0); // save intial power settings to powerM for (i = 0; i < MSs; i += 1){ powerM[i][0] = powerT0[i][0]; }; // Iterate over time and update power // levels according to DPC algorithm var time; for (time = 1; time < t; time += 1){ // p[t+1] = DFp[t] + v powerT1 = numeric.add(numeric.dot(numeric.dot(D,F),powerT0),V); for (i = 0; i < MSs; i += 1){ powerM[i][time] = powerT1[i][0]; }; powerT0 = powerT1; }; // Plotting ******************************** // ***************************************** // Plot tower over time for each mobile station dpc.x.domain([0, t-1]); dpc.y.domain([0, Math.ceil(d3.max(powerM, function(row){ return d3.max(row); }))]); // remove old plots and axes d3.selectAll(".YAXIS").remove(); d3.selectAll(".XAXIS").remove(); d3.selectAll(".PLOT").remove(); // x axis dpc.svg .append("g") .attr("class", "x axis XAXIS") .attr("transform","translate(0," + dpc.height + ")") .call(dpc.xAxis) // x axis label dpc.svg .append("text") .attr("class","XAXIS") .attr("x", dpc.width/2) .attr("y", dpc.height + 40) .style("text-anchor","middle") .text("Iteration") .attr("font-size", "14px"); // y axis dpc.svg .append("g") .attr("class", "y axis YAXIS") .call(dpc.yAxis) // y axis label dpc.svg .append("text") .attr("class","YAXIS") .attr("transform","rotate(-90)") .attr("x", 0-dpc.height/2) .attr("y", 0-35) .style("text-anchor","middle") .text("Transmit Power (mW)") .attr("font-size", "14px"); // add lines for each mobile station for (i = 0; i < MSs; i += 1){ dpc.svg.append("path") .attr("class", "PLOT") .datum(powerM[i]) .attr("d", dpc.line) .style("stroke", dpc.colors[i]); }; }; // Event Handlers ****************************** // ********************************************* d3.select("#seedValue").on("input", function() { dpc.inputs.seed = +this.value; dpc.update(); }); d3.select("#selectbox").on("change", function() { dpc.inputs.MSs = +this.value; dpc.update(); }); d3.select("#selectboxNoise").on("change", function() { dpc.inputs.ns = +this.value; dpc.update(); }); d3.select("#selectboxSteps").on("change", function() { dpc.inputs.t = +this.value; dpc.update(); }); dpc.update = function(){ dpc.algorithm(dpc.inputs); }; // First Call and Default Settings *************** // *********************************************** dpc.inputs = { seed:1934, MSs:3, ns:0.1, t:10, powerRange:[1,3], sirRange:[1,3], gainRange:[0.01,0.10] }; dpc.update();