# C-field driver - again¶

After some work I have designed at this C-field driver: The main change since first version a couple of extra resistors supply the stable current for the buried zener in the LM399 voltage reference.

I’ve run a monte-carlo analysis for the tempco of the components over a ±10 {K} temperature range.

## VCC & R4¶

VCC is the +20V regulated supply, which I allowed to vary ±0.5 {V}

If R4 is 1M with 100 {ppm/K} tempco, the frequency noise is 6.5e-17 {s/s}.

If R4 is 100k with 100 {ppm/K} tempco, the frequency noise is 5.7e-16 {s/s}.

I have not checked how small R4 needs to be to ensure startup, but given the low offset voltage of U1, I don’t expect problems.

## R2 & R3¶

The voltage over these is the same (± U1’s Vos) and their ratio sets the U2 zener current relative to the C-field current.

With 50 {ppm/K} each of them contributes 6.7e-17 {s/s} frequency noise.

## U1¶

LT1007 has a guaranteed max drift with temperature of 0.6 {µV/K}, which contributes 1.1e-15 {s/s} frequency noise.

There is no need to trim the offset of U1.

## R1 & U2¶

R1 is a Vishay Z201 with a typical tempco of ±0.2 {ppm/K}

U2 is a LM399 (without -A suffix) with a typical tempco 0.3 {ppm/K}

If we use these typical tempcos, the frequency noise is 4.3e-15 {s/s}

If we use the max tempco, 2 {ppm/K}, for the LM399 and the typical for R1, the noise rises to 2.4e-14 which is above my 1e-14 {s/s} goal.

There is no max tempco specified for the Z201, and the datasheet doesn’t give me high confidence that the typical is very typical after all.

## Temperature¶

The limiting factor is R1 and U2, and all in all there is about 1.5 {ppm/K} tempco to share between them.

Of course ±10 {K} is a pretty brutal condition for a device which presumably lives in a somewhat civilized laboratory.

If we can keep the excursions to ±2{K}, then R1 can have 3 {ppm/K} tempco and still stay below target.

## Tunable C-field current¶

Mechanical trimmers have two digit tempcos, and since they would go between U2 and U1, math isn’t even necessary.

A digital solution may be possible, there are special DACs for driving 4-20 {mA} industrial circuits, for instance Analog’s AD5422, which could possibly be beaten into submission, given a good external reference.

That would be neat, since it would open the way for a GPS discipline implementation, but that is a project for another day.

Right now I just want to get the Fluke 732A and the long wire out of the picture.

## Monte-Carlo Code¶

Here is my monte-carlo simulation in python:

```#!/usr/bin/env python
#
#
# VCC
#  |
#  |
# R4
#  |              |\
#  *--------------| \
#  |              |  >--- L1 --+
#  |           +--| /          |
#  |           |  |/           |
#  |           |               |
#  *---- R3 -------+-----------+
#  |           |   |
#  |           |  R2
#  |           |   |
# D1           +---*
#  |               |
#  |              R1
#  |               |
# GND             GND
#

from __future__ import print_function

import random
import math

def calc(comp):
d = dict(comp)
for i in range(5):
d["vr1"] = d["D1"] + d["U1"]
d["ir1"] = d["vr1"] / d["R1"]
d["vr2"] = d["ir1"] * d["R2"]
d["vl1"] = d["ir1"] * d["L1"]
d["vout"] = d["vl1"] + d["vr2"] + d["vr1"]
d["vr3"] = d["vr1"] + d["vr2"] - d["D1"]
d["ir3"] = d["vr3"] / d["R3"]
d["ir4"] = (d["VCC"] - d["D1"]) / d["R4"]
d["id1"] = d["ir3"] + d["ir4"]
d["D1"] = comp["D1"] + d["id1"] * .66
return d

def show(d):
l = d.keys()
l.sort()
for i in l:
print("%s\t%17.9f" % (i, d[i]))

def ppm(n):
r = random.uniform(-n, n)
r *= 1e-6
r += 1.0
return r

comp0 = {
"R1":   5000./3,        # Ohm
#"R1":  1000.,          # Ohm
"R2":    500,           # Ohm
"R3":   2000,           # Ohm
"R4":    1e5,           # Ohm
"D1":      6.9,         # Volt
"L1":     12.0,         # Ohm
"U1":      0.0,         # Volt
"VCC":    20.0,         # Volt
}

d = calc(comp0)
show(d)
iref = d["ir1"]

sy = 0.0
syy = 0.0
n = 0.0
for i in range(1000):
x = dict(comp0)
dt = 10

# 2.4e-15 @ 2ppm (LM399), +/- 10K
x["D1"] *= ppm(2 * dt)

# 2.5e-15 @ .2ppm (Z201 TYP!), +/- 10K
x["R1"] *= ppm(3.0 * dt)

# 1.1e-15 @ .6PPM/K (LT1007A), +/- 10K
x["U1"] = 1e-6 * random.uniform(-.6 * dt, .6 * dt)

# 6.7e-17 @ 50pmm, +/- 10K
x["R3"] *= ppm(50 * dt)

# 6.7e-17 @ 50ppm, +/- 10K
x["R2"] *= ppm(50 * dt)

# 6.5e-17 @ 100ppm, +/- 10K, 19.5-20.5 VCC
x["VCC"] = random.uniform(19.5, 20.5)
x["R4"] *= ppm(100 * dt)

d = calc(x)
df = (d["ir1"] - iref) * 5e-7
sy += df
syy += df * df
n += 1.0

avg = sy / n
stddev = math.sqrt((syy - sy * sy / n) / (n - 1))
print("%.1e" % stddev)
```

phk