FFT capabilities integrated into LTSPICE simulator are nice and flexible. However, if you would like to evaluate frequency or amplitude dependence of distortions, you have to take these measurements point by point and then manually plot them.

I created an LTSPICE add-on to automate THD measurements and plot result in the form of THD vs. Amplitude and THD vs. Frequency graphs.

**How my LTSPICE Audio THD Analyzer works:**

It outputs sinusoidal signal with amplitude or frequency stepping sweep into device under test (DUT). Output signal from DUT is feed into analyzer input. After waiting some time for signal to become steady state, analyzer restores fundamental and subtracts it from input signal. This subtraction allows to increase resolution or reduce measurement time for the same resolution. You can monitor residual components at “Notch output”.

Residual signal is then fed into synchronous filters and detector. Each harmonic is filtered and measured separately. Maximum of 10 harmonics are analyzed. Amount of harmonics could be easily increased by adding corresponding filters and possessing.

This is how waveforms look after analysis is completed:

Total Harmonic Distortions vs. Output Amplitude plot looks like this:

Total Harmonic Distortions vs. Frequency plot looks like this:

**How to use LTSPICE Audio THD Analyzer:**

Place **THD_Analyzer.asy** symbol and **Analyser_Controls.txt** files in the same directory, where you are saving schematic (DUT schematic),

that you would like to analyze.

Put SPICE directives **“.inc Analyzer_Controls.txt”** and** “.tran 0 {AnalysisTime} {SettlingTime} {MaxTimestep}” ** in DUT schematic .

Edit “**Analyzer_Controls.txt**” to enable (uncomment) appropriate sweep (amplitude or frequency ) and save this file.

Setup **“.param Ag=xxx”** as amplitude for frequency sweep or **“.param Fg=xxx”** as frequency for amplitude sweep.

Run the simulation.

After simulation is complete, go to View menu and open **SPICE Error Log** or use **Ctrl+L** command.

Click with right mouse button on opened **Log file**.

Execute “**Plot .step’ed .meas data**” command. Right mouse button click on opened plot and use Add Trace or Ctrl+A and select the data that you want to plot.

You may want to double click on axis to change axis limits or switch to logarithmic scale.

Notch output shows residual components, after fundamental removal.

Please note that fundamental may not be removed completely. This is not necessarily affecting resolution of measurements as soon as additional synchronous filtering is used to measure amplitude of harmonics.

Increasing **SettlingTime** and **StrobeLength**, or (and) decreasing **MaxTimestep** would likely improve fundamental rejection.

Generator output is DC coupled and has 0 Ohm output impedance. Use external AC coupling and appropriate series resistor if required, to ensure proper operation of simulated circuit.

**THD_Analyzer** contains all necessary files and example. Unzip all files in the same directory, open “Example_BJT_THD_TEST.asc” and run simulation.

You can monitor analysis progress in the left lower corner of LTSPICE window. After simulation and analysis is complete (including completion of .MEASURE), follow the instructions to display

results.

## Comment moderation is in use. Your post will appear shortly.

Spammers, don't worry! Don't bother wasting your time!

Really huge and great job!!!! Thanks for sharing this! I have one questions for an upgrade: is it possible to add THD+N plotting (THD including noise) as an option to the pure THD? This would be helpful to conduct THD+N vs Frequency and THD+N vs Voltage plots.

Also how to output THD vs Power and not voltage level?

Hello Luca. I’m not sure about THD+N, because noise requires different type of analysis. And for most of real analyzers it is like additional error that you have to leave with, but would like to get rid of. Because noise decrease resolution of THD measurements.

Calculating power is really easy. Open script file with any text editor and find place where .MEASURE commands are located (somewhere close to the end).

Find the line :

.meas Fundamental_Out_V_RMS param sqrt(2)*hypot(aH1S,aH1C)

Somewhere after this line add line:

.meas Output_Power param (Fundamental_Out_V_RMS*Fundamental_Out_V_RMS)/Rload

Use value of your load instead of Rload. Like in this example:

.meas Output_Power param (Fundamental_Out_V_RMS*Fundamental_Out_V_RMS)/8

Save changed script file.

When you will be plotting analysis results, double click on horizontal axis (the same as if you wanted to change horizontal scale) and instead of ag or fundamental put Output_Power.

Dear Eugene,

noted your thinking about Noise contribution to Distorsion measurement. Thinking back about this, as from my experience, there is so big difference between “simulated” noise and “real world” noise that you are right….there is no sense to add it.

Thanks about the hint on how to plot THD vs. Power, I will test it shortly!!!

Thanks again for the great job you have done and donated to the public community!

Excellent plugin man. Thanks for the great work!

Hello,

I am trying to get this running however I have a misunderstanding. I dont exactly know what “Setup “.param Ag=xxx” as amplitude for frequency sweep or “.param Fg=xxx” really means so I have skipped this step. The simulation runs and then in the log file i just get failure messages:

Circuit: * C:\Program Files (x86)\LTC\LTspiceIV\RailTOrail-2.asc

Direct Newton iteration for .op point succeeded.

.step fg=20

.step fg=43.0887

.step fg=92.8318

.step fg=200

.step fg=430.887

.step fg=928.318

.step fg=2000

.step fg=4308.87

.step fg=9283.18

.step fg=20000

Measurement “ah1s” FAIL’ed

Measurement “ah1c” FAIL’ed

Measurement “avh2s” FAIL’ed

Measurement “avh2c” FAIL’ed

Measurement “avh3s” FAIL’ed

Measurement “avh3c” FAIL’ed

Measurement “avh4s” FAIL’ed

Measurement “avh4c” FAIL’ed

Measurement “avh5s” FAIL’ed

Measurement “avh5c” FAIL’ed

Measurement “avh6s” FAIL’ed

Measurement “avh6c” FAIL’ed

Measurement “avh7s” FAIL’ed

Measurement “avh7c” FAIL’ed

Measurement “avh8s” FAIL’ed

Measurement “avh8c” FAIL’ed

Measurement “avh9s” FAIL’ed

Measurement “avh9c” FAIL’ed

Measurement “avh10s” FAIL’ed

Measurement “avh10c” FAIL’ed

Measurement “i_in_s” FAIL’ed

Measurement “i_in_c” FAIL’ed

Measurement “fundamental_out_v_rms” FAIL’ed

Measurement “gain” FAIL’ed

Measurement “gain_db” FAIL’ed

Measurement “phase_deg” FAIL’ed

Measurement “z_in_mod” FAIL’ed

Measurement “z_in_ph_deg” FAIL’ed

Measurement “h2” FAIL’ed

Measurement “h3” FAIL’ed

Measurement “h4” FAIL’ed

Measurement “h5” FAIL’ed

Measurement “h6” FAIL’ed

Measurement “h7” FAIL’ed

Measurement “h8” FAIL’ed

Measurement “h9” FAIL’ed

Measurement “h10” FAIL’ed

Measurement “thd_persent” FAIL’ed

Measurement “thd_db” FAIL’ed

Date: Sat Dec 07 21:13:45 2013

Total elapsed time: 105.237 seconds.

tnom = 27

temp = 27

method = modified trap

totiter = 1100051

traniter = 1100040

tranpoints = 550021

accept = 550021

rejected = 0

matrix size = 70

fillins = 94

solver = Normal

Matrix Compiler1: 11.1 KB object code size 5.6/4.0/[2.3]

Matrix Compiler2: off [2.7]/3.0/5.3

Please help…

Can you send me a simulation file?

“.param Ag=xxx” means – set the amplitude. Example:

means amplitude of 1V.param Ag=1“.param Fg=xxx” means – set the frequency. Example:

means frequency of 20K.param Fg=20KEugene,

Thanks for the extra help with that.

I got it going but I got another anomaly. When I plot the error log I get an empty chart. I took your example file and replace that circuit with my own one and ran it. I can see the waves ok but for some reason it doesn’t wanna plot. The circuit that I want to ran is a discrete op amp. If I ran your circuit it plots ok. Here is the error log for my circuit:

Circuit: * C:\Program Files (x86)\LTC\LTspiceIV\THDvsAmplitude.asc

Questionable use of curly braces in “b_time timescale 0 v={time}”

Error: undefined symbol in: “[time]”

WARNING: Less than two connections to node TIMESCALE. This node is used by B:U2:_TIME.

WARNING: Less than two connections to node S_TIME. This node is used by B:U2:_STROBETIME.

WARNING: Less than two connections to node E_TIME. This node is used by B:U2:_ENDTIME.

WARNING: Less than two connections to node H2SF. This node is used by B:U2:_H2S.

WARNING: Less than two connections to node H2CF. This node is used by B:U2:_H2C.

WARNING: Less than two connections to node H3SF. This node is used by B:U2:_H3S.

WARNING: Less than two connections to node H3CF. This node is used by B:U2:_H3C.

WARNING: Less than two connections to node H4SF. This node is used by B:U2:_H4S.

WARNING: Less than two connections to node H4CF. This node is used by B:U2:_H4C.

WARNING: Less than two connections to node H5SF. This node is used by B:U2:_H5S.

WARNING: Less than two connections to node H5CF. This node is used by B:U2:_H5C.

WARNING: Less than two connections to node H6SF. This node is used by B:U2:_H6S.

WARNING: Less than two connections to node H6CF. This node is used by B:U2:_H6C.

WARNING: Less than two connections to node H7SF. This node is used by B:U2:_H7S.

WARNING: Less than two connections to node H7CF. This node is used by B:U2:_H7C.

WARNING: Less than two connections to node H8SF. This node is used by B:U2:_H8S.

WARNING: Less than two connections to node H8CF. This node is used by B:U2:_H8C.

WARNING: Less than two connections to node H9SF. This node is used by B:U2:_H9S.

WARNING: Less than two connections to node H9CF. This node is used by B:U2:_H9C.

WARNING: Less than two connections to node H10SF. This node is used by B:U2:_H10S.

WARNING: Less than two connections to node H10CF. This node is used by B:U2:_H10C.

Direct Newton iteration for .op point succeeded.

Ignoring empty pin current: Ix(u2:analyzer_in)

Ignoring empty pin current: Ix(u2:analyzer_in)

.step ag=0.01

.step ag=0.0316228

.step ag=0.1

Measurement: ah1s

step v(ref_s) at

1 0.00965556032077 0.01

2 0.0305335635626 0.01

3 0.0965555918836 0.01

Measurement: ah1c

step v(ref_c) at

1 -8.43252872588e-006 0.01

2 -2.73289685266e-005 0.01

3 -8.70847478853e-005 0.01

Measurement: avh2s

step v(h2sf) at

1 -2.11852910661e-011 0.02

2 -2.11621496592e-010 0.02

3 -2.11630425195e-009 0.02

Measurement: avh2c

step v(h2cf) at

1 -4.7705201674e-010 0.02

2 -4.77949177394e-009 0.02

3 -4.78041446972e-008 0.02

Measurement: avh3s

step v(h3sf) at

1 5.70093625464e-012 0.02

2 1.80416291238e-010 0.02

3 5.70630086246e-009 0.02

Measurement: avh3c

step v(h3cf) at

1 1.00080441573e-012 0.02

2 7.81369744796e-013 0.02

3 -8.74136711367e-012 0.02

Measurement: avh4s

step v(h4sf) at

1 2.12757688874e-016 0.02

2 -1.74272910437e-014 0.02

3 6.25513938116e-014 0.02

Measurement: avh4c

step v(h4cf) at

1 1.00762184834e-012 0.02

2 1.14468755347e-012 0.02

3 2.93457432994e-012 0.02

Measurement: avh5s

step v(h5sf) at

1 -3.11325389013e-014 0.02

2 -3.27953030123e-015 0.02

3 -1.61781582248e-013 0.02

Measurement: avh5c

step v(h5cf) at

1 9.99089654605e-013 0.02

2 1.15216872732e-012 0.02

3 2.7830953627e-012 0.02

Measurement: avh6s

step v(h6sf) at

1 -1.02843369323e-014 0.02

2 -8.78138478758e-016 0.02

3 -1.09351504002e-014 0.02

Measurement: avh6c

step v(h6cf) at

1 9.92177855116e-013 0.02

2 1.1357725472e-012 0.02

3 2.78538209024e-012 0.02

Measurement: avh7s

step v(h7sf) at

1 -1.02264828207e-014 0.02

2 -1.83328598102e-014 0.02

3 -3.11968223455e-014 0.02

Measurement: avh7c

step v(h7cf) at

1 1.00319213007e-012 0.02

2 1.16489498191e-012 0.02

3 2.7811661078e-012 0.02

Measurement: avh8s

step v(h8sf) at

1 -1.62602378597e-014 0.02

2 -2.40356917128e-016 0.02

3 -3.24897696568e-014 0.02

Measurement: avh8c

step v(h8cf) at

1 1.00902876967e-012 0.02

2 1.14591046825e-012 0.02

3 2.78286278973e-012 0.02

Measurement: avh9s

step v(h9sf) at

1 -1.61490441867e-014 0.02

2 5.17499908589e-015 0.02

3 -3.31179139598e-014 0.02

Measurement: avh9c

step v(h9cf) at

1 1.00142662953e-012 0.02

2 1.13410833518e-012 0.02

3 2.79675796889e-012 0.02

Measurement: avh10s

step v(h10sf) at

1 -7.44483778435e-015 0.02

2 -1.66483598066e-014 0.02

3 -3.74061241714e-014 0.02

Measurement: avh10c

step v(h10cf) at

1 1.00878395626e-012 0.02

2 1.13688394034e-012 0.02

3 2.79177645555e-012 0.02

Measurement: i_in_s

step v(is_s) at

1 -2.96332278776e-009 0.01

2 -9.37076003605e-009 0.01

3 -2.96330350827e-008 0.01

Measurement: i_in_c

step v(is_c) at

1 -1.0766925421e-010 0.01

2 -3.87241255854e-010 0.01

3 -1.27133209699e-009 0.01

Measurement: fundamental_out_v_rms

step sqrt(2)*hypot(ah1s,ah1c)

1 0.0136550295654

2 0.0431809969942

3 0.136550283103

Measurement: gain

step sqrt(2)*fundamental_out_v_rms/ag

1 1.9311128006

2 1.9311128923

3 1.9311126231

Measurement: gain_db

step 20*log10(gain)

1 5.71615285255

2 5.71615326504

3 5.7161520542

Measurement: phase_deg

step atan(ah1c/ah1s)

1 -0.0500383372617

2 -0.0512823907264

3 -0.0516757969531

Measurement: z_in_mod

step 0.5*ag/(hypot(i_in_s,i_in_c))

1 1686182.44797

2 1685872.31877

3 1685755.36105

Measurement: z_in_ph_deg

step (-1)*atan(i_in_c/i_in_s)

1 -2.08086724258

2 -2.36636864563

3 -2.45662723988

Measurement: h2

step sqrt(2)*hypot(avh2s,avh2c)*100/fundamental_out_v_rms

1 4.94556497378e-006

2 1.56685692289e-005

3 4.95579241898e-005

Measurement: h3

step sqrt(2)*hypot(avh3s,avh3c)*100/fundamental_out_v_rms

1 5.99459101949e-008

2 5.90883899355e-007

3 5.90986511047e-006

Measurement: h4

step sqrt(2)*hypot(avh4s,avh4c)*100/fundamental_out_v_rms

1 1.04356604181e-008

2 3.74938138397e-009

3 3.03994792498e-009

Measurement: h5

step sqrt(2)*hypot(avh5s,avh5c)*100/fundamental_out_v_rms

1 1.03523170233e-008

2 3.77346368649e-009

3 2.88724080892e-009

Measurement: h6

step sqrt(2)*hypot(avh6s,avh6c)*100/fundamental_out_v_rms

1 1.02762630344e-008

2 3.71975065866e-009

3 2.88476552017e-009

Measurement: h7

step sqrt(2)*hypot(avh7s,avh7c)*100/fundamental_out_v_rms

1 1.03903226419e-008

2 3.81560037424e-009

3 2.88055811878e-009

Measurement: h8

step sqrt(2)*hypot(avh8s,avh8c)*100/fundamental_out_v_rms

1 1.04515880752e-008

2 3.75295216395e-009

3 2.88233053641e-009

Measurement: h9

step sqrt(2)*hypot(avh9s,avh9c)*100/fundamental_out_v_rms

1 1.03728464832e-008

2 3.71433778249e-009

3 2.89672804379e-009

Measurement: h10

step sqrt(2)*hypot(avh10s,avh10c)*100/fundamental_out_v_rms

1 1.04479803259e-008

2 3.72378865668e-009

3 2.89162528097e-009

Measurement: thd_persent

step sqrt(h2*h2+h3*h3+h4*h4+h5*h5+h6*h6+h7*h7+h8*h8+h9*h9+h10*h10)

1 4.94600465505e-006

2 1.56797099432e-005

3 4.99090614506e-005

Measurement: thd_db

step 20*log10(thd_persent/100)

1 -146.114909585

2 -136.093239511

3 -126.036411941

Date: Sat Dec 14 15:01:22 2013

Total elapsed time: 33.743 seconds.

tnom = 27

temp = 27

method = modified trap

totiter = 172941

traniter = 172934

tranpoints = 75021

accept = 75021

rejected = 0

matrix size = 111

fillins = 92

solver = Normal

Thread vector: 37.4/32.8[2] 6.4/4.5[2] 21.7/7.5[2] 2.2/5.1[1] 2592/500

Matrix Compiler1: 11.0 KB object code size 7.2/7.0/[2.6]

Matrix Compiler2: off [2.9]/6.1/4.8

Hi Eugene,

Thanks for this great tool.

I´m new with LTSpice and I don’t understand how the get the plot “Total Harmonic Distortions vs. Frequency”.

Please help.

Best regards

Michael

i’m getting same error as Marcel…

what should the analyse_in input

Look at an example. Analyse_in should be connected to the point where you want to measure THD

Dear Eugene,

Thanks Eugene…that example was really helpful.

Here the out_e is voltage at that node.But if i want to find the THD of differential current output, then what all changes needs to be done..

My circuit needs to find the THD of difference of cuurents through two nodes.

Please Hep.

Thanks & regards,

Jithya