Variable Load: Initial Programming

Now that the board is built, and I can power it up, let’s try programming it!

First is the hardware set-up. I have to power the board and hook up the AVR programmer to it. Below is what it looks like:

Hardware set-up. Shows the board, AVR ICE programmer, and the barrel connector that powers the board with 12 volts.

I’m using Atmel Studio 7 to program the board. Now, in order to see if the programmer recognizes the microcontroller, I open up the Device Programmer and try to read the fuses in the microcontroller.

Fuses, by the way, have nothing to do with the piece of metal that melts when too much current goes through it. Fuses, for AVR microcontrollers, are configuration bits that affect how the microcontroller behaves. Fuses will decide what drives the microcontroller’s clock, whether the watchdog timer is running, etc.

Initial fuse settings

The image above shows the fuses that are being read in the microcontroller. Good news and bad news. The good news is that the microcontroller is responding, and is therefore working. We know this because we can see what the fuses are, and we can get the Device Signature (0x1E9587). The bad news is that the fuses are not setup the way I’d like.

First, this is a 5 V system, so I’d like the Brown Out Detect (BOD) to be closer to 5 volts. So I’ll have to change that to be larger. Secondly, I don’t plan to use the bootloader, so HWBE can be turned off. Adding on to that, since I won’t use a bootloader, I’ll make the boot flash size smaller to make more room for my application code. Third, I’m only planning on using AVR ICE to program the device, which uses a JTAG interface, so I don’t need to program the chip through SPI, so I’ll turn that off. Lastly, the CKDIV8 divides the input clock by 8, which is good for power savings, but not necessary for this application. A higher clock speed allows the microcontroller to work faster, and power is not a concern here, so I’ll turn that off.

Erase chip to allow fuses to be changed

Unfortunately, if you try to change the fuses, you might see that it doesn’t work. This is because of lock bits, which keeps the fuses from changing. If you try to change the lock bits, they can’t be changed either! In order to reset the fuses and the lock bits, you have to erase the chip. You can do that by going to Memories in the Device Programmer window, and click “Erase now” button. Now, you can adjust the fuses as you please.

New fuse settings

The new fuses are shown above. Now, the microcontroller will be put into reset if the 5 volt droops below 4.3 volts, the microcontroller can only be programmed through JTAG, the bootloader size has been made smaller, and the clock-divide-by-8 is disabled. Should be good to go!

One fuse setting I’d like to point out is the last one: SUT_CKSEL. This fuse is, I’d say, the most important one. It controls the Start Up Time (SUT) and what clock the microcontroller will use. The microcontroller can use it’s internal RC oscillator, use an external crystal, or use an external clock; which one you use will affect how fast the microcontroller runs and how much power it uses. If the fuse is set-up incorrectly, then the microcontroller may be waiting for a clock that doesn’t exist, and never run. Make sure it’s what you want! In this case, the fuse is set-up to use an external crystal oscillator that runs above 8 MHz. This is what I want since the crystal oscillator I have runs at 16 MHz. The start-up time is pretty large (65 ms), which is good if you want to make sure the oscillator is good to go when you run the program. If you’re application requires your code to be up and running as soon as possible after power is applied, you’ll want to reduce the start-up time.

Import delay library
Note you must define F_CPU, which tells delay library the oscillator frequency

I want to write a simple code to turn LEDs on and off, the embedded systems equivalent of Hello World. First, I import two libraries: avr/io and util/delay. avr/io is where registers for the ATMEGA32U4 (and other AVR microcontrollers) is defined (for example port, pin and data direction registers), and utill/delay just has delay functions that are useful for testing simple programs. Note that you have to define F_CPU and set it to the crystal oscillation frequency, which is 16 MHz in this case.

Simple code to toggle all four LEDs on and off sequentially

Here’s the application code. In the schematic, I have LEDs hooked up to PE6, PF0, PC6 and PC7. The code above just turns those LEDs on and off, sequentially.

The section outside of the while loop initializes those pins by writing HIGH to them, and then setting them to be outputs by writing to the data direction registers. Since the LEDs are only on when the GPIOs sink current, at this point the LEDs will be off. Inside the while loop, I turn the GPIOs LOW then HIGH one at a time, and this will turn the LEDs on and off, respectively.

Upon programming this code into the microcontroller, the LEDs blinked! So that means the microcontroller is powered and programmable. What’s next?

The code example above is pretty messy. I can understand it because I wrote it a couple of minutes ago, but next week, I may not remember how the code works. Fortunately, the code is simple enough that I can figure it out in a couple of minutes, but as the code gets more complicated, that won’t be feasible. Obviously commenting is helpful, but the real problem is that I have no hardware abstraction.

Hardware abstraction is the concept of “hiding hardware information from the application code.” How this is done is by creating functions that deal with the low level registers, so the application code doesn’t have to worry about it. Below is an example:

Example of what hardware abstraction looks like
This is pseudo code, so there are errors

Ignore the red squiggly lines. Here, you can clearly see what’s happening; you have four LEDs, and you are turning them on and off after setting them up. You don’t have to worry about what registers are involved, or how they’re being manipulated. The application code doesn’t care about that stuff; it only want to turn LEDs on and off. Hardware abstraction allows the application code to not worry about the details and focus on what’s important, keeping the code simple and easy to understand. Another advantage of hardware abstraction is that it improves code maintenance; if you have to change how the registers are being manipulated, then you can do that without touching anything in main() at all!

My point is hardware abstraction is crucial for embedded systems, since they improve code readability and maintenance. For that reason, I’m going to start building a Hardware Abstraction Layer (HAL) that lets you use the microcontroller’s peripherals without having to understand the nitty-gritty details. Of course, I can download one that others have created, or get one directly from Atmel; almost always, chip manufacturers have HALs available on their website (or IDE) so that programmer can start working on application code right away. But since the point of this blog, and this project, is to learn, I’m going to re-invent the wheel. Let’s learn how to program embedded systems!

Variable Load: PCB Build

The board and parts finally arrived! Here, I’ll talk about building the boards.

PCB Fixture

I didn’t want to have a exposed PCB on my work station since they’re pretty fragile, and there’s a risk that you can short things out. I therefore decided to 3D print a little fixture to hold the PCB:

Variable Load PCB Fixture, isometric view
Fixture, top view

I designed the fixture in OnShape. The board will be installed, top side face down, onto the top of the fixture. As you can see, it’s basically a cup that will cover one side of the PCB, which means the microcontroller, ADCs and DAC, as well as almost all of the passives, will be covered. The PCB’s connectors and test points, though, will be exposed, so testing and debugging the PCB while it is in the fixture shouldn’t be a problem.

The PCB is held up by the supports at the edges as well as two cylinders near the middle of the fixture. One of the cylinders has a hole in it; that’ll be tapped by an M3 tap after printing, which will allow me to put a M3 screw into it. This will keep the PCB from coming out of the fixture. Since the tapping, as well as the screwing and unscrewing, may stress that support, I added ribs for extra stability. I originally didn’t want to have the edge supports, but because the PCB is half as thick as typical PCBs, the board is pretty flimsy, so supports are necessary if I want to easily hook up connectors to the headers. The edge supports need to have slots cut out of them to make sure that the supports do not interfere with the through hole connectors, which would prevent the PCB from sitting flush inside of the fixture. The fixture also has a slot cut out of one of its walls to expose the USB connector.

Built PCB

Variable Load PCB, top side
PCB inside of the fixture, bottom side visible

I built two PCBs at once. I seriously underestimated the amount of work that building these boards was; it looks simple, since there are so few ICs, but the large number of passives make the work tedious and time consuming. The process was the same as building of the Stampduino: I used a stencil to put solder paste on the PCB, put the components onto the PCB using tweezers, and then I put the whole thing in my reflow oven. Afterwards, I examined the soldered PCB and cleaned up any failed solder joints, shorts or components that shifted / tombstoned during reflow.

In addition to soldering all of the components on the top side, I had to install the through hole connectors as well as populate the resistors and LEDs on the back side. Not difficult, but again, more time consuming than one may think. The hardest part was getting the LEDs right; they all look the same unpowered but have different colored lights when powered, so making sure that the right LED was on the right pads for each board took some time. Also, the polarity markings are on the bottom of the LEDs, so flipping and then reflipping each tiny component was pretty annoying.

I used 0402 components since that’s what I used for my Stampduino, but in that application space was a premium, and there were relatively few parts. In this case, space was not an issue, and the board was much more complex, so 0603 components probably would have made the assembly a lot less painful.

One thing to note is that I made an error ins the schematic; for the LDO, one of the feedback resistor values is incorrect. R7 should be 1.87 kΩ, but the schematic says 18.7 kΩ. That’ll be fixed when I publish my schematic.

My grumbling aside, it was definitely worth the effort; the PCBs look great, and they look even greater on the fixture! The PCB fits very well in the fixture, and the whole thing feels very secure, so I’m not worried about the fixture falling apart or the board falling out of the fixture or anything like that. One thing to note is that I found a polarized version of the 4 pin male header connector that the fan hooks up to, so I decided to use it to prevent accidents. The connector sticks out a bit, and interferes with the fixture a little, but it should be fine.

I’ve done minimal testing so far. First, I checked the resistance from ground to the power rails and made sure there were no shorts. Then, I supplied 6 volts to the 12 volt input to test the LDO. Since the regulator is hooked up to a bunch of chips, I was worried that the LDO would output a voltage over 5 volts and potentially damage the chips. By providing a 6 volt input, rather than 12 volts, this ensures that even if the LDO isn’t regulating its output correctly, the chips that the LDO power aren’t seriously over-driven. Fortunately, since I fixed R7, the LDO output the correct voltage (4.95 V, which is fine). I also saw that there were no large currents, which means that there was no short to ground on the power rails. After seeing that the regulator worked properly, I raised the input to the expected 12 volts, and the LDO still output the correct value. This testing shows that none of the power rails are shorted to ground, and the main voltage regulator functions properly, so I can move on to functional testing. Next I’ll have to confirm that I can program the microcontroller, and then start writing code to check all of the ICs. One step at a time!

Measuring Resistance Part 1

Resistors are used everywhere in electronics. Their defining characteristic is, not surprisingly, resistance. Resistance determines what the voltage across a resistor is for a given amount of current; this relationship is captured using Ohm’s Law:

V = IR

So let’s say you want to measure the resistance of a resistor. Unfortunately, there’s no way to measure resistance directly. Fortunately, you can use Ohm’s Law to calculate it! For example, you could force a voltage, say 1 volt, across a resistor and then measure the resulting current; then you can calculate resistance by dividing 1 volt by whatever the current was. But since it’s MUCH easier to measure voltage rather than current, you do the opposite: you force a set amount of current through a resistor, and measure the resulting voltage. For example, if you force 1 A of current, then 1 Ω will yield 1 V, and 10 kΩ will yield 10 kV. By measuring the voltage across the resistor, you can determine the resistance since you know the amount of current you’re pumping through the resistor. To do this, you’ll need a volt meter and a current source:

Simplified schematic for an ohmeter

The 1 A test current example above reveals two complications. First, you should not force 1 A through something just for the sake of performing a measurement. This raises the question: how much current should be used? Second, the massive range of resistors makes getting a good voltage difficult for a set amount of current. 1 µA will yield 1 µV for 1 ohm (too small) and 10 V for 10 MΩ (too big; even if the ohmeter could safely generate and measure this amount of voltage, the resistor or the circuit the resistor is in may not be able to handle it).

The answer is to set a voltage limit, and to use ranges. For example, say you limit the current source to only output 1 volt, and you only want to measure up to 100 ohms. Then, you should use a test current of 10 mA. If you want to measure up to 1000 ohms, then use 1 mA. If you want to measure up to 10 kohms, then use 0.1 mA. This is why in many older multimeters, you had to manually select what range of resistance you were interested in:

Image from Amazon
Bottom right of the dial shows different ranges for resistance, and different amounts of test currents

Most digital multimeters, however, have auto-ranging capabilities, so manually selecting the range isn’t necessary. For example, the multimeter may force 0.1 mA through a 100 ohm resistor initially. The multimeter will then see that the voltage across the resistor is a minuscule 0.01 V, and increase the test current to 1 mA. Again, the multimeter will see 0.1 V, so it’ll up the test current to 10 mA. Upon seeing the voltage is a respectable 1 V, the multimeter will stop adjusting the test current. That’s not to say digital multimeters can only do auto-ranging; you can manually adjust the range by pressing the “range” button. We’ll talk about why you may want to do this in a future post.

The ranges and test current amounts we’ve talked about so far are hypothetical (AKA I made them up). Let’s perform some measurements on an actual multimeter for reference. I’m using a Thsinde 18B+ digital multimeter in ohm mode and an oscilloscope to measure voltage. Here’s my setup:

Test setup
  1. I noticed that the oscilloscope was picking up a lot of noise, so I added a 10 µF cap for filtering. This capacitor is too small to affect this test (as long as you let the multimeter stabilize), but as we’ll talk about in a future post, a large capacitor in parallel with a resistor can prevent the multimeter from working properly. I also bandwidth limited the probe for the sake of reducing noise.
  2. I configured the oscilloscope to measure several seconds of data, and then average the waveform to get the voltage across the resistor; I did this because I only have one multimeter.
  3. The oscilloscope uses a 10X probe, which has an input impedance of 10 MΩ. This primarily affects readings when measuring resistance in the megaohm range. I also used this to load the multimeter with a 10 MΩ resistor by only connecting the multimeter to the 10X probe.

I measured various resistors while the multimeter was in auto-range and collected the following data:

#Measured Resistance (Ω)RangeAverage Voltage (mV)Test Current (µA)
110< 600 Ω2.82282
220< 600 Ω6.7335
346.8< 600 Ω16.93361.7521368
4100.1< 600 Ω36.49364.5354645
5217.9< 600 Ω76.49351.0325838
6471.6< 600 Ω152.98324.3850721
71000< 6 kΩ79.3379.33
82239< 6 kΩ161.1871.98749442
94645< 6 kΩ285.861.5285253
101.01E+04< 60 kΩ90.478.98
112.22E+04< 60 kΩ179.168.07
124.69E+04< 60 kΩ316.746.75
131.03E+05< 600 kΩ92.890.90
142.19E+05< 600 kΩ180.760.83
154.55E+05< 600 kΩ315.170.69
169.16E+05< 6 MΩ86.59.44E-02
171.00E+07< 60 MΩ505.495.04E-02
Auto-range data
  1. I find it curious that the ranges are what they are. You’d think the ranges would be < 100 Ω, < 1 kΩ, etc., but they’re < 600 Ω, < 6 kΩ, etc. I’ve noticed other multimeters do this as well.
  2. Interestingly, the test current seems to vary even within a single range. But generally, the test currents are 300 µA for <600 Ω, 70 µA for < 6 kΩ, 8 µA for < 60 kΩ, 0.8 µA for < 600 kΩ, 90 nA for < 6 MΩ and 50 nA for < 60 MΩ.
  3. The multimeter likes to measure voltages in the hundreds of millivolts, rather than microvolts or volts. This makes sense; microvolts would be extremely sensitive to noise, and difficult to measure, while volts might accidentally damage or otherwise influence whatever circuit the resistor is in.

The data clearly shows the range affects the test current. Now let’s see how the range and resistance affects the output voltage. For these measurements, I had the same setup as the previous test. However, I hooked the multimeter up to a single resistor and then played with the manual range. Here are my results for 4.7 kΩ, 10 kΩ, 22 kΩ, 100 kΩ, 220 kΩ, 470 kΩ, and 10 MΩ:

4.7 kΩ
#ValueRangeVoltage (mV)Current (µA)
1OL.< 600 Ω641.25136.50
24.647 kΩ< 6 kΩ285.1860.71
304.65 kΩ< 60 kΩ47.8710.19
4004.6 kΩ< 600 kΩ5.091.08
50.003 MΩ< 6 MΩ0.3930.08
600.00 MΩ< 60 MΩ0.3350.07
10 kΩ
#ValueRangeVoltage (mV)Current (µA)
1OL.< 600 Ω800.980.17009
2.OL< 6 kΩ470.6347.110063
310.09 kΩ< 60 kΩ93.189.327318
4010.0 kΩ< 600 kΩ11.81.18118
50.009 MΩ< 6 MΩ3.090.309309
600.00 MΩ< 60 MΩ3.150.315315
22 kΩ
#ValueRangeVoltage (mV)Current (µA)
1OL.< 600 Ω891.3240.60
2.OL< 6 kΩ656.4329.90
322.20 kΩ< 60 kΩ180.218.21
4022.3 kΩ< 600 kΩ24.961.14
50.022 MΩ< 6 MΩ1.225.56E-02
600.02 MΩ< 60 MΩ1.255.69E-02
100 kΩ
#ValueRangeVoltage (mV)Current (µA)
1OL.< 600 Ω980.129.899212
2.OL< 6 kΩ906.659.157165
3O.L< 60 kΩ508.985.140698
4103.2 kΩ< 600 kΩ95.970.969297
50.103 MΩ< 6 MΩ12.410.125341
600.10 MΩ< 60 MΩ12.410.125341
220 kΩ
#ValueRangeVoltage (mV)Current (µA)
1OL.< 600 Ω989.284.60
2.OL< 6 kΩ949.014.41
3O.L< 60 kΩ682.223.17
4218.8 kΩ< 600 kΩ179.020.83
50.218 MΩ< 6 MΩ21.329.90E-02
600.21 MΩ< 60 MΩ21.499.98E-02
470 kΩ
#ValueRangeVoltage (mV)Current (µA)
1OL.< 600 Ω997.782.22
2.OL< 6 kΩ976.922.18
3O.L< 60 kΩ819.021.82
4455.3 kΩ< 600 kΩ312.680.70
50.457 MΩ< 6 MΩ41.479.24E-02
600.45 MΩ< 60 MΩ41.379.22E-02
10 MΩ
#ValueRangeVoltage (mV)Current (µA)
1OL.< 600 Ω10000.10
2.OL< 6 kΩ10000.10
3O.L< 60 kΩ9969.96E-02
4OL.< 600 kΩ9159.15E-02
5.OL< 6 MΩ506.55.07E-02
610.08< 60 MΩ506.55.07E-02
  1. Based on this data, the current source has a 1 V limit. That’s high enough to turn some transistors on or be read as a HIGH in some low voltage applications, so keep that in mind.
  2. Not all OL (short for overload) result in the maximum voltage across the resistor. This suggests that even in manual mode, the multimeter has some intelligence beyond just voltage limiting / current output.
  3. Unsurprisingly, putting the multimeter in a range that is too high for the resistor value will result in loss of resolution, so you should keep the range as small as possible for best results.
  4. Interestingly, it looks like < 6 MΩ and < 60 MΩ use the same amount of test current in manual mode, based on the fact that the voltage across the resistor does not change much when transitioning between these two ranges.

I hope you enjoyed reading about how multimeters measure resistance. By pumping a set amount of current through a resistor, and then measuring the resulting voltage, the multimeter can tell what the resistance of a component is. However, this theory only works when there is no capacitance; I’ll explain why in a future post.

Variable Load: Layout

Schematic Update

Before I get into the layout, I’d like to mention that I added another ADC to the system.

I realized that even though the system should have control of the current, and therefore measuring the current isn’t necessary, in actuality whatever power supply that the load is connected to may not be able to meet the variable load’s current demand. Therefore, even though the system thinks it is consuming 5 amps, it may be consuming less than that, and without a high resolution measurement, the system has no way of figuring out what the actual current consumption is. That’s why I added the LTC2451, a very small 16-bit, sigma-delta ADC. It is a low speed ADC, which is fine, since the system will only need to measure current at a low rate in order to update the LCD.

I also added various LEDs and test points to unused GPIO pins, which will be helpful during debugging.

Lastly, I added a TVS (transient voltage suppressor) on the input to the variable load. I realized that if the variable load is put in series with an inductor, then turning the variable load off will cause the inductor to force a large voltage across the load transistor, potentially damaging it. The TVS is designed to conduct above 33 V and be open below it, and the transistor is rated for 40 V, so the TVS should keep the transistor safe from over-voltage conditions.

Layout

Top (left) and bottom (right) of PCB

The vast majority of components are on the top side of the board. The bottom side only has test points, some resistors and LEDs, as well as connectors. This is a 4 layer board that is 2.35 x 2.5 inches, 0.8 inches thick. I made the board thinner than usual to improve coupling between ground and power plane as well as decrease thermal mass so that the board is easier to reflow.

I used a pretty standard approach for the layout for the most part. Bypass capacitors for chips are placed as close to the power pins for that chip as possible, analog traces are as short as possible, circuits are grouped together by function, and signal cross talk is avoided as much as possible. I also grouped buses (SPI, I2C and serial) together for the sake of cleanliness.

Fan

The fan I chose to cool the heatsink consumes a lot of current. In order to meet this need, as well as keep the fan noise away from the rest of the circuit, I made some special accommodations:

Top layer: thick copper connection between capacitor and connector to fan
Note thick copper connection is duplicated on the bottom of the board

The fan has a 100 µF capacitor for bypassing, which will hopefully reduce noise generated by the fan motor. The layout above was done for two reasons: first, it provides a very low resistance path between the leads of the capacitor and the pins of the fan connector, making it a more effective bypass capacitor. Secondly, the isolation of the ground copper from the rest of the ground pour on the top of the board helps keep the noise of the fan isolated from the rest of the PCB. If there is any rapid or large current flow between the fan and the capacitor, the current surges will not leak out to the rest of the ground pour.

Left: ground plane, right: power plane

The capacitor and the fan are powered through the ground plane and power plane, rather than a trace on the top or bottom of the board. This decision was made to simplify routing, as well as provide low resistance and high amapacity copper connections. As you can see on the left in the figure above, the ground plane has a notch in it. This notch was placed so that any current flow between the barrel connector (at the top left of the PCB) and the fan would not leak out onto the rest of the PCB, reducing noise. The power plane is similar, but this is mostly to provide a low resistance connection between the barrel connector and the fan. No other circuit, besides a linear regulator, uses the 12 V input from the barrel connector, so the separation between the 12 V pour from the VCC pour on the power plane does not provide much advantage in terms of noise reduction.

Load

Since the load can consume many, many amps, special attention to the layout was needed. First, note the thick copper traces connecting the VLOAD+ to VLOAD- through D2. Though I suspect it won’t be necessary, having thick copper traces allows the TVS to shunt a very large amount of current.

More pressingly, a very large amount of current can go from VLOAD- to GND through the pins of U3. In order to minimize the resistance of this connection, all four layers were used:

bottom (top), ground plane (middle), power plane (bottom)

Since all four layers should share the current, a lot of vias were used to stitch the layers together as much as possible. Note how the copper is poured on the ground plane: the ground copper ring has the connection to U3, as well as connection to the ground copper pour of the ground plane. These two pieces of copper only connect through the ground copper ring. As with the fan, this was done so that the large amount of current flowing from VLOAD- to GND would not flow to the rest of the board, reducing noise for unrelated circuitry.

Exposed copper on top layer

One last attempt to increase the current carrying capability of the PCB is to expose the copper on the top and bottom for VLOAD- and GND. This helps in two ways. First, the exposed copper is tinned during PCB manufacturing; in this case, the copper undergoes HASL (Hot Air Solder Level). This tinning will increase the amount of metal available for current carrying. Secondly, since the copper is exposed, if more solder is necessary, then I can apply solder paste to the exposed copper to further increase ampacity. I will have to wait and see if this is necessary, but this option was made available in the layout.

Kelvin connection between GND and VLOAD+ to ADC, highlighted in pink

One last thing to note about the layout is the kelvin connection between the ADC and the input voltage. In order to measure the input voltage, the ADC will need access to GND and VLOAD+. Since the PCB has a ground plane, it is possible to just use a via to feed GND to the ADC. However, the ground plane will be carrying current for a lot of other miscellaneous signals, introducing noise into the ADC. Therefore, a cleaner way to feed the ADC is through a kelvin connection as shown above; the two signals of interest are routed directly from origin to the ADC, using differential routing. The highlighted ground trace carries no other current than for the ADC measurement, so the input voltage measurement should be cleaner than if we had used a via to the ground plane.

Miscellaneous

Bottom layer: three mounting holes are highlighted in pink

There are three M3 mounting holes on the board. I personally like to plate the mounting holes, which makes them less brittle, but I also like to leave solder mask on to prevent the metal from being completely exposed.

Also visible in the picture above is the various labeled connectors and test points, as well as the labels for the copper rings. I can’t stress enough just how much of a quality-of-life improvement labels make. You don’t have to have the layout open in a window or second guess yourself; taking a few minutes to neatly organize the labels for various things on your board will pay off extremely handsomely in the long run. Of particular note is the barrel connector label, where I note the dimensions for the connector as well as the polarity. I always have a hard time determining what a barrel connector’s size is, so I thought it was a nice touch in case I ever forget.

Variable Load: Schematic

I’ve finished the schematic for the variable load, so let’s talk about it! I made many changes to the system, which unfortunately renders my last post obsolete, but I’ll fill you in on the changes here. I’ll highlight the major components.

Power connections

There are 3 power connections. First is a barrel connector which provides 12 volts to the system, powering the fan and the various chips on the board. Second is the input to which the variable load is attached. Last is an internal connection, which connects to the power MOSFET. Because the load is expected to draw many amps of current, I’ll have to do without thermal relief to the high current connections. For this reason, the electrical connections from the PCB to the input power and MOSFET will not be established through soldered on connectors, but rather ring terminals attached to the board through washers, bolts and nuts. This will allow for a high amperage connection that’s easy to assemble and disassemble.

Current sensor

I changed the current sensor from ACS711 to ACS71240. The change was made to increase the resolution for measuring current. The ACS711 has 41 mV/A, but ACS71240 has nearly double at 80 mV/A. ACS71240 is also unidirectional, which is fine for this application, and can go up to 50 A instead of ±31 A. It should be noted that the two chips have very different output levels due to the difference in directionality; ACS711 outputs mid-rail at 0 A, or 2.5 V, while ACS71240 outputs 10% of the rail, which is 0.5 V in this case.

Main DAC

The DAC that sets the load current has changed from MCP48FVB21-E/UN to MAX5216. The change was to increase the system’s current resolution. Previously, at 12 bits and a reference voltage of 5 V, the DAC had a voltage resolution of 5 V / (2^12) = 1.22 mV / LSB. Then, since the old current sensor had a resolution of 41 mV / A, the system has a current resolution of (1.22 mV / LSB) * (1 A / 41 mV) = 29.8 mA / lsb. This means that the circuit can only change the current in steps of nearly 30 mA! That’s a pretty large step size, and I wanted to change the design (this by the way is why I changed so many components from my last post).

Let’s calculate the new current resolution with the new DAC and current sensor. The new DAC has a reference voltage of 5 V, and has a resolution of 16 bits, so you have a voltage resolution of 5 V / (2^16) = 76.3 µV / LSB; 16 times better (which is expected since we went from 12 bits to 16 bits of resolution without changing the reference voltage). The new current sensor has a resolution of 80 mV / A, which is about two times better, so all together we have increased the resolution by a factor of 32. The new resolution is (76.3 µV / LSB)*(1 A / 80 mV) = 0.95 mA / LSB. Now, instead of controlling the current at a scale of tens of milliamps, we should be able to control the system on the scale of milliamps.

Main ADC

Previously, I was going to go with the ADC124S051, a 4-channel 12 bit ADC. Since the DAC has been upgraded to 16 bits, it made sense to upgrade the ADC as well. However, finding a high sample rate, multi-channel, high resolution ADC became prohibitively expensive. From my search, I found that I could have two of those three qualities.

I ultimately decided to give up the multi-channel aspect of my ADC and go with the ADS8685. This was for two reasons:

  1. I was going to use the ADC to measure the temperature of the load, the current through the load, the output of the DAC, and the voltage across the load. But I only need accurate, frequent sampling of one of those signals: the voltage across the load. I don’t need to feed the temperature to the ADC since temperature changes slowly, and I only need a ball-park temperature. I realized that I don’t need to measure the current through the load, since that’s something the microcontroller will control, and therefore will be known to the system. I don’t need to measure the output of the DAC, since again that will be controlled by the microcontroller and will therefore be known. The voltage across the load, however, is not something that can be calculated nor can it be directly controlled. Therefore, the ADC will only need to measure one signal.
  2. The microcontroller has a 10 bit ADC built into it, which I’ll use to measure temperature, current and DAC output. It’s very low resolution (10 bits, 5 V reference voltage), but that’s fine since the signals I’m measuring don’t need high resolution. Temperature is the most important one, but that can be measured infrequently and with low resolution, as said above. And since current and DAC output should already be known to the system, they don’t really need to be measured. However, it will be good to let the microcontroller measure these signals anyway for debugging and self-test purposes.
Opamps

The opamps have not changed much since the last post. The MOSFET controller has simple RC filters on its inputs to reduce sensitivity to noise, and a fairly large output resistor since the MOSFET has a fairly high gate capacitance. The temperature circuit has not changed since the last post, and is expected to output 0.67 V to 4.4 V over 10 °C to 85 °C.

I am a bit worried about the opamp’s input offset voltage; it’s 1 mV, which is fairly large. Since the current sensor has a sensitivity of 80 mV / A, a 1 mV error could mean an error as large as (1 A / 80 mV) * (1 mV) = 12.5 mA. However, I’m sure finding a drop-in replacement further down the line is easy, so I’ll worry about that if it proves to be a problem during testing.

Power regulator

I’m using the same linear regulator as for my Stampduino project. It can output 300 mA, which I think should be enough. None of the chips are expected to consume much current. The only thing that may consume a fair amount of current is the LCD display, but I can adjust the brightness on that, so for now this should be fine.

Microcontroller

The microcontroller is setup exactly the same way as for the Stampduino, configured to 5 volt operation. Almost all of the pins are used up, unfortunately, so future expansion will be difficult if it is needed. The only thing to comment on the microcontroller is that I’ve increased the number of bypass capacitors for VCC since the application involves analog voltages, which wasn’t necessarily the case with the Stampduino.

JTAG Connector

Instead of programming the microcontroller through USB using the bootloader, I’m going to program the microcontroller using my Atmel ICE since I may need its debugging capabilities. I got the pinout for the AVR JTAG connector from table 3-1.

Encoder Debouncing

Since the encoder is just a bunch of switches, it’ll need debouncing. This is the simplest, cheapest scheme I could come up with. When the switches aren’t on, BTN, A and B will be at VCC, or 5 volts. When they are pressed, BTN, A and B will be at 5 * (1150)/(1150+22000) = 248 mV. According to the microcontroller datasheet table 29-1, at VCC of 5 volts, a logic low is anything below 900 mV, so we should be good.

Misc. connectors

Lastly are a bunch of connectors. In no particular order:

  • H5 connects to the fan. I put a high value capacitor near it in case the fan’s high current consumption becomes a problem, though I’ll also address this concern in the layout.
  • H6 connects to the thermistor, which is off the board since it’ll be near the MOSFET and heat-sink. R20 lets you forgo the thermistor, if you’re okay with the system always thinking the load is super hot, in which case the fan will be blasting all the time.
  • H3 and H4 are for the encoder. I decided to have two connectors for the encoder since the encoder itself has two different groups of pins; each connector corresponds to one group.
  • H2 will connect to the LCD display, and provides it power as well as I2C.
  • H7 is for debugging purposes. I suspect the USB port won’t be used in this project, since USB consumes a very large amount of resources which may not be available. Therefore, I need a simple way to communicate with the microcontroller, hence the serial port.

There are some minor parts of the schematic I have not touched upon here, like test points and some filters, but I hope this gave you a good idea of how the schematic works as is. Note that the schematic does not show components that are off the PCB, such as the LCD, encoder, power adaptor, MOSFET, fan and thermistor.

Grounding Cube

When working with electronics, it is important to ground yourself and your setup. Without proper grounding, you may accidentally damage or destroy sensitive electronics by zapping it, discharging the charge you’ve built up just by walking around. Grounding keeps you, your setup, and whatever electronics you’re working on all at the same voltage, which means that an ESD (Electro Static Discharge) event does not occur.

As the name suggests, grounding means connecting something to earth ground, as in the dirt. Electrical connection to earth is achieved by power companies by driving long metal rods into the ground, and then providing wires that connect to that rod to buildings. The buildings, then, provide earth ground to people using three prong outlets.

All this to say that having a good, convenient access to earth ground is very useful. So how do you go about doing that? Well, the system I’ve been using gives me anxiety:

Ground prong on one end, exposed metal on the other

The cable shown above connects to a three prong outlet on one side, and has a metal stub that you can use to ground yourself (be sure to ground yourself through a large value resistor, typically 1 MΩ; more on that at the end of the post). Besides the fact that I feel like I’m going to get electrocuted using this thing, the cable’s thickness makes it cumbersome, and the fact that the part that plugs into the outlet only has a ground prong means the cable tends to move and rotate during use. I didn’t like this setup, so I looked into an upgrade.

The Qube shown above is what we use at my workplace. Unfortunately, each Qube costs about $20! This is a nice product that does what I want, but I’m not willing to pay that much, especially since it’s so simple; all this does is turn a ground prong into banana jacks. So I decided to make my own!

Grounding cube in three pieces

I made my grounding cube out of three pieces; one connects to the outlet (outlet plate), the other holds a couple of banana jacks (banana plate), and the third holds the other two pieces together. This multi-part approach makes the assembly very easy.

Grounding cube assembled; tube is translucent

The fully assembled cube is shown above. The outlet face and the banana face are held together by a M3, 20 mm long, female-to-female, metal hex standoff. The banana face has an M3 screw going through one of its holes, and the outlet face has a M3, 20 mm long, male-to-female, metal hex standoff, which acts as the ground prong. The assembled and disassembled pictures are shown below.

Disassembled grounding cube
Various views of assembled grounding cube

As you can see from the disassembled picture, a o-ring is used to electrically connect the bananas jacks to earth ground.

Ground prongs, in typical cables, are about 5 mm in diameter. In my first design, I used an M5 screw instead of a hex standoff. However, the threads on the screw made it REALLY hard to push into and pull out of outlets, so I had to change the design. While sticking various metal things into outlets to test what would work well (carefully, of course; would not recommend), I found that M3 hex standoffs, with 4.5 mm width, work very well. The outlets I’ve used have a bit of resistance to the standoffs, but I actually like that; it means the outlet has a firm grip, which means a good connection, both mechanically and electrically.

The hexagonal shape of the standoff provides two advantages over a round shape. First, the counterbore I put into the outlet plate of the grounding cube prevents that standoff from rotating over time, which means the threading is less likely to be undone over time.

Outlet plate; notice the orientation of the hexagon with respect to outlet

Second, the hexagon has a edge-to-edge distance of 4.5 mm, but a maximum vertex-to-vertex distance of over 5.7 mm. This means that the hex standoff, once inside of the outlet, cannot rotate very much. The two plastic prongs that go in the outlet prevent the grounding cube from rotating, but the hex standoff is also capable of resisting rotation as well, which means I won’t have to worry about the cube rotating while it’s in use, which is a great improvement from my old setup.

Two last things I’d like to point out.

  1. The grounding cube has two banana jacks that connect to earth ground. However, the screw below the banana jacks connects to earth ground as well. This means that if you have something that needs to be grounded, then you can connect to the screw instead of using the banana jack if that’s more convenient. This may be the case if the grounding mat you bought, for example, has a ground wire that ends with an o-ring.
  2. The grounding cube provides a dead short to earth ground; there is not built-in resistor. You should not use this cube directly to ground yourself; instead, you should use the cube to ground ESD mats and ESD straps. Mats and straps typically have 1 MΩ resistors built in to them. The reason you want high resistance between yourself and earth ground is to prevent large currents, since that may be dangerous. For example, if you’re tied directly to earth ground and touch a high voltage wire (above 100 volts with respect to ground), then you could get seriously injured since the wire will pump current to earth ground through you. The high resistor will significantly reduce the current, possibly saving your life.

All in all, I was very happy with this mini-project. It was a good excuse to use my new 3D printer, and I got to print something I’ll use regularly.

Variable Load: Component Selection

EDIT: a lot of this post has been made obsolete; check out the schematic overview instead.

For the variable load, I’ve decided that a power adaptor will provide 12 V to the system. This 12 V will be used directly for a fan that will cool a heatsink, and it will also be regulated down to 5 V for the various ICs in the system. I’ve also decided to use SPI interface for the ADC and DACs, since I2C is limited in maximum bandwidth. Bandwidth will be important if I want to increase ADC and DAC sampling rate, which may be necessary during constant voltage operation mode, where the microcontroller will have to rapidly sample the ADC and adjust the DAC accordingly.

With these two design decisions made, I was able to pick out the chips I wanted:

  • ADC: ADC124S051CIMM/NOPB
    • 500 ksps (kilo samples per second)
    • SPI
    • 12 bit resolution
    • Operates on 3V3 and 5V
    • Uses power rail as reference
  • DAC: MCP48FVB21-E/UN
    • High sample rate; supports SPI clk up to 20 MHz
    • SPI
    • 12 bit resolution
    • Operates on 3V3 and 5V
    • Can use power rail as reference, external reference or band gap as reference (internal)
  • Current sensor: ACS711KEXLT-31AB-T
    • ±31 A limit
    • 45 mV / A, outputs mid-rail at no current
    • Operates on 3V3 and 5V
  • OpAmp: MCP6L02T-E/MS
    • Rail to rail, input and output
    • Operates on 1V8 to 6V
    • 1 MHz bandwidth
    • Input offset 5 mV
  • Thermistor: MF52A1104J3950
    • 100 kΩ @ 25 °C
    • B25/50 = 3950 K
    • -55°C ~ 125°C
  • Power Transistor: IXTN600N04T2
    • Limits: 40V, 600 A, 940 W
    • VGS_threshold < 3.5 V
  • Fan: QFR1212GHEEVT
    • 12 V, 2.7 A
    • 190 CFM
    • 120 mm x 120 mm
    • Speed can be controlled by PWM
  • Heatsink: salvage
    • 12.3 cm x 4.4 cm x 15.24 cm
    • Using AH12310V06000GE as reference, suspect thermal resistance is 1 °C/W
  • System Power Supply: L6R48-120400
    • 12 V, 4 A
    • Barrel connector, 5.5 x 2.1 mm, positive center
  • Encoder: EN11-HSM1BF20
    • 20 dents per rotation
    • Quadrature output
    • Will use knob 1230-J

The transistor is really expensive; it’s over $20! On top of that, the heatsink would be expensive if I had to buy it, but fortunately I got one that was being thrown out. If I’m okay with a temperature rise of 50°C, then the heatsink should be able to dissipate around 50°C / (1 °C / W) = 50 W. I’m planning on adding a fan to the heatsink, though, which will decrease its thermal resistance. However, I can’t quantify how much the fan will help, so I’ll have to do some testing once I have the system set up.

To make sure the transistor does not overheat, I have designed a thermistor circuit. The output of the opamp increases as the transistor gets hotter (the thermistor will be thermally coupled to the transistor). This voltage will be fed into the ADC, which the microcontroller will then read. For now, I’m thinking of just having the fan off or on, depending on how hot the transistor is, but I can also scale the fan speed based on the temperature of the transistor.

Thermistor Circuit
Thermistor resistance vs temperature
Opamp output vs temperature

As you can see, the opamp output covers nearly the full range between 0°C and 85°C. This will give good resolution for temperature. One drawback is that the thermistor only specifies a B value between 25°C and 50°C, so for now I’m assuming that value does not change very much, but I’ll have to revisit that by driving the thermistor to a known temperature; I’m thinking of using my reflow oven for that, since I can manually drive the oven to a set temperature.

Variable Load: Intro

I thought a fun project I could work on while trying to develop my embedded programming skills was a variable load, often used to test power circuits. A variable load is exactly what it sounds like; a load, which the user attaches to the output of a power supply, that can be programmed to act in a couple of different ways. The load I’m designing will primarily function as a constant current load, but I would like to add a couple of other modes as well:

  1. Constant Voltage: this mode probably won’t be used very often, since I’ll mostly be testing constant voltage supplies rather than constant current ones. However, it shouldn’t be too hard to program the load to act this way.
  2. Constant Power: a constant power load will be very helpful when testing switching power supplies whose input voltage can vary. For constant power loads, when the voltage across the load doubles, the current should half.
  3. Constant Resistance: a constant resistance load will be helpful if I just need a big fat resistor, but don’t have that value power resistor on hand. For constant resistance loads, when the voltage across the load doubles, the current should also double, resulting in a four-fold increase in power.

Along with several operating modes, I would like the variable load to display useful information onto an LCD screen, have an interface on it so that a user can change modes and parameters as necessary, and have serial output of some sort for debugging / logging purposes.

My load will be composed of the following components:

  1. Microcontroller: I’ll use the same microcontroller as my stampduino, the ATMEGA32U4. I chose this microcontroller because it has all the peripherals I need (USB, SPI, I2C, UART), as well as general familiarity.
  2. LCD: just a typical I2C controlled LCD display; 16 x 2 characters is probably sufficient.
  3. Interface: I’ll use an encoder, which is a dial with a button built in to it. I recently got a 3D printer which has this interface, and I was impressed with how much you can do with such a simple interface.
  4. Power circuit: I’ll use a power MOSFET driven by an opamp to control the amount of current the load consumes. The opamp will have one of its inputs driven by a DAC, and the current through the load, as well as the voltage across it, will be monitored by an ADC.

A high level diagram of the system is shown below:

Variable load, hardware architecture

A first draft of the power circuit is shown below. Note that it is extremely preliminary.

VADC1 and VADC2 will go into the ADC, while VDAC is the output of the DAC. VADC1 will let the system know the voltage of the input, while VADC2 will let the system know how much current is being consumed by the power transistor, M1. There are a couple of things I’d like to note about this design:

  1. I chose to use a hall effect sensor instead of a current sense resistor, despite the increase in cost and complexity. There are two reasons for this:
    1. The resistor will produce heat. I want to minimize the amount of components that dissipate large amounts of heat since that’ll allow me to minimize the number of heatsinks and simplify the thermal management inside the enclosure for this project. If I use a 1Ω resistor, and the load is consuming 10 A, then the resistor will dissipate 100 W of power! I could use a smaller value resistor, but then it becomes harder to measure the amount of current through the load since the voltage across the resistor will be smaller.
    2. The resistor will have voltage across it. This makes it difficult to test low voltage, high current power supplies. For example, if the current sense resistor is 1 Ω, it would be impossible to draw more than 1 A out of a 1 V supply. If the supply could output up to 10 A, I would not be able to test that.
  2. The opamp is configured for current control rather than voltage control. That is to say, the output of the DAC controls the current through the transistor, not the voltage across it. I chose is configuration because (a) I primarily want this to be a current load, (b) I’ll test more constant voltage supplies than constant current supplies, and (c) I think having better control of the current, rather than the voltage, will make the load less likely to damage the power supply it is connected to. I considered the option of having multiple opamps and multiple transistors, but increasing the number of power transistors (which are fairly expensive) as well as increasing the complexity of the system didn’t seem worth it. The multiple transistors problem compounds with the next point.
  3. The transistor will be dissipating almost all of the heat. Since the heat can get very large (50 W is my goal for now), I can / may have to parallel multiple transistors so that the load is spread out over multiple components. Of course, the transistor(s) will also need a heatsink(s) and a fan.
  4. I’ll probably add a temperature sensor circuit to the system. This will allow me to only turn the fan for the heatsinks on only when the system gets too hot, which makes the load silent at light loads, but it’ll also allow me to create a fail-safe when the transistors overheat. When the microcontroller detects that the transistors are getting too hot, it’ll turn the transistors off, rendering the the load inoperable until the system has cooled down sufficiently. The temperature sensor circuit will produce a voltage proportional to the temperature of the heatsink and will feed this voltage into the ADC.
  5. The ADC and DAC aren’t strictly necessary; the microcontroller has a built-in ADC, and a PWM output that can be made into an analog signal. However, dedicated chips will improve the system’s ability to monitor voltages as well as control the load. Additionally, it gives me more stuff to program for, since a large motivation for me is improving my embedded systems programming skills by getting more experience.

As stated, my goal for this load is 30 V, 5 A and 50 W. I’ll have to see how feasible these numbers are as I flesh out more of the hardware design.

Complex Numbers

In electrical engineering, specifically in circuit analysis, you’ll see a lot of complex numbers. This can be very confusing because complex numbers don’t exist in the real world; for example, your oscilloscope or multimeter is never going to measure 5+2j volts. So why do we use complex numbers in circuit analysis, and if a signal is complex, what should we expect when we measure that signal with an oscilloscope?

Before we can get to complex numbers, we have to understand sinusoids first. Even before that, let’s take a quick look at physics.

Decomposing a vector into its x and y component

You may remember learning about vector decomposition. This is the process of breaking a vector down to its fundamental pieces. For example, the initial vector has a magnitude of 3 meters per second, and is 20° above the horizontal. This vector has an x component and a y component. In other words, this vector is the sum of a vector going only in the x direction and another vector going only in the y direction. This is a very useful procedure as it allows you to break down complex vectors into simple components. But what does that have to do with sinusoids?

Turns out, you can also decompose sinusoids! Just like how a vector not aligned with an axis can be decomposed to vectors that do align, you can decompose a sinusoid with a phase shift to sinusoids with no phase shifts.

The left shows the axis used to decompose a vector to its x and y components. On the right is the axis used to decompose sinusoids. By convention, the horizontal axis is cos, while the vertical axis is sin. Because cos(x) = sin(x + 90°), the sin axis is 90° clockwise from the cos axis. It’s a bit confusing that the sin axis points down, but it just means that a negative sin will point up instead of down, as we’ll see in the example below.

Just like how the vector is decomposed to 2.819 m/s in the x direction and 1.026 m/s in the y direction, the sinusoid is decomposed to cos and sin components. Just like how the magnitude of the x direction vector is 3*cos(20°), the magnitude of the cos is 3*cos(20°). Just like how the magnitude of the y direction vector is 3*sin(20°), the magnitude of the sin is 3*sin(20°).

Two more points about breaking down sinusoids. First, note how the trig identities are preserved; the line drawn 20° counterclockwise from the positive cos axis is 110° counterclockwise from the positive sin axis, and 70° clockwise from the negative sin axis. Second, you can do sinusoid addition using this method, just like how you can do vector addition. If you have two sinusoids, draw them on the cos and sin graph with one sinusoid starting where the other ends. Then, you can find the resulting sum by seeing where the second sinusoid ends on the cos and sin axis. Alternatively, you can decompose both sinusoids to simple cos and sin, add them up, then convert the new cos and sin to a new sinusoid with a phase shift.

So all that’s pretty nifty, but what does that have to do with complex numbers?

Complex numbers are composed of a real part and an imaginary part. For example, 5+2j has a real component, 5, and an imaginary component, 2. Because complex numbers have two components, just like how vectors have x component and a y component, you can plot complex numbers on a graph. By convention, the real part is horizontal axis, while the imaginary part is the vertical axis.

The example shows 5+2j plotted on a complex plane. It looks a lot like a vector that has an x component of 5 m/s, and a y component of 2 m/s. And just like how a vector can be expressed as a sum of its components or as a magnitude & angle, complex numbers can be expressed as a sum of real and imaginary numbers, or as magnitude and angle.

Mathematically, sinusoids and complex numbers are related by Euler’s formula:

Euler’s formula visualized, from Wikipedia

I’m an engineer, so I’ll just focus on the applications of Euler’s formula: the take-away here is that complex numbers can be used to describe sinusoids. Since cos and sin can be used to put information on a graph, and real and imaginary numbers can also put information on a graph, both sinusoids and complex numbers can be used to represent the same data. The reason complex numbers are useful is because they’re much more compact than sinusoids. Put another way, complex numbers give an easy way to describe magnitude and phase of a sinusoid.

For example, you can say a sinusoid is cos(wt+20°), but you can also describe the sinusoid as 2.819*cos(wt)-1.026*sin(wt), as we’ve seen. Since writing out all of that is rather cumbersome, you can describe the signal as 2.819+1.026j. The sum of cos and sin, as well as the complex number, end up being identical when plotted, so they represent the same information. The real part of a complex number is the magnitude of the cos, while the imaginary part is the magnitude of the sin.

The sign of the sin is inverse of the value of the complex number, which is annoying, but thankfully you don’t use the cos and sin representation very much in circuit analysis; you’ll almost exclusively use complex numbers. The cos and sin representation was done for demonstration purposes.

Before getting into a circuit example, let’s do a quick review:

  1. A sinusoid with a phase shift can be described as a sum of cos and sin, neither of which have a phase shift.
  2. The sinusoid can alternatively be described as a complex number, where the amplitude of the cos is the real part, and the amplitude of the sin is the inverse of the imaginary part.
  3. The sinusoid with a phase shift, the sum of cos and sin, and the complex number all serve the same function: describe the underlying signal’s amplitude and phase.

Now that we understand that a complex number is just a fancy way of describing magnitude and phase shift of a sinusoid, let’s look at a simple low pass filter.

The example shows a 100 kΩ resistor, a 1.59µF capacitor and a voltage source that generates a sinusoid with a frequency of 1 Hz. The reactance of a capacitor is 1/(s*C), where s = j*w and w = 2*pi*f. In other words, the reactance of a capacitor is 1/(j*2*pi*f*C). At 1 Hz (f=1) with a capacitor value of 1.59µF (C=1.59*10^-6), the reactance of the capacitor is 1/(j*0.00001), or -100,000j Ω.

The relationship between VOUT and VIN is very similar to a voltage divider: VOUT/VIN = (-100,000j)/(-100,000j+100,000). Simplifying the equation, we get:

So what does this mean? Let’s say VIN = 1; that is to say, VIN is a cos (with no phase shift) with an amplitude of 1. Then VOUT would be 1/2*(1-j). Let’s plot this on the complex plane.

The graph reveals two things:

  1. At 1 Hz, the output amplitude is about 70% of the input. The graph shows this by the length of the line, which is 0.707 in this case. For example, if the input is a cos with a peak to peak voltage of 2 volts, then the output will be a peak to peak sinusoid with a voltage of 1.414 volts.
  2. At 1 Hz, the output is lagging behind the input by 45°. The graph shows by having the line be 45° clockwise from the input (remember that the input is a cos, which is 1, which is on the positive real axis).

If we were to put an oscilloscope probe on the output of this circuit, we shouldn’t expect a complex voltage. Instead, we would expect the output to be 70% of the input with a delay of 45° when the input is a sinusoid of 1 Hz. Let’s run the simulation and double check our calculations.

Plot of input (green) and output (blue)

The input signal has a peak to peak voltage of 2 volts, and the output has a peak to peak voltage of 1.41 volts, as we predicted. The maximum of the output occurs 125 ms after the output of the input. Since the sinusoids have a frequency of 1 Hz, which means the period of the sinusoids is 1 second, 125 ms is an eighth of the full period, which corresponds to a phase shift of 360/8, or 45°. As you can see, our calculations match the simulation results.

The signals you compare do not have to be the input and output voltages of the circuit; in fact, they don’t have to be voltages at all. Let’s compare the voltage across the capacitor with the current through the capacitor.

As we discussed, the reactance of the capacitor is -100,000j Ω. Since V = I*Z, if we say I = 1 (again, this means I is a cos with an amplitude of 1), then we see that the voltage across the capacitor is V=1*-100,000j = -100,000j V. This means that the current, which is 1, is on the positive real axis. Meanwhile, the voltage is negative and purely imaginary, which means it points straight down. Since the voltage is 90° clockwise from the current, that means the voltage across the capacitor is 90° behind the current through the capacitor, or 250 ms at 1 Hz. The simulation results below agree with our calculations.

Plot of current (green) and voltage (blue) of capacitor

Lastly, let’s compare the voltage across the capacitor with the voltage across the resistor. In this schematic, the current through the resistor and capacitor are the same since those two components are in series. If we say that the current is 1 (as in, it is a cos), then as we already discussed the voltage across the capacitor is -100,000j V. Meanwhile, the voltage across the resistor is V = I*R = 1*100,000 = 100,000 V. If you were to plot this, you would see that the voltage across the resistor, since it is positive and real, points to the right, while the voltage across the capacitor, being negative and imaginary, points down. This means that the voltage across the capacitor is 90° behind the voltage across the resistor (or 250 ms). In addition, since they are equal in magnitude, we should expect voltage sinusoids to be the same amplitude:

Plot of voltage across capacitor (green) and voltage across resistor (blue)

This result is consistent not only with our calculations, but also our previous results. Remember that the output of the circuit is equal to the voltage across the capacitor. Meanwhile, the input of the circuit is equal to the voltage across the capacitor plus the voltage across the resistor. Let’s plot that:

As you can see, when I = 1, VOUT points straight down, while VIN is 45° counterclockwise from VOUT; this means that, as we found before, VIN is 45° ahead of VOUT. In addition, when I = 1, VOUT has a magnitude of 100,000, while VIN has a magnitude of sqrt(2)*100,000, which again means that VOUT is about 70% of VIN. Numerically, the results are different from what we found before, but that’s because our assumptions are different as well. When we were looking at VOUT/VIN, we said that VIN was 1 and then calculated for VOUT. Here, however, we assume that I = 1, and calculate VIN and VOUT based off of that. Regardless, the conclusions we can draw, in terms of magnitude and phase relationships between various signals, remains the same.

Plotting signals with respect to a reference on the complex plane shows the magnitudes of the signals, as well as the angles between the signals and the reference. The magnitudes and angles from the graph show what you should expect when you’re measuring the signals in the real world: how much the signals are amplified / attenuated, and how much phase delay / gain the signals experience. Hopefully this post helped you understand that complex numbers, for circuit analysis, is just a convenient way of describing magnitude and phase shifts of signals.

DSP: Nyquist Frequency

In my last post, I mentioned that you have to sample at least twice the rate of the highest frequency component you expect in your system. For example, if you expect a signal that you’re sampling to only have frequencies below 100 kHz, then you have to sample at least 200 thousand times per second. Where does this limitation come from, and what happens if you violate it?

Theory

Before we talk about minimum or recommended sampling rate, let’s first see what happens when you sample a signal, first in the time domain, then in the frequency domain.

An analog signal is continuous in two ways. First, it is continuous in time: the signal continues to exist in between any two instances in time, no matter how close those instances are. Second, the signal is continuous in value: it can take an infinite number of values even within a tiny range. By sampling, you make the signal discrete in time; the signal can still take any value it wants, but the signal only exists at discrete steps. (Sampling also makes the signal discrete in value in the real world; for example, a 10 bit ADC will reduce the number of values the signal can be to 1024 values, but that’s not the focus of this post.)

Example of sampled signal

The graph above shows an analog waveform on the left, and a discrete waveform created by sampling that waveform on the right. When you’re sampling a signal, you’re effectively multiplying that signal by a train of impulses, which is shown in the middle. The train of impulses has impulses that are a set time apart; if you’re sampling at 1 kHz, then the impulses are 1 ms apart, for example. But this multiplication is key to understanding the Nyquist frequency, which is the minimum frequency you need to sample your signal.

Multiplication in the time domain, as shown above, is convolution in the frequency domain. As it turns out, a train of impulses in the time domain is also a train of impulses in the frequency domain. If you’re sampling at 1 kHz, then the train of impulses in the frequency domain are 1 kHz part. The convolution of the original signal and the train of impulses is where minimum frequency requirement comes from.

Here are two rules to know when it comes to convolving impulses:

  1. Any signal convolved with an impulse will result in the original signal.
  2. Any signal convolved with an impulse shifted by F will result in the original signal, but shifted by F

The train of impulses is just a bunch of impulses shifted by different amounts; if you’re sampling at 1 kHz, then you have impulses shifted by 0 kHz (so an impulse at the origin), 1 kHz, 2 kHz, etc. That means the original signal, in the frequency domain, will be shifted by 0 kHz, 1 kHz, 2 kHz, etc.

Example signal that has frequency components up to 300 Hz, in frequency domain

Another important fact to remember is that frequencies have positive and negative components; for example, if the input signal has frequency components up to 300 Hz, then it also has frequency components down to -300 Hz, as shown above.

Signal sampled at 1 kHz

When the signal is convolved with a train of impulses which are 1 kHz apart, then a new signal is generated, which is shown above. The new signal has the original signal shifted by various amounts; in this case, 0 kHz, 1 kHz, 2 kHz, etc. One of the copies, which is shifted by 1 kHz, exists in the range of 700 Hz to 1300 Hz. There is another copy at 2 kHz, which similarly exists in the range of 1700 Hz to 2300 Hz. The copies also exist for negative frequencies; for example, the copy at -1 kHz exists from -1300 Hz to -700 Hz.

Of critical importance here is that the signals do not overlap; since the original signal has a full range of 600 Hz (-300 Hz to 300 Hz), shifting it by more than 600 Hz will ensure the copies do not interact with each other. If the copies do overlap, then the original signal is distorted and ultimately destroyed; we’ll see an example of this below. This distortion, or misrepresentation of the original signal, is called aliasing. But key here is the fact that copies must be placed far enough apart that they do not interact. The bare minimum is twice the highest frequency component in the signal.

Let’s do a quick review:

  1. The original signal exists, and is composed of frequencies [-Fc, Fc]
  2. You wish to sample this signal at a rate of Fs
  3. In the frequency domain, you have the original signal [-Fc, Fc], but also have a copy at [-Fc+Fs, Fs+Fc]
  4. In order to ensure the original and the copy do not interact, they must not touch. That is, Fc < -Fc+Fs.
  5. Simplifying the inequality reveals that 2Fc < Fs; in other words, the sampling frequency must be greater than twice the highest frequency component in the original signal.

Examples

Let’s see what a 20 kHz sinusoid looks like when it is sampled at various rates. In the pictures shown below, the original signal is blue, while the signal constructed through sampling is shown in black.

Sampling below Nyquist frequency

Let’s ignore the fact that the sampled signal signal is very, very jagged. The original signal is 20 kHz, but the sampled signal has a frequency of 5 kHz! What happened?

20 kHz sinusoid in the frequency domain

The original, because it is a sin wave, only exists at one frequency, 20 kHz. It also has the negative component at -20 kHz. Let’s see what happens when we sample this signal at 25 kHz.

20 kHz sampled at 25 kHz in the frequency domain. Brown is aliasing in negative frequencies, while orange is aliasing in positive frequencies.

The original signal existed at -20 kHz and 20 kHz. When you sample at 25 kHz, you create copies that are shifted by intervals of 25 kHz. This means when the signal is shifted right by 25 kHz, the copy exists at 5 kHz and 45 kHz. When the signal is shifted left by 25 kHz, the copy exists at -45 kHz and -5 kHz. The copies that exist at -5 kHz and 5 kHz is what we’re seeing in the sample; that is, the sampled signal, due to aliasing, is misrepresenting 20 kHz as 5 kHz.

So now let’s try sampling at the Nyquist frequency, 40 kHz.

Sampling at Nyquist frequency

That’s not much better. Kind of worse, in fact. The 20 kHz looks like a DC signal. But we’re sampling at the correct frequency; what happened? Let’s try sampling at 40 kHz again, but shift the sampling point a bit.

Sampling at Nyquist frequency with shift

So the sinusoid now looks like a triangle wave. Makes sense, actually; the sinusoid is 20 kHz, and you’re sampling at 40 kHz. That means you’ll only have two points per period; if you connect the dots together, then you either get a flat line or a triangle wave. But can you really say that the triangle wave accurately represents the original sinusoid? I mean the triangle wave has the right frequency of 20 kHz, but it has a smaller amplitude than the original signal. Even more distressing is the fact that the amplitude of the triangle wave varies depending on how much shift the sampling point! You can get a triangle wave with an amplitude of zero (as we’ve seen), an amplitude that’s the same as the original sinuisoid, or anything in-between.

This is where theory clashes with practice. In theory, you only have to sample at the Nyquist frequency to accurately capture the signal. And by accurately capture the signal, I mean prevent aliasing. What this means is that sampling at or above the Nyquist frequency only guarantees you’ll have accurate frequency data; it does not guarantee you’ll have accurate amplitude data. In fact, it is impossible to deduce the amplitude of the original sinusoid when sampling at the Nyquist frequency!

Sampling over Nyquist frequency

Here, we’re sampling at 90 kHz, which is 4.5 times the sinusoid frequency. You can see that it looks much better than when we sampled at the Nyquist frequency, but there’s still a lot of room for improvement. We get a much better idea of the amplitude of the sinusoid based off of the samples, but the samples within a period do not look consistent from one period to the next, so it almost makes it look like the sinusoid is modulated.

Sampling much more than the Nyquist frequency

Here, we’re sampling at 235 kHz, which is 11.75 times the sinusoid frequency. I’d say this is a reasonable frequency to sample at. The samples always come close enough to the minimum and maximum values each period to capture the amplitude of the sinusoid pretty well.

Sampling way over Nyquist frequency

Finally, we have sampling at 517 kHz, which is over 25 times the sinusoid frequency. Thanks to the very high sampling rate, we get a very accurate representation of the sinusoid. We have captured the frequency of the sinusoid, as well as accurately represented the amplitude. Remember that fully capturing the amplitude is nearly impossible; in order to truly capture the amplitude, you would have to sample the sinusoid right at its maximum or minimum value, which only exists for an instant.

I hope this post was helpful in understanding aliasing, the Nyquist frequency, minimum sampling rate, and why you usually want to sample much higher than the Nyquist frequency.

Design a site like this with WordPress.com
Get started