Adjusting Brakes and Gears on Bicycle
This applies to my blue bicycle.
Brakes
Release Bowden cable clamp, push brakes together until they are each 1mm from rim, then tighten the clamp again.
Notice the two screws on each side of the break. These adjust the symmetry in open position. If you tighten one screw, the open breaks will shift towards that screw. Pull and release the breaks repeatedly while adjusting these screws. I think they work best if you feel a bit of resistance in both screws.
Gears
You have a Shimano Deore transmission.
Flip the bike onto its seat and handlebar. On the rear derailleur you'll see three screws: Two right next to each other (let's call them "twins"), and a bigger screw close to the hub. You won't need this bigger screw, it's for adjusting the distance between the "eye" and the cogset when the chain is on the smallest sprocket.
None of your standard screwdrivers fit the heads of those screws, so you'll have to dig into your supply of bits. Take a medium-wide but thin, flat screwdriver.
Shift the chain onto the middle front sprocket and the smallest back sprocket.
Release the clamp on the the Bowden cable.
Turn the inside "twin" such that the derailleur is sits right above the smalles sprocket. Turning the screw in moves the derailleur towards the hub. On my bike, this screw must be turned out almost all the way. (In a mechanical sense. The screw is still almost all the way in, just turning it out further doesn't do anything.)
Make sure you can turn the fine-adjust on the end of the Bowden cable at least a few notches in each direction.
Pull the end of the Bowden cable with moderate force and clamp it.
Shift into 6th gear (the next bigger sprocket). If it doesn't go up there, increase the Bowden tension by turning the fine-adjust screw out by a few notches. Shift back into 7th. It should go back smoothly, otherwise release some thension in the cable and try with a different adjustment of the inside twin.
Note: Problems on shifting "down" are somewhat expected due to shoddy, dirty, unmaintained bowden cables. If it gets too bad, bite the bullet and clean the bowden cables, or buy new ones.
Shift into first gear on the back cogset. Adjust the outside twin such that the derailleur sits above that sprocket. I think turning it out moves it towards the hub. Careful: If you turn it out too much, the chain will fall between cogset and hub, if you turn in too much, you won't be able to shift into this gear. Some guy on the internet (TM) suggested to turn it in until you feel resistance, then back out by a quarter turn. That might also be good advice.
Shift around and play with the cable tension. Shifting down might not work very well due to shoddy bowden cables. Either buy new ones or live with that.
Early vs. Late Binding
These terms refer to methods (functions attached to objects), specifically how to find methods. Stackexchange has a nice post on this.
Early binding: The compiler knows that the method exists (important!) and the adress of the method code. It can - more or less - hardcode the method address into your code, and it can also do all kinds of type checking, argument counting, etc.
Late binding: The compiler only knows the name (a text string) of the method and inserts code that looks up the method at run time. This takes time, the method might not exist, and type checking and such can often not be done by the compiler itself. Scripting languages are all "late binding".
Javascript and NodeJS
For the longest time, I have been looking for a better "Google Calculator" - one that supports units, fundamental constants, has a simple syntax, and is optimized for "back-of-the-envelope" calculations. Bonus points for quick-and-dirty Monte-Carlo error propagation.
This does not yet exist, but there are folks who try to marry mathjs with mathjax, which is a start. [Edit: Just yesterday, some random person released a pretty substantial update that allows this. So my efforts on this exact front are pretty much moot.] I never really got far in javascript-programming, but fortunately there are great refreshers online. But I am completely lost about the hot and new topics, such as how to write modules and javascript libraries.
I installed nodejs, which is a server-side scripting engine that
coincidentally gives me a convenient REPL for tinkering. Installing
mathjs was then as easy as npm install -g mathjs
.
Npm allows me to execute node
in a command window, and I am dropped
into a javascript REPL. Here, .break
gets you out of a multiline-mode,
and .exit
quits.
You load a module with
var mathjs = require("mathjs");
var math = mathjs();
Reminder about var
: This doesn't make a difference in global
contexts. In local (say, in function) contexts, it makes sure that the
declared variable is local.
C Caveats
I needed to dabble in C again, and of course I had forgotten almost everything about it...
Pointers
int *np; // np is a pointer to an int. Read: "*np is of type int".
*np = 3; // Errror! You are dereferencing an unitialized pointer.
// The address stored in np is most likely garbage.
int num = 3; // Now there is actually something we can point to.
np = &num // Makes np point to num.
*np = 4 // * dereferences the pointer, so that you can write/read what
// it is pointing to. Both num and *np now "are" 4.
np // this is just the value of the pointer, i.e. an adress
np+1 // Points to the next element. Depending on architecture and
// typeof(*np), the actual address may be bigger by 1,2,4,...
*np++ // Note the precedence: it is *(np++), meaning: give me the
// value stored at np, and incr. the pointer.
Null vs. Void
int *np = NULL; // NULL is a preprocessor macro that makes the
// pointer point to "nothing interesting", "something safe."
void *np2; // Declares a generic pointer. Points to "void", which is
// a type, just like int and float, only it's always empty.
// A void pointer is a "promiscuous" pointer. Use it if you
// can't say what it will end up pointing to. This, on purpose,
// circumvents the strict static typing of C.
Static vs. Const
const int a = 3; // a is a variable (with allocated memory!) that is not allowed
// to change. You can still change it via pointers. Don't.
# define a 3 // The symbol "a" is replaced by the symbol "3" by the
// preprocessor. It (probably) won't take up memory.
const int *ap; // ap is a pointer to a const int. Often used when pointers are
// passed to functions, and the functions are not allowed to
// change the content that the pointers point to.
int * const ap; // ap is a "constant pointer", meaning the pointer must not
// change. You can change what it points to, though. Array
// names are like this. (?)
int arr[10]; // somewhat comparable to int * const arr. (?)
static int a = 3 // If in a function: Compiler "initializes" it and let's the
// function have access to it. Value is "remembered" through
// multiple function calls.
static void fun(void) {..}
// Caution: Meaning is different now, outside function: fun
// is only "visible" from the same (object) file.
Declare vs. Define vs. Initialize
extern int a; // Declaration: Tell compiler about a thing "int a". This thing
// is defined somewhere else, though, so don't reserve memory.
int b; // Declaration + (tentative) definition: Compiler reserves
// memory. Tentative: If there is another, agreeing one, it's ok.
int b; // Legal because "tentative definition".
float b; // error
int b = 3; // Declaration, definition and initialization in one statement.
// Memory is reserved and filled with meaningful stuff.
Code Blocks in Wordpress
Short version: When writing about code blocks in Wordpress, use a
smart mixture of visual and text editor. Wrap code with
<pre><code>...</code></pre>
.
Long version: Use the visual editor to paste the code block into your post. The visual editor appropriately escapes html-tags and other weird code constructs that can mess up a browser.
Then switch to the visual editor, mark the text and click the "code"
button. This gives you <code>
tags around it.
Lastly, to keep the original formatting intact, wrap
everything in <pre>
tags.
In the end, it should look this this:
<pre><code>Sample Code
Many Lines
Very wow</code></pre>.
Note, much, much later: I am now using static site generation and have different, funner loops to jump through.
Fundamentals of Arbitrary Waveform Generation Ch. 5
This chapter deals with the generation of serial signals for testing purposes.
Serial data is typically transported without a clock signal (this is reconstructed in the receiver). During generation, the most important defect of the signal is jitter.
Often, serial data is heavily degraded during propagation, due to cross-talk, attenuation, dispersion, reflection, and noise. Differential signalling helps with some of these problems.
The encoding of serial data is usually done with high/low levels, but PAM (pulse amplitude modulation) encodes more than one bit per sample through several levels. Data can be transmitted using "de-emphasis" (basically overdriving a bit if there was a transition) to compensate losses. Sometimes, data is transmitted by the polarity of short pulses, so that there is less DC on the line. Many protocols also specify an "idle level" between high and low.
Real-world signals are characterized, among other things, by high level, low level, rise time, fallilng time, noise, crosstalk, jitter, and frequency. Rise and fall times are usually measured at the 10%, 90% levels (or 20%, 80%, or some other combination).
Timing control of digital signal ist not really limited by the sampling rate. If you place a few (one is enough) samples on the edge, you can position the edge finely by adjusting the amplitude of the edge samples. But, quantization noise leads to (small) jitter in much the same way, especially if you have many samples per edge (and thus slope is small). The optimum samples per edge is pretty broad, where jitter is dominated by other, mostly sampling clock jitter and random noise.
Rule of thumb: Use two samples/edge for minimizing intrinsic jitter and getting full timing control. This limits serial baud rate to 1/5 of sampling frequency. Make sure to use a good "reconstruction filter" (sort-of low pass at the output chain.)
If you want to create jitter for testing purposes, you can modulate the 10 MHz reference (for low frequency jitter, internal PLL acts as filter), or, if your AWG supports it, you can feed it a modulated DAC frequency. Best is, of course, to calculate a jittered waveform.
There is such a thing as inter symbol jitter (ISI) in digital signals, which basically means that the last few bits (symbols) influence the edge of the current bit (symbol). A low-pass filter, for instance, adds this ISI.
Embedding is simulating the distortion of a signal path. "De-Embedding" is the opposite, where you predistort your signal such that it arrives cleanly. You need to measure/simulate the S21 parameter (sigh) of your circuit for this. It's more difficult for differential signals.
When simulating Gaussian noise, you have to clip it, because it is unbounded. It's easy to accidentally clip too much - the rare events are those that cause errors in the real world. Real noise is rarely Gaussian. It has thicker tails (a higher crest factor).
If you want to measure low bit-error rates under tested "random" noise, make sure your test-waveform is long enough. Man, they try to sell memory whereever they can... Or, you add noise programmatically, which of course they also have a product for.
Fundamentals of Arbitrary Waveform Generation Ch. 4
Choosing a DAC sampling rate close to the Nyquist limit allows saving memory, but will make filtering of unwanted images harder. The Agilent publication shows a scary example on page 116, where you can see how this degrades a signal even in the time-domain, because the reconstruction filter just doesn't work as well close to the Nyquist frequency. Also, digital equalizing will eat up more of the SFDR (spurious free dynamic range), and the noise power density of the quantization noise increases.
Using a "way too high" sampling rate is known as oversampling. It helps a lot.
Beware of record length granularity (RLG). For single shot signals, you can 0-pad (or otherwise pad) the waveform accordingly.
For periodic signals, 0-padding can lead to phase-jumps in loops. In that case, one way to deal with RLG is to adjust the sample rate of the waveform, but due to the fixed sample-rate of the DAC, this can lead to jitter, especially in digital signals. (I guess trueform is supposed to help here.) For sine waves, you may want this effect, because it can make sure that quantization noise is spread evenly across the first Nyquist band. The other way to deal with RLG is to use a record length where the waveform repeats an appropriate number of times. You can also combine both techniques.
A completely different method to combat periodic quantization noise is dithering, where you add some small, random value (uniform distribution within [-1/2 LSB, +1/2 LSB] to the ideal waveform before quantization (so before it is loaded into the AWG). If done intelligently, this add's a surprisingly small amount of noise, but spreads the quantization noise spectrum across the whole band. It can also increase the effective DAC-resolution for DC signals (like low-pass-filtered PWM).
Careful when digitally filtering a looped signal: Make sure the filter convolution is cyclic, too, otherwise you get "filter discontinuities". This is trivial for FIR, but IIR might need several passes to converge onto a final, filtered signal. When using sequences, things become even more complicated: Use link-segments!
Of course, you can also play back capture signals. Agilent recommends setting the sampling rate of the scope and AWG to the same value (or an integer fraction in between), both being as high as possible. The captured signal (captured with ) has to be digitally filter such that it contains nothing above . It is then resampled. Playack creates sidebands in the other Nyquist band of the DAC, which are, as always, filtered by the output stage.
You can increase the fidelty of the played-back signal through averaging multiple waveforms, smoothing, and further digital filtering.
Side-Note: A scope's high-res mode usually means sampling the signal at a higher frequency, then binning it, and storing only the averages of the bins to memory. Analog noise acts as natural dithering, so this gives a better resolution.
Fundamentals of Arbitrary Waveform Generation Ch. 3
Waveform memory is usually SRAM, which is fast and does not need to be refreshed like DRAM. Drawback: Expensive and only room for tens of MSample. Waveform is acessed via adress-counter that periodically resets -> Ring memory.
SRAM is not as fast as high-speeds DACs, so you typically read several points in parallel across a wider bus.
You can also use DRAM, but you need additional processing horsepower to deal with the dynamic refreshing. Gives huge waveforms (GSample). Drawback: Waveforms must have some minimal length for the buffer to be always filled.
Wrap-around-glitches: Reading n samples in parallel means that waveform length should be a multiple of n. This is called the Record Length Granularity. If you neglect this, the AWG may just truncate your waveform.
Memory can be organized in a single memory bank (only one waveform at a time; long switchtime between waveforms), several banks (fast switching, but all limited in size), or segmented memory (one bank, many pointers to start adresses). The latter two allow "sequencing".
Sequencing means iterating over several "segments", with each segment comprising several samples. AWG's may support several stored sequences, and may also allow programmatic control of the sequences using external triggers.
Transitioning between segments may take time. The DAC may play each sample, but the sequencer might take a longer time to be able to jump to another segment again.
If the AWG can store several sequences, it might be possible to define scenarios (playback of sequences in a certain order). Inception.
Sequence Control: "Automatic" = step through the sequence in a predefined order (incl. possible loops). "Conditional": Loop the current sequence until a trigger occurs, then either finish current sequence and go to next, or go to next immediately. "Repeat": Like "Conditional", but don't loop - instead repeat the last sample until the trigger occurs. If you do the latter for all segments, you call this "stepped mode". "Gated Mode": Only run through sequence while trigger is high.
Dynamic Sequence Control: Not only one trigger, but several signals in a parallel bus-configuration can control the sequence playback. Advanced stuff. Limited by bus width (13 bit is typical), and switching time (latency). You can use this to store long binary outpus (by storing 256 sequences that each correspond to one byte).
You can use markers in the waveform to control the synch output. These are either stored as extra bits along the waveform, or in some sort of special stream at reduced timing resolution. Markers are aligned with waveform samples, but waveform samples are not necessarily aligned with features of the waveform (think of a 10 Hz sine sampled with 21 Hz). This can lead to jitter, unless sample-period and signal period are some multiple of each other. Alternatively, you can use a second channel to generate low-jitter clock/synch.
Synchronizing AWG's: Using a 10 MHz refernce for multiple, identical AWG's leads to fixed phase relationships (but the phase of the sampling clock will be arbitrary!!). The AWG's need to be time-aligned for different trigger delays, especially in master/slave configuration, and fine-time-aligned for the sampling clock phase problem. If you use different makes/models of AWG's, they may generate the sampling frequency a bit differently from the clock, which can lead to slow drifts!