# CS 395 Fall 2002 Individual Assignment 2: Signal Conditioning tricks

Out: Wednesday, October 30
Due: Wednesday, November 6

## Overview

Signal conditioning is a term for all the ad-hoc processing techniques (read: hacks) engineers do to try to remove noise from the signals in their systems.  Here we assume that the readings we get on a wire are some kind of a combination of a "signal" (what we're really trying to measure) and some "noise" (some other extraneous data).  (Note that there is an unfortunate confusion of terminology: up to this point, we have called the wire itself the signal).  Sometime the combination process involves adding the signal and noise together, sometimes it involves occasionally replacing the signal with the noise, and often it is more complicated.  In any case, signal conditioning classically means trying to remove the noise and leave the signal.

For this assignment, we'll interpret the term more broadly here to mean "hacks you do to broken signals (in the wire sense) to make them work better."  The GRL library has a large number of specialized operators for signal conditioning.  For this assignment, you should read the documentation on the GRL library and use the operators in it to solve the following problems.  Note that:

• This is a pencil-and-paper assignment (or text-editor-and-paper, as the case may be).  You don't need to test things out on the robot or demonstrate them.  Although you are free to test things out if you want to.
• Some terms aren't defined in the documentation.  A low-pass filter is (more or less) something that returns a weighted average of the most recent values of a signal.  The time-constant parameter determines how slowly it's willing to change its output.  This has the effect of "passing" low (slow changing) frequencies and suppressing high (fast changing) frequencies.  The median of a set of numbers is the one in the middle, i.e. the median of 1,2,3 is 2, the median of 1, 2, 482 is also 2.
• Do not write your own custom transducers for this.  Use only the primitives given in the GRL library.  However, you may define new signal procedures if you want.  In other words, don't turn in any code that contains a `define-transducer` or `define-machine` form.
• When you need to specify thresholds, gains, timer values, etc., just put in symbolic names like "threshold" or "gain2" or what have you.

## Problems

Suppose you have a sensor that's measuring some smoothly-varying phenomenon in the world.  That is, it's measuring a number and you expect the numbers to be close to the same from measurement to measurement, even though they will vary significantly over long periods of time.  Now suppose the sensor is sensitive to some kind of interference (RF, cosmic rays, glare from the sun, whatever) so that its readings are always the sum of the "real" reading and some small random number.

Given the output signal `x` of the sensor, give a GRL expression for a signal in which the noise is removed, or rather greatly reduced.

Assume:
• The noise (the random number) is very small, say in the range from -2 to +2 units.
• The signal (the "real" reading) is big, say in the range from -500 to +500 units.
• The noise is uncorrelated, meaning that there's no relationship between the noise levels on successive measurements; they're each completely unrelated random numbers.
• The signal is slowly varying, meaning it might take 100 measurements for it to change by 10 units.
2. Shot noise (aka salt-and-pepper noise)
Now suppose the noise has a different character:
• The noise is big, say in the +/- 100 unit range.
• The noise is "shot noise" - it's almost always zero (no noise), but once in a while, you'll get a single, isolated reading with a lot of noise.
• The signal (the real reading) is still slowly varying.

Again, write a GRL expression that will remove the noise, or rather, greatly diminish it.

3. Sporadic noise in a piecewise-constant signal
Suppose you are running in an office building with corridors of various widths and you want to determine whether the robot is in a wide corridor or a narrow one.  You could use `(+ left-distance right distance)` as a rough-and-ready measure of corridor width..  The problem is that if there are objects in the hallway, open doors, etc. you'll hallucinate that you're in a different-sized corridor.  Unlike the shot noise above, you can't assume that the errors last for only one clock tick.  On the other hand, you know that the signal you're looking for is piecewise-constant: it stays the same for a long periods of time and only makes changes when you move from one corridor to another.  Write an expression that will remove the noise caused by open doors and objects in the hallway from the width signal.

4. Chattering
Suppose you have an unwedger that's written like this:

```(define-signal unwedge    (behavior (and (< center-distance threshold)                   (< (abs (- left-distance right-distance))                      threshold2))              (rt-vector ```...` 0)))`

so that the system performs some kind of fixed turn whenever the center distance is too low and the side distances are balanced.  Suppose you run this and you get the following behavior:
• The robot drives along
• It gets pointed into a corner, triggering the unwedger
• It starts to turn left (unwedge), making the left distance decrease and the right distance increase
• Now the side distances are different, so the unwedger stops.
• But then the freespace follower takes over again and immediately steers the robot back into the corner, because, after all there's more free space on the right...

So basically, the robot just sits there and thrashes.  This is a common failure mode with unwedgers.  Propose an alteration to subexpression:

```(< center-distance threshold) ```that will solve the problem.  You may not use `true-time`.

5. Oscillation
You're implementing a feedback controller to orient toward a target:

```(define-signal orient    (behavior #t              (rt-vector (* target-direction gain)                         0))) ```
Suppose you want to orient quickly toward the general target, but you don't care whether you're perfectly aligned with it.  You know the standard problem: if you use a high gain, you get there fast, but you oscillate.  If you use a low gain, you're stable, but you take a long time to converge.  Propose a solution to the problem by transforming the output of the P-controller.  That is, suggest a function f, such that:

```(define-signal orient    (behavior #t              (rt-vector (```f``` (* target-direction gain))                         0))) ```
will let the system use a large get to get close to the target without oscillating.
6. Suppose you're writing a program that navigates by counting open doors using the following code:

```(define-signal door?    (> left-distance threshold)) (define-signal position    (count door? #f)) ```where `left-distance` is assumed to be the amount of freespace on the left side of the screen as in the freespace follower.  This will work when the robot is driving down a corridor and is aligned with the axis of the corridor (i.e. facing the end of the corridor).  When that happens, we should get small readings for `left-distance` normally:

and large readings when we pass an open door:

Therefore, the `position` signal should tell us the number of doors we've passed so far.  Unfortunately, this doesn't work.  When you try the code, the robot gets to the first door and suddenly `position` is a huge number like 300.  Explain the problem and give a fix.
7. Now what happens when the robot passes someone in the hallway?  If the person passes the robot on the left it will start to steer to the right to get around them:

It will keep turning until the left and right distances are the same.  But then when the person walks past the robot, there will suddenly be extra space on the left, and the robot will think it's at a door:

We could fix this by changing the definition of ` door?` to be:

```(define-signal door?    (and aligned?         (> left-distance threshold)))```

where `aligned?` is true whenever the robot is aligned with the corridor.  Write a definition for `aligned?` to try to guess when the robot is driving straight along the corridor.  Assume there is a signal, `rotational-velocity`, that tells you how the robot is turning.
8. Suppose we want to write a program that goes into an office when it finds an open door.  We could use use the `door?` signal to trigger a 90 degree ballistic turn. But if we do that, the robot ends up pointing at the wall because it turns too early:

write a definition for a signal, `turn-now!`, that causes the robot to turn at the right time.
9. What happens if we have doors of different sizes?  If we want to turn at the biggest door, we can just raise the threshold for our door detector.  But what if we want to turn only at small doors?  We could change the code to look for openings that are big, but not too big:

```(define-signal door?    (and aligned?         (> left-distance threshold)         (< left-distance threshold2)))```

However, if we come to a big door, it will start out with a large left-distance but then that distance will steadily decrease as the robot drives past the door, until the big door "looks" like a small door.
1. Modify the definition above so that the system won't mistake big doors for little doors.
2. Give an example of how your system can still be fooled (mistake a big door for a little door or miss a little door entirely) if there is a person around.
10. A common cheat for sanity-checking a Boolean (true/false) signal is to use a timer (e.g. with `true-time`) to make sure it's true for a reasonable period of time before believing it.  For example, suppose we want to determine whether we're in a part of the building that has a dark carpet rather than a light carpet using a signal, `center-brightness`, that gives us the image intensity of the center pixel of the image (not that you'd really want to do it this way...)

`(define-signal dark-area? (< center-brightness threshold))`

One problem with this is that it's susceptible to noise, e.g. if the robot drives past a coffee stain on the rug.  The standard cheat is to just add a timer:

```(define-signal dark-area?   (< (true-time (< center-brightness threshold))       threshold2))```

The idea being that if it stays true (dark) for a while, there must be a big area that is dark.  Of course, this isn't really true.  It assumes that time=distance.  If a person stands in front of the robot, so that the center pixel is reading the brightness of the person's black pants, then the robot can be fooled into thinking it's in a dark area.  A (somewhat) better solution is to check whether the signal is true over a long distance rather than a long time.  Write a signal procedure, `true-distance`, that's just like true time except that it reports the distance over which its input has been true.  Assume you have available a signal, `translational-velocity`, that reports the robot's present speed.  Do not worry about whether the robot is moving in a straight line.

## Extra credit

Propose a design for a freespace follower that will "learn" the right gains (or other parameters) to let it follow the corridor as fast as possible without oscillating.

## Turning it in

Send your assignments to Aaron <khoo@cs.northwestern.edu> via email by 2:00pm Wednesday November 6 (i.e. class time).  Papers received after that will be counted as late.