element14 Community
element14 Community
    Register Log In
  • Site
  • Search
  • Log In Register
  • Community Hub
    Community Hub
    • What's New on element14
    • Feedback and Support
    • Benefits of Membership
    • Personal Blogs
    • Members Area
    • Achievement Levels
  • Learn
    Learn
    • Ask an Expert
    • eBooks
    • element14 presents
    • Learning Center
    • Tech Spotlight
    • STEM Academy
    • Webinars, Training and Events
    • Learning Groups
  • Technologies
    Technologies
    • 3D Printing
    • FPGA
    • Industrial Automation
    • Internet of Things
    • Power & Energy
    • Sensors
    • Technology Groups
  • Challenges & Projects
    Challenges & Projects
    • Design Challenges
    • element14 presents Projects
    • Project14
    • Arduino Projects
    • Raspberry Pi Projects
    • Project Groups
  • Products
    Products
    • Arduino
    • Avnet Boards Community
    • Dev Tools
    • Manufacturers
    • Multicomp Pro
    • Product Groups
    • Raspberry Pi
    • RoadTests & Reviews
  • Store
    Store
    • Visit Your Store
    • Choose another store...
      • Europe
      •  Austria (German)
      •  Belgium (Dutch, French)
      •  Bulgaria (Bulgarian)
      •  Czech Republic (Czech)
      •  Denmark (Danish)
      •  Estonia (Estonian)
      •  Finland (Finnish)
      •  France (French)
      •  Germany (German)
      •  Hungary (Hungarian)
      •  Ireland
      •  Israel
      •  Italy (Italian)
      •  Latvia (Latvian)
      •  
      •  Lithuania (Lithuanian)
      •  Netherlands (Dutch)
      •  Norway (Norwegian)
      •  Poland (Polish)
      •  Portugal (Portuguese)
      •  Romania (Romanian)
      •  Russia (Russian)
      •  Slovakia (Slovak)
      •  Slovenia (Slovenian)
      •  Spain (Spanish)
      •  Sweden (Swedish)
      •  Switzerland(German, French)
      •  Turkey (Turkish)
      •  United Kingdom
      • Asia Pacific
      •  Australia
      •  China
      •  Hong Kong
      •  India
      •  Korea (Korean)
      •  Malaysia
      •  New Zealand
      •  Philippines
      •  Singapore
      •  Taiwan
      •  Thailand (Thai)
      • Americas
      •  Brazil (Portuguese)
      •  Canada
      •  Mexico (Spanish)
      •  United States
      Can't find the country/region you're looking for? Visit our export site or find a local distributor.
  • Translate
  • Profile
  • Settings
RoadTests & Reviews
  • Products
  • More
RoadTests & Reviews
Blog LEDRoadTestPlus - Post 10
  • Blog
  • RoadTest Forum
  • Documents
  • RoadTests
  • Reviews
  • Polls
  • Files
  • Members
  • Mentions
  • Sub-Groups
  • Tags
  • More
  • Cancel
  • New
Join RoadTests & Reviews to participate - click to join for free!
  • Share
  • More
  • Cancel
  • Author Author: amgalbu
  • Date Created: 31 Dec 2015 1:44 PM Date Created
  • Views 120 views
  • Likes 1 like
  • Comments 0 comments
Related
Recommended
  • android
  • ledroadtest
  • vlc
  • ledroadtestplus

LEDRoadTestPlus - Post 10

amgalbu
amgalbu
31 Dec 2015

After introducing the structure of a camera-based Android application, let’s have a look at the algorithms implemented to decode VLC data

 

image

 

 

smooth

The smooth function applies a moving average to the data captured by the camera according to the formula

 

image

 

private void smooth()
{
    int[] output = new int[numSamples];
    int oldestSample = 0;
    for (int i=0; i<numSamples; i++)
    {
        if (i == 0)
        {
           oldestSample = samples[i];
            output[i] = samples[i];
        }
        else
            output[i] = (int)(output[i-1] + (1.0/MOVING_WINDOW_SIZE)*(samples[i]-oldestSample));


        if (i >= MOVING_WINDOW_SIZE)
            oldestSample = samples[i-MOVING_WINDOW_SIZE];
    }


    for (int i=0; i<numSamples; i++)
        samples[i] = output[i];
}

 

 

 

detectPeaks

This function scans the sampled values looking for peaks. The distances of the peaks gives the frequency of the PWM signal and hence the logical bit being encoded

 

private void detectPeaks()
{
    numPeaks = 0;
    peaks = new ArrayList<PeakInfo>();
    int[] deltas = new int[numSamples];


    // compute deltas
    deltas[0] = 0;
    for (int i=1; i<numSamples; i++)
        deltas[i] = samples[i]-samples[i-1];

    for (int i=DELTAS_WINDOW_SIZE; i<numSamples; i+=DELTAS_WINDOW_SIZE)
    {
        if (isPositive(deltas, i-DELTAS_WINDOW_SIZE) && isNegative(deltas, i))
        {
            // new peak
            PeakInfo peak = new PeakInfo();
            peak.value = samples[i];
            peak.index = i;
            peaks.add(peak);
            numPeaks ++;
        }
    }
}

 

 

 

detectStartOfData

This function loops through the detected peaks looking for the end of the preamble

 

private int detectStartOfData(int[] idx)
{
    int i;
   
    // look for preamble
    for (i=1; i<numPeaks; i++)
    {
        int dist = peaks.get(i).index - peaks.get(i-1).index;
        if (classifyDistance(dist) == DISTANCE_PREAMBLE) {
            break;
        }
    }


    // scans until the end of the preamble
    for (; i<numPeaks; i++)
    {
        int dist = peaks.get(i).index - peaks.get(i-1).index;
        if (classifyDistance(dist) != DISTANCE_PREAMBLE) {
            idx[0] = i;
            return peaks.get(i).index;
        }
    }


    return -1;
}

 

detectBit

After the start of data is detected, single bits are decoded. To decode bits, a window is applied in order to eliminate out-of-sync due to the slightly variable frame rate of the smartphone camera

For this reason, only half of the theorical duration of a single bit is checked

In the detectBit function, the peakIndex represents the index in the array of samples (built during the frames capturing phase). startIdx is the index (used as both input and output parameter) in the list of detected peaks. The distances between consecutives peaks in the acquisition window are classified as logical “0” or logical “1”. If the number of peaks detected as “0” or “1” is above a certain threshold, the bit is assumed to be correctly decoded

 

private int detectBit(int peakIndex, int[] startIdx)
{
    int startIndex = peakIndex + (BIT_WINDOW_SIZE / 4);
    int endIndex = startIndex + (BIT_WINDOW_SIZE / 2);


    // look for the first entry after startIndex
    int peakIdx = startIdx[0];
    int index = peaks.get(peakIdx).index;
    while ((peakIdx < numPeaks) && (index < startIndex))
    {
        peakIdx ++;
        index = peaks.get(peakIdx).index;
    }


    if (peakIdx >= numPeaks)
        return -1;


    int numBit1 = 0;
    int numBit0 = 1;
    int numOther = 0;


    peakIdx ++;
    index = peaks.get(peakIdx).index;
    while ((peakIdx < numPeaks) && (index <= endIndex))
    {
        int dist = peaks.get(peakIdx).index - peaks.get(peakIdx-1).index;
        int bit = classifyDistance(dist);
        if (bit == DISTANCE_BIT_0)
            numBit0 ++;
        else if (bit == DISTANCE_BIT_1)
            numBit1 ++;
        else
            numOther ++;


        peakIdx ++;
        index = peaks.get(peakIdx).index;
    }


    startIdx[0] = peakIdx;


    if (numBit1 >= MIN_EXPECTED_PEAKS_1)
        return 1;
    if (numBit0 >= NUM_EXPECTED_PEAKS_0)
        return 0;


    return -1;
}

 

 

decodeSamples

The above functions are called in the decodeSamples function

 

private void decodeSamples()
{
    smooth();
    detectPeaks();


    int[] idx = { 0 };
    int peakIndex = detectStartOfData(idx);
    if (peakIndex == -1)
        return;


    String peaks = "";
    int value = 0;
    int bitIdx;
    for (bitIdx=0; bitIdx<15; bitIdx++)
    {
        int bit = detectBit(peakIndex, idx);
        if (bit == -1)
            break;


        peaks += String.format("%d; ", idx);


        value = (value << 1) | bit;
        peakIndex += BIT_WINDOW_SIZE;
    }


    // check parity (Hamming encoded)


    // update UI with the decoded value
    tv3.setText(peaks);


    if (bitIdx >= 15)
        tv4.setText(String.format("Value: %04X", value));
}

  • Sign in to reply
element14 Community

element14 is the first online community specifically for engineers. Connect with your peers and get expert answers to your questions.

  • Members
  • Learn
  • Technologies
  • Challenges & Projects
  • Products
  • Store
  • About Us
  • Feedback & Support
  • FAQs
  • Terms of Use
  • Privacy Policy
  • Legal and Copyright Notices
  • Sitemap
  • Cookies

An Avnet Company © 2025 Premier Farnell Limited. All Rights Reserved.

Premier Farnell Ltd, registered in England and Wales (no 00876412), registered office: Farnell House, Forge Lane, Leeds LS12 2NE.

ICP 备案号 10220084.

Follow element14

  • X
  • Facebook
  • linkedin
  • YouTube