# How to create a PWM source with fixed frequency and decreasing duty cycle (at some interval) in LTspice?

I'm trying to simulate a PWM signal whose duty cycle decreases by a fixed amount over a given interval from 100% to 0. For example, if the PWM frequency is 2 MHz, I want to ramp down the on-time from 100% to 0 in 11 equal steps (9.1% each) and I want each duty cycle step to "dwell" for 10 cycles of the 2 MHz clock, or 5usecs. So, the 2MHz clocks duty cycle starts at 100%, then after 5usecs, changes the 91%, then after another 5usecs, changes to 82%, etc.

I haven't figured out how to do this. I think I should be able to do it with BV-type devices, but I can't figure out how to have a 2 MHz square wave source, and somehow use it in conjunction with a BV source to set the switching frequency, and then change the duty cycle perhaps based on yet another source with some sort of ramp for which I could "look" for levels to trigger the changes in duty cycle.

In real life, I will be setting the PWM duty cycle digitally (in an FPGA), so I can easily change the duty cycle in steps after x-number of microseconds. But, for the purposes of simulating the analog circuity interfacing with this PWM signal, I would like to be able to create this "stimulus" in the simulation, to verify, among other things, what the dwelling-for-5usecs on each step looks like at the output of the RC filter (i.e., to ensure the filter's time constant is fast enough to settle in time).

I appreciate any suggestions, and will post my solution if I figure it out in the meantime.

Probably brute-forcing a solution using a PWL source is the quickest way to a solution. It's very useful for weird and/or complex sources. Once you dabble in generating your own PWLs using a programming language (or even Excel), you can also use what you learned to import CSV files from real-life oscilloscope data as PWL sources in LTspice.

However, one big downside to PWL sources is that each PWL point overrides SPICE's internal timestep control algorithm and forces the simulator to calculate a solution for the entire circuit at each point. So if you can manage a solution uniquely using LTspice primitives, you can get a significant speed boost.

Below is one such method I've used before for a similar problem as yours. It uses a sample&hold (sample found under the category [SpecialFunctions]) and a diffschmtbuf (found under [Digital]) used as an ideal comparator...along with a bunch of ramps and clocks.

The sample&hold takes a ramp input and generates a stair-step pattern which holds the duty cycle constant for 10 clock cycles of your 2MHz clock before stepping down to the next step which translates to a different duty cycle. This stair-step output goes into a comparator which compares against a 2MHz ramp to generate the PWM output. Vhigh should be the VCCIO of your FPGA bank and the Vt and Vh help set the comparator up to work how we need it to.

Below are the contents of the .asc LTspice schematic file. Copy/paste it into a text file with a .asc extension and you can open the schematic on your machine and play around with it.

Version 4
SHEET 1 1028 680
WIRE -336 0 -384 0
WIRE -160 0 -336 0
WIRE -384 32 -384 0
WIRE -160 32 -288 32
WIRE 80 48 16 48
WIRE 256 48 80 48
WIRE -288 64 -288 32
WIRE -192 64 -240 64
WIRE -160 64 -192 64
WIRE 592 64 320 64
WIRE 656 64 592 64
WIRE 208 80 176 80
WIRE 256 80 208 80
WIRE 592 96 592 64
WIRE 176 128 176 80
WIRE -384 160 -384 112
WIRE -240 160 -240 64
WIRE 592 208 592 176
WIRE 176 256 176 208
WIRE -240 288 -240 240
FLAG -384 160 0
FLAG -240 288 0
FLAG -288 64 0
FLAG 176 256 0
FLAG 592 208 0
FLAG 656 64 out
FLAG -192 64 clk
FLAG 80 48 stair
FLAG 208 80 ramp2
FLAG -336 0 ramp1
SYMBOL voltage -384 16 M0
WINDOW 123 0 0 Left 0
WINDOW 39 0 0 Left 0
SYMATTR InstName V1
SYMATTR Value PULSE(1 0 0 55u 5u 1p 55u)
SYMBOL voltage -240 144 R0
WINDOW 123 0 0 Left 0
WINDOW 39 0 0 Left 0
SYMATTR InstName V2
SYMATTR Value PULSE(0 1 0 1p 1p 2.5u 5u)
SYMBOL SpecialFunctions\\sample -80 32 R0
SYMATTR InstName A1
SYMBOL voltage 176 112 R0
WINDOW 123 0 0 Left 0
WINDOW 39 0 0 Left 0
SYMATTR InstName V3
SYMATTR Value PULSE(1 0 0 500n 1p 1p 500n)
SYMBOL Digital\\diffschmtbuf 256 0 R0
WINDOW 3 39 89 Left 2
WINDOW 123 41 120 Left 2
SYMATTR InstName A2
SYMATTR Value Vhigh=3.3
SYMATTR Value2 Vt=0 Vh=0.01
SYMBOL res 576 80 R0
SYMATTR InstName R1
SYMATTR Value 100k
TEXT -554 256 Left 2 !.tran 120u

I just wanted to mention that regardless of what method you use to generate the waveform, it would probably be a good idea to find the IBIS models for your FPGA so you can create a proper Thevenin equivalent of your FPGA output pin instead of assuming zero source resistance. This is particularly useful if you're interfacing into RC circuits. There is more information regarding how to do this in this answer: https://electronics.stackexchange.com/a/573907

Lastly, there is a new SPICE program that just came out several months ago called QSPICE. It is written by the same author of LTspice (the actual person, not the company), so you'll notice many similarities in the interface. One of the most advertised features of QSPICE is the ability to create custom C++ or Verilog modules which can run much faster since everything inside a module is isolated from the rest of the SPICE circuit matrix. I'm still struggling to find good use cases for these "DLL modules", but one I did find is being able to generate arbitrary sources directly using code. You can try using this feature to create your waveform programmatically within the actual SPICE simulator software, and also without a performance hit.

• This is great. Although I created an input file with a Matlab script to achieve what I wanted, this solution is great, and I will try it as well when I have a some time. I'll even try using Verilog (I am currently using Qspice as well)....Thank you. Dec 1, 2023 at 3:53
• @jrive Sure, no problem. I was originally very interested in the Verilog support within QSPICE, but it uses something called "Verilator" to convert the Verilog into C++. So if you already have stuff written in Verilog then it seems like the way to go, but if you're creating something from scratch it seems doing it directly in C++ makes more sense??? I dunno, I haven't played around enough myself to land on a general approach. Dec 1, 2023 at 6:15

For an arbitrary stimulus in SPICE I write a program in some other language (I like AWK, you might prefer something else like Python) that writes an output file containing the definition of a PWL source. Then I include it in the circuit with .include or explicitly on the command line.

I don't know about LTspice, but in ngspice there is no apparent limit to the number of steps allowed.

• This is a good idea… I can do this in python. I’ll give this a shot. Thanks! Nov 29, 2023 at 1:45
• I ended creating a quick script in Matlab.. Dec 3, 2023 at 5:57

I'm not exactly sure what you want to do, but I might have a way to accomplish it that is unproven.

Look at the models for the LTC6993 (there are several with different features. They can do many various timing tasks. If you need to program the delay then use a PWL variable resistor (voltage source with R={V(votlagenet)}. The models should all be avalible in LT spice for the LTC6993 family.

Here is an example of one of the chips functionality, if that doesn't work you should be able to find one of the chips that could work for your application.

• I appreciate the suggestion, but that may turn into its own project! I will look at this at a later time. It is always useful to know how to uses these multivibrators. Thank you. Nov 29, 2023 at 1:51