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 Apr 15 15:49:04 2015 +0000
Revision:
3:8d13bf073e92
Parent:
2:5e37831540c7
Child:
4:27a2eaee71ac
Corrected value, added skip of starting sequence and overflow remark.

Who changed what in which revision?

UserRevisionLine numberNew contents of line
pscholtens 0:dc1b041f713e 1 #include "mbed.h"
pscholtens 0:dc1b041f713e 2
pscholtens 3:8d13bf073e92 3 /* version 0.0.6, P.C.S. Scholtens, Datang NXP, April 14th, 2015, Shanghai, PR China
pscholtens 3:8d13bf073e92 4 - Corrected duty-cycle output for actual value of symbols (Thanks to Richard Zhu!).
pscholtens 3:8d13bf073e92 5 - Skipped run-in cycles to avoid pollution of the histogram with the first, most
pscholtens 3:8d13bf073e92 6 likely partial, sequence captured.
pscholtens 3:8d13bf073e92 7 - Added warnings for overflow.
pscholtens 3:8d13bf073e92 8 */
pscholtens 3:8d13bf073e92 9
pscholtens 2:5e37831540c7 10 /* version 0.0.5, P.C.S. Scholtens, Datang NXP, April 14th, 2015, Shanghai, PR China
pscholtens 3:8d13bf073e92 11 Implement histogram to find run lengths of zeroes and ones. */
pscholtens 2:5e37831540c7 12
pscholtens 1:2551859fbc25 13 /* version 0.0.4, P.C.S. Scholtens, Datang NXP, April 14th, 2015, Shanghai, PR China
pscholtens 1:2551859fbc25 14 Implement histogram to find run lengths of zroes and ones. */
pscholtens 1:2551859fbc25 15
pscholtens 1:2551859fbc25 16 /* version 0.0.3, P.C.S. Scholtens, Datang NXP, April 14th, 2015, Shanghai, PR China
pscholtens 1:2551859fbc25 17 Initial version. No synchronixzation of the symbols is done. */
pscholtens 0:dc1b041f713e 18
pscholtens 0:dc1b041f713e 19 /* See also:
pscholtens 0:dc1b041f713e 20 https://developer.mbed.org/forum/bugs-suggestions/topic/3464/
pscholtens 0:dc1b041f713e 21 */
pscholtens 0:dc1b041f713e 22
pscholtens 1:2551859fbc25 23 #define DEPTH 128
pscholtens 1:2551859fbc25 24
pscholtens 1:2551859fbc25 25 /* Reserve memory space for the histogram */
pscholtens 1:2551859fbc25 26 unsigned int zeros[DEPTH];
pscholtens 1:2551859fbc25 27 unsigned int ones[DEPTH];
pscholtens 1:2551859fbc25 28
pscholtens 1:2551859fbc25 29 DigitalIn bitstream(p11);
pscholtens 0:dc1b041f713e 30 DigitalOut myled(LED1);
pscholtens 0:dc1b041f713e 31 Serial pc(USBTX, USBRX); // tx, rx
pscholtens 0:dc1b041f713e 32
pscholtens 0:dc1b041f713e 33 Timer t;
pscholtens 0:dc1b041f713e 34
pscholtens 1:2551859fbc25 35 /* A function to clear the contents of both histograms */
pscholtens 1:2551859fbc25 36 void clear_histogram() {
pscholtens 1:2551859fbc25 37 for(unsigned int i = 0; i < DEPTH; i++) {
pscholtens 1:2551859fbc25 38 zeros[i] = 0;
pscholtens 1:2551859fbc25 39 ones[i] = 0;
pscholtens 1:2551859fbc25 40 }
pscholtens 1:2551859fbc25 41 }
pscholtens 1:2551859fbc25 42
pscholtens 1:2551859fbc25 43 /* Print the contents of the histogram, excluding the empty values */
pscholtens 1:2551859fbc25 44 void print_histogram() {
pscholtens 1:2551859fbc25 45 pc.printf("sequence zeros ones\n");
pscholtens 3:8d13bf073e92 46 for (unsigned int i = 0; i < DEPTH-1; i++) {
pscholtens 1:2551859fbc25 47 if ( zeros[i]+ones[i] != 0 ) {
pscholtens 2:5e37831540c7 48 pc.printf("%8i %8i %8i\n",i,zeros[i],ones[i]);
pscholtens 1:2551859fbc25 49 }
pscholtens 1:2551859fbc25 50 }
pscholtens 3:8d13bf073e92 51 if ( zeros[DEPTH-1]+ones[DEPTH-1] != 0 ) {
pscholtens 3:8d13bf073e92 52 pc.printf("Overflow %8i %8i\n",zeros[DEPTH-1],ones[DEPTH-1]);
pscholtens 3:8d13bf073e92 53 }
pscholtens 3:8d13bf073e92 54
pscholtens 1:2551859fbc25 55 }
pscholtens 1:2551859fbc25 56
pscholtens 1:2551859fbc25 57 /* Function which fill the histogram */
pscholtens 1:2551859fbc25 58 void fill_histogram(unsigned int num_unsync_samples) {
pscholtens 1:2551859fbc25 59 unsigned int count = 0;
pscholtens 1:2551859fbc25 60 unsigned int run_length = 0;
pscholtens 2:5e37831540c7 61 bool previous_bit = (bool) bitstream;
pscholtens 3:8d13bf073e92 62 /* Implements run-in: skip the first sequence as it is only a partial one. */
pscholtens 3:8d13bf073e92 63 while((previous_bit == (bool) bitstream) && (run_length < DEPTH-1)) {
pscholtens 3:8d13bf073e92 64 run_length++;
pscholtens 3:8d13bf073e92 65 };
pscholtens 3:8d13bf073e92 66 /* Start actual counting here */
pscholtens 3:8d13bf073e92 67 run_length = 0;
pscholtens 1:2551859fbc25 68 while(count < num_unsync_samples) {
pscholtens 2:5e37831540c7 69 while((previous_bit == (bool) bitstream) && (run_length < DEPTH-1)) {
pscholtens 1:2551859fbc25 70 run_length++;
pscholtens 1:2551859fbc25 71 };
pscholtens 1:2551859fbc25 72 if (previous_bit) {
pscholtens 1:2551859fbc25 73 ones[run_length]++;
pscholtens 1:2551859fbc25 74 }
pscholtens 1:2551859fbc25 75 else {
pscholtens 1:2551859fbc25 76 zeros[run_length]++;
pscholtens 1:2551859fbc25 77 }
pscholtens 2:5e37831540c7 78 count += run_length;
pscholtens 2:5e37831540c7 79 run_length = 0;
pscholtens 2:5e37831540c7 80 previous_bit = !previous_bit;
pscholtens 1:2551859fbc25 81 }
pscholtens 1:2551859fbc25 82 }
pscholtens 1:2551859fbc25 83
pscholtens 1:2551859fbc25 84 /* Here we count the number of unsynchronized symbols, mimicing previous implementation */
pscholtens 1:2551859fbc25 85 unsigned int get_num_unsync_symbols(int symbol) {
pscholtens 1:2551859fbc25 86 unsigned int sum = 0;
pscholtens 1:2551859fbc25 87 for (unsigned int i = 0; i < DEPTH; i++) {
pscholtens 1:2551859fbc25 88 if (symbol == 0) {
pscholtens 1:2551859fbc25 89 sum += zeros[i];
pscholtens 1:2551859fbc25 90 } else {
pscholtens 1:2551859fbc25 91 sum += ones[i];
pscholtens 1:2551859fbc25 92 }
pscholtens 1:2551859fbc25 93 }
pscholtens 1:2551859fbc25 94 return sum;
pscholtens 1:2551859fbc25 95 }
pscholtens 1:2551859fbc25 96
pscholtens 3:8d13bf073e92 97 /* Calculate the value, using the unsynchronized method */
pscholtens 3:8d13bf073e92 98 unsigned int get_value_unsync_symbols(int symbol) {
pscholtens 3:8d13bf073e92 99 unsigned int sum = 0;
pscholtens 3:8d13bf073e92 100 for (unsigned int i = 0; i < DEPTH; i++) {
pscholtens 3:8d13bf073e92 101 if (symbol == 0) {
pscholtens 3:8d13bf073e92 102 sum += i*zeros[i];
pscholtens 3:8d13bf073e92 103 } else {
pscholtens 3:8d13bf073e92 104 sum += i*ones[i];
pscholtens 3:8d13bf073e92 105 }
pscholtens 3:8d13bf073e92 106 }
pscholtens 3:8d13bf073e92 107 return sum;
pscholtens 3:8d13bf073e92 108 }
pscholtens 3:8d13bf073e92 109
pscholtens 1:2551859fbc25 110 /* The main routine of the program */
pscholtens 1:2551859fbc25 111
pscholtens 0:dc1b041f713e 112 int main() {
pscholtens 3:8d13bf073e92 113 unsigned int num_of_zeros, num_of_ones, value_of_unsync_zeros, value_of_unsync_ones;
pscholtens 3:8d13bf073e92 114 float unsync_dutycycle, synced_dutycycle, unsync_voltage, synced_voltage;
pscholtens 1:2551859fbc25 115 pc.baud(115200);
pscholtens 3:8d13bf073e92 116 pc.printf("Bitstream counter, version 0.0.6\n");
pscholtens 0:dc1b041f713e 117 /*LPC_TIM2->PR = 0x0000002F; / * decimal 47 */
pscholtens 0:dc1b041f713e 118 /*LPC_TIM3->PR = 24;*/
pscholtens 1:2551859fbc25 119 clear_histogram();
pscholtens 0:dc1b041f713e 120 t.start();
pscholtens 0:dc1b041f713e 121 while(1) {
pscholtens 0:dc1b041f713e 122 t.reset();
pscholtens 0:dc1b041f713e 123 myled = 1;
pscholtens 1:2551859fbc25 124 clear_histogram();
pscholtens 3:8d13bf073e92 125 //pc.printf("Cleared\n");
pscholtens 2:5e37831540c7 126 fill_histogram(1e6);
pscholtens 3:8d13bf073e92 127 //pc.printf("Filled\n");
pscholtens 1:2551859fbc25 128 print_histogram();
pscholtens 3:8d13bf073e92 129 //pc.printf("Printed\n");
pscholtens 1:2551859fbc25 130 num_of_zeros = get_num_unsync_symbols(0);
pscholtens 1:2551859fbc25 131 num_of_ones = get_num_unsync_symbols(1);
pscholtens 3:8d13bf073e92 132 value_of_unsync_zeros = get_value_unsync_symbols(0);
pscholtens 3:8d13bf073e92 133 value_of_unsync_ones = get_value_unsync_symbols(1);
pscholtens 3:8d13bf073e92 134 unsync_dutycycle = ((float) value_of_unsync_ones)/(value_of_unsync_zeros+value_of_unsync_ones); /* We need to typecast one of the integers to float, otherwise the result is rounded till zero. */
pscholtens 3:8d13bf073e92 135 unsync_voltage = (0.5*13*unsync_dutycycle+1)*0.9; /* This is the ADC formula, see analysisSigmaDeltaADC.pdf */
pscholtens 3:8d13bf073e92 136 pc.printf("Count = %i/%i, value = %i/%i, measured in %f sec, dutycycle = %f, voltage = %f\n",
pscholtens 3:8d13bf073e92 137 num_of_zeros, num_of_ones, value_of_unsync_zeros, value_of_unsync_ones, t.read(), unsync_dutycycle, unsync_voltage);
pscholtens 0:dc1b041f713e 138 myled = 0;
pscholtens 0:dc1b041f713e 139 wait(1.0);
pscholtens 0:dc1b041f713e 140 }
pscholtens 0:dc1b041f713e 141 }