the development of a linear kalman filter for...
TRANSCRIPT
THE DEVELOPMENT OF A LINEAR
KALMAN FILTER FOR RESPONSIVE
MYOELECTRIC CONTROL
BURCH, RUSTY DANIEL
B.S. Honors Physics| Purdue University | West Lafayette, IN
Master of Science in Bioengineering | College of Engineering and Applied Sciences University of Colorado Denver | 2019
i
Masters Approval Page
This thesis for the Master of Science degree by
Rusty Daniel Burch
has been approved for the
Bioengineering Program
by
Richard ff. Weir, Chair
Erin Austin
Steven Lammers
Date: December 15, 2018
ii
Burch, Rusty Daniel (M.S., Bioengineering) The Development of a Linear Kalman Filter for Responsive Myoelectric Control Thesis directed by Professor Richard ff. Weir
Abstract
Quick and smooth estimation of the surface electromyographic (EMG) signal amplitude
is essential to providing users with intuitive control of a myoelectric prosthesis. Muscle
contraction creating an electric potential is detected on the skin surface and translated into a
prosthesis command signal. Because of its complexity, characterizing EMG requires a statistical
approach. A standard amplitude estimator has been the root-mean-square (RMS) statistic;
however, RMS calculation introduces significant delay in prosthesis control, generating a
requirement for faster estimators. A Bayesian statistical approach predicting future data using
past observations was developed using a Kalman filter. This Kalman filter produces estimates
more quickly and even more smoothly than RMS but probably is not yet perfected. The
successful development of this filter represents progress towards intuitive myoelectric control.
iii
ACKNOWLEDGEMENTS
It has been three years since I left a career in Intelligence in the hopes of helping people
more tangibly. Arriving at grad school, I was stuck in my head and afraid to come out.
That is why I am indebted to Professor Richard Weir, because he motivated me to get my
hands dirty, so I could become a successful and useful engineer. Dr. Jacob Segil helped me in
this regard as well.
I am grateful to Professor Erin Austin for his kindness and passion in teaching me
statistics. I thank Professor Steve Lammers for simplifying the coding process for me and for
talking polynomials.
I thank Dr. Cathy Bodine for the example she sets in her zeal for advocating for persons
with cognitive disabilities and similarly I thank Dr. Brad Smith for his example of work
excellence.
A single dude, I thank my scrumtrulescent parents, nine siblings, friends, family, and
church for their love, encouragement, and prayers. This project is by no means perfect, but God
was doing it alongside me this whole time and I glorify Him for that. Ps. 127:1, “Unless the Lord
builds the house, those who build it labor in vain.”
iv
Table of Contents
MASTERS APPROVAL PAGE I
ABSTRACT II
ACKNOWLEDGEMENTS III
EXECUTIVE SUMMARY 1
INTRODUCTION. 2
PREVALENCE OF LIMB LOSS. 2
PROSTHESIS TYPES. 4
INTRODUCTION TO THE ISSUE OF CONTROL. 7
THE PHYSIOLOGY BEHIND EMG. 9
USING STATISTICS TO DESCRIBE EMG. 12
THE MATHEMATICAL ROOTS OF RMS AND OF THE STANDARD OF CARE. 13
SNR OF RMS. 18
THE PROBLEM OF TIME CONSTRAINT IN MYOELECTRIC CONTROL. 19
EXPLANATION OF THE BAYESIAN APPROACH. 21
WHAT THE KALMAN FILTER IS. 22
DERIVATION OF THE PROCESS MODEL. 25
CONSIDERATIONS FOR REPRESENTING EMG NOISE IN THE KALMAN FILTER. 30
KALMAN FILTER CONVERGENCE. 32
SPEED PERFORMANCE OF THE EMG LINEAR KALMAN FILTER. 33
v
KALMAN FILTER VERSUS RMS SNR. 38
INCORPORATING AN FIR BANDPASS FILTER TO FOCUS ON EMG SIGNAL. 44
THE RAUCH-TUNG-STRIEBEL SMOOTHER. 49
CONCLUSION. 50
MATLAB CODE 51
ARDUINO CODE 56
REFERENCES 80
1
EXECUTIVE SUMMARY
The linear Kalman filter developed for surface electromyographic (EMG) signal under
this thesis produces proportional EMG amplitude estimates about 5-15 milliseconds (ms) faster
than a sliding-window root-mean-square (RMS) processor, depending on the length of the RMS
window (25 – 250 samples), at a sampling frequency of 1 kHz, and the values used for process
and measurement noise. In figure 1, the Kalman estimate arrives about 12 ms before that of the
short-window RMS. The EMG Kalman filter over a series of 12 muscle contraction patterns
produced an average signal-to-noise ratio (SNR) of 14.3 whereas an RMS estimator having a
window length of 150 samples resulted in an average of 12.1. The quality of amplitude
estimation can be quantified using SNR. Based on Farrell and Weir, an RMS processor with a
window length longer than 150 would not be sufficiently responsive for a myoelectric prosthesis
user. [1] To obtain high-enough SNR, researchers have used RMS windows often 250 or more
samples long.[2, 3]
The successful development of this filter represents progress towards a myoprocessor that
provides a limb-absent user with intuitive, reliable control of a myoelectric prosthesis.
Figure 1. Comparison of Kalman filter and RMS timing. The EMG Kalman filter estimates amplitude faster than a short-window RMS processor.
2
INTRODUCTION.
Quick and smooth estimation of the surface electromyographic (EMG) signal amplitude
is essential to providing users with intuitive control of a myoelectric prosthesis. Prosthesis users
need signal processing solutions that produce amplitude estimates predictably and more
responsively than the standard of care. A Kalman-filter-based algorithm has been developed to
meet these needs.
Prevalence of Limb Loss.
An estimated 1.6 million persons in the United States were living with limb loss in 2005.
[4] Between 1988 and 1996, about 133,000 limb-loss-related hospital discharges occurred
annually in the United States, roughly 80 percent of which involved lower extremity amputation
due to vascular conditions like diabetes. Upper-limb amputations stemming from trauma
comprised about 9.5 percent. More than three-quarters of upper-limb trauma amputations
occurred at the lowest, finger level. [5] As of 2005, about 41,000 persons in the United States
were categorized as having undergone major upper-limb amputations. Major upper limb
amputations included the following except those at the thumb and finger levels: thumb, finger,
hand, wrist, transradial, elbow, transhumeral, shoulder, and forequarter amputation levels. [4]
3
Figure 2. Upper-limb-loss classifications. Copied from [6].
In the United States between 2004 and 2006, an estimated 1454 children were born with
upper-limb congenital anomalies. [8] A 2013 study investigating the opinions of children with
congenital anomalies on prosthesis use and rejection suggested they chose to wear prostheses
primarily for cosmetic reasons to achieve social integration. [9] A 2006 study of 260 children
with unilateral congenital upper-limb deficiencies treated between 1954 and 2004 indicated the
best prosthetic outcomes occurred when treatment, to include fitting of a myoelectric prosthesis,
adapted to the child’s consistently-changing development. [10]
Even though upper-limb amputation is rare, over two-thirds of amputations due to trauma
occur among adolescents and adults below the age of 45 years. It is likely such persons would
have prosthetic needs for many years to ensure high-quality, active, and productive lives. [4]
Well-engineered prostheses have the potential to become an integral part of a person’s everyday
life and engineers aim to reduce prosthesis rejection. Rejection occurs when a user ceases to
wear a particular prosthesis. According to a 2009 study, 21 percent of adults and 19 percent of
children who responded to a questionnaire rejected prosthesis use entirely, while 67 percent of
adults and 57 percent of children used a prosthesis on a regular basis. [11]
4
Prosthesis Types.
Prostheses can be divided into three categories: passive, body-powered, and electric.
Passive prostheses are made to look like arms and hands and their primary purpose is cosmetic.
They may be molded into a fixed shape or made such that the fingers can be positioned into
poses as the user desires. They are commonly covered by a soft plastic glove that comes in a
variety of standard skin tones. At an additional cost, a prosthetic artist can create a custom
silicone glove crafted to match the remaining hand with an intricate level of detail. [6] Passive-
prosthesis users prioritize comfort and appearance. [11] Passive prostheses are affiliated with
widely variable rejection rates with reports ranging from 6 [12] to 100 percent [13]. Even though
they lack functionality, passive prostheses tend to elicit the fewest user concerns, the most
significant being wear temperature. [14]
Although body-powered prostheses generally do not incorporate the most advanced
technology, they have remained a popular choice in upper limb prosthetics. [15] This has been
attributed to their relatively low cost and lightweight compared to myoelectric prostheses as well
as their high functionality and reliability. [16, 17]
Body-powered prostheses are largely mechanical devices. To control them, amputees use
remaining-shoulder movements to pull on a cable and sequentially operate prosthetic functions
such as the elbow, wrist, and terminal device. To switch between functions, users must lock the
joints they wish to remain stationary by pressing a switch or using body movements to pull a
locking cable. [16] Terminal device options for body-powered prostheses include a hook,
prehensor, hand, or activity-specific devices. [17]
5
Figure 3. Side-by-side: body-powered and myoelectric prostheses. Copied from [16].
Overall rejection rates of body-driven prostheses ranged from 16 [18] to 66 percent [19].
Evidence indicates acceptance of body-powered prostheses depends largely on the type of
terminal device, be it hand or hook. Body-powered hands are typically associated with rejection
rates as high as 80 [20] and 87 percent [12], with common complaints surrounding slowness in
movement and awkward use. Overall, body-powered hooks are more acceptable to users.
Reported consumer complaints with respect to body-driven prostheses generally include
excessive wear temperatures and abrasion of clothes, with the most commonly recounted
hindrance being harness discomfort or breakage. [20]
Myoelectric prostheses are motorized and controlled through surface EMG signals from
residual muscle sites. [16] They are perceived to offer advantages in appearance, increased pinch
strength, ease of operation, and lack of harness. [21] [22] [23] [24] Current state-of-the-art
prosthetic hands are electric single-degree-of-freedom (opening and closing) devices often
implemented with myoelectric control. [25] Prosthetic arms requiring control of multiple degrees
6
of freedom such as movement of the arm about an elbow joint often use sequential control with
locking mechanisms to switch from one degree of freedom to another.
One of the major reasons why myoelectric signals have been widely accepted as being
useful for prosthesis control is the ease with which the signals are picked up. Surface electrodes
(electrical conductors) applied over a voluntarily controllable muscle serve as convenient
transducers for myoelectric control. Electrodes can be made small, light-weight and
unnoticeable. [26] Research incorporating surface EMG measurement is ubiquitous, in part
because EMG amplitude has the potential to estimate muscle force.
De Luca wrote; however, if a quantitative relationship between the EMG signal and force
is required then the contraction must be isometric. [27] During isometric contractions muscles
are contracted but there is no body movement so muscle fiber length stays constant. Such a
restriction is not realistic for prosthesis users. For this reason, the emphasis in myoprocessing is
on creating a reliable node of proportional control for the user instead of accurately estimating
muscle force.
Myoelectric prosthesis components include electrodes for surface EMG, a rechargeable
battery, dc electric motors to produce motion, a transmission for producing motion of a joint,
wrist, or terminal device, and control circuitry. Users can expect increased maintenance such as
glove and battery replacement, in addition to higher cost and weight. [14] Like body-powered
users, myoelectric users also prioritize function and comfort. [11]
7
Figure 4. Basic myoelectric setup. The intent signal is initiated in the brain, sent through the central nervous system, relayed to the peripheral nervous system, and manifested in the EMG signal through muscle-contraction-associated voltage. The signal is further processed for reliable control. Copied from [25].
Reported rejection rates from 22 studies for myoelectric prostheses indicate a highly
variable range from 0 [28] to 75 percent [29]. As of 2007, no trends suggested a decrease in
rejection rates commensurate with advances in engineering. The same 2007 survey indicated
electric hands sparked the greatest interest for future use in both adult and pediatric populations.
[14]
Introduction to The Issue of Control.
Replacing both the function and looks of a human arm and hand with one prosthesis is an
incredibly complex problem. [6] There are over 30 muscles acting on the forearm and hand. The
human hand has 27 major bones and at least 18 joint articulations with at least 27 degrees of
freedom. The arm positions the hand in space while the hand enables a person to interact with the
environment. The design of a fully functioning artificial arm and hand replacements with
physiological speeds-of-response and strength that can be controlled almost without thought is
the goal of upper-extremity prosthetics research. [25]
Much effort in the field of upper-extremity prosthesis research is directed toward the
creation of prostheses as true limb replacements instead of simply being used as tools. The
8
biggest factor limiting prostheses to the role of a tool is finding appropriate control sources to
manipulate many degrees of freedom. This lack of independent control sources imposes the most
severe impediment to the development of modern prosthetic arm-hand systems.
Consequently, upper-limb prosthetics research is somewhat dominated by considerations
of control. [25] The ultimate goal in the development of myoelectric control systems is to have
simultaneous, independent, and proportional control of multiple degrees of freedom with
acceptable performance and near “normal” control complexity and response time. [30]
Proportional control is realized when prosthesis speed or position is proportional to accurate
EMG amplitude estimates. In [26], Childress et al. indicated it had been shown that if the signal
has a gaussian amplitude probability density with zero mean then the integrated electrical
activity is proportional to the standard deviation (RMS value).
Because muscle contraction works in part through the flow of calcium ions, when a
muscle contracts an electric potential is produced as a by-product. Surface electrodes placed on
the skin near the muscle can detect this signal. The signal is amplified and processed to become
the control input of a prosthesis. Although EMG behaves nonlinearly it is broadly monotonically
increasing with muscle effort and the human operator perceives the prosthesis response as
basically linear. [25]
Figure 5. Stages of processing the EMG signal for prosthesis control. The signal starts out in the microvolt range and is amplified to a few volts. It is rectified and then amplitude is estimated and smoothed before the signal directs prosthesis movement. Copied from [25].
9
The Physiology Behind EMG.
The EMG signal represents the spatiotemporal sum of motor unit activity within the pick-
up area of one or more electrodes. A motor unit is the single smallest controllable muscular unit.
It consists of a single neuron, the neuromuscular junction, and a few-to-thousands of innervated
muscle fibers. [31]
To activate a motor unit the brain sends a signal down the spinal cord that appears in the
peripheral nervous system (PNS) as a short-duration low-amplitude voltage pulse called an
action potential. [31] The action potential is a transient (< 1 millisecond) reversal in the polarity
of a neuron’s transmembrane potential which propagates down the axon towards the axon
terminals. [32] This potential is the voltage level inside a neuron relative to its immediate
exterior.
Figure 6. The Radial Nerve of the PNS innervates muscles in the upper limb. The path of an action potential to its target muscle can be imagined. Copied from [33].
Propagation of an action potential down the axon is a complex process. Once the reversal
of polarity of the neuron membrane is initiated inside the spinal cord, “voltage-gated” channels
10
allow Na+ influx into the axon. This depolarization generates local currents that depolarize
adjacent areas of the axon membrane, causing propagation. [32]
Figure 7. Sketch of an action potential, which propagates down the nerve towards a muscle. Copied from [34].
In the PNS, Schwann cells insulate the axon to lengthen the distance over which local
currents are conducted. There is a limit to this distance; however, leading to the presence of the
so-called “nodes of Ranvier” which contain high densities of Na+ channels in-between Schwann
cells and bolster current flow. The action potential propagates by jumping from node to node
through what is called “saltatory conduction.” [32]
After an action potential has passed through a neuron segment, the neuron works to reset
itself to resting potential there. Na+ channels are closed off after being open for only about one
millisecond and voltage-gated channels pump K+ outside the neuron over several milliseconds to
drop the potential back down towards the cell’s resting state. The resetting capabilities of these
channels govern the maximum frequency at which an axon can generate potentials. [32]
The action potential reaches the neuromuscular junction (NMJ) at the axon terminal. At
the NMJ, information is passed from nerve to muscle. Voltage-gated channels in the axon
membrane are opened, allowing Ca2+ to flow into the axon. Vesicles in the axon containing the
11
neurotransmitter acetylcholine (ACh) are then moved and docked at the membrane. They fuse
with the membrane and release their contents into the synaptic cleft. ACh binds to receptors
allowing Na+ to flow into a muscle fiber’s sarcolemmal membrane and initiate a propagating
action potential there. [35]
The sarcolemma extends itself into all regions within the muscle fiber cell so an action
potential can initiate contraction in sarcomeres throughout. The sarcolemma has tubules
collocated with a second tubular system called the sarcoplasmic reticulum. Excitation of the
sarcolemma and its tubules causes Ca2+ release from the sarcoplasmic reticulum and initiation of
contraction by the myofilaments. [36] It is this flow of calcium ions into sarcomeres which is
detected as the EMG signal.
Figure 8. Muscle fiber and sarcomere structure. Each fiber consists of a series of sarcomeres. Each sarcomere has the same length and experiences the same force. Myosin myofilaments (dark lines) overlap with actin myofilaments (thin lines) to produce contraction. Copied from [37].
The myofilaments make up the contracting components of a muscle and are situated in a
functional repeating unit called the sarcomere. There are thin filaments composed primarily of
the protein actin which form “ladders” and thick filaments based on myosin containing globular
heads that ratchet along the actin ladders to produce contraction. Typically, a protein band covers
ladder sites to prevent muscle contraction but if calcium ions flow into a sarcomere as a result of
an action potential they cause this band to be moved, leading to muscle contraction. [38]
12
Using Statistics to Describe EMG.
It is clear the contraction of a single muscle fiber is a cascade of intricate physiological
stages. A nominal skeletal muscle will have tens [39] to several hundred [40] independent motor
units with each comprised of many hundreds of fibers. While studying EMG power spectra,
Fuglsang-Frederiksen and Ronager identified 164 motor units in the biceps brachii of subjects.
[41] To produce a desired force or torque the brain will activate a dynamic subset of motor units
using a variety of firing frequencies and timings. Even at moderate contraction levels, so many
motor units are active that EMG has the character of random noise. [42]
Figure 9. A motor unit action potential (MUAP) is the spatiotemporal summation of multiple motor units firing, i.e. many fibers contracting. The degree of summation of action potentials at the site of recording probably depends on the number of motor units firing near the site at a given force, the properties of the electrode and of the surrounding tissue. [41] Copied from [43].
EMG is the spatiotemporal sum of motor unit action potentials (MUAPs) multiplied by
the transfer functions of biological tissue and measurement hardware. Investigators since at least
the 1950s, therefore, have turned to the field of statistics to make inference on and describe
characteristics found in the EMG signal such as amplitude, interpulse intervals, pulse duration,
13
and estimates of muscle force. [44] A random process like the EMG signal is one in which the
outcome of any one occurrence of the phenomenon cannot be predicted but is rather governed by
chance. [45]
Roesler and Boecker in 1970 established the probability density curves of surface EMG
amplitudes of various muscles under isometric contractions were well described as gaussian
distributions. [46] Roesler in [26] later specified amplitudes could be described very precisely as
gaussian and the strength of isometric contraction, fatigue, choice of control muscle and other
characteristics had no influence on the law of distribution. He further indicated with increasing
isometric contraction, the standard deviation of the adjusted gaussian distribution also increases.
Experimentation and statistical analysis verify surface EMG can be satisfactorily modeled as a
normal random process having a mean of zero. [44, 47-50] According to Clancy, it has long been
held that the surface EMG recorded from bipolar electrodes during constant-force, constant-
angle, non-fatiguing contractions can be well modeled as a zero-mean, correlation-ergodic,
random process which is gaussian in distribution. [49]
The Mathematical Roots of RMS and of the Standard of Care.
Because surface EMG can be modeled as a gaussian process, a key statistic of interest for
decades has been the root-mean-square (RMS) value of a signal. [31] RMS is the square root of
the mean of the squares of a set of values.
Given a set of observations 𝒙 = {𝑥&, 𝑥(, 𝑥)}, the RMS would be calculated by
𝑅𝑀𝑆(𝒙) = 0
𝑥&( + 𝑥(( + 𝑥)(
3 . (1)
If 𝒙 = {1, −2, 2}, then 𝑅𝑀𝑆(𝒙) = 3.
14
In the case of a zero-mean gaussian signal that is stationary over a period of time, RMS is
the maximum likelihood estimator for standard deviation. For EMG, the standard deviation is the
signal amplitude. [51]
Calculating the RMS of 100 surface EMG samples produces a single scalar value
representative of activity during that time window. One approach is to divide collected samples
into non-overlapping, short segments of time and compute one RMS value to represent an entire
segment.
Figure 10 shows an example of RMS computed for non-overlapping windows of 100 ms
superimposed on associated raw EMG.
Figure 10. RMS of non-overlapping bins of raw EMG can have a “skyline” appearance.
A preferred method, however, is to slide a window of constant length continuously over a
series of samples, producing one RMS value per point instead of a single line representing the
entire window. This method can produce higher SNR but imposes an increased calculational
burden on a microprocessor.
15
Figure 11. Sliding RMS follows the raw signal more dynamically than non-overlapping RMS and it produces higher SNRs.
The definition of a statistic is very broad but generally, they are produced by performing
mathematical manipulation on random variables. Given a sample from a population, a statistic
may give the smallest or largest value in the sample, the average value, or a measure of the
variability between values. [52] It is worth noting in the field of statistics, a sample is the set of
observations drawn from a population whereas in signal processing, i.e. in other portions of this
paper, sampling is the reduction of a continuous-time signal to a discrete-time signal and a
sample is a realized value from sampling. Statistics are a method of summarizing data and
making inferences about large populations using only samples from a population.
The method of maximum likelihood is, by far, the most popular technique for deriving
statistics that are estimators of parameters of probability distributions. A probability distribution
is characterized by location and scale parameters such as mean and variance. Maximum
likelihood estimators (MLEs) are found first by constructing a likelihood function from a joint
probability density function (pdf) or probability mass function (pmf) and setting its derivative
equal to zero to find the point where likelihood may be maximized. Whereas probability is the
16
proportion of an event in an infinite number of trials, likelihood is analogous to the conditional
probability a series of events occurred based on a fixed parameter value.
Figure 12. A plot of the standard normal distribution, which is a gaussian distribution with mean 𝜇 = 0 and variance 𝜎( = 1.
It is important to see RMS is the MLE of standard deviation for a zero-mean gaussian
process. If we assume a random variable 𝑋 is distributed as a normal random variable with mean
𝜇 and variance 𝜎( where 𝜇 ∈ ℝ and 𝜎 ∈ (0,∞), written as 𝑋~𝑁(𝜇, 𝜎(), the pdf is
𝑓(𝑥) =
1√2𝜋𝜎(
𝑒D(EDF)G (HG⁄ . (2)
Or, if 𝜇 = 0, as is the case for a zero-mean process
𝑓(𝑥) = 1
√2𝜋𝜎(𝑒DEG (HG⁄ . (3)
Having a random sample of size 𝑛, 𝑋&,… , 𝑋L, from this population the likelihood
function, equivalent to the joint pdf, is the product of the individual pdfs
𝐿(𝜎(|𝑋&, … , 𝑋L) = O1
√2𝜋𝜎(𝑒DEPG (HG⁄
L
QR&
. (4)
17
Where Π indicates the product of 𝑛 pdfs and each pdf has an indexed random variable 𝑥Q,
where 𝑖 = 1,… , 𝑛. To simplify, it is convenient to take the natural logarithm of 𝐿, denoted by 𝑙.
𝑙(𝜎(|𝑋&, … , 𝑋L) = −𝑛2 log
(2𝜋𝜎() −Y𝑥Q(
2𝜎(
L
QR&
. (5)
To find a maximum (or minimum), take the derivative of this function with respect to 𝜎(.
𝜕𝑙𝜕𝜎( = −
𝑛2𝜎( +Y
𝑥Q(
2𝜎[ .L
QR&
(6)
Then, set the derivative equal to zero and solve for 𝜎 . To ensure it is a maximum instead
of a minimum one would check whether 𝜕(𝑙 𝜕(𝜎()(⁄ < 0.
0 = −𝑛2𝜎( +Y
𝑥Q(
2𝜎[
L
QR&
, (7)
𝜎( = 1𝑛Y𝑥Q(,
L
QR&
(8)
𝜎]^_` = a1𝑛Y𝑥Q(
L
QR&
. (9)
Equation 9 shows RMS is the MLE for the standard deviation of a zero-mean normal
process (compare with equation 1). RMS has been a favored estimator of EMG amplitude for
decades because EMG amplitude is the signal standard deviation. De Luca in 1997 also wrote
RMS represents EMG signal power (after a square root is taken) and thus has a clear physical
meaning. [27] Signal power is the average squared value of a signal. Therefore, RMS has
become a standard calculation for processing EMG signals.
Another common statistic is the mean absolute value (MAV). Moreover, in pattern
recognition systems various waveform features like the number of zero crossings in a time epoch
are extracted. [53] A study by Clancy and Hogan in 1999 indicated there is little difference
between MAV and RMS in their abilities to estimate EMG amplitude. [49]
18
When developing a myoprocessor it is important to have a benchmark against which to
compare the new processor. Commercial myoelectric devices have incorporated a variety of
processing techniques over the decades [30], although published information detailing
algorithms used in contemporary prostheses is scant. Because RMS is popular in myoelectric
control research, this paper assumes the standard of care for single-channel EMG amplitude
estimation is sliding window RMS.
SNR of RMS.
While RMS amplitude demodulation—separation of signal from its multiplied carrier
wave—is a reliable method for producing sufficiently high signal-to-noise (SNR) ratios, those
SNRs are a function of the length of time window over which RMS is calculated. The higher
accuracy desired in proportional control the longer the time window which must be used.
St-Amant et al. in 1996 studied the influence of smoothing window length on the SNR of
RMS estimates of EMG amplitude. The quality of amplitude estimation can be quantified using
SNR. Based on data from a previous experiment, they studied window length durations spanning
24-500 ms. Results showed SNR increases in a square root fashion with smoothing window
length, as predicted by classical theory. They compared single-channel results with those in
which multiple channels were combined to produce a composite EMG signal. [3] Pre-whitening
of a signal increases its randomness and produces higher SNRs [2] by decorrelating successive
samples of myoelectric activity, thereby increasing the amount of information each sample
contributes. [50]
19
Figure 13. SNR versus window length for four different RMS processors: multiple channel, whitened (—); multiple channel, unwhitened (…); single channel, whitened (-.-); single channel, unwhitened (---). The mean + standard deviation SNRs are shown where each entry averaged across 660 single channel recordings/100 multiple channel recordings. Copied from [3]. The Problem of Time Constraint in Myoelectric Control.
If the problem of myocontrol were not time-constrained, RMS would be a satisfactory
approach. The issue, however, is one of producing sufficiently high SNR in as short a time as
possible. Longer signal processing windows cause delays in control. With a window of 250 ms,
Meek produced SNRs in the range of 18-21 using externally measured force as ground truth and
Parker obtained SNRs of 8-11 when three different contraction levels were the targets. [2] [30]
Paciga et al. in 1980 examined the ability of prosthesis users to produce five different
levels of an EMG signal for a five-state prosthesis controller. It was shown that introducing a
200 ms delay into the visual feedback path provided to the subject would increase the measured
errors six-fold from 1.1 to 6.6 percent. Farrell and Weir in 2007 followed suit by performing a
study introducing artificial control delays of varying length to users undergoing a box and block
test with electric prehensors. They found the optimal delay between a user’s command and
20
actuation of a prosthesis was 100-125 ms, depending on the speed of the prosthesis. A longer
delay caused a clinically significant change in performance for the box and block test. [1]
RMS behaves as a lowpass filter and the step response of sliding RMS shows the rise
times of sliding RMS windows of different size.
Figure 14. The rise times of window sizes of 25, 75, and 150 samples for sliding RMS are 20, 60, and 120 ms, respectively, at a sampling frequency of 1 kHz.
Using a step input, figure 14 shows the response of three sliding RMS processors of
different window length. Rise time, a metric for filter response speed, can be inferred from these
plots. Rise time is the time required to go from 10 to 90 percent of the final value (0.1 to 0.9 in
Figure 14) reached by a filter in response to a step input, although RMS is not a frequency filter
in the classic sense. [54]
Calculating signal RMS is an effective approach for smoothing of an EMG signal and
estimating its amplitude; however, the speed of this approach arguably is either barely sufficient
for myoelectric control or insufficient if additional EMG processing stages are added such as
noise filtering the raw signal beforehand or feeding the smoothed signal as input into classifiers
for pattern recognition. If one set an engineering requirement for single-channel EMG amplitude
estimation of obtaining an SNR of 15 using only pre-whitening and RMS, then the window
21
would have to be about 200 ms long, breaching the optimal controller ceiling of 125 ms. An
SNR of 10 would be attainable, however, within the time allotment of the optimal delay. Parker
et al. indicated an SNR of less than 10 would be considered relatively low.
The approach for this project, therefore, was simple. Make as fast and smooth an EMG
amplitude estimation processor as possible, bound only by the constraints of the author’s
knowledge! The focus on speed lent itself to using prior estimates to predict future ones, which is
a Bayesian approach. It will be shown the Bayesian approach allows for point-by-point
estimation, eliminating the need for long processing windows to obtain amplitude estimates.
Explanation of the Bayesian Approach.
Two prime examples of Bayesian point-by-point processing of EMG have been
published. Sanger in 2007 proposed a method for processing EMG point-by-point using
stochastic differential equations. The focus was on rapid and accurate response to changes in the
EMG signal so as to respond as quickly as possible to the onset of muscle contraction.
Proportionality of the signal to user input did not appear to be a major concern. [55] Hofmann et
al. pushed on this concept further and more methodically. They found able-bodied and limb-
deficient subjects could reach prompted virtual targets more quickly with a Bayesian processor
than with MAV smoothing. [56] Although the statistics were advanced, these efforts were the
impetus for the Kalman project.
The purpose of Bayesian inference is to provide a mathematical tool that can be used for
modeling systems, where the uncertainties of the system are taken into account. In Bayesian
inference, the probability of an event does not mean the proportion of the event in an infinite
number of trials, but the uncertainty of the event in a single trial as the event is now considered a
random variable. [57] The difference between the Bayesian inference and the classical method
for estimating parameters, the maximum likelihood method, is the starting point of Bayesian
22
inference is to formally consider the parameter𝜃 as a random variable instead of a fixed value.
For EMG,𝜃 would be represented EMG amplitude, or equivalently, signal standard deviation 𝜎.
Given a set of measurements 𝒚&:e = {𝑦&, … , 𝑦e}, the posterior distribution of the
parameter can be computed using Bayes’ rule. The posterior distribution represents the
information we have after the measurement 𝒚 has been obtained. As is typical, vectors and sets
of observations will be represented by bold, lowercase letters and matrices by bold uppercase
letters.
Bayes’ rule 𝑝(𝜽|𝒚&:e) = 𝑝(𝒚&:e|𝜽)𝑝(𝜽)
𝑝(𝒚&:e). (10)
Where 𝑝(𝒚&:e|𝜽) is the measurement model that gives the probability distribution of
observation 𝒚 given the parameters 𝜽, 𝑝(𝜽) is the prior model selected to represent the
probability of the parameters 𝜽 before seeing any observations, and 𝑝(𝒚&:e) is a normalization
constant ensuring the posterior probability integrates to unity; this constant is often omitted.
What the Kalman Filter Is.
The Kalman filter is a closed form Bayesian solution for linear filtering, where the
process and measurement models are linear gaussian [58]
𝒙i = 𝑨iD&𝒙iD& +𝒒iD&, (11)
𝒚i = 𝑯i𝒙i +𝒓i. (12)
Here 𝒙i is the state at time index 𝑘, 𝒚i is the measurement, 𝒒iD&~𝑁(𝟎,𝑸iD&) is the
process noise, 𝒓i~𝑁(𝟎, 𝑹i) is the measurement noise, and the prior distribution which initializes
the recursion is gaussian 𝒙r~𝑁(𝒎r, 𝑷r). The matrix 𝑨iD& is the transition matrix of the process
model and 𝑯i is the measurement model matrix. The state of the system refers to the collection
23
of state-space physical variables such as position, velocity, orientation, and angular velocity,
which fully describe the system. The time evolution of the state is modeled as a dynamic system
which is perturbed by a certain process noise. This noise is used for modeling the uncertainties in
the system dynamics. [57]
Assuming a model of signal and noise as independent random variables, Kalman in 1960
argued the probability with which a particular sample of the signal plus noise observation would
occur could be estimated using conditional distribution functions. Using least-square error as the
optimality criterion, Kalman indicated explicit calculation of optimal estimates for signal and for
noise is generally impossible, except if both processes are gaussian. Linear functions like
conditional expectation on a gaussian random process are gaussian random variables. He
constructed an approach using vector spaces and arrived at equations for minimizing the square
of the distance (error) between actual and estimated signal and noise values. [58] His result has
become widely used over the decades since in many fields of science and engineering. [57]
The Kalman filter can be separated into two steps: 1) predict state and error covariance
for the next time index based on a process model, and 2) update the estimate by compensating
for the difference between measurement and prediction using the Kalman gain. Error covariance
represents the difference between the state estimate from the Kalman filter and the true but
unknown state value. In other words, error covariance is a degree of accuracy of the final
Kalman estimate. [59]
The prediction step includes
Predicted state 𝒙iD = 𝑨iD&𝒙iD&, (13)
Predicted error covariance 𝑷iD = 𝑨iD&𝑷iD&𝑨iD&e +𝑸iD&. (14)
The update step includes
Difference between actual and predicted measurement 𝒗i = 𝒚i − 𝑯i𝒙iD, (15)
24
Innovations covariance 𝑺i = 𝑯i𝑷iD𝑯ie +𝑹i,
(16)
Kalman gain 𝑲i = 𝑷iD𝑯ie𝑺iD&, (17)
Updated state 𝒙i = 𝒙iD + 𝑲i𝒗i (18)
Updated error covariance 𝑷i = 𝑷iD − 𝑲i𝑺i𝑲iD&e . (19)
For the filter presented in this paper, 𝒙i would be represented by EMG amplitude at
discrete time sample indexed by 𝑘, 𝒙iD is the amplitude predicted just before the measurement 𝒚i
is taken, and 𝑷iD is the predicted error covariance. [57] The relationship between the true
unknown value 𝒙𝒌 and the estimate 𝒙y𝒌 is 𝒙𝒌~𝑵(𝒙y𝒌, 𝑷𝒌).
Bayes’ rule term Kalman filter term
𝑝(𝜽|𝒚&:e) 𝑝(𝒙i|𝒚&:iD&) = 𝑁(𝒙i|𝒙iD, 𝑷iD)
𝑝(𝒚&:e|𝜽) 𝑝(𝒚i|𝒙i) = 𝑁(𝒚i|𝑯i𝒙i, 𝑹i)
𝑝(𝜽) 𝑝(𝒙i|𝒙iD&) = 𝑁(𝒙i|𝑨iD&𝒙iD&, 𝑸iD&)
𝑝(𝒚&:e) 𝑝(𝒚i|𝒚&:iD&) = 𝑁(𝒚i|𝑯i𝒙𝒌D, 𝑺i)
Table 1. Identification of Bayes’ rule terms in the Kalman filter approach.
Because the problem was reduced to one dimension, all vectors and matrices in equations
13-19 became scalars, significantly simplifying the computations required. Matrix transpose and
inverse terms became scalar operations having the commutative property of multiplication,
which would otherwise be atypical if they were matrices. Additionally, computing inverse
matrices is a potential source of divergence in the Kalman algorithm. Having only scalars
ensures algorithm stability so long as 𝑄 or 𝑅 is greater than zero, although both should be for
model accuracy. Because the approach of this thesis was to represent amplitude using one state
25
variable and the values for Q, R, A, and H were assumed to be constant, the algorithm can be
succinctly displayed as
𝑃iD = 𝐴𝑃iD&𝐴 + 𝑄, (20)
𝐾i = 𝑃iD𝐻/(𝐻𝑃iD𝐻 + 𝑅), (21)
𝑃i = (1 − 𝐾i𝐻)𝑃iD, (22)
𝑥i = 𝐴𝑥iD& +𝐾i(𝑦i − 𝐻𝐴𝑥iD&). (23)
The Kalman filter functions on a point-by-point basis, producing estimates at each time
instant and providing much faster EMG amplitude estimates than any calculation requiring a
time window, such as RMS or MAV.
Derivation of the Process Model.
Essential to the success of a Kalman filter is deriving values for the elements of
𝑸,𝑹, 𝑨,and 𝑯. For a brief section, these will return to being matrices for the benefit of
understanding how they function. Of those, as Kim indicates, the most difficult to derive and the
most important is the process model.[59] The matrix 𝑨 is the mathematical manifestation of the
process model, which is typically determined by physics equations. For example, if one were
tracking the position of an object with constant velocity, the state vector could look like
�
𝑥i�̇�i�. (24)
Here 𝑥i is the object’s position and �̇�i its velocity. The process model matrix 𝑨 would
then be
𝑨 = �1 𝑑𝑡0 1 �,
(25)
26
Here 𝑑𝑡 is the sampling period. Therefore, the predicted state (equation 13) would be
�𝑥iD
�̇�iD� = �1 𝑑𝑡
0 1 � �𝑥iD&�̇�iD&
�. (26)
Finding an appropriate physics-based equation to describe the time evolution of EMG
amplitude was challenging. A state-space model comprised of physical variables used in multiple
studies involving EMG measurements was the Hill-type muscle model. All of these studies,
however, used EMG as a means to estimate force through muscle- or neural-activation. [60-62]
Figure 15. Hill-type model for contraction dynamics of muscle tissue. Total muscle force FM is the sum of passive force FPE from the passive element (PE) and active force FCE from the contractile element (CE). FCE depends on muscle fiber length LM and velocity vM, and the degree of activation of the muscle fibers a(t). Copied from [37].
In a Hill-type model, total muscle force is the sum of force from the tendon (PE) and the
fiber (CE). Zajac details equations that govern output force F as a function of inputs a(t), LM, vM,
and the length of the contractile element. [37]
Menegaldo used EMG amplitude to estimate muscle activation level a(t) and force during
isometric contractions. [60] Mohammadi et al. constructed an Extended Kalman filter—a
Kalman approach for linearizing nonlinear systems using partial derivatives—for state prediction
27
of a two-muscle agonist-antagonist model. Aside from requiring two muscles to be recorded in
separate channels their approach incorporated a significant amount of calculation and did not
seem useable in a real-time application. [61] Han et al. posited several mathematical
relationships for state variables in a muscle model to reduce the number of measured variables.
Their goal was to estimate joint dynamics and associated torque using a plethora of polynomials,
exponentials, trigonometric functions, and normalization that potentially would be too complex
or require too precise a calibration for myoelectric control.
The next attempt at finding a process model was to use a sequence of EMG points to
predict a future point using cubic polynomials. The polynomial coefficients were derived from a
least-squares approach. This method was compared to the existing model to determine its
performance. The existing model was simply to make 𝐴 equal to the identity matrix. This model
could be called the “straight line” model since it predicted the next EMG estimation to be
equivalent with the last updated one. Here is the polynomial methodology.
Form vector of 11 EMG observations (11 for matrix inverse stability) and associated time vector.
𝒚 = {𝑦&, … , 𝑦&&}
𝒕 = {𝑡&, … , 𝑡&&}
(27)
(28)
Create matrix of the following form.
𝑿 =�1 𝑡& ⋯ 𝑡&)⋮ ⋮ ⋱ ⋮1 𝑡&& ⋯ 𝑡&&)
� (29)
Find vector of polynomial coefficients.
𝒂 = ((𝑿�𝑿)D&) ∙ 𝑿� ∙ 𝒚�
(30)
28
Figure 16. Straight line prediction does a better job than cubic polynomial extrapolation when working with a rectified EMG signal.
Extrapolating the next point in an EMG times series using a cubic polynomial,
unfortunately, was not shown to be an effective method. The polynomial coefficients were
derived using the least-squares method. The accuracy of polynomial prediction increased as the
number of data points used to find polynomial coefficients decreased, consistent with EMG
being a random process.
Extrapolate 12th point.
𝑦&(,����Q���� = 𝑎(1) + 𝑎(2) ∙ 𝑡 + 𝑎(3) ∙ 𝑡( + 𝑎(4) ∙ 𝑡) (31)
Compare prediction with actual.
𝑑𝑖𝑓𝑓𝑒𝑟𝑒𝑛𝑐𝑒 = 𝑦&(,����� − 𝑦&(,����Q���� (32)
For straight line method.
𝑑𝑖𝑓𝑓𝑒𝑟𝑒𝑛𝑐𝑒 = 𝑦&(,����� − 𝑦&&,����� (33)
29
Figure 17. The EMG record used to compare cubic polynomial versus straight line prediction. For the least-squares method, 11 EMG data points were used to find coefficients and the 12th point was extrapolated using a polynomial.
Because no suitable equations were found, the next attempt was to arrive at values for 𝐴
along with 𝑄, 𝑅, and 𝐻 algorithmically. There are several algorithms available for estimating all
four parameters (or the elements of all four matrices) using an MLE or expectation-maximization
(EM) approach. Significant effort was applied to developing such an algorithm that would
repeatedly produce effective parameter estimates.
Of those researched, Ghahramani’s explanation is the most lucid but potentially is too
simple for a signal as dynamic as surface EMG. [63] Zheng-ou and Bavdekar et al. each explain
a similar method involving iterative convergence through EM onto the most likely values. [64]
These approaches seem promising but will take concerted effort to implement. Zheng-ou’s is
recommended if not working with an Extended Kalman filter. Mehra’s solution is representative
of what seems to be the most commonly used approach in adaptive Kalman filtering (real-time
algorithmic identification of process and measurement noises), which involves a fair amount of
matrix math potentially worth pursuing. [65]
It is possible modeling EMG as a linear gaussian process with additive noise has reached
its limits with the filter presented in this paper and any algorithm solving for these four
30
parameters might not be effective or reliable. Such efforts should continue to be pursued but lack
of success might not be surprising for this reason. That said, a better process model in 𝐴 might
help to overcome this would-be barrier for the remaining three parameters 𝑄, 𝑅, and 𝐻.
In short, the best process model found in the time devoted was the “straight line” model.
Given the large variation between a point and its subsequent point in surface EMG, it seems
intuitive that the best guess, or perhaps the least incorrect guess, for the next point would follow
a straight line.
Considerations for Representing EMG Noise in the Kalman Filter.
Over the decades, surface EMG has been established as the result of a Poisson point
process which has been spatially and temporally filtered through biological tissue and electrodes,
amounting to the zero-mean gaussian process. The gaussian probability distribution for a random
process is required for a linear Kalman filter to operate. Moreover, the measurement noise must
also be an independent zero-mean gaussian process that behaves as additive noise. It is known
noise introduced into the original MUAP signal is multiplied by it and not added to it. [50]
Because EMG noise is multiplicative instead of additive, Hogan and Mann argued a
linear Kalman filter is the wrong approach to muscle force estimation. [50] Evans et al.,
however, used logarithmic transformation to change multiplied components into additive ones
and derived a Kalman filter for EMG. Their Kalman filter showed speed and decent SNR but did
not seem to gain much momentum in the research community. [66] The filter presented herein
assumes additive noise even without a logarithmic transformation. The justification for this
treatment is simply the empirically observed performance of the filter. Kreifeldt provides a
morsel of mathematical justification by showing there is additive noise power in the EMG signal,
even if this noise is not independent as would be required by a Kalman approach. [67] The
31
primary interest with this filter is the estimation of EMG amplitude and perhaps this divorce
from muscle force estimation allows more for a linear Kalman filter approach.
Along with other filters which have been designed for EMG processing, the Kalman filter
does not require stationarity, which is perhaps its greatest strength. Two factors have the greatest
effect on signal stationarity: (a) stability of the electrode position with respect to active muscle
fibers (any such movement would affect the amplitude of the MUAPs and possibly bring the
electrode to the territory of an active motor unit not previously detected) and (b) stability of the
motor unit activation pattern. [27]
From the noise sources discussed below, it should be clear 𝑅 is an important aggregate
parameter for eliminating noise. The majority of noise introduced into the surface EMG signal
could be represented as measurement noise, which is manifested algorithmically in the Kalman
filter parameter 𝑅. Because EMG is a random process and several sources of noise are
introduced during its collection, significant effort must be undertaken to smooth variations in the
signal before it can be used to command a prosthesis. Otherwise, prosthesis control could be as
unpredictable as the EMG signal itself. The primary objective in processing the EMG signal for
prosthesis control is the estimation of the true signal amplitude masked by noise.
Noise can be defined as any unwanted signal detected together with the desired signal.
[31] The desired true signal is viewed as a physical manifestation of user intent. [50] Potential
sources of noise include electrode noise, movement artifact, cable motion artifact, interference
from the power grid, analog-to-digital conversion quantization error, lowpass filtering from
muscle and fat tissue, and electrode location. [68] While the effects of these noise sources can be
mitigated, there will always be some noise in a collected signal.
Movement artifact noise is generated when muscle near an electrode moves underneath
the skin or when a force impulse causes movement at the electrode-skin interface. A good
32
approach is to set a highpass cutoff frequency at 20 Hz, which attenuates the impact of this noise
without removing significant signal information. [69]
Ambient electromagnetic fields exist near main power sources at specific frequencies and
near electrical instruments like power tools, producing noise in the range of volts at industrial
sites. [70] Well-designed bipolar electrodes significantly reduce this noise but do not eradicate it.
Implementing a notch filter at targeted harmonic frequencies can also reduce unwanted
interference but may remove desirable signal components as well because EMG contains
significant power near 50 and 60 Hz in its signal power spectrum. Another option is an adaptive
interference cancellation method in which a reference input, which provides a signal correlated
with the interference signal, is adaptively filtered and subtracted from the corrupted signal. [71]
[42]
Because of the many sources of measurement noise, 𝑅 must be estimated as an aggregate
parameter representing all the sources one may have. Values for process noise 𝑄 and
measurement noise 𝑅 were arrived at heuristically, which is inevitable when developing a
Kalman filter according to Kim. [59] 𝐻 is assumed to be unity but further analysis below will
show the impact varying all four of these parameters 𝑄, 𝑅, 𝐴, and 𝐻 has on filter performance.
Kalman Filter Convergence.
A characteristic of the EMG Kalman filter is it converges towards the optimal possible
values of error covariance and Kalman gain given values for 𝑄, 𝑅, 𝐴, and 𝐻. It is necessary to
select initial values for 𝑥r and 𝑃r to permit the filter to begin its recursion towards convergence.
The filter is initialized with a postulated error covariance and then converges on the optimum
value. For this model, the initial state 𝑥r was chosen to be 𝑥r~𝑁(𝑦r, 1). That is, the initial
estimate is set to the first observation value in an effort to tailor each initialization to the current
EMG record and the initial error covariance 𝑃r was set to unity for the sake of simplicity. In the
33
author’s experience, 𝑃r typically converges to less than 1, regularly about 0.5 and stays there
independent of muscle contraction level.
Figure 18. Both the Kalman gain and error covariance converge within the first milliseconds of recording. Speed Performance of the EMG Linear Kalman Filter.
The most important discussion surrounding the filter is that of its performance, in both
speed and the signal-to-noise ratios (SNRs) it produces. The following figure provides a snapshot
summarizing the filter performance.
34
Figure 1. The developed Kalman filter estimates EMG amplitude faster than a short-window RMS processor.
Because the problem was reduced to one dimension, this Kalman filter can be represented
as a single-pole infinite impulse response (IIR) filter derived from the Kalman filter equations.
Finite impulse response (FIR) filters like the bandpass filter employed as a pre-processor in this
project have only zeros (in the sense of poles and zeros) and can be implemented in real-time.
Their output is a function of observations whereas IIR filters incorporate previous outputs as well
through recursion. Some IIRs are non-causal, requiring an entire data record on which to perform
filtering. These are effective filters but not usable in a real-time environment. IIRs like the one
modeling the EMG Kalman filter require only a certain number of recursions and can be
implemented in real time, in this case, one recursion is needed.
One of the EMG Kalman filter equations is
𝑥i = 𝐴𝑥iD& +𝐾¡¡(𝑦i − 𝐻𝐴𝑥iD&).
(34)
Here 𝐾¡¡ is the scalar steady-state Kalman gain. Translated into typical 𝑦 as the output
and 𝑥 as the input format for discrete-time filters this becomes
35
𝑦[𝑛] = 𝐴𝑦[𝑛 − 1] +𝐾¡¡(𝑥[𝑛] − 𝐻𝐴𝑦[𝑛 − 1]).
(35)
This formula in the z-domain translates into
𝑌(𝑧) + 𝑌(𝑧)(𝐾𝐻𝐴 − 𝐴)𝑧D& = 𝐾¡¡𝑋(𝑧),
(36)
𝐻(𝑧) = 𝑌(𝑧)𝑋(𝑧),
(37)
𝐻(𝑧) = 𝐾¡¡
1 − 𝐴(1 − 𝐾𝐻)𝑧D&, (38)
Entering equation 38 as a dynamic system model into Matlab, the step response and
impulse response of the EMG Kalman filter can be found for a specific set of {𝑄, 𝑅, 𝐴, H} values.
The default values have been selected by heuristic method after seeing the output of the filter
operating on a diverse set of EMG records. They are “middle ground” values and by no means
represent the optimum ones for future recordings. They are {𝑄, 𝑅, 𝐴, H} = {0.05, 5, 1,1} and
their step response is shown in figure 19.
Figure 19. The EMG Kalman with default, “middle ground” parameter values has approximately the same rise time as a sliding RMS of size 25 at a sampling frequency of 1 kHz.
36
Figure 20. The impulse response of an IIR analog to the EMG Kalman filter using steady-state Kalman gain and error covariance values.
37
Figu
re 2
1. T
he fr
eque
ncy
resp
onse
of t
he II
R a
nalo
g to
the
EMG
Kal
man
filte
r usi
ng d
efau
lt pa
ram
eter
val
ues.
38
Here is a comparison of Kalman output for default versus optimized {𝑄, 𝑅, 𝐴, H} for an
EMG record. The parameter values were optimized manually to produce high SNR and they are
{𝑄, 𝑅, 𝐴, H} = {0.001,7,1,1}. Broadly speaking, a smaller Q will result in a lower-variance, tight
estimate, analogous to moving the corner frequency closer to zero, while also increasing the rise
time. Although the EMG Kalman filter performs well, the classic filter trade-off between
smoothness and responsiveness remains.
Figure 22. The impact of optimizing Kalman parameter values. Kalman Filter versus RMS SNR.
The Kalman filter provides a rapid response but a myoprocessor must be both fast and
sufficiently smooth. To calculate SNR of the filter and to gauge the frequency response of the
bandpass FIR filter implemented during this project, a series of 12 EMG recordings were made
in accordance with a variety of pre-selected arbitrary muscle contraction patterns. The author
performed and recorded all 12 contractions. The patterns were as follows with also a quiescent
and a maximum voluntary contraction recording.
39
Figure 23. Illustration of 10 muscle contraction patterns to be recorded for calculating SNR along with a quiescent and a maximum voluntary contraction record. The percentages indicated are percent of maximum voluntary contraction.
0%
50%
0%25%
0%
100%
0%10%
0%
50%
0%10%
100%
2𝑥
0%
0%
25%50%
75%100%
2𝑥
Meetings Page 1
40
Figu
re 2
4. E
xam
ples
of B
andp
ass,
Kal
man
, and
RM
S ou
tput
s for
4 o
f 12
EMG
reco
rds c
ompa
red
with
low
pass
“gr
ound
tru
th”
sign
al.
41
For each of the 12 recordings, a signal-to-noise ratio (SNR) was calculated for the EMG
Kalman filter having default parameter values and for sliding RMS of multiple window sizes.
The input for both was band-limited raw EMG with the passband being defined by 0-dB
frequencies at 22 and 405 Hz. For FIR design like that used for the bandpass filter, the LabView
interface is based on 0 dB frequencies as the “corner” frequencies instead of the typical 3 dB or 6
dB levels.
The SNR values were calculated using a formula based on the one found in Meek and
Fetherston [2]
𝑆𝑁𝑅 = ∑(𝐹𝑜𝑟𝑐𝑒)(
∑(𝐹𝑜𝑟𝑐𝑒 − 𝐸𝑀𝐺)(. (39)
Because no force measurements were made, it was decided to use a 2 Hz lowpass filter to
produce a “ground truth” signal against which the filtered EMG would be compared, based on a
method found in Menegaldo. [60] The closer a filtered signal approximates the lowpass line, the
better SNR it will have. For this reason, the values presented below probably are inflated
compared to the case where external force measurements are made. It is possible the Kalman
filter would still produce better SNR than RMS if an external measurement were used because
RMS results include both signal and noise whereas the Kalman filter approximates the amount of
noise and removes it from the final amplitude estimate.
𝑆𝑁𝑅 = 10 ∙ 𝑙𝑜𝑔&r �
∑(𝐿𝑜𝑤𝑝𝑎𝑠𝑠)(
∑(𝐿𝑜𝑤𝑝𝑎𝑠𝑠 − 𝐸𝑀𝐺)(� (40)
42
Figure 25. A comparison of “ground truth”—a term invented for this paper—force measurements and the associated EMG amplitude estimates having a time constant of 80 ms, which would correspond to a sliding RMS window of about 185 ms at a sampling frequency of 1 kHz. Copied from [2].
Here is an example of one of the records (“Dual Ramp Try 2”), alongside the Kalman and
RMS estimates as well as the lowpass signal. The SNR values were computed using the default
parameters for the Kalman filter.
Figure 26. Visualization of RMS and Kalman filter estimation of lowpass signal.
43
What is perhaps surprising is the variance of RMS 150 signal is about the same as that of
the Kalman filter even though the KF signal seems like its variance would be significantly
higher. In this specific case, 𝜎±^²&³r( = 8.3 ∙ 10D³ and 𝜎µ¶( = 7.3 ∙ 10D³. The level of the
variance of RMS 150 is attributed to its increased rise time, making for a longer time window
where the filtered signal is far from signal mean.
Averaged over the 12 contractions the SNRs were
Band-limited 3.90
RMS 25 11.76
RMS 75 12.29
RMS 150 12.13
Kalman 14.34
ProControl* 14.37
*The ProControl rectified and filtered output was attenuated by a factor of 20 to make the means of the ProControl and lowpass signals approximately match. Table 2. Signal-to-Noise ratios of various Myoprocessors averaged over 12 EMG records.
The reason for the RMS 150 average SNR being slightly lower than RMS 75 is unclear.
A key takeaway from table 2, however, is the Kalman outperformed all RMS window sizes
implemented and matched the ProControl output. Tacking on a short-sliding-window RMS to the
Kalman filter could improve SNR by over 10 percent, according to a single test calculation.
Another method for calculating SNRs also was attempted because it had been used by St-
Amant et al. [3] and Evans et al. [66] This formula for SNR is computed as the square root of the
ratio of the squared amplitude estimate sample mean divided by the amplitude estimate sample
variance. Or,
𝐸[𝑠(]&/( 𝜎⁄ . (41)
44
Here 𝐸[𝑠(] is the expectation value of sample variance and 𝜎 is the standard deviation of
the signal. The numbers produced by this method were seemingly too high (or too low after
taking logarithm), 80 (1.9) for example, so the previously discussed formula was used.
Incorporating an FIR Bandpass Filter to Focus on EMG Signal.
A signal pre-processing state implemented into the final algorithm was an FIR equiripple
bandpass filter designed in LabView. The goal was to eliminate DC noise, motion artifact, and to
produce an output having a frequency spectrum with much less noise while retaining significant
signal. According to De Luca et al., an EMG frequency filter ought to have a highpass 3-dB
corner frequency of 20 Hz and a lowpass corner frequency in the range of 400-450 Hz. [69] It
also should have a rolloff slope of 12 dB/octave. The bandpass filter used in this project is based
on these design requirements with the pass band having 0-dB frequencies of 20 and 405 Hz and a
rolloff slope of about 10 dB/octave in the transition region. The slope requirement was relaxed a
little to keep the filter order to a self-imposed order of 50. The equiripple approach was used
primarily because such filter design was found to be more user-friendly than window-based
FIRs.
45
Figu
re 2
7. T
he fr
eque
ncy
resp
onse
func
tion
of th
e ba
ndpa
ss F
IR fi
lter.
46
Figu
re 2
8. ( L
eft t
op) T
he im
puls
e re
spon
se o
f the
ban
dpas
s filt
er a
nd (R
ight
top)
the
step
resp
onse
. (Le
ft bo
ttom
) The
pha
se d
elay
is
the
amou
nt o
f del
ay a
filte
r int
rodu
ces a
t a p
artic
ular
freq
uenc
y. ( R
ight
bot
tom
) The
gro
up d
elay
is a
mea
sure
of h
ow c
onst
ant,
i.e. h
ow li
near
, is t
he p
hase
del
ay.
47
Figure 29. The Equiripple bandpass FIR configuration as designed in LabView.
A comb filter probably should be added to the algorithm in the future, as there was a
significant amount of power mains noise in the 12 EMG records used to determine the bandpass
frequency response function. The figures below show the frequency response functions before
and after bandpass filtering with no other processing.
Figure 30. Power spectra of 12 EMG records before and after bandlimiting. The equiripple design was effective.
48
Additionally, a feedback comb filter could be implemented to add power back into the
spectrum taken by the differential-filter behavior of bipolar electrodes although the dips shows in
figure 29 below are not as dramatic in figure 28 above. [42, 72] Such a filter would be simple to
realize but probably would need to be adaptable to specific inter-electrode distance. Insufficient
effort was put forth to produce meaningful results on the potential impact of a feedback comb
digital filter.
Figure 31. (Left) The filter function of bipolar surface electrodes for an electrode separation of 1 cm and assuming a nominal muscle fiber conduction velocity of 𝑣 = 4𝑚/𝑠. Its behavior is that of a feedforward comb filter. (Right) The impact this filter had on the power spectrum of an EMG record is seen in periodic dips also visible in figure 29.
Figure 32. EMG has well-established ideal spectrum shape. The jagged plot is the discrete Fourier transform estimate of the EMG power spectrum. The smooth plot is the 4th-order auto-regressive estimate of the spectrum. Copied from [71]
49
Figure 33. (Bottom) An idealized version of EMG frequency spectrum with parameters median frequency fmed, mean frequency fmean, and bandwidth designated. Copied from [31] The Rauch-Tung-Striebel Smoother.
In addition to computing the best possible estimate of the current system state given prior
data, it is possible to improve estimates and reduce estimator variance by incorporating all
measurements past and future; however, it is a data post-processing technique not intended for
real-time application. This method is called Bayesian smoothing, which is a type of forward-
backward algorithm. The closed form smoothing solution for linear gaussian models is called the
Rauch-Tung-Striebel (RTS) smoother. [57] It was pursued in this project out of curiosity and for
comparison with the EMG Kalman filter is shown below.
Figure 34. Comparison of Kalman filter and RTS smoother outputs using non-default values 𝑄 =0.001 and 𝑅 = 10 for lower-variance output.
50
The smoother performs well and probably contains more high-frequency information
than the 2-Hz lowpass signal, making it respond earlier to amplitude change. For this particular
signal the SNR of RTS output was about 12-percent higher than that of the Kalman filter but this
increase depended on parameter values 𝑄 and 𝑅. For default parameter values, RTS’s SNR was
only 1-percent higher.
Conclusion.
Overall, the goals set for this project were met with success. Namely, the development of
a responsive and sufficiently smooth EMG amplitude estimation algorithm. There is work to be
done in terms of developing reliable and effective algorithms for determining parameters values
𝑄, 𝑅, 𝐴, and 𝐻 as well as for finding an appropriate set of equations to implement into the process
model𝐴. The EMG Kalman filter will be of use in myoelectric control because of its rapid and
accurate capabilities. A few filter add-ons were suggested, to include a feedback comb filter. A
short-window sliding RMS processor could be added onto the Kalman filter to improve SNR
even more if control lag remained satisfactory.
51
MATLAB Code emgKalmanVector.m function [x,P,xf,Pf] = emgKalmanVector(y,P0,x0) N = length(y); if (N < 2) || (size(y,1) > 1 && size(y,2) > 1) msg = 'y may only be a vector with length > 1'; error(msg) end Q = .001; R = 5; I = 1; A = 1; H = 1; P = zeros(1,N); x = zeros(1,N); switch nargin case 1 P(1) = 1; x(1) = y(1); case 2 P(1) = P0; x(1) = y(1); case 3 P(1) = P0; x(1) = x0; otherwise msg = 'Inputs are not correct'; error(msg) end for i = 1:N-1 P(i+1) = A*P(i)*A + Q; K = P(i+1)*H/(H*P(i+1)*H + R); P(i+1) = (I - K*H)*P(i+1); x(i+1) = A*x(i) + K*(y(i+1) - H*A*x(i)); end Pf = P(N); xf = x(N); end emgKalmanPtbyPt.m function [x, K, P] = emgKalmanPtbyPt(x, y, P, Q, R, A, H) P = A*P*A + Q; K = P*H/(H*P*H + R); P = (1 - K*H)*P; x = A*x + K*(y - H*A*x);
52
end IIRfind.m fs = 1000; dt = 1/fs; z = tf('z',dt); Q = 0.001; R = 5; A = 1; H = 1; % need EMG input for y [x,K] = emgKalmanIIRfind(y,Q,R,A,H); t = 0:dt:1; H = K/(1 + A*(K*H-1)*z^-1); figure impulse(H,t); figure [y_step,t_step] = step(H,t); freqs = 0:500; frf = frd(H,freqs,'Hz'); response = squeeze(frf.ResponseData); response = abs(response); response = log10(response); figure plot(freqs,response); title('Frequency Response Function of KF') emgKalmanIIRfind.m function [x,K] = emgKalmanIIRfind(y,Q,R,A,H) N = length(y); if (N < 2) || (size(y,1) > 1 && size(y,2) > 1) msg = 'y may only be a vector with length > 1'; error(msg) end P = zeros(1,N); x = zeros(1,N); P(1) = 1; x(1) = y(1); I = 1; for i = 1:N-1 P(i+1) = A*P(i)*A + Q;
53
K = P(i+1)*H/(H*P(i+1)*H + R); P(i+1) = (I - K*H)*P(i+1); x(i+1) = A*x(i) + K*(y(i+1) - H*A*x(i)); end % Pf = P(N); % xf = x(N); end burchLowpassForSNR.m % need EMG input y d = designfilt('lowpassiir', 'PassbandFrequency', 2, 'StopbandFrequency', 5, 'PassbandRipple', 1, 'StopbandAttenuation', 60, 'SampleRate', 1000); lp = filtfilt(d,abs(y)); emgKalmanSmoother.m function [xSm, x] = emgKalmanSmoother(y, Q, R, A, H) N = length(y); if (N < 2) || (size(y,1) > 1 && size(y,2) > 1) msg = 'y may only be a vector with length > 1'; error(msg) end switch nargin case 1 Q = .001; R = 5; A = 1; H = 1; case 2 R = 5; A = 1; H = 1; case 3 A = 1; H = 1; case 4 H = 1; case 5 otherwise msg = 'Inputs are not correct'; error(msg) end eps = zeros(1,N); P = zeros(1,N); P(1) = 1; V = zeros(1,N); V(1) = 1;
54
K = zeros(1,N); K(1) = 1; x = zeros(1,N); x(1) = y(1); xIB = zeros(1,N); % in-between xIB(1) = x(1); for i = 1:N-1 % prediction xIB(i+1) = A*x(i); V(i+1) = A*P(i)*A + Q; % update K(i+1) = V(i+1)*H/(H*V(i+1)*H + R); P(i+1) = (1 - K(i+1)*H)*V(i+1); eps(i+1) = y(i+1) - H*xIB(i+1); x(i+1) = xIB(i+1) + K(i+1)*eps(i+1); end J = zeros(1,N); xSm = zeros(1,N); xSm(N) = x(N); % Smoother for i = 1:N-1 k = N-(i-1); J(k-1) = P(k-1)*A'*V(k)^(-1); xSm(k-1) = x(k-1) + J(k-1)*(xSm(k) - (x(k-1) - K(k-1)*eps(k-1))); end end emgBandpass.m function band_y = emgBandpass(y) bpCoefficients = [-0.00348291, -0.0287043, -0.0332166, 0.0145718, -0.0368817, 0.0102642, -0.0327594, -0.00469909, -0.0164771, -0.0278803, -0.000200483, -0.0406399, -0.00324646, -0.0287632, -0.0297156, -0.00097259, -0.0578426, 0.0118232, -0.0538653, -0.018979, -0.00152817, -0.091767, 0.0781205, -0.168753, 0.137508, 0.79827, ... 0.137508, -0.168753, 0.0781205, -0.091767, -0.00152817, -0.018979, -0.0538653, 0.0118232, -0.0578426,-0.00097259, -0.0297156, -0.0287632, -0.00324646, -0.0406399, -0.000200483, -0.0278803,-0.0164771,-0.00469909,-0.0327594, 0.0102642, -0.0368817, 0.0145718,-0.0332166, -0.0287043, -0.00348291]; if size(y,1) > size(y,2) y = y'; tflag = 1; end
55
if (size(y,1) > 1 && size(y,2) > 1) msg = 'y cannot be a matrix'; error(msg) end M = length(bpCoefficients); N = length(y); z = zeros(1,M-1); % pad with zeros y = [z y]; band_y = zeros(1,N); for i = 1:N band_y(i) = dot(bpCoefficients,y(i:i+(M-1))); end if tflag band_y = band_y'; end end
56
Arduino Code emgKalman.ino #include <CircularBuffer.h> #define buffLen 51 #define SAMPLE_PIN A2 #define PWM_out 25 double bpCoefficients[buffLen] = {-0.00348291, -0.0287043, -0.0332166, 0.0145718, -0.0368817, 0.0102642, -0.0327594, -0.00469909, -0.0164771, -0.0278803, -0.000200483, -0.0406399, -0.00324646, -0.0287632, -0.0297156, -0.00097259, -0.0578426, 0.0118232, -0.0538653, -0.018979, -0.00152817, -0.091767, 0.0781205, -0.168753, 0.137508, 0.79827, 0.137508, -0.168753, 0.0781205, -0.091767, -0.00152817, -0.018979, -0.0538653, 0.0118232, -0.0578426,-0.00097259, -0.0297156, -0.0287632, -0.00324646, -0.0406399, -0.000200483, -0.0278803,-0.0164771,-0.00469909,-0.0327594, 0.0102642, -0.0368817, 0.0145718,-0.0332166, -0.0287043, -0.00348291}; //symmetric about median. CircularBuffer<double, buffLen> buffer1; double bandpass(double coefficients[buffLen], double passArray[buffLen], double bpOut) { double output = 0; //Bandpass filter the data for (int i = 0; i < buffLen; i++){ output += passArray[i]*coefficients[i]; } bpOut = output; return bpOut; } unsigned long microtime; unsigned long chk; int reading = 0; int ct = 0; bool flg = 0; double bpOut; double bufferArray[buffLen] = { 0 };
57
//play around with these parameters: Q, R, A, H double Q = 0.001; //process noise, smaller value gives smoother output but longer rise time; double R = 5; //measurement noise; aggregate noise estimator. double A = 1; //process model; 1 is "straight line" model. double H = 1; //measurement model double I = 1; double K; //Kalman gain struct kParams { //kalman filter requires a structure b/c of feedback of two parameters double Pval; //error covariance double Xval; //Kalman estimate } k3,k4; struct kParams kalman(struct kParams k1, struct kParams k2, double bpScalar) { double eps = 0; //difference between predicted and measured double P = k1.Pval; double x = k1.Xval; //prediction x = A*x; P = A*P*A + Q; eps = bpScalar - H*x; //update K = P*H/(H*P*H + R); P = (I - K*H)*P; x = x + K*eps; k2.Pval = P; k2.Xval = x; return k2; }; void setup() { analogReadResolution(12); //12-bit ADC on Due. analogWrite(PWM_out,0); delay(100); //Make sure motor is stopped microtime = micros(); } void loop() { chk = micros(); if (chk - microtime > 999) { // sample every 1000 microseconds microtime = micros(); ct+=1;
58
reading = analogRead(SAMPLE_PIN); buffer1.push(reading); if (buffer1.isFull()) { //copy array for passing to function for (int i = 0; i < buffLen; i++){ bufferArray[i] = buffer1[i]; } //bandlimit the data bpOut = 0; bpOut = bandpass(bpCoefficients, bufferArray, bpOut); bpOut = abs(bpOut); if (!flg) { flg = !flg; k3.Pval = 1; k3.Xval = bpOut; } else { k3 = k4; } k4 = kalman(k3, k4, bpOut); //output data point as PWM and use y = mx + b approach to calibrate desired control for user-motor combination, where m = gain and b = offset. double driveVal = k4.Xval; double gain = 3; double offset = 30; driveVal = map(pX,0,4095, 0,255); //Due map // driveVal = map(pX,0,1023, 0,255); //Uno map driveVal *= gain; driveVal += offset; analogWrite(PWM_out,driveVal); } // (buffer1.isFull()) } // (chk - microtime > 999) } // void loop emgKalmanSmoother.ino #include <CircularBuffer.h> #define buffLen 51
59
#define smLen 20 #define SAMPLE_PIN A2 #define PWM_out 25 unsigned long microtime; unsigned long chk; double bpCoefficients[buffLen] = {-0.00348291, -0.0287043, -0.0332166, 0.0145718, -0.0368817, 0.0102642, -0.0327594, -0.00469909, -0.0164771, -0.0278803, -0.000200483, -0.0406399, -0.00324646, -0.0287632, -0.0297156, -0.00097259, -0.0578426, 0.0118232, -0.0538653, -0.018979, -0.00152817, -0.091767, 0.0781205, -0.168753, 0.137508, 0.79827, 0.137508, -0.168753, 0.0781205, -0.091767, -0.00152817, -0.018979, -0.0538653, 0.0118232, -0.0578426,-0.00097259, -0.0297156, -0.0287632, -0.00324646, -0.0406399, -0.000200483, -0.0278803,-0.0164771,-0.00469909,-0.0327594, 0.0102642, -0.0368817, 0.0145718,-0.0332166, -0.0287043, -0.00348291}; //symmetric about median. CircularBuffer<double, buffLen> bufferBP; double bandpass(double coefficients[buffLen], double passArray[buffLen], double bpOut) { double output = 0; //Bandpass filter the data for (int i = 0; i < buffLen; i++){ output += passArray[i]*coefficients[i]; } bpOut = output; return bpOut; } int reading = 0; int smInd = 0; bool flg = 0; double SMarr[smLen]; double bufferArray[buffLen]; double bpOut; double I = 1; //parameters: Q, R, A, H double Q = 0.03; double R = 10;
60
double A = 1; double H = 1; struct kParams { double Vval, // error covariance mid-calculation Pval, //error covariance result Kval, //Kalman gain EPSval, //difference between measurement and prediction. Jval, //backwards (inverse) Kalman gain? Xval, //Kalman estimate XSMval; //smoothed Kalman estimate }; struct kParams kalmanFW(struct kParams kFW_1, struct kParams kFW_2, double y) { //y is measurement // Kalman forward double V, P, K, EPS, J, X, XSM; V = kFW_1.Vval; P = kFW_1.Pval; X = kFW_1.Xval; K = kFW_1.Kval; EPS = kFW_1.EPSval; XSM = kFW_1.XSMval; J = kFW_1.Jval; V = A*P*A + Q; K = V*H/(H*V*H + R); EPS = y - H*A*X; X = A*X + K*EPS; P = (I - K*H)*V; kFW_2.Vval = V; kFW_2.Pval = P; kFW_2.Xval = X; kFW_2.Kval = K; kFW_2.EPSval = EPS; kFW_2.XSMval = XSM; kFW_2.Jval = J; return kFW_2; } struct kParams kalmanBW(struct kParams kBW_1, struct kParams kBW_2) { // Kalman backward/smoother double J, K, EPS, P, V, X, XSM; XSM = kBW_2.XSMval; // i+1 V = kBW_2.Vval; // i+1
61
X = kBW_1.Xval; K = kBW_1.Kval; EPS = kBW_1.EPSval; P = kBW_1.Pval; J = kBW_1.Jval; J = P*A/V; XSM = X + J*(XSM - A*X); kBW_1.XSMval = XSM; kBW_1.Jval = J; kBW_1.Vval = V; kBW_1.Xval = X; kBW_1.Kval = K; kBW_1.EPSval = EPS; kBW_1.Pval = P; return kBW_1; } kParams kFW[smLen], kBW[smLen], kFW_input1, kFW_input2; double y; void setup() { pinMode(PWM_out,OUTPUT); // for PWM output analogReadResolution(12); //Due only microtime = micros(); } void loop() { chk = micros(); if (chk - microtime > 999) { microtime = micros(); reading = analogRead(SAMPLE_PIN); bufferBP.push(reading); if (bufferBP.isFull()) { //copy array for passing for (int i = 0; i < buffLen; i++){ bufferArray[i] = bufferBP[i]; } //bandlimit the data bpOut = 0; bpOut = bandpass(bpCoefficients, bufferArray, bpOut); bpOut = abs(bpOut);
62
SMarr[smInd] = bpOut; smInd+=1; if (smInd == smLen) { smInd = 0; if (!flg) { //initial conditions very first time Kalman is run; really, only Pval and Xval must be set but others set just in case something unpredicted happens kFW[0].Xval = SMarr[0]; kFW[0].Kval = 1; kFW[0].EPSval = 0; kFW[0].Pval = 1; kFW[0].Vval = 1; kFW[0].XSMval = 0; kFW[0].Jval = 0; flg = !flg; } else { kFW_input1 = kFW[0]; kFW_input2 = kFW[0]; kFW[0] = kalmanFW(kFW_input1, kFW_input2, SMarr[0]); kFW[0] = kalmanBW(kFW[0],kFW_input2); } for (int i = 0; i < smLen - 1; i++) { //can't run up to i < smLen b/c of i+1 indexing y = SMarr[i+1]; kFW_input1 = kFW[i]; kFW_input2 = kFW[i+1]; kFW[i+1] = kalmanFW(kFW_input1, kFW_input2, y); kBW[i+1] = kFW[i+1]; } //for loop kBW[0] = kFW[0]; kBW[smLen-1].XSMval = kFW[smLen-1].Xval; for (int i = smLen - 2; i > -1; i--) { //backwards! kFW_input1 = kBW[i]; kFW_input2 = kBW[i+1]; kBW[i] = kalmanBW(kFW_input1,kFW_input2); } //for loop double Gain = 3; double offset = 30; for (int i = 0; i < smLen; i++) { double pXSM = kBW[i].XSMval; pXSM = map(pXSM,0,4095, 0,255); //map 0 to 1023 on Uno. pXSM *= Gain; pXSM += offset; Serial.println(pXSM,5);
63
analogWrite(PWM_out,pXSM); delayMicroseconds(900); //output frequency should approximate input frequency, accounting for calculation time that has passed. } kFW[0] = kBW[smLen-1]; } // (smInd == smLen) } //(bufferBP.isFull()) } //(chk - microtime > 999) } //loop() emgKalman_2Ch.ino #include <CircularBuffer.h> #define buffLen 51 #define ch1 A0 #define ch2 A1 #define PWM_pin 38 #define ch1_enable 47 #define ch2_enable 53 double bpCoefficients[buffLen] = {-0.00348291, -0.0287043, -0.0332166, 0.0145718, -0.0368817, 0.0102642, -0.0327594, -0.00469909, -0.0164771, -0.0278803, -0.000200483, -0.0406399, -0.00324646, -0.0287632, -0.0297156, -0.00097259, -0.0578426, 0.0118232, -0.0538653, -0.018979, -0.00152817, -0.091767, 0.0781205, -0.168753, 0.137508, 0.79827, 0.137508, -0.168753, 0.0781205, -0.091767, -0.00152817, -0.018979, -0.0538653, 0.0118232, -0.0578426,-0.00097259, -0.0297156, -0.0287632, -0.00324646, -0.0406399, -0.000200483, -0.0278803,-0.0164771,-0.00469909,-0.0327594, 0.0102642, -0.0368817, 0.0145718,-0.0332166, -0.0287043, -0.00348291}; //symmetric about median. CircularBuffer<double, buffLen> buffer_ch1; CircularBuffer<double, buffLen> buffer_ch2; double bandpass(double coefficients[buffLen], double passArray[buffLen], double bpOut) { double output = 0; //Bandpass filter the data for (int i = 0; i < buffLen; i++){ output += passArray[i]*coefficients[i];
64
} bpOut = output; return bpOut; } unsigned long microtime; unsigned long chk; int reading_ch1 = 0; int reading_ch2 = 0; int ct = 0; bool flg = 0; double bpOut; double bufferArray[buffLen] = {0}; //play around with these parameters: Q, R, A, H double Q = 0.001; //process noise, smaller value gives smoother output but longer rise time; double R = 5; //measurement noise; aggregate noise estimator. double A = 1; //process model; 1 is "straight line" model. double H = 1; //measurement model double I = 1; double K; //Kalman gain struct kParams { //kalman filter requires a structure b/c of feedback of two parameters double Pval; //error covariance double Xval; //Kalman estimate } k1,k2,k3,k4; struct kParams kalman(struct kParams k1, struct kParams k2, double bpScalar) { double eps = 0; //difference between predicted and measured double P = k1.Pval; double x = k1.Xval; //prediction x = A*x; P = A*P*A + Q; eps = bpScalar - H*x; //update K = P*H/(H*P*H + R); P = (I - K*H)*P; x = x + K*eps; k2.Pval = P; k2.Xval = x;
65
return k2; }; void setup() { analogReadResolution(12); //12-bit ADC on Due. pinMode(PWM_pin,OUTPUT); pinMode(ch1_enable,OUTPUT); pinMode(ch2_enable,OUTPUT); analogWrite(PWM_pin,0); delay(100); //Make sure motor is stopped for (int i = 0; i < buffLen; i++) { buffer_ch1.push(0); buffer_ch2.push(0); } microtime = micros(); // Serial.begin(9600); } bool trigger_ch1 = 0; bool trigger_ch2 = 0; // on > off int onThresh = 2000; int offThresh = 1500; int zero = 0; double offset_ch1 = 30; double offset_ch2 = 0; double A_gain = 6; double B_gain = 1; void loop() { double A = 0; double B = 0; chk = micros(); if (chk - microtime > 999) { // sample every 1000 microseconds microtime = micros(); ct+=1; reading_ch1 = analogRead(ch1); reading_ch2 = analogRead(ch2); buffer_ch1.push(reading_ch1);
66
buffer_ch2.push(reading_ch2); if (buffer_ch1.isFull()) { //copy array for passing to function for (int i = 0; i < buffLen; i++) bufferArray[i] = buffer_ch1[i]; //bandlimit the data bpOut = 0; bpOut = bandpass(bpCoefficients, bufferArray, bpOut); bpOut = abs(bpOut); if (!flg) { flg = !flg; k1.Pval = 1; k1.Xval = bpOut; } else { k1 = k2; } k2 = kalman(k1, k2, bpOut); A = k2.Xval; A *= A_gain; if (A > onThresh) trigger_ch1 = 1; } // (buffer_ch1.isFull()) if (buffer_ch2.isFull()) { //copy array for passing to function for (int i = 0; i < buffLen; i++) bufferArray[i] = buffer_ch2[i]; //bandlimit the data bpOut = 0; bpOut = bandpass(bpCoefficients, bufferArray, bpOut); bpOut = abs(bpOut); if (!flg) { flg = !flg; k3.Pval = 1; k3.Xval = bpOut; } else { k3 = k4; }
67
k4 = kalman(k3, k4, bpOut); B = k4.Xval; B *= B_gain; if (B > onThresh) trigger_ch2 = 1; } // (buffer_ch2.isFull()) // int drive_ch1 = (int) A; // drive_ch1 = map(drive_ch1,0,4095, 0,255); //Due map // drive_ch1 += offset_ch1; // if (drive_ch1 > 255) drive_ch1 = 255; // // int drive_ch2 = (int) B; // drive_ch2 = map(drive_ch2,0,4095, 0,255); //Due map // drive_ch2 += offset_ch2; // if (drive_ch2 > 255) drive_ch2 = 255; // Serial.print(drive_ch1); // Serial.print(","); // Serial.println(drive_ch2); //output data point as PWM and use y = mx + b approach to calibrate desired control for user-motor combination, where m = gain and b = offset. if ((A >= B) && (trigger_ch1)) { int drive_ch1 = (int) A; drive_ch1 = map(drive_ch1,0,4095, 0,255); //Due map drive_ch1 += offset_ch1; digitalWrite(ch2_enable,LOW); digitalWrite(ch1_enable,HIGH); if (drive_ch1 > 255) drive_ch1 = 255; analogWrite(PWM_pin,drive_ch1); if (A <= offThresh) trigger_ch1 = 0; } else if ((B > A) && (trigger_ch2)) { int drive_ch2 = (int) B; drive_ch2 = map(drive_ch2,0,4095, 0,255); //Due map drive_ch2 += offset_ch2; digitalWrite(ch1_enable,LOW); digitalWrite(ch2_enable,HIGH); if (drive_ch2 > 255) drive_ch2 = 255; analogWrite(PWM_pin,drive_ch2); if (B <= offThresh) trigger_ch2 = 0; } else { digitalWrite(ch2_enable,LOW); digitalWrite(ch1_enable,LOW);
68
} } // (chk - microtime > 999) } // void loop RMS_2Ch.ino #include <CircularBuffer.h> #define buffLen 51 #define rmsLen 250 #define ch1 A0 #define ch2 A1 #define PWM_pin 38 #define ch1_enable 47 #define ch2_enable 53 double bpCoefficients[buffLen] = {-0.00348291, -0.0287043, -0.0332166, 0.0145718, -0.0368817, 0.0102642, -0.0327594, -0.00469909, -0.0164771, -0.0278803, -0.000200483, -0.0406399, -0.00324646, -0.0287632, -0.0297156, -0.00097259, -0.0578426, 0.0118232, -0.0538653, -0.018979, -0.00152817, -0.091767, 0.0781205, -0.168753, 0.137508, 0.79827, 0.137508, -0.168753, 0.0781205, -0.091767, -0.00152817, -0.018979, -0.0538653, 0.0118232, -0.0578426,-0.00097259, -0.0297156, -0.0287632, -0.00324646, -0.0406399, -0.000200483, -0.0278803,-0.0164771,-0.00469909,-0.0327594, 0.0102642, -0.0368817, 0.0145718,-0.0332166, -0.0287043, -0.00348291}; //symmetric about median. CircularBuffer<double, buffLen> buffer_ch1; CircularBuffer<double, buffLen> buffer_ch2; CircularBuffer<double, rmsLen> bufferRMS_ch1; CircularBuffer<double, rmsLen> bufferRMS_ch2; double bandpass(double coefficients[buffLen], double passArray[buffLen], double bpOut) { double output = 0; //Bandpass filter the data for (int i = 0; i < buffLen; i++){ output += passArray[i]*coefficients[i]; } bpOut = output; return bpOut; } unsigned long microtime;
69
unsigned long chk; int reading_ch1 = 0; int reading_ch2 = 0; int ct = 0; bool flg = 0; double bpOut; double bufferArray[buffLen] = {0}; double rmsArray[rmsLen] = {0}; void setup() { analogReadResolution(12); //12-bit ADC on Due. pinMode(PWM_pin,OUTPUT); pinMode(ch1_enable,OUTPUT); pinMode(ch2_enable,OUTPUT); analogWrite(PWM_pin,0); delay(100); //Make sure motor is stopped for (int i = 0; i < buffLen; i++) { buffer_ch1.push(0); buffer_ch2.push(0); } for (int i = 0; i < rmsLen; i++) { bufferRMS_ch1.push(0); bufferRMS_ch2.push(0); } microtime = micros(); Serial.begin(9600); } bool trigger_ch1 = 0; bool trigger_ch2 = 0; // on > off int onThresh = 2000; int offThresh = 1500; int zero = 0; double offset_ch1 = 0; double offset_ch2 = 0; double A_gain = 1; double B_gain = 1;
70
void loop() { double A = 0; double B = 0; chk = micros(); if (chk - microtime > 999) { // sample every 1000 microseconds microtime = micros(); ct+=1; reading_ch1 = analogRead(ch1); reading_ch2 = analogRead(ch2); buffer_ch1.push(reading_ch1); buffer_ch2.push(reading_ch2); if (buffer_ch1.isFull()) { //copy array for passing to function for (int i = 0; i < buffLen; i++) bufferArray[i] = buffer_ch1[i]; //bandlimit the data bpOut = 0; bpOut = bandpass(bpCoefficients, bufferArray, bpOut); bpOut = abs(bpOut); bufferRMS_ch1.push(bpOut); if (bufferRMS_ch1.isFull()) { for (int i = 0; i < rmsLen; i++) rmsArray[i] = bufferRMS_ch1[i]; double rms_ch1 = 0; for (int i = 0; i < rmsLen; i++) rms_ch1 += sq(rmsArray[i]); rms_ch1 /= rmsLen; rms_ch1 = sqrt(rms_ch1); A = rms_ch1; A *= A_gain; if (A > onThresh) trigger_ch1 = 1; } } // (buffer_ch1.isFull()) if (buffer_ch2.isFull()) { //copy array for passing to function for (int i = 0; i < buffLen; i++) bufferArray[i] = buffer_ch2[i]; //bandlimit the data bpOut = 0;
71
bpOut = bandpass(bpCoefficients, bufferArray, bpOut); bpOut = abs(bpOut); bufferRMS_ch2.push(bpOut); if (bufferRMS_ch2.isFull()) { for (int i = 0; i < rmsLen; i++) rmsArray[i] = bufferRMS_ch2[i]; double rms_ch2 = 0; for (int i = 0; i < rmsLen; i++) rms_ch2 += sq(rmsArray[i]); rms_ch2 /= rmsLen; rms_ch2 = sqrt(rms_ch2); B = rms_ch2; B *= B_gain; if (B > onThresh) trigger_ch2 = 1; } } // (buffer_ch2.isFull()) int drive_ch1 = (int) A; drive_ch1 = map(drive_ch1,0,4095, 0,255); //Due map drive_ch1 += offset_ch1; if (drive_ch1 > 255) drive_ch1 = 255; int drive_ch2 = (int) B; drive_ch2 = map(drive_ch2,0,4095, 0,255); //Due map drive_ch2 += offset_ch2; if (drive_ch2 > 255) drive_ch2 = 255; Serial.print(drive_ch1); Serial.print(","); Serial.println(drive_ch2); //output data point as PWM and use y = mx + b approach to calibrate desired control for user-motor combination, where m = gain and b = offset. //if ((A >= B) && (trigger_ch1)) { // int drive_ch1 = (int) A; // drive_ch1 = map(drive_ch1,0,4095, 0,255); //Due map // drive_ch1 += offset_ch1; // digitalWrite(ch2_enable,LOW); // digitalWrite(ch1_enable,HIGH); // // if (drive_ch1 > 255) drive_ch1 = 255; // analogWrite(PWM_pin,drive_ch1); // if (A <= offThresh) trigger_ch1 = 0; //} //
72
//else if ((B > A) && (trigger_ch2)) { // int drive_ch2 = (int) B; // drive_ch2 = map(drive_ch2,0,4095, 0,255); //Due map // drive_ch2 += offset_ch2; // digitalWrite(ch1_enable,LOW); // digitalWrite(ch2_enable,HIGH); // // if (drive_ch2 > 255) { // drive_ch2 = 255; // } // analogWrite(PWM_pin,drive_ch2); // // if (B <= offThresh) { // trigger_ch2 = 0; // } //} //else { // digitalWrite(ch2_enable,LOW); // digitalWrite(ch1_enable,LOW); //} } // (chk - microtime > 999) } // void loop The code for the circular buffer was taken from https://github.com/rlogiacco/CircularBuffer. The files CircularBuffer.h and CircularBuffer.tpp must be added to your Arduino library before running any of the Kalman filter or RMS ino files. If you have the entire CircularBuffer-master folder, add that to your library instead. CircularBuffer.h /* CircularBuffer.h - Circular buffer library for Arduino. Copyright (c) 2017 Roberto Lo Giacco. This program is free software: you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
73
You should have received a copy of the GNU General Public License along with this program. If not, see <http://www.gnu.org/licenses/>. */ #ifndef __CIRCULAR_BUFFER__ #define __CIRCULAR_BUFFER__ #include <inttypes.h> #ifndef CIRCULAR_BUFFER_XS #define __CB_ST__ uint16_t #else #define __CB_ST__ uint8_t #endif #ifdef CIRCULAR_BUFFER_DEBUG #include <Print.h> #endif template<typename T, __CB_ST__ S> class CircularBuffer { public: CircularBuffer(); ~CircularBuffer(); /** * Adds an element to the beginning of buffer: the operation returns `false` if the addition caused overwriting an existing element. */ bool unshift(T value); /** * Adds an element to the end of buffer: the operation returns `false` if the addition caused overwriting an existing element. */ bool push(T value); /** * Removes an element from the beginning of the buffer. */ T shift(); /**
74
* Removes an element from the end of the buffer. */ T pop(); /** * Returns the element at the beginning of the buffer. */ T inline first(); /** * Returns the element at the end of the buffer. */ T inline last(); /** * Array-like access to buffer */ T operator [] (__CB_ST__ index); /** * Returns how many elements are actually stored in the buffer. */ __CB_ST__ inline size(); /** * Returns how many elements can be safely pushed into the buffer. */ __CB_ST__ inline available(); /** * Returns how many elements can be potentially stored into the buffer. */ __CB_ST__ inline capacity(); /** * Returns `true` if no elements can be removed from the buffer. */ bool inline isEmpty(); /** * Returns `true` if no elements can be added to the buffer without overwriting existing elements.
75
*/ bool inline isFull(); /** * Resets the buffer to a clean status, making all buffer positions available. */ void inline clear(); #ifdef CIRCULAR_BUFFER_DEBUG void inline debug(Print* out); void inline debugFn(Print* out, void (*printFunction)(Print*, T)); #endif private: T buffer[S]; T *head; T *tail; #ifndef CIRCULAR_BUFFER_INT_SAFE __CB_ST__ count; #else volatile __CB_ST__ count; #endif }; #include <CircularBuffer.tpp> #endif CircularBuffer.tpp /* CircularBuffer.tpp - Circular buffer library for Arduino. Copyright (c) 2017 Roberto Lo Giacco. This program is free software: you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License
76
along with this program. If not, see <http://www.gnu.org/licenses/>. */ #include <string.h> template<typename T, __CB_ST__ S> CircularBuffer<T,S>::CircularBuffer() : head(buffer), tail(buffer), count(0) { } template<typename T, __CB_ST__ S> CircularBuffer<T,S>::~CircularBuffer() { } template<typename T, __CB_ST__ S> bool CircularBuffer<T,S>::unshift(T value) { if (head == buffer) { head = buffer + S; } *--head = value; if (count == S) { if (tail-- == buffer) { tail = buffer + S - 1; } return false; } else { if (count++ == 0) { tail = head; } return true; } } template<typename T, __CB_ST__ S> bool CircularBuffer<T,S>::push(T value) { if (++tail == buffer + S) { tail = buffer; } *tail = value; if (count == S) { if (++head == buffer + S) { head = buffer; } return false;
77
} else { if (count++ == 0) { head = tail; } return true; } } template<typename T, __CB_ST__ S> T CircularBuffer<T,S>::shift() { void(* crash) (void) = 0; if (count <= 0) crash(); T result = *head++; if (head >= buffer + S) { head = buffer; } count--; return result; } template<typename T, __CB_ST__ S> T CircularBuffer<T,S>::pop() { void(* crash) (void) = 0; if (count <= 0) crash(); T result = *tail--; if (tail < buffer) { tail = buffer + S - 1; } count--; return result; } template<typename T, __CB_ST__ S> T inline CircularBuffer<T,S>::first() { return *head; } template<typename T, __CB_ST__ S> T inline CircularBuffer<T,S>::last() { return *tail; } template<typename T, __CB_ST__ S> T CircularBuffer<T,S>::operator [](__CB_ST__ index) {
78
return *(buffer + ((head - buffer + index) % S)); } template<typename T, __CB_ST__ S> __CB_ST__ inline CircularBuffer<T,S>::size() { return count; } template<typename T, __CB_ST__ S> __CB_ST__ inline CircularBuffer<T,S>::available() { return S - count; } template<typename T, __CB_ST__ S> __CB_ST__ inline CircularBuffer<T,S>::capacity() { return S; } template<typename T, __CB_ST__ S> bool inline CircularBuffer<T,S>::isEmpty() { return count == 0; } template<typename T, __CB_ST__ S> bool inline CircularBuffer<T,S>::isFull() { return count == S; } template<typename T, __CB_ST__ S> void inline CircularBuffer<T,S>::clear() { head = tail = buffer; count = 0; } #ifdef CIRCULAR_BUFFER_DEBUG template<typename T, __CB_ST__ S> void inline CircularBuffer<T,S>::debug(Print* out) { for (__CB_ST__ i = 0; i < S; i++) { int hex = (int)buffer + i; out->print(hex, HEX); out->print(" "); out->print(*(buffer + i)); if (head == buffer + i) { out->print(" head");
79
} if (tail == buffer + i) { out->print(" tail"); } out->println(); } } template<typename T, __CB_ST__ S> void inline CircularBuffer<T,S>::debugFn(Print* out, void (*printFunction)(Print*, T)) { for (__CB_ST__ i = 0; i < S; i++) { int hex = (int)buffer + i; out->print(hex, HEX); out->print(" "); printFunction(out, *(buffer + i)); if (head == buffer + i) { out->print(" head"); } if (tail == buffer + i) { out->print(" tail"); } out->println(); } } #endif
80
References 1. Farrell, T.R. and R.F. Weir, The optimal controller delay for myoelectric prostheses. IEEE
Trans Neural Syst Rehabil Eng, 2007. 15(1): p. 111-8. 2. Meek, S.G. and S.J. Fetherston, Comparison of signal-to-noise ratio of myoelectric filters
for prosthesis control. J Rehabil Res Dev, 1992. 29(4): p. 9-20. 3. St-Amant, Y., D. Rancourt, and E.A. Clancy, Influence of smoothing window length on
electromyogram amplitude estimates. IEEE Trans Biomed Eng, 1998. 45(6): p. 795-800. 4. Ziegler-Graham, K., et al., Estimating the prevalence of limb loss in the United States:
2005 to 2050. Arch Phys Med Rehabil, 2008. 89(3): p. 422-9. 5. Dillingham, T.R., L.E. Pezzin, and E.J. MacKenzie, Limb amputation and limb deficiency:
epidemiology and recent trends in the United States. South Med J, 2002. 95(8): p. 875-83.
6. Mooney, R.L., The Handbook, Information for New Upper Extremity Amputees, Their Families, and Friends. 1995: The Mutual Amputee Aid Foundation.
7. Ekblom, A.G., T. Laurell, and M. Arner, Epidemiology of congenital upper limb anomalies in 562 children born in 1997 to 2007: a total population study from stockholm, sweden. J Hand Surg Am, 2010. 35(11): p. 1742-54.
8. Parker, S.E., et al., Updated National Birth Prevalence estimates for selected birth defects in the United States, 2004-2006. Birth Defects Res A Clin Mol Teratol, 2010. 88(12): p. 1008-16.
9. Vasluian, E., et al., Opinions of youngsters with congenital below-elbow deficiency, and those of their parents and professionals concerning prosthetic use and rehabilitation treatment. PLoS One, 2013. 8(6): p. e67101.
10. Davids, J.R., et al., Prosthetic management of children with unilateral congenital below-elbow deficiency. J Bone Joint Surg Am, 2006. 88(6): p. 1294-300.
11. Biddiss, E., D. Beaton, and T. Chau, Consumer design priorities for upper limb prosthetics. Disability and Rehabilitation: Assistive Technology, 2009. 2(6): p. 346-357.
12. Kejlaa, G.H., Consumer concerns and the functional value of prostheses to upper limb amputees. Prosthet Orthot Int, 1993. 17(3): p. 157-63.
13. van Lunteren, A., et al., A field evaluation of arm prostheses for unilateral amputees. Prosthet Orthot Int, 1983. 7(3): p. 141-51.
14. Biddiss, E.A. and T.T. Chau, Upper limb prosthesis use and abandonment: a survey of the last 25 years. Prosthet Orthot Int, 2007. 31(3): p. 236-57.
15. Shaperman, J., S.E. Landsberger, and Y. Setoguchi, Early Upper Limb Prosthesis Fitting: When and What Do We Fit. JPO: Journal of Prosthetics and Orthotics, 2003. 15(1): p. 11-17.
16. Schultz, A.E. and T.A. Kuiken, Neural interfaces for control of upper limb prostheses: the state of the art and future possibilities. PM R, 2011. 3(1): p. 55-67.
17. Radocy, R., The Benefits of Body Power in O&P Edge. 2003, O&P Edge. 18. Bhaskaranand, K., A.K. Bhat, and K.N. Acharya, Prosthetic rehabilitation in traumatic
upper limb amputees (an Indian perspective). Arch Orthop Trauma Surg, 2003. 123(7): p. 363-6.
81
19. Kruger, L.M. and S. Fishman, Myoelectric and body-powered prostheses. J Pediatr Orthop, 1993. 13(1): p. 68-75.
20. Millstein, S.G., H. Heger, and G.A. Hunter, Prosthetic use in adult upper limb amputees: a comparison of the body powered and electrically powered prostheses. Prosthet Orthot Int, 1986. 10(1): p. 27-34.
21. Scotland, T.R. and H.R. Galway, A long-term review of children with congenital and acquired upper limb deficiency. J Bone Joint Surg Br, 1983. 65(3): p. 346-9.
22. Datta, D., J. Kingston, and J. Ronald, Myoelectric prostheses for below-elbow amputees: the Trent experience. Int Disabil Stud, 1989. 11(4): p. 167-70.
23. Glynn, M.K., et al., Management of the upper-limb-deficient child with a powered prosthetic device. Clin Orthop Relat Res, 1986(209): p. 202-5.
24. Weaver, S.A., L.R. Lange, and V.M. Vogts, Comparison of myoelectric and conventional prostheses for adolescent amputees. Am J Occup Ther, 1988. 42(2): p. 87-91.
25. Weir, R., Standard Handbook of Biomedical Engineering & Design. 2004. pp. 32.1 – 32.61.
26. Herberts, P., The Control of upper-extremity prostheses and orthoses. 1974, Springfield, Ill.,: Thomas. xii, 261 p.
27. De Luca, C.J., The Use of Surface Electromyography in Biomechanics. Journal of Applied Biomechanics, 1997. 13: p. 135-163.
28. Dalsey, R., et al., Myoelectric prosthetic replacement in the upper-extremity amputee. Orthop Rev, 1989. 18(6): p. 697-702.
29. Crandall, R.C. and W. Tomhave, Pediatric unilateral below-elbow amputees: retrospective analysis of 34 patients given multiple prosthetic options. J Pediatr Orthop, 2002. 22(3): p. 380-3.
30. Parker, P., K. Englehart, and B. Hudgins, Myoelectric signal processing for control of powered limb prostheses. J Electromyogr Kinesiol, 2006. 16(6): p. 541-8.
31. Basmajian, J.V. and C.J. De Luca, Muscles alive : their functions revealed by electromyography. 5th ed. 1985, Baltimore: Williams & Wilkins. xii, 561 p.
32. Barnett, M.W. and P.M. Larkman, The action potential. Pract Neurol, 2007. 7(3): p. 192-7.
33. Leis, A.A. and V.C. Trapani, Atlas of Electromyography. 2000: Oxford University Press. 34. Action potential. Available from: https://en.wikipedia.org/wiki/Action_potential. 35. Zimmerberg, B. Synaptic Transmission: A Four Step Process. Multimedia Neuroscience
Education Project 1998; Available from: https://web.williams.edu/imput/synapse/pages/introduction.htm.
36. Deisch, J., Muscle and Nerve Development in Health and Disease, in Pediatric neurology : principles & practice, K.F. Swaiman, Editor. 2017, Elsevier/Saunders: Philadelphia.
37. Zajac, F.E., Muscle and tendon: properties, models, scaling, and application to biomechanics and motor control. Crit Rev Biomed Eng, 1989. 17(4): p. 359-411.
38. Sarcomere. Available from: https://en.wikipedia.org/wiki/Sarcomere. 39. Stevens, D.E., et al., Anconeus motor unit number estimates using decomposition-based
quantitative electromyography. Muscle Nerve, 2014. 50(1): p. 52-9. 40. Bromberg, M.B. and J.R. Daube, Motor Unit Number Estimates, in American Association
of Neuromuscular & Electrodiagnostic Medicine (AANEM) Workshop. 2003.
82
41. Fuglsang-Frederiksen, A. and J. Ronager, The motor unit firing rate and the power spectrum of EMG in humans. Electroencephalogr Clin Neurophysiol, 1988. 70(1): p. 68-72.
42. Lindstrom L.H., M.R.I. Interpretation of Myoelectric Power Spectra. 1977. IEEE. 43. De Luca, C.J., Physiology and mathematics of myoelectric signals. IEEE Trans Biomed
Eng, 1979. 26(6): p. 313-25. 44. Clamann, H.P., Statistical analysis of motor unit firing patterns in a human skeletal
muscle. Biophys J, 1969. 9(10): p. 1233-51. 45. Jazwinski, A.H., Stochastic processes and filtering theory. Dover ed. Dover books on
engineering. 2007, Mineola, N.Y.: Dover Publications. xiv, 376 p. 46. Roesler, H. and W. Becker. Investigation of peak amplitude and pulse length spectra of
gross EMG signals by multi-channel analyzation. . in Advances in External Control of Human Extremities. 1970. Belgrade, Yugoslavia: Yugoslav Committee for Electronics and Automation.
47. Brody, G., R.N. Scott, and R. Balasubramanian, A model for myoelectric signal generation. Med Biol Eng, 1974. 12(1): p. 29-41.
48. Nazarpour, K., et al., A note on the probability distribution function of the surface electromyogram signal. Brain Res Bull, 2013. 90: p. 88-91.
49. Clancy, E.A. and N. Hogan, Probability density of the surface electromyogram and its relation to amplitude detectors. IEEE Trans Biomed Eng, 1999. 46(6): p. 730-9.
50. Hogan, N. and R.W. Mann, Myoelectric signal processing: optimal estimation applied to electromyography--Part I: derivation of the optimal myoprocessor. IEEE Trans Biomed Eng, 1980. 27(7): p. 382-95.
51. Clancy, E.A., S. Bouchard, and D. Rancourt, Estimation and application of EMG amplitude during dynamic contractions. IEEE Eng Med Biol Mag, 2001. 20(6): p. 47-54.
52. Casella, G. and R.L. Berger, Statistical inference. 2002, Australia; Pacific Grove, CA: Thomson Learning.
53. Englehart, K. and B. Hudgins, A robust, real-time control scheme for multifunction myoelectric control. IEEE Trans Biomed Eng, 2003. 50(7): p. 848-54.
54. Nise, N.S., Control systems engineering. 5th ed. 2008, Hoboken, NJ: Wiley. xviii, 861 p. 55. Sanger, T.D., Bayesian filtering of myoelectric signals. J Neurophysiol, 2007. 97(2): p.
1839-45. 56. Hofmann, D., et al., Bayesian Filtering of Surface EMG for Accurate Simultaneous and
Proportional Prosthetic Control. IEEE Trans Neural Syst Rehabil Eng, 2016. 24(12): p. 1333-1341.
57. Sarkka, S., Bayesian Filtering and Smoothing. 2013: Cambridge University Press. 254. 58. Kalman, R.E., A New Approach to Linear Filtering and Prediction Problems. Transactions
of the ASME—Journal of Basic Engineering, 1960. 82: p. 35-45. 59. Kim, P.-y.n., L. Huh, and A.J. Publishing, Kalman Filter for Beginners : with MATLAB
Examples. 2011. 60. Menegaldo, L.L. Exploring Possibilities for Real-Time Muscle Dynamics State Estimation
from EMG signals. in The Fourth IEEE RAS/EMBS International Conference on Biomedical Robotics and Biomechatronics. 2012. Roma, Italy.
83
61. Mohammadi, H., et al., Extended Kalman filtering for state estimation of a Hill muscle model. IET Control Theory & Applications, 2018. 12(3): p. 384-394.
62. Han, J., et al., A State-Space EMG Model for the Estimation of Continuous Joint Movements. IEEE Transactions on Industrial Electronics, 2015. 62(7): p. 4267-4275.
63. Ghahramani Z., H.G., Parameter Estimation for Linear Dynamical Systems, C. Science, Editor. 1996: University of Toronto.
64. Zheng-ou, W., A New Method of On-Line Estimation of Noise Covariances Q and R. IFAC Proceedings Volumes, 1985. 18(5): p. 1501-1506.
65. R.K., M., On the Identification of Variances and Adaptive Kalman Filtering. IEEE Transactions on Automatic Control, 1970. AC-15(2): p. 175-184.
66. Evans, H.B., et al., Signal processing for proportional myoelectric control. IEEE Trans Biomed Eng, 1984. 31(2): p. 207-11.
67. Kreifeldt, J.G., Signal versus noise characteristics of filtered EMG used as a control source. IEEE Trans Biomed Eng, 1971. 18(1): p. 16-22.
68. Gygi A.E., M.G.S. Low-Pass Filter Effect in the Measurement of Surface EMG. in Tenth IEEE Symposium on Computer-Based Medical Systems. 1997.
69. De Luca, C.J., et al., Filtering the surface EMG signal: Movement artifact and baseline noise contamination. J Biomech, 2010. 43(8): p. 1573-9.
70. Bernstein V.M., F.B.S. Involvement of Noise Immunity Systems of Myoelectric Control of Prostheses. in MyoElectric Controls/Powered Prosthetics Symposium. 1993. Fredericton, New Brunswick, Canada.
71. Clancy, E.A., E.L. Morin, and R. Merletti, Sampling, noise-reduction and amplitude estimation issues in surface electromyography. J Electromyogr Kinesiol, 2002. 12(1): p. 1-16.
72. Xu, Z. and S. Xiao, Digital filter design for peak detection of surface EMG. J Electromyogr Kinesiol, 2000. 10(4): p. 275-81.