So I've been talking a lot about devices of various types, about components and how they plug together and things like that. Next, we're going to be talking about something a little bit more technical, I want to be talking about encoding. Encoding is the science of taking bits and data, and translating them into physical patterns that can be realized over wires to transmit information, and send information to other devices. So this problem comes up all over the place. Sometimes you need to take data, you need to send that between various chips on a single circuit board, between different circuit boards within a device. You might need to send data between different devices at home over a network, or between devices and different buildings. You need to have some way of taking bits, and taking data, and encoding them, and having ways to send them over wires. So this seems easy, but how do you actually do it? So one idea is maybe you can connect your devices and your components together with wires, and maybe change some properties of that wire that can be read by the other side. Seems like some intuitive way to do that. But then the question is, what properties of the wire do you actually change to send information? There's really only two kind of properties you have an option to change, your current and voltage. If you want to send data to another device, or another component, and you are connected by a wire, it can send electricity in different ways and send information. If you're going to change properties of electricity, there's only really two things, you can change the current or the amount of electricity going through the wire, or you can change the voltage because it's like how hard the electricity is pushing through the wire. So when we design encoding schemes, and communication mechanisms, we could use either of these, but everybody uses voltage, because voltage turns out to be much more efficient for sending information. Because you can send current over wires but the longer the wire is, the more it degrades, there's resistance through wire, so current decreases, requires more electricity if you're sending a lot of current, it requires more electricity to send information. So voltage turns out to be more efficient for a number of reasons. Okay, so we're going to send information using voltage, changing properties of voltage. But then the question is, what voltage levels should we use to send data? Well, when we choose what voltage levels to use for this problem, is I should use lower levels, because if we use lower voltage levels that reduces power consumption, sending high-voltage levels over wires requires a lot of electricity, it's going to drain your battery. So you only have encoding schemes that use lower values for voltages. Also improves safety, people touch devices, we want to keep them safe, we don't electrocute them. At the same time, you don't want to use voltage levels are too low, because higher levels of voltage reduces sensitivity to noise. Because it turns out in these wires, you've got low voltage spice happening all over the place. You can use high voltage pulses to send information, you really distinguish your signal from the background noise. Also, higher voltage levels are good at traveling over longer distance with less loss. So people thought about this long time ago, and they chose different voltage levels for different goals and different use cases. There's a few specific values which you're going to see all over the place. I list them here, 15 volts, 12 volts, five volts, 3.3 volts. You see them all over the place, the last few are very common in digital logic. So if you've got your AND gates and OR gates, and you have ICs and things like that, most of those are powered off for five volts and 3.3 volts. There's nothing magic about these values, they're around for historical reasons, and someone came up with a new component, they use a different value, no one would buy it because it wouldn't be compatible with all the power sources that are out there and so on. So these are the voltage levels which everybody uses for discrete communications using encodings. Okay, so let's get into this. How do you actually do this? Well, the problem that we're trying to address is, you have two devices, maybe you have like a sensor, something collecting data, and back-end computer that wants to receive the data. Maybe you have like, ICs in a device, what's doing sensing, what's recording, and generally, you have two things that need to communicate. How do we take information and encode it? So one tempting way to do this is, we can vary the voltage, we can take the wire and the sender can raise the voltage for a one, and lower it for zero. Then the other side can decode that, can have a threshold, or a level detector where it detects if the voltage is above a level or below a level, and then it'll decode that as a zero or a one. So for example, I have this pattern coming across. Can you tell what pattern I'm sending? That first bit is going to be a zero because it's low, and then the next bit is going to be a one, because it's high, and then a zero and a zero. So if the source sent a signal like this, the receiver might decode it like this, zero one zero zero one, and so on. So you can see that you can take data, encoded as voltage changes, and then read off those voltage changes on the other side, so we can send data. So does this look good? Actually, there is a little bit of a problem here because if you look at this, at the very end there, there's three zeros. Is at right? Did the sender sent three zeros, or did the sender send four zeros. To me it's hard to tell where the bit transitions are just looking at this. Some are obvious, you can see the voltage goes up, and then down right after that, that's clearly a single one. If it's a little bit longer, that's probably two ones. But there's a little bit of ambiguity here where if I'm sending data, and then have a string of zeros or a string of ones, it's not clear how many there should be. So that's an issue with encoding directly like this. So to solve this problem, one idea is, we could agree on when bit transition should occur. If both sides had a clock, synchronized clock where it periodically go off, and both sides could agree on when to sample a bit, and when to send a bit, then there'd be no vagueness here at all. Both sides would know exactly when bit transition should occur. So the receiver would know exactly how many zeros there would be in this example. So we could do that but then the problem is clock synchronization. How do we make sure that these two end points have exactly the same clock, and they transition at the same time? One challenge here is doing his clock synchronization, because we can't build perfect clocks, especially when we're dealing with very minute timescales, we're sending these bits, and these bits are hundreds of nanoseconds wider, microseconds wide, and so making clocks that can actually sync up on those fine timescales is actually really challenging. Problem is, if one drifts, you can get bit errors, you can read the wrong number of bits or the wrong sequence of bits. So what can we do to address this problem? Well, one thing we could do is develop some mechanism to ensure that the clocks are synchronized, or that they remain as synchronized as possible. So this concept is called a Phase Locked Loop. So in electronics, we developed Phase Locked Loops which are algorithms and techniques to ensure that the two end points have synchronized clocks in some way. One of the simplest ways to do this is, you add another line, and you transmit the sender's clock over that line. So the sender is sending data, and sending ones and zeros, and the sender is going to send pulses on the clock line. So the sender is going to start off, it's going to lower the voltage to send zero, and then on the clock line, is going to send a pulse, and the receiver is going to see that pulse, and it will know exactly when to read the bit. So when the sender sends a pulse, it might not send the pulse right away because you want to leave a little bit of transition time, you want to send the zero and then wait for the zero to propagate across before receiving the the pulse, so the receiver doesn't read the bit too early. You might want to leave a little bit a time where you leave the pulse high to distinguish the pulse from noise on the clock line, but in general, you end up with something like this, where you have your data line, you're sending bits, and then your clock line using pulses, and then you keep going like this. So the sender will send a one for the data, and then wait a little bit and send a pulse on the clock line, and so on. So this process continues, and then it's very clear what the bits are. You don't have to worry about long strings of zeros causing ambiguity, because it's very clear when the bit transitions are because the sender is telling you exactly when each bit is by sending a separate clock signal. This is a great solution and this works really well, but it's not used a lot in practice because there are some costs associated with it. One cost is you need an additional wire which doesn't seem like a big deal. But, when you're dealing with IoT systems where you need to reduce your power constraints, do you really want to power a completely separate line? Do you want to pay the costs of having a separate line in all these different places in your circuit that's additional cost, additional power requirements? And also this increases your bandwidth requirements on your links because notice the clock transitions faster than your actual data signal. So you need more expensive components as well. So this is not a very desirable solution because of that. These additional lines have various sorts of costs. Now there's a few other challenges with this tool which might not be so intuitive. Let me tell you about those as well. One other issue that comes up is something called DC balance. So if I'm sending a signal and I'm sending ones and zeros and I'm raising my voltage, lowering my voltage over time. Then I'm sending that data across and the receiver sitting there, and the receiver needs to distinguish between the ones and zeros. So the way we do that is, we have something called a level detector, or a level slicer. What a level detector or level slicer does is, it's a little circuit that just figures out if your signal's above a threshold. So you might have a pair of thresholds where it says, if the signal's above 4.7 volts, then count that as a one. If it's below one volt, count it as a zero and that leaves a little bit of wiggle room. So if there's kind of a little bit of noise which affects things, or maybe a little bit of resistance which pulls down your voltage a little bit, it's not going to degrade your signal. So we can build level slicers, but it's hard to build perfect level slicers. We can't do that. One problem is level slicer circuits can get biased. Where if I send a signal which has a lot of zeros in it, it'll actually pull down the level slicer. It'll create bias in it. The problem with that is, it makes it more susceptible to noise because if I have a little tiny voltage spikes, suddenly they won't be below the threshold anymore, suddenly that will be above the threshold. There'll be read as a one when they're actually zeros. So low voltages can bias level slicers down. High voltages can bias them up. Not a problem if you have a nice alternation between zeros and ones. But if you have a signal with a lot of zeros or a lot of ones that introduces bias in your level of detection circuitry. So that's a problem. Another problem is if you're sending a lot of ones than you're sending voltage, and so you're sending electricity to another party or circuit, this makes it hard to galvanically isolate your circuit. You've got a circuit over here, he's got some noise in it and then another circuit, you're kind of connecting them together because you're introducing a constant voltage which can allow noise to propagate across. You maybe pushing electricity into parts of your circuit that don't need it. It could get overloaded. It requires more transmission power because you're sending a lot of ones, you're sending electricity. So all these issues are kind of called DC balance. You want to keep your, it'd be nice if your signal is more balanced. If you had an equal number of zeros or or ones, but you might not if you don't use the right encoding scheme. Another challenge with encoding is what's called noise. When I talk about noise, I'm not talking about audio noise, I'm talking about changes in voltage that can occur randomly in your circuits. Because when I send a signal, usually it doesn't look clean like this. It's not like perfectly clean margins. Your signal often really looks like this at the receiver, where you have the original signal, you can kind of see it. But there's some kind of noise, some kind of random variations layered on top. The problem with that is when the receiver receives the signal, it might read the noise as incorrect bits. So you can get bit errors if the noise randomly jumps above the threshold. Since it may introduce false readings and noise comes from a lot of sources. Can come from thermal noise. It turns out electrons kind of randomly just jump around in wires and components. There's also shot noise because electrons traversing gaps and jumping through components. There's coupled noise where noise can kind of be leaked from cosmic radiation and atmosphere and then leakage noise, where motors, and speakers, and bolts, and all these things kind of introduce random variations in your electricity. So noise can come from a lot of sources. So when we get into encoding schemes, we're going to kind of design encoding schemes that are kind of resilient to these different issues and it would be nice to have a coding scheme that could be resilient to noise because it's another big challenge. Another issue that comes up is what's called loss or attenuation. The issue here is that when you generate a pulse and it goes through a wire, wires have resistance into kind of reduce the magnitude of the pulse. The longer the wire, or the more resistance it has, the more the amplitude of your signal is reduced. So wires have resistance and also components have resistance. Some components are really famous for this like lowpass filters turned out to introduce a lot of loss. These resistances can kind of combine in different ways and sometimes in non-intuitive ways. So this is another challenge you need to deal with. Why it's not so simple just kind of take voltage pulses and put them over wire, you have to deal with this as well. Another issue is what's called dispersion. When you send a nice clean peak, or spike for your ones, it can get spread out in the wire because not all electrons are going to go the same speed. More precisely, not all parts of the electron wave are going to propagate at the same speed. There's going to be electrons at the leading edge that are going to go a little bit faster. Ones at the trailing edge, they are going to go a little bit slower. And so these nice peaks that you're going to send, are going to get spread out as they go further through the wire and that can cause bits to melt into each other which can make them hard to distinguish. Some components have more dispersion than others. Low-pass filters are famous for this as well. These are a bunch of issues that you have when you do encoding. So it's really not as simple as kind of taking bits and using high and low signals. You have to deal with all these issues when you're coding at the physical layer. Especially in the context of IoT when you're building devices that operate in the desert, up in the air. These situations can get worse. So how can we deal with these issues? Well, I'm going to talk about that next.