Generating a clean 10kHz sine wave from PWM - Page 1
Forum section: electronics / projects

author: robca
author_rank: Frequent Contributor
timestamp: June 30, 2022, 12:01:44 am
content: (not sure if this belongs here or in Beginners)I'm quite familiar with digital logic and microprocessors, get lost in the analog part...I'm working with a prototype sensor that changes impedance when environmental conditions change (sorry, can't provide too many details on the sensor itself).Currently the sensor is read by generating a 10kHz sine wave, and measuring the phase difference using two fast comparators and a digital 12 bit counter with a 2MHz clock. The comparators generate a pulse on zero crossing, one starting and one stopping the counter. The sensor value is read as a 12 bit value from the counter. I did not work on that circuitI'm now trying to use a microprocessor to, as much as possible, duplicate the entire functionality. Everything runs at 1.8V. I can generate a PWM sine wave at 10kHz (albeit with only 40 values, and 40 steps to define the wave). I plan to use an active lowpass filter to generate as clean a sine signal as possible, 0.9V centered (1.8V Vpp). Then the sine wave is used to excite the sensor, which behaves like a variable inductance, and the excitation signal is fed into the microprocessor differential comparator 1, using 0.9V as a reference to detect zero crossing. That event will automatically start a 16MHz timer, no software needed.The other end of the sensor is fed into another differential comparator, and the zero crossing there will stop the timer and generate an interrupt so that I can read the value in my code. The timer value is directly proportional to the phase difference, which is directly proportional to the sensor value, in turn reflecting an environmental value.I tried using a basic lowpass RC filter to clean up my sine, with poor results and a very low Vpp as a result of the filtering. Please note that I don't really need a super-clean sine in the top and bottom part, which from everything I know it's the hardest to achieve. I need the cleanest possible signal at zero crossing, where the curve slope is almost linear and should be the easiest to achieve with a lowpass filter.I've tried to explain my idea in the drawing below. I used a "mystery opamp filter", because I think that an active filter will help me achieve the best results, and help get a sine as close to 1.8V as possible. I can use up to 3 individual opamps and as many passives as needed, but keeping to BOM simple is a nice to have. One of the opamps in the quad opamp is needed to create a 0.9V reference for the sine wave/sensor. I might need to amplify further the sensor signal, if the sensor/resistor results in a too small signal. If not, probably I could use a dual opamp, not a quad one.Please note that I'm aware that there is a logical circuit simplification: since I'm controlling the PWM signal, in theory I don't need the first comparator. I could start the timer for the phase difference when the PWM signal generator starts the wave from the 0 point. But I know that filters add a phase offset, so I plan to build the circuit, use the first comparator to get a reading of the offset, and use that in the future to calculate the actual phase difference due to the sensor. So the final circuit will only have one comparator. I designed it with two, to clarify better.In any case, a clean 10kHz sine wave is a requirement. Can you please help me figure out a good active filter and help pick the passive values for my frequency? A single PWM pulse is 16MHz, and I use 40 pulses to represent values 0 to 40. So the PWM frequency is 400kHz. I have a 40 items LUT, to build the sineAny type of input is appreciated

author: mawyatt
author_rank: Super Contributor
timestamp: June 30, 2022, 12:44:54 am
content: Interesting concept.Just a question, could you just use a squarewave and measure the edge shift?If you require an active LPF then and simple Sallen Key might be in order. You have 40 samples per waveform period so the sampling harmonic content should be far out frequency wise. Maybe a 2nd, 3rd order Butterworth SK might suffice. Watch out for the SK LP feedthru since these unwanted waveform artifacts will be relatively high frequency, and maybe high enough for considering a passive LC filter, or hybrid (active & passive).SK LP feedthru is when the input couples thru the feedback capacitor since the op-amp output impedance isn't low enough. There are several ways to deal with this, use an op-amp with very high GBW product relative to the desired waveform frequency, bleed current from the output or add an output buffer to the op-amp to lower the output impedance, or use a topology where the input "sees" an RC lowpass before the feedback cap (3rd order).Anyway, hope this helps.Best,

author: Someone
author_rank: Super Contributor
timestamp: June 30, 2022, 01:00:10 am
content: Quote from: robca on June 30, 2022, 12:01:44 amHow many orders/stages/poles were you planning? Whats the PWM counter frequency and length/range options?You are probably fine to just generate a 10kHz square wave and round it off with the active filter (5th order lowpass is cheap enough)

author: robca
author_rank: Frequent Contributor
timestamp: June 30, 2022, 01:26:36 am
content: Quote from: Someone on June 30, 2022, 01:00:10 amWell, how many poles is kind of the questionThat's what I'm trying to figure out. The simplest circuit that gets me a good enough slope to measure phase offsetAs I mentioned the fastest PWM pulse frequency is 16MHz. I determined that using 40 possible pulses to represent 0-40 and 40 LUT points to define the values of the sine is the best compromise. That results in a 400kHz PWM frequency with 40 possible values. Using 40 points LUT, results in a neat 10kHz sineFrom my point of view, the "cost" of using PWM or a square wave is the same. Once I program the microprocessor registers with the right values, the generation uses no CPU cycle. So I assumed that to get a clean sine, starting from a PWM sine would be better than a square wave. But that's an area I know very little

author: robca
author_rank: Frequent Contributor
timestamp: June 30, 2022, 01:33:40 am
content: Quote from: mawyatt on June 30, 2022, 12:44:54 amIn speaking with the sensor developer, he thinks that a sine wave is the best, given that we are dealing with an organic polymer that might not like the steep voltages in a square wave. Not sure I understood the chemical explanation, but intuitively it makes sense to me. And I'm also trying to approximate the existing circuit as much as possible, as least as a starting point (to avoid adding even more variables)Thanks for all your other comments. If I may ask: I'm not sure I understand what frequency I should target for my lowpass filter. I'm sure it's a silly question, but that's one of the areas I get lost. In playing with the passive RC lowpass, a filter frequency of 5kHz seemed to work better than a 10kHz one. Given the passive filter slope, it kinda makes sense, but I still can't figure out what I should be shooting for, without trying a lot of values, if you had to filter a 400kHz signal with 16MHz pulses in order to get a clean 10kHz sine, what filter frequency would you start from?

author: Someone
author_rank: Super Contributor
timestamp: June 30, 2022, 01:51:38 am
content: Quote from: robca on June 30, 2022, 01:26:36 amSo its an autonomous timer with DMA? or some circular buffer to feed the pattern of pulse widths? Those are the details that decide what is possible for frequency. How did you decide that division/rate is optimal when you havent included the filter design?Quote from: robca on June 30, 2022, 01:33:40 amThose arent the frequencies I would describe the system by (from your explanation so far). There are a range of "clever" modulation methods/techniques (even within "PWM") that reduce the demands on the anti aliasing filter. But since you have a 10kHz signal as the measurement, thats a fixed gain point, and any other signal is "noise" that needs to be reduced to some (unspecified) level relative to the fundamental/signal.

author: Someone
author_rank: Super Contributor
timestamp: June 30, 2022, 01:54:31 am
content: Quote from: robca on June 30, 2022, 01:26:36 amAlso "cheap" depends on other constraints of unit cost vs engineering time, size/power constraints, etc etc etc.

author: robca
author_rank: Frequent Contributor
timestamp: June 30, 2022, 02:05:08 am
content: Quote from: Someone on June 30, 2022, 01:54:31 amFair enough, you are right "cheap" means nothing. It's a proof-of-concept prototype, so I'm just trying to minimize components. Ideally I'd like to use the TSZ122 (dual opamp) or TLV9004 (quad) I already have in my box of random components. One opamp is gone for the voltage reference at midpoint (0.9V), so that leaves one or 3 opamps to play with. Passives as many as needed, but since I'll be point soldering cockroach style, the fewer, the better. Power for now is not a concern, but it has to work at 1.8V (the current prototype is 5V, but the sensor should work just fine at lower voltages)Not production-level optimization. Just a prototype that shows that a circuit currently using 22 ICs and 75 odds passives plus a microprocessor, can be reduced to a microprocessor plus a few opamps and passive. To be fair, the original circuit was designed to fully validate the sensor, so it has a lot of additional features to handle multiple frequencies, etc. So I'm not dissing the original one. But it's still a complex circuit now that we know the range of operation and are dealing with a well understood sensor

author: Someone
author_rank: Super Contributor
timestamp: June 30, 2022, 02:50:11 am
content: Quote from: robca on June 30, 2022, 02:05:08 amThose opamps have pretty high output impedance, so you'll be fighting to get them to work as an active filter. As above, I'd be stuffing a mostly passive filter in there with the opamp just for gain and "solving" the quality of the sine wave in the modulation.

author: iMo
author_rank: Super Contributor
timestamp: June 30, 2022, 06:05:22 am
content: FYI - MAX7400/7401 (Elliptic/Bessel) 8th order low pass filter.For 10kHz corner you would need 1MHz clock to feed into the chip (100:1 clock to corner ratio). Also add a simple RC on their outputs to filter out the clock.

author: emece67
author_rank: Frequent Contributor
timestamp: June 30, 2022, 06:42:41 am
content: .

author: Kleinstein
author_rank: Super Contributor
timestamp: June 30, 2022, 06:53:10 am
content: There are 2 general concepts, both with pros and cons:A) use PWM as a kind of DAC and try to sample the sine wave with this. Ideally this would be a kind of 1 bit SD data stream. This gives quite a bit of higher frequency (e.g. > 100 kHz) amplitude, but not very much below. In theory this makes this filter simpler.B) start with a simple 10 kHz square wave and apply the fitler directly to that. With little filtering one may get closer to a triangle wave than a sine, but that may be good enough for the sensor.If the sensor is OK with a not so perfect signal this can be the much easier solution.The filters have to cope with less higher frequency energy.Active filters have a somewhat hard time at higher frequencies, like >100 kHz. The real OP amp circuit may no longer behave ideal as the basic therory. An unwanted feed through via the feedback path is common problem with active SK filters if the OP-amp is relatively slow. The simple SK low pass does not work well much above GBW / 10.The <100 kHz range is however also the range where classic LC fitlers are not yet that attractive, as the inductors get quite bulky, but they get simpler for the higher frequencies. RC filters are OK, but loose some amplitude. This is however not a big deal, as one can amplify later on. A sharp cross over is also not needed, just a good suppression of the high frequency part.Especially for the path A) one may have to consider a combination of first a passive filter (maybe LC with some 100-200 kHz cross over) to get rid of most of the higher frequencies and only than use an active filter. Active filters want a GBW much higher than the frequency of interest. A 1 MHz OP is far from ideal for 100 kHz and higher.

author: Slh
author_rank: Regular Contributor
timestamp: June 30, 2022, 08:29:36 am
content: There's a trick you can do by adding a digital inverter and AC coupling the output with the pwm output to reduce the output ripple. I think I found it in the Art of Electronics. It might reduce the required output filter by a factor of 10 or the pwm frequency by the same amount.

author: Kleinstein
author_rank: Super Contributor
timestamp: June 30, 2022, 08:36:27 am
content: Quote from: Slh on June 30, 2022, 08:29:36 amThis trick adds effectively an other order to the low pass filter. It may still be somewhat simpler than another filter stage, but not much and a single OP active filter is usually 2nd order.

author: voltsandjolts
author_rank: Unknown
timestamp: June 30, 2022, 08:48:45 am
content: Just another option: DDS sine genSearch ebay for AD9833 ...oh wow, DigiKey actually has stock too!

author: mawyatt
author_rank: Super Contributor
timestamp: June 30, 2022, 01:10:08 pm
content: If I understand correctly you are measuring the zero crossing shift cause by the sensor inductive reactance changing with what's being monitored. Maybe consider using the chip-set utilized by the LCR meters like the DE-5000 which is based upon a synchronous technique and produces the measured phase shift?Best,

author: Picuino
author_rank: Super Contributor
timestamp: June 30, 2022, 01:27:54 pm
content: If the purpose of the circuit is to measure inductance, I think it is simpler from a hardware point of view and much more accurate to make an oscillator by placing a capacitor in parallel to the inductance. Then you can measure the frequency of the LC oscillator and calculate the inductance from there.It is similar to what this circuit does:https://electronics-diy.com/lc_meter.phpEdit:You can remove SW2, the relay and first 1000pF capacitor

author: Picuino
author_rank: Super Contributor
timestamp: June 30, 2022, 01:39:48 pm
content: Another option is to use a VCO (Voltage Controlled Oscillator) and a PLL (Phase Locked Loop) matched with the 10kHz PWM signal.AN-263 Sine Wave Generation Techniqueshttps://www.ti.com/lit/an/snoa665c/snoa665c.pdfThe sine wave can be obtained from a rounded triangular signal with a suitable circuit.For example as does the old ICL8038 (https://www.mit.edu/~6.331/icl8038data.pdf)Or Exar XR2206 (https://www.sparkfun.com/datasheets/Kits/XR2206_104_020808.pdf)With 0.5% of distorsion.

author: robca
author_rank: Frequent Contributor
timestamp: June 30, 2022, 04:33:02 pm
content: Thanks everyone for all the input so far. Lots to digest and experiment with, thanks. I need to play with a few options and see how clean of a signal I can get, if I plan to use my original approachQuote from: Picuino on June 30, 2022, 01:27:54 pmAfter reading this (and the similar one from mawyatt), I slapped myself hard. I was so focused on reproducing/simplifying the original circuit, that I did not think about alternative approaches like an LC oscillator. Measuring a frequency is much simpler using a microprocessor. This is really promising, looking into the linked project nowAs for the suggestions to use a dedicated chip to generate the sine, that's something I ruled out for many reasons. I'm familiar with, for example, the AD9833 and I have a working module. But it would add one more chip to the BOM, and more importantly will require using two comparators and my microprocessor has only oneGenerating the sine with the processor means I can start the hw timer with the PWM and stop it with the single comparator. An external generator would add complexity.Will update this post once I have made some progress

author: Kleinstein
author_rank: Super Contributor
timestamp: June 30, 2022, 04:41:01 pm
content: An analog filter does cause some phase shift and depending on the details this phase shift can drift with temperature. To keep this effect small one should avoid a sharp bandpass and for the low pass filter consider the cross not too close to 10 kHz. So even with PWM and filter a 2nd comparator may be a good idea. Alternating between in the sensor and drive path may be an option here.A DDS could run in sync with the µC. I would still consider this overkill.

author: robca
author_rank: Frequent Contributor
timestamp: June 30, 2022, 04:50:48 pm
content: Quote from: Kleinstein on June 30, 2022, 04:41:01 pmYes, you are right. I oversimplified my explanation. I will need to ensure I periodically "zero out" the PWM/filter phase drift, otherwise I will have erroneous readings. And your suggestion is what I planned to do, appreciate you confirming the approachAssuming I get a good enough sine from the PWM, my code will first use the only comparator to stop the timer and read zero crossing i.e. the filter phase using a pin connected to the filter output (the "drive path"), store that value as the actual starting point of the zero crossing of the signal to the sensor.Then switch the comparator input pin to the sensor output, and use that to stop the timer (the timer starts with the PWM generation in both cases). Subtracting the two values will give me the phase difference due to the sensor value. Every second or so, re-read the drive path to minimize drift.Using a free running oscillator requires to program the processor to program the comparator to start a time on zero crossing for pin 1, then immediately after the timer is started, reprogram the comparator on the fly to stop the timer using pin 2. It can be done, but requires very precise IRQ handling and won't work for mall phase difference. It was my initial approach, but I realized it could be done smarter using your approachAnd, yes, a programmable DDS can be synced, but it's a lot of pain and, as you say ,overkill

author: mawyatt
author_rank: Super Contributor
timestamp: June 30, 2022, 05:01:26 pm
content: Quote from: robca on June 30, 2022, 04:50:48 pmAnother thought.If you select a free running (~10KHz) oscillator with the variable inductance, then you could use a frequency divider and measure the divider period with the microprocessor. This would give very good resolution and depends on how long a period (division ratio) you select.Best,

author: robca
author_rank: Frequent Contributor
timestamp: June 30, 2022, 05:07:09 pm
content: Quote from: mawyatt on June 30, 2022, 05:01:26 pmUnless I misunderstand you, are you suggesting to build an oscillator with the sensor inductance as part of the circuit, then measure the oscillator frequency? If so, it's in line with the "LC oscillator" measurement technique. Completely change my approach and instead of measure phase difference, measure a frequency generated by a circuit driven by the sensor inductance.Is that what you are saying, or am I missing your point completely?

author: SiliconWizard
author_rank: Super Contributor
timestamp: June 30, 2022, 06:19:59 pm
content: Just thinking out loud - whether PWM here would yield lower distortion than a simple square wave going through some low-pass filter, that may not be as trivial as it sounds.You may in particular consider whether harmonic or non-harmonic distortion is better in your specific application.

author: mawyatt
author_rank: Super Contributor
timestamp: June 30, 2022, 06:44:02 pm
content: Quote from: robca on June 30, 2022, 05:07:09 pmYes that's the concept. What Picuino indicated using the sensing inductor in an oscillator except don't try and measure the oscillator frequency directly but the period after it's been divided down. The measured period will be D/F, where F is the oscillator frequency and D is the division ratio. This eliminates the need for a comparator and only requires a CMOS divider chip, some CMOS divider chips even have an oscillator gain element (usually a separate inverter) available. Select D for the resolution required based upon the microprocessor clock and ability to measure pulse widths on the I/O pin.Best,Edit: A little math to show how this might be implemented.Freq ~ 1/[Sqrt(LC)]Period = 1/F ~ Sqrt(LC)dP/dL ~ [(1/2)*C]/[Sqrt(LC)]dP ~ [(1/2)*C*F]*dLSo the change in Period is directly proportional to the change in inductance, with a proportionality constant of (1/2)*C*F.With the divider then this becomes:dP ~ D*[(1/2)*C*F]*dLWhere D is the division ratio and acts like "Gain" in the system to improve resolution.Of course this assumes the math is correctBest,

author: Marco
author_rank: Super Contributor
timestamp: June 30, 2022, 09:22:32 pm
content: Do you have 1 more output available? Then you can do 3 level PWM modulation, which has a much reduced third harmonic.

author: ledtester
author_rank: Super Contributor
timestamp: June 30, 2022, 10:30:27 pm
content: Quote from: Picuino on June 30, 2022, 01:27:54 pmThis circuit is simple enough that it is worth building and testing. It has been around for a long time and was even sold as a product. You can find reviews, comments, etc. by searching the web for "AADE LC meter".One criticism is that it doesn't test inductors at a specific frequency and you don't get to choose the test frequency. Real inductors have frequency dependent characteristics.Here is a similar approach of using frequency to measure inductance/capacitance:https://circuitcellar.com/research-design-hub/projects/building-an-lc-meter/It references a Silicon Chip article which you can view at:https://siliconchip.com.au/Issue/2020/JuneThe author goes into a lot of detail on the steps he took to make the meter as accurate as possible.

author: moffy
author_rank: Super Contributor
timestamp: June 30, 2022, 10:42:07 pm
content: I built and played with the LC measuring circuit you have shown and found it is very dependent upon the Q of the measured components. Low Q coils would have difficulty or not resonate at all, too much damping. The lower Q would also pull the resonant frequency off what is expected.

author: Le_Bassiste
author_rank: Frequent Contributor
timestamp: July 01, 2022, 12:47:27 pm
content: Quote from: robca on June 30, 2022, 12:01:44 aman LTC1564 might do the trick, and it probably won't get much simpler than that in terms of usage.https://www.analog.com/en/products/ltc1564.html

author: robca
author_rank: Frequent Contributor
timestamp: July 01, 2022, 04:06:09 pm
content: Quote from: Marco on June 30, 2022, 09:22:32 pmI have plenty of outputs, and plenty of extra PWM channels I can use. But I'm not sure how 3 level PWM would work to create a single analog signal. I did some searches, but mostly seemed related to motor drives and used H bridges. I could not find a simple proof of concept (and sample connection guide) on how to sum the PWM signals to create a single 0-1.8V signalDo you have a pointer or an example I can use as a starting point?

author: robca
author_rank: Frequent Contributor
timestamp: July 01, 2022, 04:08:42 pm
content: Quote from: moffy on June 30, 2022, 10:42:07 pmI spoke some more with the creator of the sensor, and they tried an LC circuit but was too problematic and in the end they abandoned the effort. The sensor is, in reality, much more complex than a single inductorSo I'm back to the original plan: generate a sine wave, measure phase differences. I'm exploring both the PWM option and the square wave to sine one...

author: robca
author_rank: Frequent Contributor
timestamp: July 01, 2022, 04:15:30 pm
content: Quote from: Le_Bassiste on July 01, 2022, 12:47:27 pmSimple, sure... but at more than $20 in single quantity, not cheapIt would be the 3 times the cost of the nRF52840 (BLE-enabled processor), and by far the most expensive component on the PCB... not to mention adding yet another semiconductor that can be impossible to find when needed, with no easy replacements.

author: Kleinstein
author_rank: Super Contributor
timestamp: July 01, 2022, 04:19:52 pm
content: One can use 2 equal resistors to combine 2 phase shifted rectangular signals to get a 3 level signal with less (ideally no) 30 kHz contend. With a 60 degree phase shift for the 10 kHz the 30 kHz harmonics see a 180 degree phase shift and thus cancel. This would simplify filtering, as less amplitude (about half) and a larger frequency ratio (1:5 instead 1:3).Chances are a first or second order passive followed by a 2nd order active filter (1 OP-amp) could be enough to get a sufficiently good signal (e.g. ~ 1% THD).

author: gf
author_rank: Super Contributor
timestamp: July 01, 2022, 07:49:35 pm
content: If the sine wave is supposed to be generated with a 1-bit DAC, then I'd prefer PDM / delta-sigma modulation instead of PWM. With the same clock frequency (16 MHz), and just with a first order delta-sigma modulator and 1st order lowpass filter with 10kHz cut-off I get the attached spectrum. SFDR is better than 60dBc. SINAD (over 8MHz bandwidth) is about 49dBc. A higher order modulator and/or higher filter order would certainly lead to further improvements. The modulator does not even need to run in real-time. Since the waveform is fixed, it is sufficient to store a pre-calculated stream of 1600 bits in memory and send it repeatedly.EDIT: Added spectrum with 2nd order chebycheff filter with 3dB ripple (one Sallen Key stage - one opamp). SINAD is now about -67dBc. Still first order modulator.

author: robca
author_rank: Frequent Contributor
timestamp: July 01, 2022, 10:16:29 pm
content: Quote from: gf on July 01, 2022, 07:49:35 pmUnfortunately the nRF52840 doesn't have PDM out, so that's a non-starter for me. I guess I could try and find some way to bit-bang the stream, but I couldn't do it in hardware (or, better, I don't know how I could do it 100% in hardware). The Nordic chip is not really hard real time, because it's using a single core to also manage the BLE radio, so if the code is being executed in what they call the Softdevice, there's no guarantee that your code will run when needed, especially not as fast as 16MHzThinking about this some more, I guess that if I were to use a 2 pulse PWM value (only possible values 0, 1, 2), I could then find a way to use 20 of those packets to precalculate PDM-like bitstreams using PWM. The downside is that I would need a big amount of RAM to hold the array for the values, since the way the code works is to identify each value sent as a 16 bit value. That would be a 800 items 16 bit array, not impossible. Maybe this can work, actually, and would be pretty clever, good suggestionDo you know of an easy way to generate the 1600 bits for the PDM sine? I can then easily break that down to simulated PWM values

author: gf
author_rank: Super Contributor
timestamp: July 01, 2022, 10:45:50 pm
content: This was mine:Code:% create 10 periods, to have room for settling of the modulators = sin([0:15999]/1600*2*pi);bit = s * 0;a=0; e=0; for i=1:16000; bit(i)=a; e+=s(i)-a; a=sign(e); end% print last 1600 bit, where the modulator hopefully has settled to a stable stateprintf("%d,", bit(end-1600+1:end)>0)Code:0,1,1,0,1,0,1,0,1,0,1,0,1,0,1,0,1,0,1,0,1,0,1,0,1,1,0,1,0,1,0,1,0,1,1,0,1,0,1,0,1,1,0,1,0,1,1,0,1,0,1,0,1,1,0,1,1,0,1,0,1,1,0,1,0,1,1,0,1,1,0,1,0,1,1,0,1,1,0,1,1,0,1,1,0,1,1,0,1,1,0,1,1,0,1,1,0,1,1,0,1,1,0,1,1,1,0,1,1,0,1,1,1,0,1,1,0,1,1,1,0,1,1,0,1,1,1,0,1,1,1,0,1,1,1,0,1,1,1,0,1,1,1,0,1,1,1,0,1,1,1,1,0,1,1,1,1,0,1,1,1,0,1,1,1,1,0,1,1,1,1,0,1,1,1,1,1,0,1,1,1,1,0,1,1,1,1,1,0,1,1,1,1,1,1,0,1,1,1,1,1,0,1,1,1,1,1,1,0,1,1,1,1,1,1,1,0,1,1,1,1,1,1,1,0,1,1,1,1,1,1,1,1,0,1,1,1,1,1,1,1,1,1,0,1,1, so that it can settle1,1,1,1,1,1,1,1,1,0,1,1,1,1,1,1,1,1,1,1,1,1,1,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,1,1,1,1,1,1,1,1,1,1,1,1,1,0,1,1,1,1,1,1,1,1,1,1,0,1,1,1,1,1,1,1,1,1,0,1,1,1,1,1,1,1,1,0,1,1,1,1,1,1,1,0,1,1,1,1,1,1,1,0,1,1,1,1,1,1,0,1,1,1,1,1,0,1,1,1,1,1,0,1,1,1,1,1,0,1,1,1,1,1,0,1,1,1,1,0,1,1,1,1,0,1,1,1,1,0,1,1,1,1,0,1,1,1,1,0,1,1,1,0,1,1,1,0,1,1,1,1,0,1,1,1,0,1,1,1,0,1,1,0,1,1,1,0,1,1,1,0,1,1,0,1,1,1,0,1,1,0,1,1,1,0,1,1,0,1,1,0,1,1,0,1,1,1,0,1,1,0,1,1,0,1,1,0,1,0,1,1,0,1,1,0,1,1,0,1,1,0,1,0,1,1,0,1,1,0,1,0,1,1,0,1,0,1,1,0,1,0,1,1,0,1,0,1,1,0,1,0,1,0,1,1,0,1,0,1,0,1,0,1,1,0,1,0,1,0,1,0,1,0,1,0,1,1,0,1,0,1,0,1,0,1,0,1,0,1,0,1,0,1,0,1,0,1,0,1,0,0,1,0,1,0,1,0,1,0,1,0,1,0,1,0,0,1,0,1,0,1,0,0,1,0,1,0,1,0,0,1,0,1,0,1,0,0,1,0,1,0,0,1,0,1,0,0,1,0,0,1,0,1,0,0,1,0,0,1,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,0,1,0,0,1,0,0,1,0,0,0,1,0,0,1,0,0,0,1,0,0,0,1,0,0,1,0,0,0,1,0,0,0,1,0,0,0,1,0,0,0,0,1,0,0,0,1,0,0,0,0,1,0,0,0,1,0,0,0,0,1,0,0,0,0,1,0,0,0,0,1,0,0,0,0,0,1,0,0,0,0,0,1,0,0,0,0,0,1,0,0,0,0,0,1,0,0,0,0,0,0,1,0,0,0,0,0,0,1,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,1,0,0,0,0,0,0,1,0,0,0,0,0,0,1,0,0,0,0,0,0,1,0,0,0,0,0,1,0,0,0,0,1,0,0,0,0,0,1,0,0,0,0,1,0,0,0,0,1,0,0,0,0,1,0,0,0,0,1,0,0,0,1,0,0,0,0,1,0,0,0,1,0,0,0,1,0,0,0,1,0,0,0,1,0,0,0,1,0,0,0,1,0,0,1,0,0,0,1,0,0,1,0,0,0,1,0,0,1,0,0,1,0,0,1,0,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,1,0,0,1,0,0,1,0,1,0,0,1,0,1,0,0,1,0,1,0,0,1,0,1,0,1,0,0,1,0,1,0,1,0,0,1,0,1,0,1,0,1,0,0,1,0,1,0,1,0,1,0,1,0,1,0,1,0,1,0,1,0,1,0EDIT: The MCU has no serial output pins which can be fed via DMA?

author: langwadt
author_rank: Super Contributor
timestamp: July 01, 2022, 10:57:37 pm
content: https://www.tinaja.com/magsn01.shtml

author: Marco
author_rank: Super Contributor
timestamp: July 01, 2022, 11:02:31 pm
content: Should be able to abuse one of the other peripherals with easydma to send the bits. SPI/UART/whatever.

author: dmendesf
author_rank: Frequent Contributor
timestamp: July 01, 2022, 11:41:20 pm
content: "Magic sines" is a voodoo name for "selective harmonic elimination". Look it up.

author: robca
author_rank: Frequent Contributor
timestamp: July 03, 2022, 06:49:19 pm
content: Update: I have been looking at ways to use the nRF52840 to generate a PDM signal.There is no programmable I/O with DMA, nor a way to use other peripherals (like SPI) at 16MHz with DMA. The nRF52 family is stellar for BLE and interfacing to standard peripherals, not as strong in the analog front.I'm trying to abuse the PWM peripheral, by using only two pulses per period, to create a bitstream. Alas, at 16MHz, it doesn't seem to work as well as hoped. I opened a ticket with Nordichttps://devzone.nordicsemi.com/f/nordic-q-a/89607/unexpected-pwm-behaviorto see if I'm doing something wrong or I'm actually running into a HW limitation. I think the latter, given that it works as expected at 8MHz.The other alternative would be to use 4 pulse PWM and what I saw called "dithering". Using a 4 pulse PWM seems to work for the nRF52. Basically a PDM stream is broken in clusters of 4 bits, and the closest possible PWM value is used. The timing won't be perfect (i.e. a 0010 PDM will become 1000 PWM), but for a smooth signal like a sine should be ok. Much better than using a 40 pulse PWM for sureIs there any other easy way to use a 8MHz bitstream to get a clean 10KHz sine, without complex filtering?

author: Marco
author_rank: Super Contributor
timestamp: July 03, 2022, 07:21:44 pm
content: Quote from: robca on July 03, 2022, 06:49:19 pmWhy not exactly? It can work at 32 MHz, it's double buffered so you should be able to keep the bitstream going, what's missing?

author: robca
author_rank: Frequent Contributor
timestamp: July 03, 2022, 07:30:10 pm
content: Quote from: Marco on July 03, 2022, 07:21:44 pmYou are right, it looks as if I missed that SPIM3 is 32MHz. All the other SPI instances are limited to 8MHz, but not SPIM3What's missing is my ability to properly read specsThanks! Need to experiment some more, then

author: gf
author_rank: Super Contributor
timestamp: July 03, 2022, 11:28:40 pm
content: Quote from: robca on July 03, 2022, 06:49:19 pmDelta-sigma modulation is not limited to binary output, but the output can be N-level quantized (say N=5), and these 5 levels (0...4) could be encoded with PWM then. Result is of course not as good as with delta-sigma modulation alone. SINAD with 1st order filter dropped to 42dBc, the PWM introduces a 2nd harmonic (-51dBc), and there arise spurs in the neighborhood of 4MHz.5-level sine wave @4MSa/s (400 samples per period):Code:2,2,2,2,2,2,2,3,2,2,2,3,2,2,3,2,3,2,3,2,3,3,2,3,3,2,3,3,3,3,2,3,3,3,3,3,3,3,3,4,3,3,3,3,4,3,3,3,4,3,4,3,3,4,3,4,3,4,3,4,4,3,4,4,3,4,4,3,4,4,4,3,4,4,4,4,4,3,4,4,4,4,4,4,4,4,4,4,3,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,3,4,4,4,4,4,3,4,4,4,4,3,4,4,3,4,4,3,4,4,3,4,3,4,3,4,3,4,3,3,4,3,3,4,3,3,4,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,2,3,3,2,3,3,2,3,2,3,2,3,2,3,2,2,3,2,2,2,2,2,3,2,2,2,2,2,1,2,2,2,2,2,1,2,2,1,2,1,2,1,2,1,2,1,1,2,1,1,2,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,1,1,0,1,1,0,1,1,0,1,0,1,0,1,0,1,0,0,1,0,0,1,0,0,1,0,0,0,0,1,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,1,0,0,0,1,0,0,1,0,0,1,0,0,1,0,1,0,1,0,1,1,0,1,0,1,1,1,0,1,1,1,1,0,1,1,1,1,1,1,1,1,2,1,1,1,1,2,1,1,2,1,1,2,1,2,1,2,1,2,2,1,2,2,2,1,2,2,2,20 => 0 0 0 01 => 1 0 0 02 => 1 1 0 03 => 1 1 1 04 => 1 1 1 1

author: gf
author_rank: Super Contributor
timestamp: July 04, 2022, 01:09:22 pm
content: Quote from: robca on July 03, 2022, 07:30:10 pmHere is a 32MHz 1st order delta-sigma bit stream (3200 bits), if you are able to send it:Code:1,0,1,0,1,0,1,0,1,0,1,0,1,0,1,0,1,0,1,0,1,0,1,0,1,0,1,0,1,0,1,0,1,1,0,1,0,1,0,1,0,1,0,1,0,1,1,0,1,0,1,0,1,0,1,0,1,1,0,1,0,1,0,1,0,1,1,0,1,0,1,0,1,1,0,1,0,1,0,1,1,0,1,0,1,0,1,1,0,1,0,1,1,0,1,0,1,1,0,1,0,1,1,0,1,0,1,1,0,1,0,1,1,0,1,0,1,1,0,1,0,1,1,0,1,1,0,1,0,1,1,0,1,1,0,1,0,1,1,0,1,1,0,1,1,0,1,0,1,1,0,1,1,0,1,1,0,1,1,0,1,1,0,1,1,0,1,0,1,1,0,1,1,0,1,1,0,1,1,0,1,1,0,1,1,1,0,1,1,0,1,1,0,1,1,0,1,1,0,1,1,0,1,1,1,0,1,1,0,1,1,0,1,1,1,0,1,1,0,1,1,0,1,1,1,0,1,1,0,1,1,1,0,1,1,1,0,1,1,0,1,1,1,0,1,1,1,0,1,1,0,1,1,1,0,1,1,1,0,1,1,1,0,1,1,1,0,1,1,1,0,1,1,1,0,1,1,1,0,1,1,1,0,1,1,1,0,1,1,1,1,0,1,1,1,0,1,1,1,1,0,1,1,1,0,1,1,1,1,0,1,1,1,0,1,1,1,1,0,1,1,1,1,0,1,1,1,1,0,1,1,1,1,0,1,1,1,1,0,1,1,1,1,0,1,1,1,1,1,0,1,1,1,1,0,1,1,1,1,1,0,1,1,1,1,0,1,1,1,1,1,0,1,1,1,1,1,0,1,1,1,1,1,1,0,1,1,1,1,1,0,1,1,1,1,1,1,0,1,1,1,1,1,0,1,1,1,1,1,1,0,1,1,1,1,1,1,1,0,1,1,1,1,1,1,0,1,1,1,1,1,1,1,0,1,1,1,1,1,1,1,0,1,1,1,1,1,1,1,1,0,1,1,1,1,1,1,1,1,0,1,1,1,1,1,1,1,1,0,1,1,1,1,1,1,1,1,1,0,1,1,1,1,1,1,1,1,1,1,0,1,1,1,1,1,1,1,1,1,1,0,1,1,1,1,1,1,1,1,1,1,1,0,1,1,1,1,1,1,1,1,1,1,1,1,1,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,1,1,1,1,1,1,1,1,1,1,1,1,1,0,1,1,1,1,1,1,1,1,1,1,1,0,1,1,1,1,1,1,1,1,1,1,1,0,1,1,1,1,1,1,1,1,1,1,0,1,1,1,1,1,1,1,1,1,0,1,1,1,1,1,1,1,1,0,1,1,1,1,1,1,1,1,1,0,1,1,1,1,1,1,1,0,1,1,1,1,1,1,1,0,1,1,1,1,1,1,1,0,1,1,1,1,1,1,1,0,1,1,1,1,1,1,0,1,1,1,1,1,1,0,1,1,1,1,1,1,0,1,1,1,1,1,1,0,1,1,1,1,1,0,1,1,1,1,1,0,1,1,1,1,1,1,0,1,1,1,1,0,1,1,1,1,1,0,1,1,1,1,1,0,1,1,1,1,0,1,1,1,1,1,0,1,1,1,1,0,1,1,1,1,0,1,1,1,1,0,1,1,1,1,0,1,1,1,1,0,1,1,1,1,0,1,1,1,0,1,1,1,1,0,1,1,1,1,0,1,1,1,0,1,1,1,0,1,1,1,1,0,1,1,1,0,1,1,1,0,1,1,1,0,1,1,1,0,1,1,1,0,1,1,1,0,1,1,1,0,1,1,1,0,1,1,1,0,1,1,1,0,1,1,0,1,1,1,0,1,1,1,0,1,1,0,1,1,1,0,1,1,0,1,1,1,0,1,1,0,1,1,1,0,1,1,0,1,1,0,1,1,1,0,1,1,0,1,1,0,1,1,0,1,1,1,0,1,1,0,1,1,0,1,1,0,1,1,0,1,1,0,1,1,0,1,1,0,1,1,0,1,1,0,1,1,0,1,1,0,1,1,0,1,0,1,1,0,1,1,0,1,1,0,1,1,0,1,0,1,1,0,1,1,0,1,0,1,1,0,1,1,0,1,0,1,1,0,1,1,0,1,0,1,1,0,1,0,1,1,0,1,0,1,1,0,1,0,1,1,0,1,0,1,1,0,1,0,1,1,0,1,0,1,0,1,1,0,1,0,1,1,0,1,0,1,0,1,0,1,1,0,1,0,1,0,1,1,0,1,0,1,0,1,0,1,1,0,1,0,1,0,1,0,1,0,1,1,0,1,0,1,0,1,0,1,0,1,0,1,0,1,1,0,1,0,1,0,1,0,1,0,1,0,1,0,1,0,1,0,1,0,1,0,1,0,1,0,1,0,1,0,1,0,1,0,1,0,1,0,1,0,1,0,1,0,1,0,1,0,1,0,0,1,0,1,0,1,0,1,0,1,0,1,0,1,0,0,1,0,1,0,1,0,1,0,1,0,0,1,0,1,0,1,0,1,0,1,0,0,1,0,1,0,1,0,0,1,0,1,0,1,0,0,1,0,1,0,1,0,0,1,0,1,0,0,1,0,1,0,1,0,0,1,0,1,0,0,1,0,1,0,0,1,0,1,0,0,1,0,0,1,0,1,0,0,1,0,1,0,0,1,0,0,1,0,1,0,0,1,0,0,1,0,1,0,0,1,0,0,1,0,0,1,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,0,1,0,0,1,0,0,1,0,0,0,1,0,0,1,0,0,1,0,0,0,1,0,0,1,0,0,0,1,0,0,0,1,0,0,1,0,0,0,1,0,0,1,0,0,0,1,0,0,0,1,0,0,0,1,0,0,0,1,0,0,0,1,0,0,0,1,0,0,0,1,0,0,0,1,0,0,0,1,0,0,0,1,0,0,0,1,0,0,0,0,1,0,0,0,1,0,0,0,0,1,0,0,0,1,0,0,0,0,1,0,0,0,0,1,0,0,0,1,0,0,0,0,1,0,0,0,0,1,0,0,0,0,1,0,0,0,0,0,1,0,0,0,0,1,0,0,0,0,1,0,0,0,0,0,1,0,0,0,0,0,1,0,0,0,0,0,1,0,0,0,0,0,1,0,0,0,0,0,1,0,0,0,0,0,1,0,0,0,0,0,0,1,0,0,0,0,0,1,0,0,0,0,0,0,1,0,0,0,0,0,0,1,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,1,0,0,0,0,0,0,1,0,0,0,0,0,0,1,0,0,0,0,0,0,1,0,0,0,0,0,0,1,0,0,0,0,0,1,0,0,0,0,0,0,1,0,0,0,0,0,1,0,0,0,0,0,1,0,0,0,0,0,1,0,0,0,0,1,0,0,0,0,0,1,0,0,0,0,1,0,0,0,0,1,0,0,0,0,0,1,0,0,0,0,1,0,0,0,0,1,0,0,0,0,1,0,0,0,1,0,0,0,0,1,0,0,0,0,1,0,0,0,1,0,0,0,0,1,0,0,0,1,0,0,0,1,0,0,0,0,1,0,0,0,1,0,0,0,1,0,0,0,1,0,0,0,1,0,0,0,1,0,0,0,1,0,0,0,1,0,0,0,1,0,0,0,1,0,0,1,0,0,0,1,0,0,0,1,0,0,1,0,0,0,1,0,0,1,0,0,0,1,0,0,1,0,0,0,1,0,0,1,0,0,1,0,0,0,1,0,0,1,0,0,1,0,0,1,0,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,1,0,0,1,0,0,1,0,1,0,0,1,0,0,1,0,1,0,0,1,0,1,0,0,1,0,0,1,0,1,0,0,1,0,1,0,0,1,0,1,0,0,1,0,1,0,1,0,0,1,0,1,0,0,1,0,1,0,1,0,0,1,0,1,0,1,0,0,1,0,1,0,1,0,0,1,0,1,0,1,0,1,0,0,1,0,1,0,1,0,1,0,0,1,0,1,0,1,0,1,0,1,0,1,0,0,1,0,1,0,1,0,1,0,1,0,1,0,1,0,1,0,1,0,1,0,1,0,1,0,1,0,1,0,1,0SFDR ~74dBc, SINAD ~52dBc.

author: robca
author_rank: Frequent Contributor
timestamp: July 07, 2022, 05:09:15 am
content: Quote from: gf on July 04, 2022, 01:09:22 pmThanks a lot for all your input, I learned a lot from you. At this time, i decided that using an active filter to get a sine out of a square wave is the better option (one of the suggestions here), and I have a working circuithttps://www.eevblog.com/forum/beginners/generating-a-good-enough-10khz-sine-wave-from-a-square-one/msg4282492/#msg4282492PWM on the nRF52 seems to be more work than it's worth, for my specific problem (might be worth for more complex waveforms)Out of curiosity (for the future), what are you using to generate the various PDM streams and pseudo streams? I have some code that works for normal PDM, below, but was curious about the 4 bit one (your post before the quoted one)Code:#define PDM_PERIOD 40void pdm_gen(int value){int v =0;for (int i=0; i<PDM_PERIOD; i++){v += value;if (v >= PDM_PERIOD){printf("1");v -= PDM_PERIOD;}else printf("0");}printf("\r\n");}int main(){for (int i=0; i<40; i++){sine_table = sin(i * 2.0 * M_PI / 40) * 20.0 + 20.5; // storing values in case I need the sine table later onpdm_gen(sine_table);}return 0;}

author: gf
author_rank: Super Contributor
timestamp: July 07, 2022, 10:25:30 am
content: Just replace the binary quantizer (whose output is only 0 or 1) with a multi-level quantizer.The code below (sorry, untested!) assumes a normalized 0...1 value range for the original signal and for the quantized levels, but this can be adapted, of course.Code:float quantize(float v, int nlevels){// number of steps between levelsint nsteps = nlevels - 1;// round v to nearest levelreturn floor(v * nsteps + 0.5f) / nsteps;}// signal is assumed to be in the range 0...1// nlevels=2 means binary quantization, i.e. {0, 1}// nlevels=5 means {0, 0.25, 0.5 ,0.75, 1}void pdm_gen(const float signal[], int nsampes, int nlevels){float v = 0;for (int i=0; i<nsampes; i++){v += signal;float qv = quantize(v, nlevels);v -= qv;printf("%f ", qv);}printf("\n");}