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:
Thu Jun 18 12:31:06 2015 +0000
Revision:
13:2a66d067310b
Parent:
12:75acace69521
Re-written core loop with use of macro's. Fixed number of un-synchronized number of samples.

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