1 | /* Class AtoD
|
---|
2 | *
|
---|
3 | * This class contains constructor and methods that will
|
---|
4 | * 1. Simulate an Analogue to Digital Converter (ADC)
|
---|
5 | * Range may be set to 0 to Vref or -Vref to +Vref
|
---|
6 | * The former is the default value.
|
---|
7 | * The quantization error for this ADC is a truncation error
|
---|
8 | * or
|
---|
9 | * 2. Simply act as a marker to be used in OpenPath and
|
---|
10 | * ClosedLoop to indicate the presence of an ADC.
|
---|
11 | *
|
---|
12 | * In the latter case the output is equal to the input plus any delay set.
|
---|
13 | *
|
---|
14 | * This class is a subclass of the superclass BlackBox.
|
---|
15 | *
|
---|
16 | * Author: Michael Thomas Flanagan.
|
---|
17 | *
|
---|
18 | * Created: 27 June 2003
|
---|
19 | * Revised: 18 August 2003, 5 May 2005, 2 July 2006, 6 April 2008
|
---|
20 | *
|
---|
21 | * DOCUMENTATION:
|
---|
22 | * See Michael T Flanagan's JAVA library on-line web page:
|
---|
23 | * http://www.ee.ucl.ac.uk/~mflanaga/java/AtoD.html
|
---|
24 | * http://www.ee.ucl.ac.uk/~mflanaga/java/
|
---|
25 | *
|
---|
26 | * Copyright (c) 2003 - 2008 Michael Thomas Flanagan
|
---|
27 | *
|
---|
28 | * PERMISSION TO COPY:
|
---|
29 | * Permission to use, copy and modify this software and its documentation for
|
---|
30 | * NON-COMMERCIAL purposes is granted, without fee, provided that an acknowledgement
|
---|
31 | * to the author, Michael Thomas Flanagan at www.ee.ucl.ac.uk/~mflanaga, appears in all copies.
|
---|
32 | *
|
---|
33 | * Dr Michael Thomas Flanagan makes no representations about the suitability
|
---|
34 | * or fitness of the software for any or for a particular purpose.
|
---|
35 | * Michael Thomas Flanagan shall not be liable for any damages suffered
|
---|
36 | * as a result of using, modifying or distributing this software or its derivatives.
|
---|
37 | *
|
---|
38 | ***************************************************************************************/
|
---|
39 |
|
---|
40 | package agents.anac.y2015.agentBuyogV2.flanagan.control;
|
---|
41 |
|
---|
42 | import agents.anac.y2015.agentBuyogV2.flanagan.complex.*;
|
---|
43 | import agents.anac.y2015.agentBuyogV2.flanagan.control.*;
|
---|
44 | import agents.anac.y2015.agentBuyogV2.flanagan.math.*;
|
---|
45 |
|
---|
46 | public class AtoD extends BlackBox{
|
---|
47 |
|
---|
48 | private int nBits = 0; // Number of bits, n
|
---|
49 | private long maximumDecimal = 0; // 2^n-1
|
---|
50 | private double vRef = 0.0D; // Reference voltage
|
---|
51 | private int[] vBinary = null; // array holding binary output
|
---|
52 | private boolean trueAtoD = true; // if true, a real ADC is simulated
|
---|
53 | // if false, the instance is simply an AtoD marker
|
---|
54 | private boolean range = true; // if true, range = 0 to vRef
|
---|
55 | // if false, range = -vRef/2 to +vRef/2
|
---|
56 | private double voltageOutput = 0.0D;// if range = true: output voltage corresponding to input voltage truncated by quantiztion error
|
---|
57 | // if range = false: output voltage equals input voltage
|
---|
58 | private String binaryOutput = ""; // if range = true: Sting holding the binary representation of the output voltage
|
---|
59 | private long decimalOutput = 0L; // if range = true: decimal representation of the binary representation of the output
|
---|
60 | private double sqnr = 0.0D; // signal to quantisation noise ratio
|
---|
61 | private double input = 0.0D; // input
|
---|
62 | private double inputC = 0.0D; // input after any clipping
|
---|
63 | private double shift = 0.0D; // voltage shift (vRef/2) if range is -vRef/2 to +vRef/2
|
---|
64 | private long decimalShift = 0L; // voltage shift as decimal represention of its binary representation
|
---|
65 | private boolean decCalcDone = false; // = true when the decimal output has been calculated
|
---|
66 | private boolean binCalcDone = false; // = true when the binary output has been calculated
|
---|
67 | private boolean inputSet = false; // = true when the input has been entered
|
---|
68 |
|
---|
69 | private boolean firstCopy = true; // check used by copy method
|
---|
70 |
|
---|
71 | // Constructor
|
---|
72 | // Simulates an ADC
|
---|
73 | public AtoD(int nBits, double vRef ){
|
---|
74 | super("AtoD");
|
---|
75 | if(nBits>63)throw new IllegalArgumentException("This program cannot accomadate an ADC simulation with a number of bits greater than 63");
|
---|
76 | this.nBits = nBits;
|
---|
77 | this.maximumDecimal = (long)Math.pow(2, this.nBits)-1L;
|
---|
78 | this.vRef = vRef;
|
---|
79 | this.vBinary = new int[nBits+1];
|
---|
80 | this.trueAtoD = true;
|
---|
81 | super.setSnumer(new ComplexPoly(1.0D));
|
---|
82 | super.setSdenom(new ComplexPoly(1.0D));
|
---|
83 | super.setZtransformMethod(1);
|
---|
84 | }
|
---|
85 |
|
---|
86 | // Constructor
|
---|
87 | // Simply marks an AtoD event
|
---|
88 | public AtoD(){
|
---|
89 | super("AtoD");
|
---|
90 | super.fixedName = "AtoD";
|
---|
91 | super.sNumerDeg = 0;
|
---|
92 | super.sDenomDeg = 0;
|
---|
93 | super.setSnumer(new ComplexPoly(1.0D));
|
---|
94 | super.setSdenom(new ComplexPoly(1.0D));
|
---|
95 | super.ztransMethod=1;
|
---|
96 | super.setZtransformMethod(1);
|
---|
97 | }
|
---|
98 |
|
---|
99 | // Reset range option
|
---|
100 | // opt = 0 for range 0 to Vref (default option)
|
---|
101 | // opt = 1 for range -Vref to + vref
|
---|
102 | public void setRangeOption(int opt){
|
---|
103 | if(opt<0 || opt>2)throw new IllegalArgumentException("argument must be either 0 or 1");
|
---|
104 | if(opt==0)this.range = true;
|
---|
105 | if(opt==1){
|
---|
106 | this.range = false;
|
---|
107 | this.shift = this.vRef/2.0D;
|
---|
108 | this.decimalShift = this.maximumDecimal/2L;
|
---|
109 | }
|
---|
110 | if(this.inputSet)this.checkInput();
|
---|
111 | this.decCalcDone = false;
|
---|
112 | }
|
---|
113 |
|
---|
114 | // Return the range option
|
---|
115 | public String getRange(){
|
---|
116 | String ran = null;
|
---|
117 | if(this.trueAtoD){
|
---|
118 | if(this.range){
|
---|
119 | ran = "0 to "+this.vRef;
|
---|
120 | }
|
---|
121 | else{
|
---|
122 | ran = "-"+this.vRef/2 + " to "+this.vRef/2;
|
---|
123 | }
|
---|
124 | }
|
---|
125 | else{
|
---|
126 | System.out.println("Class AtoD; method getRange()");
|
---|
127 | System.out.println("No range option set - this instance of AtoD is an 'ADC marker' only");
|
---|
128 | System.out.println("getRangeOption has returned 'ADC marker only'");
|
---|
129 | ran = "ADC marker only";
|
---|
130 | }
|
---|
131 | return ran;
|
---|
132 | }
|
---|
133 |
|
---|
134 | // Return the true AtoD option
|
---|
135 | public boolean getTrueAtoDoption(){
|
---|
136 | if(this.trueAtoD){
|
---|
137 | System.out.println("This instance of AtoD is a true simulation of an ADC");
|
---|
138 | System.out.println("getTrueAtoDoption has returned 'true'");
|
---|
139 | }
|
---|
140 | else{
|
---|
141 | System.out.println("This instance of AtoD is not a true simulation of an ADC");
|
---|
142 | System.out.println("It is simple an 'A to D marker'");
|
---|
143 | System.out.println("getTrueAtoDoption has returned 'false'");
|
---|
144 | }
|
---|
145 | return this.trueAtoD;
|
---|
146 | }
|
---|
147 |
|
---|
148 | // Returns the reference voltage
|
---|
149 | public double getVref(){
|
---|
150 | if(!this.trueAtoD){
|
---|
151 | System.out.println("No reference voltage set - this instance of AtoD is an 'ADC marker' only");
|
---|
152 | System.out.println("getVref has returned 0.0 V");
|
---|
153 | }
|
---|
154 | return this.vRef;
|
---|
155 | }
|
---|
156 |
|
---|
157 | // Set input
|
---|
158 | public void setInput(double input){
|
---|
159 | this.input = input;
|
---|
160 | this.checkInput();
|
---|
161 | this.inputSet=true;
|
---|
162 | }
|
---|
163 |
|
---|
164 | // Check whether input in range
|
---|
165 | public void checkInput(){
|
---|
166 | this.inputC = input;
|
---|
167 | if(this.trueAtoD){
|
---|
168 | if(this.range){
|
---|
169 | if(this.input<0.0D){
|
---|
170 | System.out.println("lower limit of the ADC range exceeded");
|
---|
171 | System.out.println("input voltage set to zero");
|
---|
172 | this.inputC=0.0D;
|
---|
173 | }
|
---|
174 | if(this.input>this.vRef){
|
---|
175 | System.out.println("upper limit of the ADC range exceeded");
|
---|
176 | System.out.println("input voltage set to "+this.vRef);
|
---|
177 | this.inputC=this.vRef;
|
---|
178 | }
|
---|
179 | }
|
---|
180 | else{
|
---|
181 | if(this.input<-this.vRef){
|
---|
182 | System.out.println("lower limit of the ADC range exceeded");
|
---|
183 | System.out.println("input voltage set to "+(-this.vRef/2));
|
---|
184 | this.inputC=-this.vRef/2.0D;
|
---|
185 | }
|
---|
186 | if(this.input>this.vRef){
|
---|
187 | System.out.println("upper limit of the ADC range exceeded");
|
---|
188 | System.out.println("input voltage set to "+this.vRef/2);
|
---|
189 | this.inputC=this.vRef/2.0D;
|
---|
190 | }
|
---|
191 | }
|
---|
192 | }
|
---|
193 | this.inputC += this.shift;
|
---|
194 | this.decCalcDone = false;
|
---|
195 | this.binCalcDone = false;
|
---|
196 | }
|
---|
197 |
|
---|
198 |
|
---|
199 | // Return decimal representation of the maximum binary number
|
---|
200 | public long getMaximumDecimal(){
|
---|
201 | if(!this.trueAtoD){
|
---|
202 | System.out.println("This instance of AtoD is not a true simulation of an ADC");
|
---|
203 | System.out.println("It is simple an 'A to D marker'");
|
---|
204 | System.out.println("getTrueAtoDoption has returned 0");
|
---|
205 | }
|
---|
206 | return this.maximumDecimal;
|
---|
207 | }
|
---|
208 |
|
---|
209 | // Return maximum quantization error
|
---|
210 | public double maximumQuantizationError(){
|
---|
211 | double error = 0.0D;
|
---|
212 | if(this.trueAtoD){
|
---|
213 | error = this.vRef/this.maximumDecimal;
|
---|
214 | }
|
---|
215 | else{
|
---|
216 | System.out.println("This instance of AtoD is not a true simulation of an ADC");
|
---|
217 | System.out.println("It is simple an 'A to D marker'");
|
---|
218 | System.out.println("getMaxQuantizationError returns zero");
|
---|
219 | }
|
---|
220 | return error;
|
---|
221 | }
|
---|
222 |
|
---|
223 |
|
---|
224 |
|
---|
225 |
|
---|
226 | // Calculate output
|
---|
227 | public void calcOutput(){
|
---|
228 |
|
---|
229 | if(this.trueAtoD){
|
---|
230 | this.decimalOutput = (long)(Math.floor(((this.inputC)/this.vRef)*this.maximumDecimal))-this.decimalShift;
|
---|
231 | this.voltageOutput = (this.vRef*this.decimalOutput)/this.maximumDecimal;
|
---|
232 | this.sqnr = 20.0D*Fmath.log10(Math.abs((this.inputC-this.shift)/(this.inputC - this.shift - this.voltageOutput)));
|
---|
233 | }
|
---|
234 | else{
|
---|
235 | this.voltageOutput = this.input;
|
---|
236 | this.sqnr = 1.0D/0.0D;
|
---|
237 | }
|
---|
238 |
|
---|
239 | super.sNumer.resetCoeff(0, new Complex(this.voltageOutput/this.input, 0.0D));
|
---|
240 |
|
---|
241 | this.decCalcDone = true;
|
---|
242 | }
|
---|
243 |
|
---|
244 | // Return SQNR (signal to quantization noise ratio)
|
---|
245 | public double getSQNR(){
|
---|
246 | if(!this.decCalcDone)this.calcOutput();
|
---|
247 | if(!this.trueAtoD){
|
---|
248 | System.out.println("This instance of AtoD is not a true simulation of an ADC");
|
---|
249 | System.out.println("It is simple an 'A to D marker'");
|
---|
250 | System.out.println("getSQNR returned INFINITY");
|
---|
251 | }
|
---|
252 | return this.sqnr;
|
---|
253 | }
|
---|
254 |
|
---|
255 | // Return output voltage for the given input
|
---|
256 | // output rescaled to input voltage but with quantization error
|
---|
257 | public double voltageOutput(){
|
---|
258 | if(!this.decCalcDone)this.calcOutput();
|
---|
259 | return this.voltageOutput;
|
---|
260 | }
|
---|
261 |
|
---|
262 | // Return decimal representation of the binary output voltage
|
---|
263 | public long decimalOutput(){
|
---|
264 | if(!this.decCalcDone)this.calcOutput();
|
---|
265 | if(!this.trueAtoD){
|
---|
266 | System.out.println("No formal A to D conversion performed - this instance of AtoD is an 'ADC marker' only");
|
---|
267 | System.out.println("decimalOutput has returned 0");
|
---|
268 | }
|
---|
269 |
|
---|
270 | return this.decimalOutput;
|
---|
271 | }
|
---|
272 |
|
---|
273 | // Convert decimal to binary number of nBits length
|
---|
274 | // Two's complement
|
---|
275 | public static int[] decimalToBinary(long decimal, int nBits){
|
---|
276 | // check sign and reverse if negative
|
---|
277 | long decSign = 1L;
|
---|
278 | if(decimal<0){
|
---|
279 | decSign = -1L;
|
---|
280 | decimal *= decSign;
|
---|
281 | }
|
---|
282 |
|
---|
283 | // check nBits is long enough to accomodate decimal
|
---|
284 | // if not extend nBits by powers of two
|
---|
285 | long len = (long)Math.ceil(Math.log(decimal)/Math.log(2));
|
---|
286 | if(nBits<len){
|
---|
287 | boolean test=true;
|
---|
288 | int ii=2;
|
---|
289 | while(test){
|
---|
290 | if(Math.pow(2, ii)>len){
|
---|
291 | nBits=ii;
|
---|
292 | test=false;
|
---|
293 | }
|
---|
294 | }
|
---|
295 | }
|
---|
296 |
|
---|
297 | // convert positive decimal to binary
|
---|
298 | int[] binary = new int[nBits];
|
---|
299 | for(int i=0; i<nBits; i++)binary[i] = 0;
|
---|
300 | boolean test = true;
|
---|
301 | int ii = 0;
|
---|
302 | while(test){
|
---|
303 | binary[ii] = (int) (decimal % 2);
|
---|
304 | decimal = decimal/2;
|
---|
305 | ii++;
|
---|
306 | if(decimal==0)test = false;
|
---|
307 | }
|
---|
308 |
|
---|
309 | // if decimal was entered as negative negate binary
|
---|
310 | if(decSign==-1L)binary = AtoD.negateBinary(binary);
|
---|
311 |
|
---|
312 | return binary;
|
---|
313 | }
|
---|
314 |
|
---|
315 | // Negate a positive binary number
|
---|
316 | // Two's complement
|
---|
317 | public static int[] negateBinary(int[] binary){
|
---|
318 | int nBinary = binary.length;
|
---|
319 | int nBin = nBinary;
|
---|
320 |
|
---|
321 | // add bit if MSB = 1 and assign it zero to give a two's complement positive number
|
---|
322 | if(binary[nBinary-1]==1)nBin += nBin;
|
---|
323 | int[] negate = new int[nBin];
|
---|
324 | int[] one = new int[nBin];
|
---|
325 | for(int i=0; i<nBin; i++){
|
---|
326 | one[i]=0;
|
---|
327 | negate[i]=1;
|
---|
328 | }
|
---|
329 | one[0]=1;
|
---|
330 | // invert all bits
|
---|
331 | for(int i=0; i<nBinary; i++){
|
---|
332 | if(binary[i] == 1)negate[i] = 0;
|
---|
333 | }
|
---|
334 | // add one
|
---|
335 | negate = AtoD.addBinary(negate, one);
|
---|
336 |
|
---|
337 | return negate;
|
---|
338 | }
|
---|
339 |
|
---|
340 | // Add two binary numbers
|
---|
341 | public static int[] addBinary(int[] aa, int[] bb){
|
---|
342 | int n = aa.length;
|
---|
343 | int m = bb.length;
|
---|
344 | int lenMax = n;
|
---|
345 | int lenMin = m;
|
---|
346 | if(m>n){
|
---|
347 | lenMax = m;
|
---|
348 | lenMin = n;
|
---|
349 | }
|
---|
350 | int[] addition = new int[lenMax];
|
---|
351 | int carry = 0;
|
---|
352 | int sum = 0;
|
---|
353 | for(int i=0; i<lenMin; i++){
|
---|
354 | sum = aa[i] + bb[i] + carry;
|
---|
355 | switch(sum){
|
---|
356 | case 0: addition[i] = 0;
|
---|
357 | carry = 0;
|
---|
358 | break;
|
---|
359 | case 1: addition[i] = 1;
|
---|
360 | carry = 0;
|
---|
361 | break;
|
---|
362 | case 2: addition[i] = 0;
|
---|
363 | carry = 1;
|
---|
364 | break;
|
---|
365 | case 3: addition[i] = 1;
|
---|
366 | carry = 1;
|
---|
367 | break;
|
---|
368 | }
|
---|
369 | }
|
---|
370 |
|
---|
371 | return addition;
|
---|
372 | }
|
---|
373 |
|
---|
374 | // Return binary representation of the output
|
---|
375 | public String binaryOutput(){
|
---|
376 | if(!this.decCalcDone)this.calcOutput();
|
---|
377 | if(this.trueAtoD){
|
---|
378 | int nBit = this.nBits+1;
|
---|
379 | // shited output to binary
|
---|
380 | long absDecOut = this.decimalOutput+this.decimalShift;
|
---|
381 | this.vBinary = AtoD.decimalToBinary(absDecOut, nBit);
|
---|
382 |
|
---|
383 | if(this.shift>0.0D){
|
---|
384 | // shift, if any, to binary
|
---|
385 | int[] binaryShift = AtoD.decimalToBinary(this.decimalShift, nBit);
|
---|
386 |
|
---|
387 | // negate binary shift
|
---|
388 | binaryShift = AtoD.negateBinary(binaryShift);
|
---|
389 |
|
---|
390 | // add binary to negated shift
|
---|
391 | this.vBinary = AtoD.addBinary(this.vBinary, binaryShift);
|
---|
392 | }
|
---|
393 |
|
---|
394 | // convert to String
|
---|
395 | this.binaryOutput="";
|
---|
396 | for(int i=nBit-1; i>=0; i--){
|
---|
397 | this.binaryOutput = this.binaryOutput + this.vBinary[i];
|
---|
398 | }
|
---|
399 |
|
---|
400 | }
|
---|
401 | else{
|
---|
402 | System.out.println("No formal A to D conversion performed - this instance of AtoD is an 'ADC marker' only");
|
---|
403 | System.out.println("binaryOutput has returned 'null'");
|
---|
404 | }
|
---|
405 |
|
---|
406 | this.binCalcDone = true;
|
---|
407 | return this.binaryOutput;
|
---|
408 | }
|
---|
409 |
|
---|
410 | // Return binary representation of the output as an int array
|
---|
411 | // LSB is the zeroth element
|
---|
412 | public int[] binaryArray(){
|
---|
413 |
|
---|
414 | if(this.trueAtoD){
|
---|
415 | if(!this.binCalcDone)this.binaryOutput();
|
---|
416 | }
|
---|
417 | else{
|
---|
418 | System.out.println("No formal A to D conversion performed - this instance of AtoD is an 'ADC marker' only");
|
---|
419 | System.out.println("binaryOutput has returned 'null'");
|
---|
420 | }
|
---|
421 |
|
---|
422 | return this.vBinary;
|
---|
423 | }
|
---|
424 |
|
---|
425 |
|
---|
426 | // Return quantization error
|
---|
427 | public double quantizationError(){
|
---|
428 | if(!this.decCalcDone)this.calcOutput();
|
---|
429 | double error = 0.0D;
|
---|
430 | if(this.trueAtoD){
|
---|
431 | error = this.inputC - this.voltageOutput;
|
---|
432 | }
|
---|
433 | else{
|
---|
434 | System.out.println("This instance of AtoD is not a true simulation of an ADC");
|
---|
435 | System.out.println("It is simple an 'A to D marker'");
|
---|
436 | System.out.println("getQuantizationError returns zero");
|
---|
437 | }
|
---|
438 | return error;
|
---|
439 | }
|
---|
440 |
|
---|
441 | // Return any clipping error
|
---|
442 | public double clippingError(){
|
---|
443 |
|
---|
444 | return this.inputC - this.input;
|
---|
445 | }
|
---|
446 |
|
---|
447 | // Deep copy
|
---|
448 | public AtoD copy(){
|
---|
449 | if(this==null){
|
---|
450 | return null;
|
---|
451 | }
|
---|
452 | else{
|
---|
453 | AtoD bb = new AtoD();
|
---|
454 | this.copyBBvariables(bb);
|
---|
455 |
|
---|
456 | bb.nBits = this.nBits;
|
---|
457 | bb.maximumDecimal = this.maximumDecimal;
|
---|
458 | bb.vRef = this.vRef;
|
---|
459 | bb.vBinary = Conv.copy(this.vBinary);
|
---|
460 | bb.trueAtoD = this.trueAtoD;
|
---|
461 | bb.range = this.range;
|
---|
462 | bb.voltageOutput = this.voltageOutput;
|
---|
463 | bb.binaryOutput = this.binaryOutput;
|
---|
464 | bb.decimalOutput = this.decimalOutput;
|
---|
465 | bb.sqnr = this.sqnr;
|
---|
466 | bb.input = this.input;
|
---|
467 | bb.inputC = this.inputC;
|
---|
468 | bb.shift = this.shift;
|
---|
469 | bb.decimalShift = this.decimalShift;
|
---|
470 | bb.decCalcDone = this.decCalcDone;
|
---|
471 | bb.binCalcDone = this.binCalcDone;
|
---|
472 | bb.inputSet = this.inputSet;
|
---|
473 |
|
---|
474 | return bb;
|
---|
475 | }
|
---|
476 | }
|
---|
477 |
|
---|
478 | // Clone - overrides Java.Object method clone
|
---|
479 | public Object clone(){
|
---|
480 | return (Object)this.copy();
|
---|
481 | }
|
---|
482 | } |
---|