File: speedcontrol.tex

package info (click to toggle)
dasher 5.0.0~beta~repack-2
  • links: PTS, VCS
  • area: main
  • in suites: stretch
  • size: 45,040 kB
  • sloc: xml: 181,314; cpp: 70,869; java: 8,020; python: 3,579; makefile: 942; sh: 324; ansic: 223; perl: 71
file content (488 lines) | stat: -rw-r--r-- 22,429 bytes parent folder | download | duplicates (5)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
\documentclass[a4paper,11pt,notitlepage]{article}

\usepackage[dvipdfm]{graphicx}

\usepackage[left = 1.125in , right = 1in, top = 1in, bottom = 1in]{geometry}

\usepackage{amsmath}

\usepackage{amsfonts}

\usepackage{fancyhdr}

\setlength{\parindent}{0pt} \setlength{\parskip}{1ex plus 1ex}

\author{\footnotesize{Christopher Ethan Hack (ceh58@cam.ac.uk), Churchill College}}

\title{\textbf{Automatic Speed Control for Dasher}}

\pagestyle{fancy} 

\lhead{} 

\chead{\textit{Automatic Speed Control for Dasher}}

\rhead{} 

\lfoot{} 

\cfoot{\thepage} 

\rfoot{} 

\headheight = 15.6pt

\renewcommand{\headrulewidth}{0pt}

\renewcommand{\footrulewidth}{0pt}

\begin{document}

\maketitle

\begin{abstract}
An automatic speed control for Dasher was implemented to enhance user
experience. A user's stress level is measured by looking at the
variation of the angle between the positive $x$-axis and the line
joining the crosshair to the cursor position. The higher the variance,
the higher the user stress; this indicates Dasher is running too
fast. User trials backed up this idea, so speed control was
implemented along these lines. So far, it has performed well in
trials.
\end{abstract}

\section{Introduction}\label{sec:Intro}

The maximum bit rate (speed) at which Dasher runs can always be set by the
speed control slider, which appears optionally at the bottom of the main
window. The maximum speed at which a user can use Dasher depends to a large
extent on the user's skill. Very experienced users will be able to write
successfully at higher bit rates. However, if a user is operating Dasher at a
bit rate which is inappropriate for them, their experience will certainly be
less enjoyable and they will probably end up writing more slowly. Furthermore,
users may not bother experimenting with the speed slider to work out a
comfortable bit rate for themselves. Worse still, users may even be
\emph{unable} to play around with the speed slider. This could make using
Dasher frustrating, so an automatic speed control is a desirable feature.

In order to implement automatic speed control for Dasher, why not ask
the question ``how can we tell how well a user is doing'' or perhaps
``how can we tell how stressful a user is finding using Dasher''? If
a user was doing badly or finding the experience stressful we could
slow Dasher down. If a user seemed bored, we could speed up.

In Dasher 1.6.8 this problem was tackled by looking at the mean $x$
coordinate of the mouse. Being far to the right of the screen on
average indicated boredom, to the left (near the crosshair), stress,
with a safe comfort zone in the middle. In general this may be
unsatisfactory; you can imagine user behaviour patterns where you
might want to write at high speed with very small gestures causing
the mouse to be kept very near the crosshair for example.

Our hypothesis is that a better indicator is \emph{the variation of
the angle between the positive $x$-axis and the line joining the
crosshair to the cursor position}. If this variance is high, it would
indicate a high level of user distress. Mathematically, our variance,
$\sigma$, is:

\begin{equation}\label{equ:var}
\sigma=-\log{\left( \langle \cos \theta \rangle^2 + \langle \sin \theta \rangle^2 \right)}
\end{equation}

$\theta$ is the angle and $\langle\ldots\rangle$ indicates some kind
of time averaging. This definition was chosen because it is
robust. Any definition based on a simple statistical variance of the
angle has the weakness that any measure of the angle must be
discontinuous at some point round the circle.

\section{Experiment}

In order to test this hypothesis, we carried out a series of simple
user trials. 4 intermediate ability Dasher (direct mode) users carried
out short text composition tasks at a range of different
speeds\footnote{See Keith Vertanen's paper, `An Empirical Evaluation
of Keyboard-less Text Composition'.}. Their behaviour was
logged. Users were also asked to give a qualitative description of
their Dasher experience after each trial.

We also had one test subject perform similar experiments using a
breath-mouse and 1-dimensional mode Dasher, and using an eyetracker.

\section{Results}

The results (not included here) were definitive (though not really
inherently interesting). A running variance (see
Section \ref{sec:Intro}) was calculated. There was a clear link between
user distress (indicated in qualitative feedback) when Dasher was
running at too high a speed for them and the variance as we calculated
it. This provided enough stimulus to continue to develop an automatic
speed control based on this measure of user performance. This held
true for direct mode and for other input modes.

By looking more closely at such results, we could also see what sort
of values the variance takes during periods of boredom and
stress. This will be instructive when it comes to designing our
auto-speed control.

\section{Design Requirements for an Automatic Speed Control}

\emph{This isn't as easy as it sounds.}

\subsection{Timescales}\label{item:time} 

Our automatic speed control can be thought of in terms of two
timescales. One is the timescale over which the variance is updated,
$\tau_v$, the other is the timescale over which changes are made to
the bit rate, $\tau_c$. If $\tau_v \gg \tau_c$, this is bad
news\footnote{DJCM}! This means the speed is changing more quickly
than our measure of user stress adapts and the change will
``overshoot''. Making sure that our system avoids this is very
important. We should aim for $\tau_c \gg \tau_v$. However, if the
speed changes \emph{too slowly}, the system will be of limited use.

\subsection{Misleading Scenarios}\label{item:back} 

We should exclude backwards data (i.e. when the user is deleting
characters). This is because when a user is backing up, their
behaviour probably isn't giving us useful information on their
performance while writing (which hopefully is the majority of the
time!). Furthermore, movement of the mouse backwards and forwards
creates annoying spikes in any measure of the variance. Though this
may well be a sign that Dasher is running too fast for the user, it may
also be that they have changed their mind about what to write. We
don't want to give too much emphasis to this. Furthermore, a user in
trouble may spend a lot of time `scrolling' vertically. Typically,
this will result in a low variance and could be mistaken for
\emph{good} performance! To avoid this, we should also exclude data in
the forward-vertical-scrolling region.

\subsection{Sampling}\label{item:samp} 

The design also involves sampling. Dasher does not guarantee that any
function will be called consistently at fixed intervals. In order to
make the design invariant to the clock rate of the machine it runs on,
we want to make sure the \emph{time period over which we measure the
variance is constant for varying clock rates}. This means sampling
more frequently when Dasher is running on a fast machine.

\subsection{Invariance to User Skill}\label{item:bitr} 

We also want to make the design invariant to a user's ability level,
which is tied in to the bit rate they use Dasher at. A more skilled
user working at a higher bit rate will inherently have a greater
variance (over a fixed time period) compared to a poor user working at
low bit rates. Essentially, this means the length of time over which
we sample should be inversely proportional to the current bit rate.

\subsection{Minimum Radius}\label{item:minr} 

Data where the mouse position is very near the central crosshair
should be excluded. There are two reasons for this. First, a user may
rest near the crosshair as they consider what to write next so this
data is not useful for speed control. Second, small changes in mouse
position near the crosshair will result in big changes of angle. This
would be bad for the model we have in mind. Some sort of minimum
exclusion radius must be included. It should also be adaptive; if a
user tends to spend all their time a long way from the crosshair, it
should be bigger.

\subsection{The Graphical User Interface}\label{item:gui} 

Automatic speed control must also be seamlessly integrated into the
Dasher user interface, as an option that can be turned on and off. A
check box and speed slider control should be added to the Preferences
dialogue box.

\subsection{Bonus Features}

We will also implement boost and brake buttons for Dasher, such that
it speeds up or slows down when the respective button is being held
down.

\section{Implementation}

Automatic speed control is implemented as part of the
\texttt{CDasherViewSquare} class. The code can be found in the files
`DasherViewSquare.h' (declarations) and `DasherViewSquare.inl'
(implementations) in the `dasher/Src/DasherCore'
directory. Initialisation of relevant class members is carried out in
the class constructor in `DasherViewSquare.cpp'. In order to slightly
modularise speed control, the functionality has been split up into
several functions. Nearly all the free numerical parameters of the
model are specified as class member variables and initialised in the
constructor. There are a lot of them!

Ideally, we want a single automatic speed control to work for all
modes of Dasher. Hence we use internal Dasher coordinates for
calculating an internal `Dasher angle' rather than screen
coordinates. This is because in eyetracker and one-dimensional modes
the mouse position in screen coordinates isn't always meaningful.

\textbf{\texttt{void CDasherViewSquare::SpeedControl(myint iDasherX,
myint iDasherY)}}. This is the main auto-speed control function and
drives auto-speed control.

The first thing we do here is coordinate transformations. We're fed
non-linear Dasher space coordinates, but we need to re-linearise them
so the geometry is sane and make the crosshair the origin of
coordinates rather than top right corner. We also use normalised
coordinates such that the width of the screen corresponds to 2.0. This
is because the minimum radius calculations (see Section \ref{sec:exr})
only works for small radii.


The angle \texttt{theta} is calculated and stored in an
\texttt{std::deque<double>} structure for later variance
calculations. Auto-speed control then works as follows.

\subsection{Changing the Bit Rate Based on the Angular Variance}\label{sec:chng}

The basic idea behind our design goes like this:

\begin{enumerate}
\item\label{item:first} Calculate our `Dasher angle', $\theta$ and
store it at the back of a deque structure. This is a single
sample. Count the number of samples we take.
\item While there are more samples in the \texttt{deque} than the current
sample size (see Section \ref{sec:Size}) remove items from the front
of the deque.
\item After we have collected enough samples i.e. enough time has
elapsed, calculate the variance using Equation \ref{equ:var}. This is
the job of \texttt{CDasherViewSquare::Variance()}. Reset the sample
count. Time averaging is accomplished by looking back at the last $n$
samples, where $n$ is the sample size as mentioned above and
calculated as per Section \ref{sec:Size}. At this point the exclusion
radius and sample size (see Sections \ref{sec:Size} and \ref{sec:exr})
are updated to take account of changing conditions. Because the sample
size can (and does) change, we need to use a more flexible
\texttt{deque} structure rather than anything simpler/more
lightweight.
\item Using a 5-tier system, update the bit rate. This 5-tier system
gives great flexibility but also simplicity. Schematically:
\begin{itemize}
\item If the variance is very low, increase the bit rate a lot.
\item If the variance is quite low, increase the bit rate a little.
\item If we're in the middle do nothing.
\item If the variance is quite high, decrease the bit rate a little.
\item If the variance is very high, decrease the bit rate a lot.
\end{itemize}
Changes are made to the bit rate on a percentage basis, so the faster
you're going already, the more the bit rate changes by. This helps
fulfill design requirement \ref{item:bitr}.
\item Never let the bit rate fall below 0.1 or above
  8.0. \texttt{CDasherViewSquare::UpdateBitrate()} takes care of these
  last 2 steps.
\item Repeat from step \ref{item:first}.
\end{enumerate}

Let's think about design requirement \ref{item:time} briefly. The bit
rate can only be changed after a certain time has elapsed. This is the
same time period over which the variance is measured. This would seem
to make $\tau_c = \tau_g$ (see design requirement
\ref{item:time}). However, things are complicated by the 5-tier system
for changing the bit rate (see above). This system means that the bit
rate doesn't always change every time \texttt{UpdateBitrate()} is
called. Hence, on average, the bit rate is actually changing on a
longer timescale than we measure the variance on. The tier system also
means the bit rate can still adapt rapidly enough to make auto-speed
control useful. We have fulfilled our design requirement.

\subsection{Excluding Misleading Data}

As design requirement \ref{item:back}, certain aspects of user
behaviour could be na\"ively mistaken for the user having a good, easy
time when this is not the case. To prevent this confusion, only the
forward sector covering roughly $\pm72^{\circ}$ from the positive
$x$-axis is included. When the cursor is outside of this area,
auto-speed control is effectively paused. This makes sure we don't
have the problems noted in design requirement \ref{item:back}.

\subsection{Sample Size}\label{sec:Size}

We sample once per Dasher frame. In order to address Design
Requirements \ref{item:samp} and \ref{item:bitr}, we keep track of the
\emph{number} of samples taken and vary this number so that if the
frame rate is the only thing that varies we sample over a constant
time. The number of samples we take per variance measure, $N$, is
given by:

\begin{equation}
N = F(m/B + c)
\end{equation}

$F$ is the frame rate, $B$ is the bit rate and $m$ and $c$ are
constants. So as $F$ varies the \emph{time} over which we sample
should be roughly constant. Furthermore, we address Design Requirement
\ref{item:bitr}; we sample over a shorter time when Dasher is running
at a higher bit rate. All of this is given in code in the function
\texttt{CDasherViewSquare::UpdateSampleSize()}. The constants are
specified in member variables of the class (see the code for details).

Note that because of the inverse relation to the bit rate, any $B < 1$
are set to $B = 1$ for the purposes of this calculation, so $N$
doesn't get too big. This is a bit of a fudge, but if $N$ is too big,
speed control is very unresponsive.

\subsection{The Minimum Radius}\label{sec:exr}

This fulfills Design Requirement \ref{item:minr}. The minimum radius
is set up to be adaptive (i.e. it will increase/decrease if a user
is always far from/near the crosshair). How do we do this? It's like a
clustering problem. To a first (very loose) approximation we think of
the distribution of radii as a mixture-of-2-centred-Gaussians, with
two standard deviations. The two means represent two different
populations, radii when the user is dawdling and radii when the user
is progressing. Every time we sample a radius we have to decide which
population it belongs to and update things according. Schematically it
works like this:

\begin{enumerate}
\item Initialise the two standard deviations and find an initial guess
for the minimum radius.
\item\label{item:mrs} Every radius we sample we assign to either the
`dawdling near crosshair' population or the `writing at the right of
the screen' population, depending on whether it is more or less than
our min. radius.
\item Update the standard deviation of that population
accordingly. These two steps are performed in \texttt{void
CDasherViewSquare::UpdateSigmas(double r)}.
\item Every now and then, recalculate the min. radius using the
updated standard deviations. This step is carried out in
\texttt{CDasherViewSquare::UpdateMinRadius()}.
\item Repeat from step \ref{item:mrs}.
\end{enumerate}

According to DJCM's mixture-of-2-centred-Gaussians model for the
distribution of radii, the critical radius is given by:

\begin{equation}\label{Equn:r}
r_{crit}^2 = \frac{\ln\left(\frac{\sigma_2^2}{\sigma_1^2}\right)}{\left(\frac{1}{\sigma_1^2} - \frac{1}{\sigma_2^2}\right)}
\end{equation}

$\sigma_1$ is the standard deviation of the `writing' population and
$\sigma_2$ is the standard deviation of the `dawdling' population. It
has been empirically noted that this formula \emph{does not work} for
$\sigma \gg 1$ (or more to the point for $r \gg 1$) so normalised
coordinates are used to keep $r$ in range.

These values are updated by the moving-average `sludgy
update rule':

\begin{equation}
S_{(k+1)} := \alpha S_{(k)} + (1 - \alpha)r^2
\end{equation}

$\alpha$ ($\alpha < 1$ always!) measures how manys guys we're
averaging over; the bigger $\alpha$ the more guys we use.

We simultaneously keeps track of 2 values of $S$, one for each
population and perform this update after assigning a value of $r$ to a
population. For each population, asymptotically, $S_{(k)} \simeq
\langle r^2 \rangle$ so we make the association $\sigma_i^2 =
S_{(k)}$. These updated values of $\sigma$ are then periodically used
to update $r_{crit}$ according to equation \ref{Equn:r}. We've
designed the system so that the minimum radius adapts much more slowly
than the bit rate.

\subsection{Brake and Boost Mode}

One non-auto-speed control bonus feature we've implemented are `boost' and
`brake' keys for Dasher. If you hold down control, Dasher slows by
75\% of the underlying bit rate; if you hold down shift Dasher speeds
up by 75\% of the underlying bit rate. This is implemented differently
under Linux and Windows because of the different ways they handle
keyboard input. See `/dasher/Src/Gtk2/DasherControl.cpp' and
`/dasher/Src/Win32/Widgets/Canvas.cpp' for details. The crucial common
factor is that the boost/brake is handled by changing the value of the
Dasher-parameter \texttt{LP\_BOOSTFACTOR}.

\subsection{Other Notes}

After some testing, it was found that the auto-speed control model did
not interact well with Dasher control mode. It would seem that that
users behave differently when using contorl mode. This confuses the
auto-speed control, and so auto-speed control should be automatically
disabled when the user enters a control node and enabled when they
leave.

The problem with this is that bugs in the implementation of the way
Dasher parses the tree of Dasher nodes mean sometimes auto-speed
control is not turned back on when you leave a control node! This is a
bug in \texttt{CDasherModel}, not in speed control. That section of the
code is due to be rewritten, as of September, 2005.

\section{Testing Automatic Speed Control}

Carrying out full statistically rigorous tests of automatic speed
control as well as evaluating its psychological and qualitative impact
on Dasher users would be time consuming and require a large volunteer
base of test subjects. This really wasn't feasible.

So instead smaller scale evaluations were carried out, without extensive
statistical calculations. Experienced Dasher users found that auto-speed
control would settle down at an appropriate bit rate for them and stay there.
Less experienced users found auto-speed control picked out a lower speed than
they might have expected but that it made them feel better about using Dasher.
A test using the breath mouse and one-dimensional mode also proved successful.

Only somewhat rudimentary tests were carried out using the eyetracker and
breath mouse. Novice users of both devices reported that speed control was
satisfactory. Eyetracker input is very similar to direct input and it is
envisaged that auto-speed control will function in a similar way in both modes.
If anything, auto speed control will be more useful for eyetracker users
because their attention is necessarily completely focussed on what they are
writing and it's hard to look away from the canvas.

\section{Discussion}

In general, automatic speed control has so far proved successful. It
speeds up and slows down appropriately when a user is bored or
stressed respectively. It settles down to a fairly consistent speed
which suits the user well. Still, certain things could be further
considered:

\begin{enumerate}
\item The whole thing could do with more extensive testing. All the
parameters have been tuned by the trials already carried out, but
there is still probably room for improvement.

\item The interaction with control mode isn't very elegant and is made
worse by the bugs in \texttt{CDasherModel}. When \texttt{CDasherModel}
is fixed up, this could be looked at.

\item As noted in section \ref{sec:chng}, the minimum time period over
which the variance can be changed is tied directly to the period over
which the variance is measured. This is partly because these periods
are both subject to being invariant to machine clock rate and user
ability (see sections \ref{item:samp}, \ref{item:bitr} and
\ref{sec:Size}). They are bound to be calculated in a similar way and
empirically having them equal was found to work. However, this need not be the
case. By decreasing the value of the member variable
\texttt{m\_dSensitivity} (currently set to 1.0) this relationship can
be altered. This could be investigated further.

\item One-dimensional mode is also something of a challenge. In tests,
the model performed quite well and satisfied our single trial
subject. However, is it optimal for 1D mode? Could improvements be
made?

\item An alternative model suggested for auto-speed control was to
model the user's behaviour as a solution to the damped, simple
harmonic oscillator differential equation. Exactly what the ideal
solution would be and how to implement this easily and efficiently was
not immediately clear. That's why we used the simpler angular variance
model. This alternative could be worth further consideration.

\item A question from an object-oriented programming perspective: Does
auto-speed control belong in \texttt{CDasherViewSquare}? Could it be
put into its own class as an abstract auto-speed control object? Or
would that be silly?

\end{enumerate}

In the end, automatic speed control based on angular variance proved
successful. It has been committed to CVS and should be released in
Dasher v4.0. Testing by the general public will ultimately decide its
worth!

\end{document}