Last update was about the single ended filters, which i thought we were done with but somehow something really important dawned on me, let me explain :
Speakers impedances are usually standardized and really low, think 1, 2 ,4 , 8 Ohms. They can therefore be driven really hard (low impedance = high current). As such, they are always in BTL configuration.
Headphones impedances are not really standardized and rather high (30 Ohm to 600 Ohm). They really don't need that much power to be driven though, usually in the tens of mW.
Here's the kicker, single ended outputs are usually reserved for signal transfer, not for for driving
RCA for instance is meant to go between a DAC and an amplifier, not an amplifier and a speaker.
3.5mm / 6.25mm jacks don't carry the current needed to drive speakers, just the signal etc.
In fact to my knowledge there is only one kind of driven single ended output : headphone out.
The rule for signal transfer is low output impedance, high input impedance. We only need a few mA at most, and we want to be load independant....
why not use an OpAmp ? an OPA1611 should deliver way enough power without coming close to bottlenecking on noise or THD...
Literally just placing it after the single ended filter should do the trick, no clue how that flew above my head but yeah.
A few design choices remain to be made :
should we use the volume control from one of the ICs, or with a variable gain at the OpAmp ?
is the opamp really load independant for smaller loads ?
Little update on the DAC, let's see what we have in store for today.
1 - Prototype Topology
First things first, Since i'm doing an output stage, i'm going to have to deal with differentials filters, differentials amps, power supply filtering etc. The board will include those elements, but they'll be somewhat isolated (i need to test them after all ! ). The entire thing will be powered by a stabilized power supply, so expect banana plugs and BNC test points.
Since my outputs can be differents (bridge tied vs single ended), It means that I will have to use AD and BD modulation.
For testing, i also want a mono single ended output.
2 - Filter Design - Single Ended output
Let's start designing ! the datasheet says that the output PWM frequency for a 96kHz 24 bit audio signal will be over sampled x4 which is 384kHz. That's a lot less than i expected (I would have thought it'd reach the MHz range). So, i think a higher order low pass will be needed because i doubt -20dB will cut it to remove all those high frequencies harmonics.
I know the actual speakers can't reproduce those sounds, i'm mainly focusing on the EMI produced by all that switching over the cables.
Might aswell go overkill, so here's my attempt at a 5th order Butterworth filter with a ~60KHz cut off frequency. I chose this frequency such that any ripple that happens after normalizing the components values would be ideally after 20KHz.
I ended up with a sliiiight ripple but it's inevitable, and check this out, -72dB at 300KHz. Take that high frequencies !
3 - Load dependency - Buffer Stage ?
So, changing the load changes the frequency response : if you plug your fancy 200Ω headphones to my nice 80Ω filter, you get -40dB (x0.01) of the sound level at 20kHz. This won't do !
The easiest way to deal with it is obviously to put a resistor in series or parallel depending on the load value , and make it variable : if your load is 2Ω then your resistor should be 72Ω in series so that the entire impedance is 80Ω. you'll get a lot of attenuation but the frequency response will be ok.
As you can see, the traces are almost the same even if the load changes, they're just offset.
This would be a good solution if i wasn't going to make an output stage for big subwoofers and whatnot down the line : if I want to output 100W then i need a resistor array rated for 100W. Still, i guess this is beyond the point for now because I'd also need a filter capable of handling 100W.
One would think a voltage follower should be usable, yet the biggest issue is that the entire point of a voltage buffer is to have a high input impedance and low output impedance, effectively nullifying the work of the comparator amplifier, and circling back to an inefficient class A amp !
After talking with some analog wizards the answer i was given was essentially "If you want a filter, you need one for all range of loads you want"
So, here are the different solutions we've agreed on:
ditch the pure class D design and go with a Class A output stage
ditch the high order filter, try to use a ferrite bead.
create a filter bank, where each individual filter work for a small load range.
scrap the whole idea entirely and go full analog
It's true that the higher order filtering isn't actually done on all the literature i've found. even datasheets only mention simple low pass LCs, which heavily imply that it's not needed at all :
4 - Filter Design - Single Ended filter bank selection
We need to be able to connect and disconnect our filters (remotely). There are 3 topologies that i have found, but one of the will be a real bore :
1 . Series inductor, disconnecting the caps
basically, by turning on/off the transistors, we let the signal go through a specific amount of inductors, the sum of which give the cut off frequency wanted. a single cap is also selected, and a path to the speaker is made.
It's perfect in theory, but there's a few problems imo :
the "control system" needs to give a high enough voltage since it's on the high side.
the inductors aren't perfect, but their value needs to be really precise. they vary with temperature etc. so matching all of them will be a pain.
the system isn't modular at all. if you have a filter for 1,2,4,...,100 Ohms and you want to add a filter for 3 Ohms then you need to redesign, remove and rewind all the inductors from L4 to L100.
For a perfectly static system i think it'd work, but i'm looking for something modular, since i frankly don't know what i'm doing and will probably need to tinker and bodge over and over. I'm not looking to redo more of my work since that's pretty much garanteed already.
2 . Latching relays : straight forward solution
This method is a tad more efficient if you want an amount of filter that is a power of 2: you always need one less relays than you have filters.
Both solution have their own ups and downs : this one is less efficient if you have an odd number of filters, it offer less modularity...
As we're still prototyping, i'm going with solution 2 !
4 . Same thing as before but with MOS as switches
I'm not against that idea, but all the biasing will be a pain. Our single ended speaker is connected to ground, so we need to separate it from the filter bank by placing the transistor on the high side, which needs a high enough voltage.
Here are the final schematics for the test circuit :
Filter bank selection module (value aren't different)
That's it for today ! next time we'll design the BTL differential filters !
As always, if there's a huge flaw i haven't seen or you have ideas / remarks, feel free. Cya !
Hello everyone, i've been hard at work ̶g̶e̶t̶t̶i̶n̶g̶ ̶m̶y̶ ̶c̶a̶d̶e̶n̶c̶e̶ ̶l̶i̶c̶e̶n̶s̶e̶ ̶b̶a̶c̶k̶ on the DAC, but also "redrawing" the whole project.
First things first, let's address a few important points/thoughts I had since last time :
What will the Output Unit (DAC unit / DAC / Power amp) topology be like.
Changing the mixing algorithm
I2S means Inter-IC Sound, so how can i make a modular system (ie : multiple PCB for multiple inputs/outputs) since length of track will be variable ?
the choice of ICs need to be done so I can start designing the circuit.
How do I test this.
Let's see those points in detail.
1 - Output Unit structure details / Amplifier talk.
One thing that might have not been clear before is that the mixing unit acts as a separation between the sound sources and the amps/headphones/whatever : Any data out of the mixer either goes back to the sources through USB (as a microphone input) or get sent out through I2S. What we're currently designing is the "DAC", or the output unit, used to transform the I2S into analog signals that can then get amplified by any kind of analog amp.
Analog amplifiers come into a really wide range of configuration, each with their own unique ups and downs. Class A, B etc. are easy enough to make but are rather inefficient, while class D amps are the opposite : really complex, really fiddly, really efficient. Making a class D amp entirely by myself is out of the question, but chips do exist that allow for the dreaded analog to 1 bit modulation. Most class D amps out there are made with ICs taking analog in and spitting HF PWM out that get filtered back to ~20Hz - 20kHz.
The idea is therefore to create a "comparator amplifier" that acts as closely as possible as an ideal opamp in comparator mode : taking the HF PWM signal (with "Voltage High" and "Voltage Low") and spitting out a symetrical Signal (±V amplifier) such that both waveform are exactly the same, just with different amplitudes.
Here's the structure of the output unit with power amplifier attached.
As you can see, volume control is entirely determined by the power supply of the entire output stage.
In our case, the output unit actually needs at least 2 analog output : Line Out and Headphones Out. I'll just do the same comparator Amplifier + Filtering Combo on the same PWM input to get both signals, with different V_amp voltages for each.
I'll also allow a PWM output because my portable DAC unit won't have a beefy variable voltage source needed for the power amplifier part. Therefore, i want to future proof it by being able to be connected to such an amp down the line : making different modules make prototyping much easier.
NB : by choosing this method, i completely bypass the analog pre amplifier needed for the input module that i was supposed to design now, which mean i'll have to design it later.
NB : This output module is entirely optional, there exist many I2S to Analog DACs out there. I'm just designing it because it's fun.
NB : This method moves the complexity away from the actual amplifier design and toward the power supply design.
2 - Sound with 32 bit-depth makes no sense
In the introduction of the project, I devised a few ways to deal with potential overflow. Since i wanted to not deal with distortion so much, i decided to just put the 24 bits + overflow onto a 32 bit channel and pretend everything was fine. it's not fine.
So, let's say we have a 32 bit DAC chip, working with a specific voltage. It takes I2S as an input and output an analog signal using what is black magic for our intents and purposes. That output should be perfectly linear. Well, let's say we're using a symmetrical 5V power supply. The DAC's resolution is 10/(2^32) volts, or roughly 2.33 nanovolts. Let's be clear, that's absolutely impossible to achieve, which means the least significant bits of our signal are straight up noise. The DACs are more expensive, I2S timings are tighter, everything is more complex... it doesn't help at all.
So, i'll have to find a way to stay with 24 bits. Luckily, i'm still a student ! I asked one of my professors and he dropped a few truth bombs on my algorithm, mainly :
Audio sources are not correlated, so the chance of overflowing aren't that great
Even if overflowing happens, it's not the job of the mixer to deal with it. rather, there should be variable gain higher up the chain.
As such, the true ,final algorithm™ should just be an addition.
Also, we talked a bit about how the mixing pipeline should go. It was a really interesting talk. no clue how i'll implement most things yet !
Hell yeah, look at me winging it as i go.
3 - How do I send the I2S far far away ?
for 24 bit 96kHz, we're looking at a ~2.3Mhz signal. That's doable, but the issue comes with the specific rise/fall times needed. Long story short, it depends on what IC I end up using but overall length of the track remains an issue.
I've found a few ways to deal with it :
Bringing the modules really close to the mixing unit (like addons directly on the main PCB), and just sending the control/PWM/analog signals to and from the rack mounted "face plate".
Making the I2S a balanced signal that gets unbalanced at each end of the wire
Using buffers (comparators really) to deal with the rise/fall times.
All of those (or a mix of them) should solve that issue, I haven't really thought about it much yet because i'd rather start designing the actual standalone DAC unit first.
4 - general IC choices
I've previously highlighted the structure I've chosen for the output unit in part 1 of this post, but all the actual hardware choices aren't made yet.
Let's recap on what ourbridge specs are :
The USB bridge MUST be duplex (USB device acts as audio input, and audio output).
The USB bridge MUST be an USB slave
The I2S lanes MUST be stereo, turning mono to stereo by copying one channel to the other if necessary.
The I2S/USB lanes MUST be 24bit 96KHz.
The I2S lines MUST be controlled by the FPGA (not the microcontroller itself). That means that buffering USB data must be done, so that the bridge and the FPGA can be synchronous.
→ The duplex 24bit 96KHz audio spec means that we'll have to deal with USB Audio 2.0 class.
→The duplex I2S lines means that we'll have to use a microcontroller with two internal I2S processors
Let's recap on what ourDAC specs are :
I2S Input (24bit 96kHz)
PWM Output
Cheap
Currently produced
Share the supply voltage with the microcontroller.
That's it. I know the THD will be correct either way so i'm not even asking for specific values.
→ Choosing the DAC chip first, i've found the TAS5548. It does everything i want.
The chip isn't a DAC but a PWM modulator, as we've talked about earlier. It needs to be driven by a microcontroller to initialize it, and i'll use the Bridge IC to do so.
→ For the Bridge / Output controller, i'll use a cheap STM32 with one USB interface and two I2S ones.
The choice of a STM32 is pretty inconsequential. I'm simply used to the dev environment. Chances are, the input module will also have a few parts to be initialized (the ADC for instance).
There's also the fact that the face panel of the Input or Output modules might act as rather complex HID devices depending on how much feature creep and rule of cool engineering i want to deal with. ( mute buttons, motorized potentiometers etc.).
If that's the case, having a bridge chip with processing power to spare might prove useful. In any case, price is key and the I2S to USB / USB to I2S pipeline seems pretty straight forward.
5 - Testing setup
Measuring is a critical step to know wether or not the system actually works, but measuring binary strings is a gigantic pain, yet I have to insure that my USB bridge works.
One quick way to know at a glance is to play a sound file on my computer and listen to what the DAC spits out, but that's obviously not enough.
Here's the plan :
I'll make a test audio file with specific values and play it on repeat. Then, i will measure what the bridge spits out over time, and see if those hex values correlate to what is expected.
Once we have a working bridge, we can go lower down the chain and connect it to our DAC. We should then be able to measure the frequency response of our system against the original audio through a digital signal generator, which should give us a clue on how linear we are (ideally we'd want 0dB)
Once we reach that point, we have a working USB Bridge and DAC. Can't wait !
Just a small word for the end, I'm sorry for the lack of actual content in these posts. I'm still actively studying, looking for overseas internship and whatnot so that doesn't leave a lot of time for leisure work. I also have a big case of no money so buying PCBs and chips is difficult to say the least. If you have any question or would like to work on that project, please don't hesitate ! it'd be fun to work together :)
Anyway, next blog post should be about routing and filtering. Cya !
The Output module will probably be one of the first module completed. Here it is :
That's right, we don't have any hard processing to do, maybe a bit of filtering here and there, a few potentiometers for volume control but overall it should be manageable. The DAC will be bought according to its availability and specs.
The Line Level will be used to connect to other beefy Amps, whereas the Headphone level will straight up be usable.
Why do it first ?
There is a very easy way to test the preamplifiers and the bridge : making a dedicated audio DAC, such as the ones you can buy. We just need to connect our USB bridge to the DAC.
Voila ! a DAC.
Once this device work, we will know our I2S bridge and Preamp works, which mean we can start working on the Input and Mixer modules !
From now on, this is on what i will be working and report.
The Input module doesn't technically needs to exist for a purely digital system, but as I plan to use this with analog devices (microphones and instruments) so I am designing it.
This module is therefore separated in two specific part :
The ADC, transforming the analog values to an I2S stream to be processed by the Mixer Module
The USB Bridge, which acts as an USB slave and talks to an USB Master (a computer) over duplex USB audio to recieve and transmit audio streams. Those I/O streams are transformed/comes from I2S streams.
From this description, it is therefore clear that the Input Module is a magic box that looks like this :
NB : the USB bridge only works as a slave. I have no plan on making it work with USB headphones, or USB microphones. I don't know how nor am I interested in that feature for now.
Also important is the fact that the USB bridge will probably be on this module : this allow clean cable management on a rack which is noice. unpopulated components will be placed on the main mixer PCB so that if you want only 2 USB devices and 4 analog inputs you don't have to buy 6 MCUs instead of 2.
Analog Processing - The Plan
As you can see, the Analog part has some processing in it, and it is crucial. Our analog devices might need phantom power, an attenuator, a pre-amp, the input might be balanced, stereo, mono etc.
The Input module is in fact the most important module because even if everything else works, if it isn't calibrated correctly the rest will sound like garbage : if the bridge doesn't work then no audio will reach the mixer/the user, if the analog part sucks then the processing won't give correct results etc.
The processing chain will look something like this :
NB : the mono/stereo/differential path are just for visuals. The "mono to stereo" module is the same for mono and differential, the low pass filter is the same for each three path. depending on the user input selection, certain modules will be shorted and ignored.
Filtering is necessary to remove the aliasing that will come after the ADC. If the user amplify a signal that is already large enough, it will clip and create harmonics that will also create aliasing.
To be honest, i don't know if both filters are necessary or only the one before the ADC. My small experience tells me to do both but i have no audio training and only saw it on highly specific metrology applications, way beyond the scope of audio. So, this will stay for now but if the OpAmps use are too expensive one might leave.
Basically : you press the phantom power button and the inputs gets polarized to a specific voltage. He uses 15V, I have yet to decide what to use.
Analog Processing - Preamp
To be done : this part will be reused for other parts, so we will study this later.
Analog Processing - Attenuators
To be done, still have to check whether resistor cause too much noise vs using dedicated audio ICs ( it'll probably be resistors)
Analog Processing - ADC
This'll be short : I'll simply use an out of the box two channel ADC that outputs I2S at 24 bit 96kHz. That's all it has to do, and most modern ADCs are so good that most of the issues will be with my circuit, not the chip.
Digital Processing - Bridge
To be done : this part will be reused for other parts, so we will study this later.
In the general description of the project, I briefly mentioned the 4 core units of the project :
a general use input module to be able to get analog data in
a general use output module to be able to get analog data out
an HID module to interact with the system
the Mixing module to actually work on the data
Those are obviously incredible simplified. In the next few logs i will write a bit about the inner workings of and limitations of each module, the protocols that will probably be used and why they'll be used.
This one will be dedicated to the star of the show, the MIXING MODULE
What does the mixer actually do ?
The mixer is able to take digitalized audio streams, process independently and together, then output them to the outputs selected. Here are all the features that i want
Feature
Use Case
Stereo Sound through USB
Using Headphones or 2.1 systems
Modularity
You want to plug 2 PC and 1 guitar or 5 microphones and 1 PC
Per Output Input selection
You want Output 1 with Input 1, Output 2 with Input 1 and 2
Per Input volume control
Allow to turn down your microphone if it's too loud
Per Output volume control
Allow to turn down music if it's too loud
Each Input get its own EQ / filter
If your microphone is hissing, you can remove it from all the outputs easily
Each Output gets its own EQ / filter
Make using a subwoofer or a tweeter at high power easier
Each Output gets its own delay line
Allows to synchronize all outputs, if one is too delayed because of filtering
Specs aren't the point of this project, i want them to be lax enough to have fun and to learn : I'm not looking for a 0.0001% THD or something like that, at least not for now.
My setup is rack mounted, so it'd be fun if the modules were rack mounted too / something akin to eurorack in a 19 server rack ? ¯\_(ツ)_/¯
What Audio Streams format are we choosing, and why ?
the audio streams will be encoded in PCM over I2S because it's a standard and makes creating input and output modules easier since compatible ICs already exist.
NB : every stream from now on is considered stereo, until specified otherwise
In simple terms, PCM means that the audio signal is encoded by saving its amplitude at a specific frequency. a 8bit 1kHz PCM stream means that every milisecond, you get a byte of data representing the amplitude of the audio signal. 0xFF is the maximum (positive values) , 0x00 is the minimum (negative value) and 0x0F is the middle point or zero.
NB : those values are not representative of volts or whatever, they're normalized. each ADC has a gain of "bits per volt" called resolution that ISN'T shared to the system. this means that over the entire processing chain, we have no clue how loud the sound is. This tie with issues like headroom, clipping etc.
The fact that we are encoding amplitude makes mixing absurdly simple : NB : this result only works if all the streams are at the same frequency
The mixer must be able to be used for recording music, so instead of the average 48kHz sampling frequency, we will go with 96kHz. This roughly means that if you want to process your instrument by slowing it down by a factor of 2, you will still end up with a 48kHz sampling frequency. This doesn't increase quality in any other way.
N.B : Some acquisition cards go up to 384kHz for the same reasons, we could but we won't go near that since i have no way to actually test it nor do i care about it.
With the same idea, we'll go into audiophile territory a bit and go with 24bit encoding instead of 16bit, even though the differences can't be heard. Following the same logic as choosing 96kHz over 48kHz, this will allow more flexibility when processing amplitude instead of frequency (ie : you can digitally amplify audio more before hearing distortions)
So, instead of going with the usual 16bit 48kHz, the inputs are 24bit 96kHz streams, which isn't that special for high end audio hardware.
Overflowing Issues and solutions
Let's say i have 4 inputs streams on 4bit playing a very loud cos wave, so loud in fact that at peaks the streams are at 0xF Let's also say those cosinus waves play a frequency f, 2f , 4f and 8f respectively.
It just so happen that at t = 2/f you get all the peaks at the same time
If you add the signals at t = 2/f you get the following (in binary)
Wow ! Nice overflow ! It just so happen that each time you add a signal you risk overflowing. The amount of bit overflown (that a word ?) actually depend on the amount of inputs, not the size of those. NB : if you add four 24bit streams you still get an overflow of 2 !
I hear you say " But you're not doing the Division by 4 which would solve the overflow problem !". Yes, it's true :
The prospect of adding 4 inputs (or 8) is quite attractive to us because division by a power of 2 is just a bit-shift. bit-shifting is x2 or /2 depending on the direction. However, our system has to work for all possible amount of inputs (1 2 3 4 etc.) so we have to do the division ourselves. and if you have 3 inputs, that division doesn't remove the overflow.
How do we deal with that ? there's three way and they all have their issue.
1 - Not dealing with the overflow and loosing information
If your input is 4bit and you want 4 inputs, just output 4 bits. that's it. Just bitshift back to 4 bit, you'll loose the least significant bits of data. over 4 bit that's quite the issue but over 24 bits and depending on the quality of your audio system i bet those bits are basically noise to your ears. still, it's not an ideal solution
2 - Not dealing with the overflow and loosing money
If your input is 4bit and you want 4 inputs, just output 6 bits. that's it.
In our case, we could normalize our outputs to be 32 bits 96kHz (it's another standard) which works out nicely. However with no post-processing your sound is suddenly 2^(32-24) = 256 times quieter. that's a whopping -48dB reduction.
Since you know your number of input you can bitshift (multiply by 2^n) the correct amount of time to deal with that sound reduction. You don't loose information that way, but you do pay a price : you now have to transfer 32 bits back instead of 24. so the DACs and USB bridges must be able to deal with 32 bits.
3 - Dealing with the overflow with math
The arctan function basically starts linear and slowly goes toward a specific value. by transforming it a bit we can achieve something like this :
NB : nothing is to scale
As you can see, for low values, x=y so the input and outputs are the same, but as the inputs tend toward infinity (or rather, as the input get overflown) the value tend toward the maximum allowed, 0xFF.
This works wonderfully, is SUPER cheap to implement (you just need a LUT ) buuuut it adds distortion.
I think i'll pass on this one, but i'm not sure yet !
EQ, Filters ?
I won't go into details, since i haven't done the math yet on what's achievable on a reasonably priced FPGA. I have experience as a student from using Artix 7 dev boards but at 150€ per chip, i'm not too keen on using those (although they are 100MHz beasts, they're way too overkill)
The idea however is just to add simple superposed digital band stop filters to act as the EQ.
Delay line ?
I won't go into details, since i don't have the appropriate hardware to implement it.
The idea is that the previous filters will offset the signals in the time domain : they'll come late by a factor of its frequency. this cannot be avoided, and it means that the smaller the frequency the bigger the offset in the time domain, which can end up in the 20s of ms.
One solution is to add a Delay line per output, and use them to add delay to every output so that they're all synchronised with the slowest output :
Output 1 is 1 ms late
Output 2 is 10 ms late
You add 9 ms of delay to Output 1
both Outputs are 10ms late and synchronised. Yay !!
The easiest way to implement this is with RAM and using a circular buffer, which our FPGA can easily handle.
USB ?
Ah. Here comes trouble. Turns out that USB is super high speed and need dedicated hardware, a run of the mill FPGA won't be able to implement with it. Also turns out that USB to I2S and I2S to USB *isn't* a standardized thing. our 24 bit 96kHz input 32bit 96kHz output don't have dedicated ICs. Also, There's no way to use other things than PCM (DSD is a big thing in the audiofools community, but it'd be fun to implement too. maybe)
The general solution if you look up for this online is to just make it yourself. so guess what we're gonna do ?
That's right, we're gonna take an STM32 or whatever and write a duplex bridge : USB to I2S and I2S to USB.