A simple example.

Dependencies:   mbed FastIO

How does it work?

Oversampling

The core loop of the sampling does only one thing: it continuously looks at the input pin and increments a counter. Only when the input toggles, the counter value is used as an index and the histogram is updated and the counter is reset. By doing so the histogram will contain the run length of observed zeroes or ones, expressed in the time grid of the sampler. For a 1MHz bit stream the LPC 1768 should be capable to over sample approximately four times.

Grouping of run length

A filled histogram of run lengths, of both the zero and one symbols, will contain groups of adjacent run lengths values separated by empty spaces. If the sigma delta is connected to an analog voltage at exactly 25% of the range, the output pattern of the bit stream, expressed in the time grid of the ADC, will be close to 000100001000100001000100001... With approximately four times oversampling the LPC board may capture a data stream like: 0000, or expressed in run lengths: 10, 4, 16, 3, 12, 3, 15, 3, 11, 3, 16, 4. The histogram of zeroes will be filled with 1 at positions 10, 11, 12, 15 and 16, while the histogram of ones will be filled with 4 and 2 respectively at position 3 and 4.

Assign values to groups

After captured the data, the histogram will be scanned for groups of adjacent run lengths. A begin and end pointer/index of each will be stored in object type "Recovered". Once the whole histogram is scanned, a list of run length groups is determined. For each groups the average value of the run length will be determined.

Calculate Over Sample Ratio and Offset

The minimum distance between two average values will be a reasonable accurate value of the over sample factor. In our example the group of symbols consists of ADC run lengths of:

  • one: occurs 4 times with length 3 and 2 times 4, thus the average is 3.333.
  • three: consists of 11, 12 and 13 and thus an average of 12.0.
  • four: consists of one time 15 and two times 16: average equals 15.666.

The average distance between one and three is now 8.666. Therefore the average distance between three and four, only 3.666, a reasonable approximation of the over sample ratio. When acquiring more data, the average values will approximate the oversampling ratio better. An alternative method would be two take the shortest symbol as a value of the oversample factor, as this is the unit. However, as the loop requires some pre-processing before actively it can start counting, the average run length of the symbol with run length one will always be to lower than the actual over sample ratio. This creates an offset in the correlation of bit stream symbol to over sample data..

Known limitations

  • The amount of samples is only approximated, or more accurate, taken as a minimum value. As only the counter is compared once a complete run length of the same symbols is seen, it will be always slightly above the require value.
  • The amount of samples taken is hard coded. No means to vary this while running the application.
  • When the ADC input is very close or the maximum input voltage (or very close tot the minimum input voltage) the resulting bit stream will contain mostly very long run length of one's and hardly any zero (or vice versa). As no clock is connected, the stream may become out of synchronization for these cases.
  • Only the DC level is calculated, as a sum of all ones divided by the amount of symbols. Technically one could add Fourier transform in the post-processing and calculate SNR, THD, SINAD, ENOB etc, This requires another data structure of the histogram: store run length in the sequence they appear.
  • The algorithm works only correct given two assumptions. There should be exactly one group of empty spaces between two groups of captured run lengths (each representing a different bit stream run length). And each group of run lengths may not contain any empty position. Another decoder http://en.wikipedia.org/wiki/Viterbi_algorithm would possibly do better and even could estimate a qualification number.
Committer:
pscholtens
Date:
Wed Jun 17 08:23:26 2015 +0000
Revision:
12:75acace69521
Parent:
11:e80e38508fe6
Child:
13:2a66d067310b
Flattened core of loop to speed-up sampling. Adding non-default unsafe option for faster loop start.

Who changed what in which revision?

UserRevisionLine numberNew contents of line
pscholtens 0:dc1b041f713e 1 #include "mbed.h"
pscholtens 10:42e390f304fc 2 #include "FastIO.h"
pscholtens 10:42e390f304fc 3
pscholtens 12:75acace69521 4 /* version 0.1.4, P.C.S. Scholtens, Datang NXP, June 17th 2015, Nijmegen, Netherlands
pscholtens 12:75acace69521 5 - Flattened core loop of the fill_histogram() function. As both symbols 0 and 1 have
pscholtens 12:75acace69521 6 their own core, sampling can be done faster: there's no comparison with the
pscholtens 12:75acace69521 7 previous value (which was the variable previous_bit) but only a comparison with a
pscholtens 12:75acace69521 8 constant 0 or 1. The sampling of longer sequences is now 1.5 times faster.
pscholtens 12:75acace69521 9 - Added compiler pre-processor directive ALLOW_OUT_OF_RANGE to allow omitting
pscholtens 12:75acace69521 10 out-of-range check of variable run_length. This improves sampling speed, but may
pscholtens 12:75acace69521 11 cause segfaults.
pscholtens 12:75acace69521 12 */
pscholtens 12:75acace69521 13
pscholtens 11:e80e38508fe6 14 /* version 0.1.3, P.C.S. Scholtens, Datang NXP, May 27th 2015, Nijmegen, Netherlands
pscholtens 12:75acace69521 15 - Added debug mode via compiler pre-processor directives, just for developers.
pscholtens 11:e80e38508fe6 16 - Repaired bug in calculation of offset.
pscholtens 11:e80e38508fe6 17 - Cleared assined values also in clear_histogram() function.
pscholtens 11:e80e38508fe6 18 - Corrected return value of new synchronization method, dutycycles was calculated
pscholtens 11:e80e38508fe6 19 in wrong way.
pscholtens 11:e80e38508fe6 20 */
pscholtens 11:e80e38508fe6 21
pscholtens 10:42e390f304fc 22 /* version 0.1.2, P.C.S. Scholtens, Datang NXP, May 27th 2015, Nijmegen, Netherlands
pscholtens 10:42e390f304fc 23 - Switched from the default I/O to FastIO library to enables faster reading of the
pscholtens 10:42e390f304fc 24 input. The distinction between various run length should be improved.
pscholtens 10:42e390f304fc 25 - Incremented number of samples to 4x10e7, with a duration of approx. 4 seconds.
pscholtens 10:42e390f304fc 26 - Repaired bug of always clipped values in run length (accidentally swapped compare
pscholtens 10:42e390f304fc 27 operator).
pscholtens 10:42e390f304fc 28 */
pscholtens 0:dc1b041f713e 29
pscholtens 8:38175daee62b 30 /* version 0.1.1, P.C.S. Scholtens, Datang NXP, April 24th 2015, Nijmegen, Netherlands
pscholtens 8:38175daee62b 31 - Average function did not return the calculated average, now repaired.
pscholtens 8:38175daee62b 32 - Offset was subtracted while it should be added to compensate loss of oversampling
pscholtens 8:38175daee62b 33 ratio in the first round of the core loop.
pscholtens 8:38175daee62b 34 - Misleading type cast set to final type as chosen by compiler.
pscholtens 8:38175daee62b 35 */
pscholtens 8:38175daee62b 36
pscholtens 7:5141bd76b08d 37 /* version 0.1.0, P.C.S. Scholtens, Datang NXP, April 22th 2015, Nijmegen, Netherlands
pscholtens 7:5141bd76b08d 38 - Added more sophisticated method to find the correct symbol values. This one should
pscholtens 7:5141bd76b08d 39 be able to interpret the signals even if not all intermediate run length are present.
pscholtens 7:5141bd76b08d 40 This extends the usable input duty cycle range from [1/3,2/3] to [1/128, 127/128],
pscholtens 7:5141bd76b08d 41 if neither analog performance nor timing quantization errors create interference.
pscholtens 7:5141bd76b08d 42 */
pscholtens 7:5141bd76b08d 43
pscholtens 6:a5fc4e2ff34b 44 /* version 0.0.9, P.C.S. Scholtens, Datang NXP, April 21th 2015, Nijmegen, Netherlands
pscholtens 6:a5fc4e2ff34b 45 - Run time counter overflow fill now continue looking for same bit, however
pscholtens 6:a5fc4e2ff34b 46 clipping the actual store value. This prevents underflow occurence of other symbol
pscholtens 6:a5fc4e2ff34b 47 and may create lock if no bitstream is present.
pscholtens 6:a5fc4e2ff34b 48 - Time out function added to prevent lock in case no bitstream is present.
pscholtens 6:a5fc4e2ff34b 49 - Timer object renamed for clarity from t to timer, see http://xkcd.org/1513/
pscholtens 6:a5fc4e2ff34b 50 - Includes updated build of library mbed.
pscholtens 6:a5fc4e2ff34b 51 - Out-of-range of run length moved outside core loop, to speed up bitstream sampling
pscholtens 6:a5fc4e2ff34b 52 and consequently improving accuracy.
pscholtens 6:a5fc4e2ff34b 53 */
pscholtens 6:a5fc4e2ff34b 54
pscholtens 5:1c0bfd69719f 55 /* version 0.0.8, P.C.S. Scholtens, Datang NXP, April 17th 2015, Shanghai, PR China
pscholtens 5:1c0bfd69719f 56 - Corrected assigned synchronized values, as the first appearance wasn't assigned.
pscholtens 5:1c0bfd69719f 57 */
pscholtens 5:1c0bfd69719f 58
pscholtens 4:27a2eaee71ac 59 /* version 0.0.7, P.C.S. Scholtens, Datang NXP, April 16/17th 2015, Shanghai, PR China
pscholtens 4:27a2eaee71ac 60 - Method written to assign synchronized values to run-length.
pscholtens 4:27a2eaee71ac 61 - Added warnings for underflow.
pscholtens 4:27a2eaee71ac 62 - After skipped run-in cycles, copy the current bit, to prevent false single hit.
pscholtens 4:27a2eaee71ac 63 */
pscholtens 4:27a2eaee71ac 64
pscholtens 4:27a2eaee71ac 65 /* version 0.0.6, P.C.S. Scholtens, Datang NXP, April 15th, 2015, Shanghai, PR China
pscholtens 3:8d13bf073e92 66 - Corrected duty-cycle output for actual value of symbols (Thanks to Richard Zhu!).
pscholtens 3:8d13bf073e92 67 - Skipped run-in cycles to avoid pollution of the histogram with the first, most
pscholtens 3:8d13bf073e92 68 likely partial, sequence captured.
pscholtens 3:8d13bf073e92 69 - Added warnings for overflow.
pscholtens 3:8d13bf073e92 70 */
pscholtens 3:8d13bf073e92 71
pscholtens 2:5e37831540c7 72 /* version 0.0.5, P.C.S. Scholtens, Datang NXP, April 14th, 2015, Shanghai, PR China
pscholtens 3:8d13bf073e92 73 Implement histogram to find run lengths of zeroes and ones. */
pscholtens 2:5e37831540c7 74
pscholtens 1:2551859fbc25 75 /* version 0.0.4, P.C.S. Scholtens, Datang NXP, April 14th, 2015, Shanghai, PR China
pscholtens 10:42e390f304fc 76 Implement histogram to find run lengths of zeroes and ones. */
pscholtens 1:2551859fbc25 77
pscholtens 1:2551859fbc25 78 /* version 0.0.3, P.C.S. Scholtens, Datang NXP, April 14th, 2015, Shanghai, PR China
pscholtens 6:a5fc4e2ff34b 79 Initial version. No synchronization of the symbols is done. */
pscholtens 0:dc1b041f713e 80
pscholtens 0:dc1b041f713e 81 /* See also:
pscholtens 0:dc1b041f713e 82 https://developer.mbed.org/forum/bugs-suggestions/topic/3464/
pscholtens 9:8136aea421e3 83 To speed up, maybe bypass the mask function in the gpio_read function of file
pscholtens 9:8136aea421e3 84 ./mbed/targets/hal/TARGET_NXP/TARGET_LPC176X/gpio_object.h
pscholtens 9:8136aea421e3 85 from git
pscholtens 9:8136aea421e3 86 git clone https://github.com/mbedmicro/mbed.git
pscholtens 9:8136aea421e3 87
pscholtens 0:dc1b041f713e 88 */
pscholtens 0:dc1b041f713e 89
pscholtens 11:e80e38508fe6 90 #define DEPTH 1024
pscholtens 10:42e390f304fc 91 #define WATCH_DOG_TIME 10
pscholtens 11:e80e38508fe6 92 #undef DEBUG_MODE
pscholtens 12:75acace69521 93 #undef ALLOW_OUT_OF_RANGE
pscholtens 1:2551859fbc25 94
pscholtens 1:2551859fbc25 95 /* Reserve memory space for the histogram */
pscholtens 1:2551859fbc25 96 unsigned int zeros[DEPTH];
pscholtens 1:2551859fbc25 97 unsigned int ones[DEPTH];
pscholtens 4:27a2eaee71ac 98 unsigned int assign[DEPTH];
pscholtens 1:2551859fbc25 99
pscholtens 10:42e390f304fc 100 FastIn<p11> bitstream;
pscholtens 0:dc1b041f713e 101 DigitalOut myled(LED1);
pscholtens 6:a5fc4e2ff34b 102 Serial pc(USBTX, USBRX); // tx, rx
pscholtens 6:a5fc4e2ff34b 103 Timer timer;
pscholtens 6:a5fc4e2ff34b 104 Timeout timeout;
pscholtens 0:dc1b041f713e 105
pscholtens 7:5141bd76b08d 106 class Recovered {
pscholtens 7:5141bd76b08d 107 public:
pscholtens 7:5141bd76b08d 108 Recovered();
pscholtens 7:5141bd76b08d 109 virtual ~Recovered();
pscholtens 7:5141bd76b08d 110 float average;
pscholtens 7:5141bd76b08d 111 void calc_average();
pscholtens 7:5141bd76b08d 112 unsigned int index_start;
pscholtens 7:5141bd76b08d 113 unsigned int index_stop;
pscholtens 7:5141bd76b08d 114 unsigned int assigned_val;
pscholtens 7:5141bd76b08d 115 Recovered *next;
pscholtens 7:5141bd76b08d 116 private:
pscholtens 7:5141bd76b08d 117 };
pscholtens 7:5141bd76b08d 118
pscholtens 7:5141bd76b08d 119 /* Constructor */
pscholtens 7:5141bd76b08d 120 Recovered::Recovered()
pscholtens 7:5141bd76b08d 121 {
pscholtens 7:5141bd76b08d 122 next = NULL;
pscholtens 7:5141bd76b08d 123 };
pscholtens 7:5141bd76b08d 124
pscholtens 7:5141bd76b08d 125
pscholtens 7:5141bd76b08d 126 /* Destructor */
pscholtens 7:5141bd76b08d 127 Recovered::~Recovered()
pscholtens 7:5141bd76b08d 128 {
pscholtens 7:5141bd76b08d 129 if (next != NULL)
pscholtens 7:5141bd76b08d 130 delete next;
pscholtens 7:5141bd76b08d 131 };
pscholtens 7:5141bd76b08d 132
pscholtens 7:5141bd76b08d 133 /* Calculate average function, only call when index start and stop are defined. */
pscholtens 7:5141bd76b08d 134 void Recovered::calc_average()
pscholtens 7:5141bd76b08d 135 {
pscholtens 7:5141bd76b08d 136 unsigned int index = index_start;
pscholtens 7:5141bd76b08d 137 unsigned int sum;
pscholtens 7:5141bd76b08d 138 unsigned int amount = 0;
pscholtens 8:38175daee62b 139 average = 0;
pscholtens 7:5141bd76b08d 140 /* Test assumptions */
pscholtens 7:5141bd76b08d 141 if (index_start > DEPTH-1 ) pc.printf("ERROR: start value to high in average function.\n");
pscholtens 7:5141bd76b08d 142 if (index_stop > DEPTH-1 ) pc.printf("ERROR: stop value to high in average function.\n");
pscholtens 7:5141bd76b08d 143 if (index_start > index_stop) pc.printf("ERROR: start value beyond stop value in average function.\n");
pscholtens 7:5141bd76b08d 144 /* Core function */
pscholtens 7:5141bd76b08d 145 while (index < index_stop) {
pscholtens 8:38175daee62b 146 sum = zeros[index]+ones[index];
pscholtens 8:38175daee62b 147 amount += sum;
pscholtens 8:38175daee62b 148 average += index*sum;
pscholtens 7:5141bd76b08d 149 index++;
pscholtens 7:5141bd76b08d 150 };
pscholtens 8:38175daee62b 151 average /= amount;
pscholtens 7:5141bd76b08d 152 return;
pscholtens 7:5141bd76b08d 153 };
pscholtens 7:5141bd76b08d 154
pscholtens 1:2551859fbc25 155 /* A function to clear the contents of both histograms */
pscholtens 1:2551859fbc25 156 void clear_histogram() {
pscholtens 1:2551859fbc25 157 for(unsigned int i = 0; i < DEPTH; i++) {
pscholtens 11:e80e38508fe6 158 zeros[i] = 0;
pscholtens 11:e80e38508fe6 159 ones[i] = 0;
pscholtens 11:e80e38508fe6 160 assign[i] = 0;
pscholtens 1:2551859fbc25 161 }
pscholtens 1:2551859fbc25 162 }
pscholtens 1:2551859fbc25 163
pscholtens 1:2551859fbc25 164 /* Print the contents of the histogram, excluding the empty values */
pscholtens 1:2551859fbc25 165 void print_histogram() {
pscholtens 4:27a2eaee71ac 166 pc.printf(" Sequence Zeros Ones Assign\n");
pscholtens 4:27a2eaee71ac 167 if ( zeros[0]+ones[0] != 0 ) {
pscholtens 4:27a2eaee71ac 168 pc.printf("Underflow %8i %8i\n",zeros[0],ones[0]);
pscholtens 4:27a2eaee71ac 169 }
pscholtens 4:27a2eaee71ac 170 for (unsigned int i = 1; i < DEPTH-1; i++) {
pscholtens 1:2551859fbc25 171 if ( zeros[i]+ones[i] != 0 ) {
pscholtens 4:27a2eaee71ac 172 pc.printf(" %8i %8i %8i %8i\n",i,zeros[i],ones[i],assign[i]);
pscholtens 1:2551859fbc25 173 }
pscholtens 1:2551859fbc25 174 }
pscholtens 3:8d13bf073e92 175 if ( zeros[DEPTH-1]+ones[DEPTH-1] != 0 ) {
pscholtens 4:27a2eaee71ac 176 pc.printf("Overflow %8i %8i\n",zeros[DEPTH-1],ones[DEPTH-1]);
pscholtens 3:8d13bf073e92 177 }
pscholtens 3:8d13bf073e92 178
pscholtens 1:2551859fbc25 179 }
pscholtens 1:2551859fbc25 180
pscholtens 6:a5fc4e2ff34b 181 /* Will only be called if measurement time exceeds preset watch dog timer. */
pscholtens 6:a5fc4e2ff34b 182 void at_time_out() {
pscholtens 6:a5fc4e2ff34b 183 pc.printf("Input clipped to level %i, no bitstream present.\n", (int) bitstream);
pscholtens 6:a5fc4e2ff34b 184 timeout.attach(&at_time_out, WATCH_DOG_TIME);
pscholtens 6:a5fc4e2ff34b 185 }
pscholtens 6:a5fc4e2ff34b 186
pscholtens 1:2551859fbc25 187 /* Function which fill the histogram */
pscholtens 1:2551859fbc25 188 void fill_histogram(unsigned int num_unsync_samples) {
pscholtens 1:2551859fbc25 189 unsigned int count = 0;
pscholtens 1:2551859fbc25 190 unsigned int run_length = 0;
pscholtens 6:a5fc4e2ff34b 191 /* Switch on watch dog timer */
pscholtens 6:a5fc4e2ff34b 192 timeout.attach(&at_time_out, WATCH_DOG_TIME);
pscholtens 12:75acace69521 193 /* Implements run-in: skip the first sequence of ZEROs as it is only a partial one. */
pscholtens 12:75acace69521 194 while(!(bool) bitstream) {
pscholtens 12:75acace69521 195 /* Do nothing, intentionally */;
pscholtens 12:75acace69521 196 };
pscholtens 12:75acace69521 197 /* Implements run-in: skip the first sequence of ONEs as we always want to start with zeros. */
pscholtens 12:75acace69521 198 while( (bool) bitstream) {
pscholtens 6:a5fc4e2ff34b 199 /* Do nothing, intentionally */;
pscholtens 3:8d13bf073e92 200 };
pscholtens 10:42e390f304fc 201 run_length = 0;
pscholtens 12:75acace69521 202 /* Start actual counting ZEROs here, store in variable run_length (will be clipped to DEPTH) */
pscholtens 1:2551859fbc25 203 while(count < num_unsync_samples) {
pscholtens 12:75acace69521 204 /* Core of the ZERO loop */
pscholtens 12:75acace69521 205 while(! (bool) bitstream) {
pscholtens 1:2551859fbc25 206 run_length++;
pscholtens 1:2551859fbc25 207 };
pscholtens 6:a5fc4e2ff34b 208 /* Increment counter before clipping to preserve accuracy. */
pscholtens 6:a5fc4e2ff34b 209 count += run_length;
pscholtens 6:a5fc4e2ff34b 210 /* Test if run length exceeds depth of histogram, if so assign clip value. */
pscholtens 12:75acace69521 211 #ifndef ALLOW_OUT_OF_RANGE
pscholtens 10:42e390f304fc 212 if (run_length > DEPTH-1) {
pscholtens 6:a5fc4e2ff34b 213 run_length = DEPTH-1;
pscholtens 6:a5fc4e2ff34b 214 }
pscholtens 12:75acace69521 215 #endif
pscholtens 12:75acace69521 216 /* Now write in histogram array of ZERO's */
pscholtens 12:75acace69521 217 zeros[run_length]++;
pscholtens 6:a5fc4e2ff34b 218 /* Reset for next run length counting loop */
pscholtens 2:5e37831540c7 219 run_length = 0;
pscholtens 12:75acace69521 220 /* Core of the ONES loop */
pscholtens 12:75acace69521 221 while( (bool) bitstream) {
pscholtens 12:75acace69521 222 run_length++;
pscholtens 12:75acace69521 223 };
pscholtens 12:75acace69521 224 /* Increment counter before clipping to preserve accuracy. */
pscholtens 12:75acace69521 225 count += run_length;
pscholtens 12:75acace69521 226 /* Test if run length exceeds depth of histogram, if so assign clip value. */
pscholtens 12:75acace69521 227 #ifndef ALLOW_OUT_OF_RANGE
pscholtens 12:75acace69521 228 if (run_length > DEPTH-1) {
pscholtens 12:75acace69521 229 run_length = DEPTH-1;
pscholtens 12:75acace69521 230 }
pscholtens 12:75acace69521 231 #endif
pscholtens 12:75acace69521 232 /* Now write in histogram array of ONES's */
pscholtens 12:75acace69521 233 ones[run_length]++;
pscholtens 12:75acace69521 234 /* Reset for next run length counting loop */
pscholtens 12:75acace69521 235 run_length = 0;
pscholtens 1:2551859fbc25 236 }
pscholtens 6:a5fc4e2ff34b 237 /* Switch off watch dog timer */
pscholtens 6:a5fc4e2ff34b 238 timeout.detach();
pscholtens 1:2551859fbc25 239 }
pscholtens 1:2551859fbc25 240
pscholtens 1:2551859fbc25 241 /* Here we count the number of unsynchronized symbols, mimicing previous implementation */
pscholtens 1:2551859fbc25 242 unsigned int get_num_unsync_symbols(int symbol) {
pscholtens 1:2551859fbc25 243 unsigned int sum = 0;
pscholtens 1:2551859fbc25 244 for (unsigned int i = 0; i < DEPTH; i++) {
pscholtens 1:2551859fbc25 245 if (symbol == 0) {
pscholtens 1:2551859fbc25 246 sum += zeros[i];
pscholtens 1:2551859fbc25 247 } else {
pscholtens 1:2551859fbc25 248 sum += ones[i];
pscholtens 1:2551859fbc25 249 }
pscholtens 1:2551859fbc25 250 }
pscholtens 1:2551859fbc25 251 return sum;
pscholtens 1:2551859fbc25 252 }
pscholtens 1:2551859fbc25 253
pscholtens 3:8d13bf073e92 254 /* Calculate the value, using the unsynchronized method */
pscholtens 3:8d13bf073e92 255 unsigned int get_value_unsync_symbols(int symbol) {
pscholtens 3:8d13bf073e92 256 unsigned int sum = 0;
pscholtens 3:8d13bf073e92 257 for (unsigned int i = 0; i < DEPTH; i++) {
pscholtens 3:8d13bf073e92 258 if (symbol == 0) {
pscholtens 3:8d13bf073e92 259 sum += i*zeros[i];
pscholtens 3:8d13bf073e92 260 } else {
pscholtens 3:8d13bf073e92 261 sum += i*ones[i];
pscholtens 3:8d13bf073e92 262 }
pscholtens 3:8d13bf073e92 263 }
pscholtens 3:8d13bf073e92 264 return sum;
pscholtens 3:8d13bf073e92 265 }
pscholtens 3:8d13bf073e92 266
pscholtens 4:27a2eaee71ac 267 /* Calculate the value, using the synchronization algorithm */
pscholtens 4:27a2eaee71ac 268 unsigned int get_value_synced_symbols(int symbol) {
pscholtens 4:27a2eaee71ac 269 bool presence = false;
pscholtens 4:27a2eaee71ac 270 int value = 0;
pscholtens 4:27a2eaee71ac 271 for (unsigned int i = 0; i < DEPTH; i++) {
pscholtens 4:27a2eaee71ac 272 if ( zeros[i]+ones[i] != 0 ) {
pscholtens 4:27a2eaee71ac 273 if (presence) {
pscholtens 5:1c0bfd69719f 274 assign[i] = value;
pscholtens 4:27a2eaee71ac 275 } else {
pscholtens 4:27a2eaee71ac 276 value++;
pscholtens 5:1c0bfd69719f 277 presence = true;
pscholtens 5:1c0bfd69719f 278 assign[i] = value;
pscholtens 4:27a2eaee71ac 279 }
pscholtens 4:27a2eaee71ac 280 } else {
pscholtens 4:27a2eaee71ac 281 presence = false;
pscholtens 4:27a2eaee71ac 282 }
pscholtens 4:27a2eaee71ac 283 }
pscholtens 4:27a2eaee71ac 284 /* Now do the actual summation of symbol values */
pscholtens 4:27a2eaee71ac 285 unsigned int sum = 0;
pscholtens 4:27a2eaee71ac 286 for (unsigned int i = 0; i < DEPTH; i++) {
pscholtens 4:27a2eaee71ac 287 if (symbol == 0) {
pscholtens 4:27a2eaee71ac 288 sum += assign[i]*zeros[i];
pscholtens 4:27a2eaee71ac 289 } else {
pscholtens 4:27a2eaee71ac 290 sum += assign[i]*ones[i];
pscholtens 4:27a2eaee71ac 291 }
pscholtens 4:27a2eaee71ac 292 }
pscholtens 4:27a2eaee71ac 293 return sum;
pscholtens 4:27a2eaee71ac 294 }
pscholtens 4:27a2eaee71ac 295
pscholtens 7:5141bd76b08d 296 /* Calculate the value, using the new synchronization algorithm */
pscholtens 7:5141bd76b08d 297 float get_dutycycle_synced_symbols_new_method() {
pscholtens 7:5141bd76b08d 298 /* First step (第一步): scan areas of non-zero content in histogram, starting at first non-overflow sequence at the end */
pscholtens 7:5141bd76b08d 299 bool presence = false;
pscholtens 7:5141bd76b08d 300 Recovered *list = NULL;
pscholtens 7:5141bd76b08d 301 Recovered *first = NULL;
pscholtens 7:5141bd76b08d 302 for (signed int i = DEPTH-2; i > -1 ; i--) {
pscholtens 7:5141bd76b08d 303 if ( zeros[i]+ones[i] != 0 ) {
pscholtens 7:5141bd76b08d 304 if (presence) {
pscholtens 7:5141bd76b08d 305 first->index_start = i;
pscholtens 7:5141bd76b08d 306 } else {
pscholtens 7:5141bd76b08d 307 /* Create new Recovered symbol and position it at the beginning of the list of dis(/re)covered symbols */
pscholtens 7:5141bd76b08d 308 first = new Recovered;
pscholtens 7:5141bd76b08d 309 first->next = list;
pscholtens 7:5141bd76b08d 310 first->index_stop = i+1;
pscholtens 7:5141bd76b08d 311 list = first;
pscholtens 7:5141bd76b08d 312 presence = true;
pscholtens 7:5141bd76b08d 313 }
pscholtens 7:5141bd76b08d 314 } else {
pscholtens 7:5141bd76b08d 315 presence = false;
pscholtens 7:5141bd76b08d 316 }
pscholtens 7:5141bd76b08d 317 }
pscholtens 7:5141bd76b08d 318 /* Step two (第二步): for each found area, calculate average values */
pscholtens 7:5141bd76b08d 319 Recovered* index = list;
pscholtens 7:5141bd76b08d 320 while (index != NULL) {
pscholtens 7:5141bd76b08d 321 index->calc_average();
pscholtens 7:5141bd76b08d 322 index = index->next;
pscholtens 7:5141bd76b08d 323 }
pscholtens 11:e80e38508fe6 324 #ifdef DEBUG_MODE
pscholtens 11:e80e38508fe6 325 int j = 0;
pscholtens 11:e80e38508fe6 326 index = list;
pscholtens 11:e80e38508fe6 327 while (index != NULL) {
pscholtens 11:e80e38508fe6 328 pc.printf("Group %i from %i to %i, average = %f\n", j, index->index_start,index->index_stop, index->average);
pscholtens 11:e80e38508fe6 329 index = index->next;
pscholtens 11:e80e38508fe6 330 j++;
pscholtens 11:e80e38508fe6 331 }
pscholtens 11:e80e38508fe6 332 #endif
pscholtens 7:5141bd76b08d 333 /* Step three (第三步): Find smallest distance between two adjacent symbols, e.g. with run length of 0.91, 6.99, 8.01, the last two define the grid/oversample ratio. */
pscholtens 7:5141bd76b08d 334 float oversample = DEPTH;
pscholtens 7:5141bd76b08d 335 Recovered* cmp1 = list;
pscholtens 7:5141bd76b08d 336 Recovered* cmp2 = list->next;
pscholtens 7:5141bd76b08d 337 if (list != NULL) {
pscholtens 7:5141bd76b08d 338 while (cmp2 != NULL) {
pscholtens 7:5141bd76b08d 339 float diff = cmp2->average-cmp1->average;
pscholtens 7:5141bd76b08d 340 if (diff < oversample) {
pscholtens 7:5141bd76b08d 341 oversample = diff;
pscholtens 7:5141bd76b08d 342 }
pscholtens 7:5141bd76b08d 343 cmp1=cmp2;
pscholtens 7:5141bd76b08d 344 cmp2=cmp1->next;
pscholtens 7:5141bd76b08d 345 }
pscholtens 7:5141bd76b08d 346 }
pscholtens 11:e80e38508fe6 347 #ifdef DEBUG_MODE
pscholtens 11:e80e38508fe6 348 pc.printf("Oversample ratio %f\n", oversample);
pscholtens 11:e80e38508fe6 349 #endif
pscholtens 7:5141bd76b08d 350 /* Step four (第四步): Divide the average run length of all found recovered symbol by the found oversample ratio. */
pscholtens 7:5141bd76b08d 351 index = list;
pscholtens 7:5141bd76b08d 352 while (index != NULL) {
pscholtens 7:5141bd76b08d 353 index->average /= oversample;
pscholtens 7:5141bd76b08d 354 index = index->next;
pscholtens 7:5141bd76b08d 355 }
pscholtens 7:5141bd76b08d 356
pscholtens 11:e80e38508fe6 357 /* Step five (第五步): find offset and remove it (Assumption that there are always symbols with run length 1 ) */
pscholtens 7:5141bd76b08d 358 index = list;
pscholtens 11:e80e38508fe6 359 float offset = 1-index->average;
pscholtens 7:5141bd76b08d 360 while (index != NULL) {
pscholtens 8:38175daee62b 361 index->average += offset;
pscholtens 7:5141bd76b08d 362 index = index->next;
pscholtens 7:5141bd76b08d 363 }
pscholtens 11:e80e38508fe6 364 #ifdef DEBUG_MODE
pscholtens 11:e80e38508fe6 365 pc.printf("Offset at initial run-in lengths %f\n", offset);
pscholtens 11:e80e38508fe6 366 #endif
pscholtens 4:27a2eaee71ac 367
pscholtens 7:5141bd76b08d 368 /* Step six (第六步): round to nearest integer and assign value to both arrays */
pscholtens 7:5141bd76b08d 369 index = list;
pscholtens 7:5141bd76b08d 370 while (index != NULL) {
pscholtens 8:38175daee62b 371 index->assigned_val = (unsigned int) (index->average+0.5);
pscholtens 7:5141bd76b08d 372 for (int i = index->index_start; i < index->index_stop; i++ ) {
pscholtens 7:5141bd76b08d 373 assign[i] = index->assigned_val;
pscholtens 7:5141bd76b08d 374 }
pscholtens 7:5141bd76b08d 375 index = index->next;
pscholtens 7:5141bd76b08d 376 }
pscholtens 7:5141bd76b08d 377
pscholtens 7:5141bd76b08d 378 /* Step seven (第七步): Now do the actual summation of symbol values */
pscholtens 7:5141bd76b08d 379 unsigned int sum0 = 0, sum1 = 0;
pscholtens 7:5141bd76b08d 380 for (unsigned int i = 0; i < DEPTH; i++) {
pscholtens 7:5141bd76b08d 381 sum0 += assign[i]*zeros[i];
pscholtens 7:5141bd76b08d 382 sum1 += assign[i]*ones[i];
pscholtens 7:5141bd76b08d 383 }
pscholtens 7:5141bd76b08d 384 /* Step eight (第八步): Delete the recovered symbol object to clear memory. As a destructor is defined
pscholtens 7:5141bd76b08d 385 this will be automatically handled recursively. And of course return the duty cycle */
pscholtens 7:5141bd76b08d 386 delete list;
pscholtens 11:e80e38508fe6 387 return ((float) sum1)/(sum0+sum1);
pscholtens 7:5141bd76b08d 388 }
pscholtens 7:5141bd76b08d 389
pscholtens 7:5141bd76b08d 390 /* The main (主程序) routine of the program */
pscholtens 1:2551859fbc25 391
pscholtens 0:dc1b041f713e 392 int main() {
pscholtens 11:e80e38508fe6 393 #ifdef DEBUG_MODE
pscholtens 7:5141bd76b08d 394 unsigned int num_of_zeros, num_of_ones, value_of_unsync_zeros, value_of_unsync_ones, value_of_synced_zeros, value_of_synced_ones,
pscholtens 7:5141bd76b08d 395 sum_of_unsync_symbols, sum_of_synced_symbols;
pscholtens 11:e80e38508fe6 396 float unsync_voltage, synced_voltage, unsync_dutycycle, synced_dutycycle;
pscholtens 11:e80e38508fe6 397 #endif
pscholtens 11:e80e38508fe6 398
pscholtens 11:e80e38508fe6 399 float synced_dutycycle_new, synced_voltage_new;
pscholtens 1:2551859fbc25 400 pc.baud(115200);
pscholtens 12:75acace69521 401 pc.printf("Bitstream counter, version 0.1.4, P.C.S. Scholtens, June 17th 2015, Nijmegen, Netherlands.\n");
pscholtens 6:a5fc4e2ff34b 402 pc.printf("Build " __DATE__ " " __TIME__ "\n");
pscholtens 0:dc1b041f713e 403 /*LPC_TIM2->PR = 0x0000002F; / * decimal 47 */
pscholtens 0:dc1b041f713e 404 /*LPC_TIM3->PR = 24;*/
pscholtens 0:dc1b041f713e 405 while(1) {
pscholtens 6:a5fc4e2ff34b 406 timer.reset();
pscholtens 0:dc1b041f713e 407 myled = 1;
pscholtens 1:2551859fbc25 408 clear_histogram();
pscholtens 6:a5fc4e2ff34b 409 timer.start();
pscholtens 10:42e390f304fc 410 fill_histogram(4e7);
pscholtens 6:a5fc4e2ff34b 411 timer.stop();
pscholtens 11:e80e38508fe6 412 #ifdef DEBUG_MODE
pscholtens 1:2551859fbc25 413 num_of_zeros = get_num_unsync_symbols(0);
pscholtens 1:2551859fbc25 414 num_of_ones = get_num_unsync_symbols(1);
pscholtens 3:8d13bf073e92 415 value_of_unsync_zeros = get_value_unsync_symbols(0);
pscholtens 3:8d13bf073e92 416 value_of_unsync_ones = get_value_unsync_symbols(1);
pscholtens 7:5141bd76b08d 417 sum_of_unsync_symbols = value_of_unsync_zeros+value_of_unsync_ones;
pscholtens 7:5141bd76b08d 418 unsync_dutycycle = ((float) value_of_unsync_ones)/sum_of_unsync_symbols; /* We need to typecast one of the integers to float, otherwise the result is rounded till zero. */
pscholtens 3:8d13bf073e92 419 unsync_voltage = (0.5*13*unsync_dutycycle+1)*0.9; /* This is the ADC formula, see analysisSigmaDeltaADC.pdf */
pscholtens 4:27a2eaee71ac 420 value_of_synced_zeros = get_value_synced_symbols(0);
pscholtens 4:27a2eaee71ac 421 value_of_synced_ones = get_value_synced_symbols(1);
pscholtens 7:5141bd76b08d 422 sum_of_synced_symbols = value_of_synced_zeros+value_of_synced_ones;
pscholtens 7:5141bd76b08d 423 synced_dutycycle = ((float) value_of_synced_ones)/sum_of_synced_symbols; /* We need to typecast one of the integers to float, otherwise the result is rounded till zero. */
pscholtens 4:27a2eaee71ac 424 synced_voltage = (0.5*13*synced_dutycycle+1)*0.9; /* This is the ADC formula, see analysisSigmaDeltaADC.pdf */
pscholtens 11:e80e38508fe6 425 #endif
pscholtens 7:5141bd76b08d 426 synced_dutycycle_new = get_dutycycle_synced_symbols_new_method();
pscholtens 9:8136aea421e3 427 synced_voltage_new = (0.5*13*synced_dutycycle_new+1)*0.9; /* This is the ADC formula, see analysisSigmaDeltaADC.pdf */
pscholtens 11:e80e38508fe6 428 pc.printf("\n------ Captured Histogram ------\n");
pscholtens 11:e80e38508fe6 429 print_histogram();
pscholtens 11:e80e38508fe6 430 #ifdef DEBUG_MODE
pscholtens 4:27a2eaee71ac 431 pc.printf("------ Unsynchronized Results ------\n");
pscholtens 4:27a2eaee71ac 432 pc.printf("Counted Sequences %8i %8i\n", num_of_zeros , num_of_ones);
pscholtens 4:27a2eaee71ac 433 pc.printf("Summed Values %8i %8i\n", value_of_unsync_zeros, value_of_unsync_ones);
pscholtens 11:e80e38508fe6 434 pc.printf("Duty Cycle %f, = %f Volt\n", unsync_dutycycle , unsync_voltage);
pscholtens 11:e80e38508fe6 435 pc.printf("----- Synchronized Results OLD -----\n");
pscholtens 4:27a2eaee71ac 436 pc.printf("Summed Values %8i %8i\n", value_of_synced_zeros, value_of_synced_ones);
pscholtens 11:e80e38508fe6 437 pc.printf("Duty Cyle %f, = %f Volt\n", synced_dutycycle , synced_voltage);
pscholtens 11:e80e38508fe6 438 #endif
pscholtens 11:e80e38508fe6 439 pc.printf("------- Synchronized Results -------\n");
pscholtens 11:e80e38508fe6 440 pc.printf("Duty Cyle %f, = %f Volt\n", synced_dutycycle_new , synced_voltage_new);
pscholtens 4:27a2eaee71ac 441 pc.printf("------------------------------------\n");
pscholtens 6:a5fc4e2ff34b 442 pc.printf("Measured in %f sec.\n", timer.read());
pscholtens 4:27a2eaee71ac 443 pc.printf("====================================\n");
pscholtens 0:dc1b041f713e 444 myled = 0;
pscholtens 5:1c0bfd69719f 445 wait(0.1);
pscholtens 0:dc1b041f713e 446 }
pscholtens 4:27a2eaee71ac 447 }