I want the DCO to work for all midi notes (C0-B8) and be within 1 to 3 cents of the correct frequency for all notes.
Looking at the Juno 6/60/106 and JX-3P DCOs I've so far set up a google docs spreadsheet, calculating all periods to get correct frequencies and the necessary voltages (currents) to get a constant amplitude.
A short intro to DCO theoryDCOs are (often) based around a relaxation oscillator, exactly like a saw core VCO (http://xonik.no/theory/vco/reference_current.html - this also explains how the capacitor is charged). A current charges a capacitor and a transistor short circuits and discharges it to restart the period.
DCOs are stable because they use a digital timer to control the discharging of a capacitor instead of relying on an accurate charging current - the period and thus frequency is computer controlled and highly accurate. For the saw ramp to reach the same amplitude as the charging period (time available to charge the capacitor during a cycle) changes, the DCO instead changes the charging current. As the frequency changes exponentially with rising notes, so must the charging current.
In my spreadsheet I have calculated two important aspects for a physical circuit - the accuracy of the timer generating the period/frequency and the accuracy of the charging current generation.
FrequencyA microcontroller timer has two properties - the minimum period and the maximum count. These limits the length of an output period and the accuracy of its length. A 16bit timer can at most count to 65535 and has a maximum accuracy of +/- 0.5 times its minimum period. For example, if the timer frequency is 8MHz, each tick of the timer is 0.125uS and the accuracy is thus +/-0.0625uS. Its maximum output period length is 65536 * 0.125uS = 8192uS or 8.19mS. The consequency is that a 16 bit timer running at 8MHz has a minimum output frequency of 1/8192uS = 122Hz. (Here we assume that the timer restarts the period whenever it has counted to its maximum).
The accuracy limitation is most important to the upper end of the frequency range. The maximum needed frequency (B8 = 7902,13282Hz) has a period of 126,55uS. An inaccuracy of 0.0625 equals an error of about 0.05%. The human ear is able to hear a difference between two notes played after eachother of about 10 cents/0.6% if the notes are sine waves, less if they are complex tones. Thus, this inaccuracy is well within what is acceptable.
But what can we do to make the timer count long enough for deeper notes? We can either use a bigger timer (32bit) or more often, use a prescaler that divides the clock running the timer. If we use a prescaler of 2, the timer frequency changes from 8MHz to 4MHz, the minimum period changes from 0.125uS to 0.25uS and the maximum time from 8.19mS to 16.38mS. This makes the lowest possible frequency 61Hz. Changing the prescaler to 8 gives a minimum frequency of 15.25Hz, which is low enough for C0.
Unfortunately, increasing the prescaler also decreases the accuracy as the minimum period gets longer. I have set 3 cents as the maximum error acceptable at the highest frequency. Using a prescaler of 8 makes some of the notes at the top of the frequency range fall outside the target accuracy.
In short - using a 16bit timer, we cannot use a single prescaler value and achieve both the frequency range and the accuracy needed. To solve this, we need to change the prescaler somewhere towards the lower end of the frequency scale. To get a constant time used setting up the timer, i propose always setting the prescaler when reloading the timer.
AmplitudeDCOs use different ways of creating a control current. As mentioned previously, the necessary charging current changes exponentially as the notes change. The Juno 6/60 seems to use an exponential converter (I may be wrong about this though, I haven't studied it closely) to achieve this, but such a converter has the same temperature dependency problems as the one controlling the pitch in a VCO (but the effect in the DCO is on the amplitude, not the pitch, and will thus not be as noticeable).
The Juno 106 and JX-3P however just feed the output of a DAC through a resistor and into the integrator (saw ramp generator). This means that the DAC must generate a voltage that accurately approximates the exponential curve needed throughout the note range (the voltage is converted to a current through a resistor). This may be problematic as the rate of change is very small at one end then suddely very large at the other.
I've once again used the spreadsheet to calculate first the real the charging voltage needed, then the current created using a DAC of arbitrary resolution. By rounding off the needed current to the nearest value achievable with the DAC, then multiplying with the per-step voltage, then using the capacitor charging formula with the known period as t, we will find the real amplitude of the wave and thus the maximum error per note.
Using a 16bit DAC and charging a 1nF capacitor through a 100k resistor, we are able to charge the capacitor to within 0.02V (of a maximum of 5V), or 0.4% of the wanted amplitude for all notes.
When calculating the capacitor charging, I've assumed that we can follow the same formula as in my older VCO research, where I found that the voltage across the capacitor at a time t after the charging starts, V(t) = t * I/C. I is found by dividing the DAC voltage Vdac with the input resistor R. Rearranging for Vdac gives us Vdac = V(t) * C * R / t, and to calculate the resulting max charging voltage, V(t_max) = Vdac * t_max / C * R.
My calculations can be found here: https://docs.google.com/spreadsheets/d/1ROhU0L4UZ2CWLu3h5LHopaB0Jv7ewNRziecj5I6D27M/pub?gid=0&single=true&output=pdf
- Figure out how to calculate timer values and dac settings (lookup tables?)
- How to interpolate efficiently between values in the lookup table to reduce its size while still allowing input pitch to be a 16 bit value
- How to do DCO sync
- Possibly: Changing timer/charge voltage in the middle of a cycle in order for the DCO to respond instantly (the Juno DCOs apparently only change pitch at the start of a cycle.