Versions Compared

Key

  • This line was added.
  • This line was removed.
  • Formatting was changed.
Comment: Made images larger.

Scatter Plot Demo

Without Eigen C++ Library

  • Linear interpolation calculated manually
  • Primary readout group running at 100 Hz
  • Encoder trigger running at 10 Hz   (10x slower  than primary readout group)

Image Added

With Eigen C++ Library

Image Added

Lab 3 Tests

The encoder simulator, triggered by readout group 5, sent a test pattern alternating between values 100 and 200. Three different ratios of trigger rate were tested: 1, 10, and 100.

slowRatio=1

No interpolation occurs because trigger rates are the same.

Image Added

slowRatio=10

The primary readout group's trigger rate is 10x the trigger rate of the encoder.

Image Added

slowRatio=100

The primary readout group's trigger rate is 100x the trigger rate of the encoder.

Image Added





Demonstration of Polynomial

...

Fit Using Eigen Package

Test Code

Code Block
languagecpp
titleeigen.cc
collapsetrue
#include <Eigen/Dense>
#include <iostream>
#include <cmath>
#include <vector>
#include <Eigen/QR>
#include <unistd.h>
#include <getopt.h>

bool lVerbose = false;

void usage(const char *name)
{
    printf("usage: %s [-r <ratio>] [-v] val1 val2 val3 [val4 ...]\n", name);
}

void polyfit(const std::vector<double> &t,
             const std::vector<double> &v,
             std::vector<double> &coeff,
             int order

             )
{
    static bool firstCall = true;

    // Create Matrix Placeholder of size n x k, n= number of datapoints, k = order of polynomial, for exame k = 3 for cubic polynomial
    Eigen::MatrixXd T(t.size(), order + 1);
    Eigen::VectorXd V = Eigen::VectorXd::Map(&v.front(), v.size());
    Eigen::VectorXd result;

    // check to make sure inputs are correct
    assert(t.size() == v.size());
    assert(t.size() >= order + 1);
    if (firstCall && lVerbose) {
        printf("t.size() = %zu\n", t.size());
        printf("v.size() = %zu\n", v.size());
        firstCall = false;
    }
    // Populate the matrix
    for(size_t i = 0 ; i < t.size(); ++i)
        {
            for(size_t j = 0; j < order + 1; ++j)
                {
                    T(i, j) = pow(t.at(i), j);
                }
        }
    //std::cout<<T<<std::endl;
    
    // Solve for linear least square fit
    result  = T.householderQr().solve(V);
    coeff.resize(order+1);
    for (int k = 0; k < order+1; k++)
        {
            coeff[k] = result[k];
        }

}

int main(int argc, char **argv)
{
    int c;
    unsigned long ratio = 10;
    int order = 2;

    while ((c = getopt(argc, argv, "r:o:vh")) != EOF) {
        switch(c) {
            case 'r':
                ratio = std::stoul(optarg);
                break;
            case 'o':
                order = std::stoul(optarg);
                break;
            case 'v':
                lVerbose = true;
                break;
            case 'h':
                usage(argv[0]);
                return 0;
            default:
                return 1;
        }
    }

    int input_count = argc - optind;
    if (input_count < 3) {
        printf("usage: %s [-r <ratio>] [-o <order>] [-v] val1 val2 val3 [val4 ...]\n", argv[0]);
        return 1;
    }

    if (lVerbose) {
        printf("ratio: %u\n", ratio);
    }

    std::vector<double> time;
    std::vector<double> velocity;
    for (int index = optind; index < argc; index++) {
        if (lVerbose) {
            printf ("Non-option argument %s\n", argv[index]);
        }
        double increment = (1.0 / (double) (input_count - 1));
        time.push_back((index - optind) * increment);
        velocity.push_back(std::stoul(argv[index]));
    }

    // placeholder for storing polynomial coefficient
    std::vector<double> coeff;
    polyfit(time, velocity, coeff, order);
    if (lVerbose) {
        printf("coeff.size = %u\n", coeff.size());
        std::cout<< "Printing fitted values (q)" << std::endl;
    }

    double vfitted;
    unsigned fast_index;
    for(unsigned fast_index = 0; fast_index < (input_count - 1) * ratio + 1; fast_index ++) {
        if (fast_index > 0) {
            std::cout << ",";
        }
        double q = ((double) fast_index / (ratio * (input_count - 1)));
        vfitted = coeff[0];
        for (int ord = 1; ord <= order; ord++) {
            vfitted += (coeff[ord] * pow(q, ord));
        }

        // if fitted value is less than zero then set it to 0
        if (vfitted < 0.0) {
            vfitted = 0.0;
        }

        // if fitted value is greater than 0xffffffff then set it to 0xffffffff
        if (vfitted > 0xffffffff) {
            vfitted = 0xffffffff;
        }

        std::cout  <<std::fixed << vfitted;
    }
    std::cout<<std::endl;

    return 0;
}
Code Block
languagetext
titleMakefile
collapsetrue
ifndef GXX
$(error GXX must be set in environment)
endif

ifndef CONDA_PREFIX
$(error CONDA_PREFIX must be set in environment)
endif

eigen: eigen.cc
$(GXX) eigen.cc -o eigen -I $(CONDA_PREFIX)/include/eigen3
polyfit.py
Code Block
languagetextpy
titlepolyfit.py
collapsetrue
#!/usr/bin/env python

import matplotlib.pyplot as plt
import argparse
import subprocess
import sys

def main():
    parser = argparse.ArgumentParser(prog="polyfit", usage="%(prog)s [options] val val val [val...]")
    parser.add_argument('val', nargs='*', help='3 or more values')
    parser.add_argument('-r', type=int, default=10, help='trigger rate ratio (default=10)')
    parser.add_argument('-o', type=int, default=2, help='order of polynomial (default=2)')
    parser.add_argument('-v', action='store_true', help='be verbose')
    args = parser.parse_args()
    ratio = args.r
    order = args.o

    cmd = ["./eigen", "-o", f"{order}", "-r", f"{ratio}"] + args.val

    if len(args.val) < 3:
        parser.error("3 or more values required")

    if args.v:
        print(f"cmd: {cmd}")

    xx = subprocess.run(cmd, capture_output=True)

    result = xx.stdout.decode('UTF-8').strip()

    res = [ float(x) for x in result.split(",") ]
    if args.v:
        print(f"ratio: {ratio}")

    slow_times = range(0, ratio * len(args.val), ratio)
    fast_times = range(0, len(res), 1)

    if args.v:
        print(f"slow_times: (len {len(slow_times)}):  {slow_times}")
        print(f"args.val:   (len {len(args.val)}):    {args.val}")
        print(f"fast_times: (len {len(fast_times)}):  {fast_times}")
        print(f"res:        (len {len(res)}):         {res}")

    intval = [int(v) for v in args.val]
    plt.plot(slow_times, intval, 'ro', markersize=12.0)
    plt.plot(fast_times, res, 'g^')
    plt.title(f'Interpolated Encoder Values  (order={order})')
    plt.grid(True)
    plt.show()

if __name__ == '__main__':
    main()

Example Plots

...

(Click on Image Below for More)

Image Added View filenameEncoder Interpolation.pdfheight250