Noise Spectral Density (NSD) - Page 1
Forum section: electronics / general

author: macaba
author_rank: Regular Contributor
timestamp: June 13, 2020, 02:49:34 pm
content: I recently built a LNA (bandwidth 0.1 to 10hz) and have been measuring various noise sources (such asthis) and wanted to investigate the effect of record length.The NSD is computed with a power spectrum FFT, the results square rooted, and an average taken of many runs. I initially started with a fixed number of points (1Mpts) and did 10s (100kSa/s) record lengths, then tried 20s (50kSa/s) and 50s (20kSa/s) where I discovered the apparent noise dropped each time. I then wondered if this is related to sample rate, so did 10Mpts at 100s (100kSa/s) and it doesn't seem to be related. I also tried different window functions and whilst they can change the trace slightly, it doesn't cause them all to converge to the same level.I did somereadingand it would seem that the longer the record length, the closer to the true NSD (that's my interpretation anyway, not 100% sure).So what record lengths do datasheets tend to use?One of the things I've been measuring is the performance of my LT3042 design, which gets close to datasheet specifications and if I took a longer record length, would probably match it perfectly.

author: TexasRanger
author_rank: Contributor
timestamp: June 13, 2020, 04:37:47 pm
content: Hi, you have to average the power spectral density and then take the square root.Also don't use window functions for noise analysis as they alter the power of your Signal.NSD should be Independent of sampling speed and lenght, for 1/f I usally average like 128 plots over 3 hours at something like 2ksps and for white noise 32 averages are usally suficient.

author: David Hess
author_rank: Super Contributor
timestamp: June 13, 2020, 04:55:03 pm
content: Quote from: TexasRanger on June 13, 2020, 04:37:47 pmI agree. Something is amiss with the results.QuoteThere is a compensation factor to produce a RBW (resolution bandwidth) of 1 Hz for noise spectral density which depends on the FFT bin width which depends on sampling rate, and the window function.Also beware of noise higher than the Nyquist frequency aliasing down into the results.https://www.edn.com/dsos-and-noise/https://www.edn.com/ffts-and-oscilloscopes-a-practical-guide/

author: macaba
author_rank: Regular Contributor
timestamp: June 13, 2020, 04:56:57 pm
content: Thank you TexasRanger - your insightful post prompted me to check my maths again with your comments in mind - I found I was computing power spectrum, and not power spectrumdensity.Just running the analysis again...

author: macaba
author_rank: Regular Contributor
timestamp: June 13, 2020, 05:02:27 pm
content: That's better!

author: JohnPi
author_rank: Regular Contributor
timestamp: June 13, 2020, 06:10:37 pm
content: If you have sampling at (say) 20 kS/s, and you care about PSD in the 10 Hz range you need to ensure there are no significant signals (no significant energy) above (20k-10) == 19.99 kHz, as they will be aliased to your region of interest.This is not precisely the same as Nyquist frequency (would be 10 kHz in this case), as you don't care about energy that is aliased to frequencies above 10 Hz.A simple R.C filter should do it. Pick a cutoff above your 10 Hz range (say 100 Hz).As an aside, I find it easier to manipulate and think of noise in power/Hz, not V/rtHz -- they you don't get confused with sqrt(Hz) calculations and values just add simply.

author: TexasRanger
author_rank: Contributor
timestamp: June 13, 2020, 07:16:40 pm
content: I don't think that aliasing is a problem here, as the signal already seems to have a lowpass at ~10Hz and even the simplest oversampling filter provide sufficient aliasing rejection for this application (given that your frequency band of interest is well below your sampling rate).But it really depends on the particular digitizer and its digital and analog aliasing filters.The datasheet of your digitizer should provide you with information about alias rejection, but you can also just test it with an signal generator at the frequencys JohnPi mentioned.

author: rhb
author_rank: Super Contributor
timestamp: June 14, 2020, 12:22:11 am
content: Quote from: TexasRanger on June 13, 2020, 04:37:47 pmThis is not correct. Implicitly the sample length imposes a window. Without tapering that is a convolution with sinc(f). A triangle aka Bartlett window is sinc(f)**2. Take a look at Wikipedia for a very large variety of windows. However, you do need to account for the window, whatever it is if you want absolute numbers rather than simply a qualitative picture.Doing DSP programming in the oil industry I most often used a raised cosine of sufficient width when there was no special requirement for something else. However, I was not interested in absolute numbers. My concern was sidelobes.Have Fun!Reg

author: Kleinstein
author_rank: Super Contributor
timestamp: June 14, 2020, 09:20:50 am
content: If one does the noise calculation via the computer, one should also include the analog filtering function. The simple filters are already effecting the signal in the pass band a little. If mainly used for the computer one could consider changing the filters to a wider band. So not just 0.1 to 10 Hz but maybe 0.02 Hz to 100 Hz. At the low end the AC coupling can add some noise in the transition region. A larger resistor to ground to lower the cross over frequency reduces the noise - this may be a little counter intuitive.For the windowing function I see the main point in avoiding aliasing / side lobes from mains hum. If windowing is used the data sets should be well longer than the minimum 10 seconds to get 0.1 Hz - this alone helps to reduce the side lobes and the effect of the windowing function. It may help to have the ADC sampling well faster then 150 SPS so that the mains frequency is well included and not causing aliasing from the ADC sampling.

author: macaba
author_rank: Regular Contributor
timestamp: June 14, 2020, 10:16:45 am
content: Quote from: Kleinstein on June 14, 2020, 09:20:50 amI had the same conclusion. Whilst knowledgable in electronics and programming in general, I am new to volt metrology so I wanted to walk before I ran by building a LNA based on the designs here in the forum (1st order HPF, LT1007/LT1037 x10000 amplifier, 4th order LPF).I’m planning v2 to simply be 1st order HPF, perhaps switchable for microvolt DC readings, amplifier, AA filter, ADC. The cost saving in removing the 4th order filtering goes along way to balancing the cost of the ADC.The digital/firmware/processing aspect of this potential v2 design is well within my comfort zone.

author: maat
author_rank: Regular Contributor
timestamp: June 14, 2020, 01:52:10 pm
content: I assume you are after anestimateof the PSD of the noise. I say estimate, because an accurate determination is obviously not possible due to the limited number of datapoints cutting off the integral, hence the use of a window function. Anyway, there is a lovely paper on the matter by Peter Welch:The use of fast Fourier transform for the estimation of power spectra: A method based on time averaging over short, modified periodograms(https://ieeexplore.ieee.org/document/1161901) and to understand what he is doingA Direct Digital Method of Power Spectrum Estimation(https://ieeexplore.ieee.org/document/5392439) . He introduced a method of cutting up the sample into multiple segments and then piecing them back together. This greatly reduces the number of computations required and the overlapping segments used, suppress noise nicely.Fortunately for everyone, who is not into a boatload of sums and integrals, thare is a nice writeup here :https://www.osti.gov/servlets/purl/5688766/and there is lovely implementation in scipy which is a no-brainer:https://docs.scipy.org/doc/scipy/reference/generated/scipy.signal.welch.htmlRegarding the window function, I typically use a flat-top window to preserve the amplitudes.

author: rhb
author_rank: Super Contributor
timestamp: June 14, 2020, 01:56:29 pm
content: There is a normalization term in the Fourier transform. In the FFT it can be applied going from time to frequency, from frequency to time or both. The first 2 use a 1/N term. The latter is 1/sqrt(N).I should have thought of that earlier. Have a look at the FFT source code or test it with a series of constant amplitude. If the FFT of a series of ones is 1, then there's a 1/N being applied going from time to frequency.You also need to be aware of wraparound. If the first and last values are very different it will distort the spectrum. To preclude that pad the series to double the length with zeros before doing the FFT.Random DataBendat & Piersol4th edis the canonical reference for these subjects.Have Fun!Reg

author: macaba
author_rank: Regular Contributor
timestamp: June 15, 2020, 11:04:44 am
content: Thanks for all the links & comments so far - I read them all and had a day of frustrating experimentation.I tried:- Different window types, taking in account their corresponding equivalent noise bandwidth factor in the density conversion.- Bartlett vs. Welch methods.- Using power spectrum and square root vs. amplitude spectrum only.The resulting trend shapes all correlate, it's just the amplitude that varied. I would like to get my trends within the correct quarter-order of magnitude.I decided to look at my LNA noise floor, estimate what the noise density at a certain frequency should be and see what method best matches it.The 3 dominant sources of noise in the LNA is the input resistor, input voltage noise & +ve input current noise.My LNA has a 1.5k resistor in the HPF before the opamp, corresponding to 4.9nVrms/rHz (290k). The metal film resistor wasn't selected for low noise, so this is likely to be higher.As seen in my previous plots, my 10hz LPF filter starts a little too early, so I decided to look at the 6hz frequency point on the LT1007/LT1037 datasheet on the input voltage noise plot.The input voltage noise at 6hz is approx. 3nVrms/rHz.The voltage noise due to +ve input current noise (2pArms/rHz) at 6hz is approx. 3nVrms/rHz.That results in a uncorrelated noise sources sum of 6.5nVrms/rHz. Likely to be a little higher due to input resistor not being wirewound or similar low noise type.I looked at which method was near to 6.5nVrms/rHz, and found this:where the noise density at 6hz is 8nVrms/rHz.The method being: Bartlett, with no window into an amplitude spectrum, RMS averaged over 100x 10 second captures. The average metrics over 100 captures is 22.85nVrms and 116.3nVpp. The downside being the requirement for a high number of captures to get a smooth spectral density line (in comparison to the Welch method which gave very smooth lines but incorrect magnitude).As a point of interest:Shows the 10hz rolloff and a small amount of 50hz noise.I'm aware the maths may not support this fully but I'm mainly after comparisons between devices, and a reasonable level of absolute accuracy (within quarter-order of magnitude of true value).

author: Kleinstein
author_rank: Super Contributor
timestamp: June 15, 2020, 11:56:46 am
content: For testing the LNA own noise one should have a short at the input. In this case the input would nearly shorten out the noise contribution of the resistor. The resistor noise would only come in at the lower frequency end, when the capacitors impedance is no longer small compared to the resistor.With essentially no DC voltage at the resistor the noise does not depend on the quality of the resistor. For thermodynamic reasons the Johnson noise does not depend on the type of resistor, but only the differential resistance. The difference between poor and low noise resistors comes only with a significant voltage at the resistor.The OPs noise in the low frequency range can vary between different units quite a bit. For a test it would be better to use the white noise range or an JFET based OP and noise from a resistor as a "reference".

author: mrprecision
author_rank: Regular Contributor
timestamp: November 20, 2020, 08:25:25 pm
content: The spectral noise density can also be simple plotted with this tool:https://www.signalanalyzer.de

author: MiDi
author_rank: Frequent Contributor
timestamp: January 21, 2022, 12:13:38 am
content: NSD in python as a starting point for discussion (welch window & overlapping).Python file& plot attached.Code:import pandas as pdimport numpy as npfrom scipy import signalimport matplotlib.pyplot as pltfrom matplotlib.ticker import EngFormatter## read data from file#df = pd.read_table (r'NSD of white noise.tsv',# header=None, skipinitialspace=True, names=['value'], encoding='latin1')num_samples = 1000000df = pd.DataFrame()np.random.seed(0)df['value'] = np.random.random(num_samples)df['value'] -= df['value'].mean() # need to remove DC## write data to file#df['value'].to_csv("NSD of white noise.tsv", header=None, index=False)df['value'].describe()# sample frequency in Hzfs = 1# Welch function gives PSDf, PSD_welch = signal.welch(df['value'], fs, nfft=8192, detrend=False, window='bartlett', average='mean')# transform to NSDPSD_welch = np.sqrt(PSD_welch)# Plotplt.subplots(figsize=(15, 10))plt.plot(f, PSD_welch, label='White noise')plt.ylim(0.4)plt.xlim([0.001, fs/2*0.99])plt.xlabel('frequency in Hz')plt.ylabel(r'Voltage noise (NDS) in V/$\sqrt{Hz}$')#plt.semilogx()plt.loglog()plt.grid(True, which="both")formatter1 = EngFormatter(sep="")plt.gca().xaxis.set_major_formatter(formatter1)#plt.gca().xaxis.set_minor_formatter(formatter1)plt.gca().yaxis.set_major_formatter(formatter1)plt.gca().yaxis.set_minor_formatter(formatter1)plt.legend()plt.savefig('NSD of white noise.png')

author: miro123
author_rank: Frequent Contributor
timestamp: January 21, 2022, 08:57:15 am
content: 1. The Script of MiDi is good starting point.2. Sample rate must be wisely selected. - OP use -sample rate 10KS/s while LNA is limited to 10Hz - 1Ks/s seem reasonable in this case. Lower sample rate will give as side affect higher ADC resolution from your acquisition system

author: Leo Bodnar
author_rank: Frequent Contributor
timestamp: January 22, 2022, 12:07:12 pm
content: Do you have any standard instruments that you can cross-check the results with?It can save you days (if now weeks) of going around in circles and having to re-test what you thought were accurate results later on.I use mostly HP89410A for this sort of tests (LNAs, PDNs, LDOs - using JW 60dB amplifier when necesary.) I love it so much that I replaced frontend opamps and put in LCD instead of CRT. You can also use audio analysers like R&S UPL, etc.My point is: when you have settled on a method, cross-check it against something else out there.Leo

author: NaxFM
author_rank: Regular Contributor
timestamp: January 22, 2022, 12:41:41 pm
content: Quote from: macaba on June 13, 2020, 02:49:34 pmCan you post the design you used and maybe a few pics? I'm very interested in one for measuring precision voltage sources

author: miro123
author_rank: Frequent Contributor
timestamp: January 26, 2022, 03:12:45 pm
content: Quote from: MiDi on January 21, 2022, 12:13:38 amInspired by MidI script I add this function to my libraryI still don't figured out the purpose of Pandas framework. For me it is kind of parasite wrapper over already good numpy and matplotlibBij lonng term measurements I use substantiating the signal with LPF instead of mean value in your case anything under 0.01Hz can be removed - same applies for the FFT size. - this numbers are base on hardware limitation of your setup 0.1...10HzCode:def nsd(self,fs=1):num_samples = 1000000np.random.seed(0)yt = np.random.random(num_samples)v_dc= np.mean(yt) # need to remove DCyt=yt-v_dc# Welch function gives PSDf, PSD_welch = signal.welch(yt, fs, nfft=8192, detrend=False, window='bartlett', average='mean')# transform to NSDNSD_welch = np.sqrt(PSD_welch)# Plotplt.plot(f, NSD_welch, label='White noise')plt.title('White noise NSD')plt.ylim(0.4)plt.xlim([0.001, fs/2*0.99])plt.xlabel('frequency in Hz')plt.ylabel(r'Voltage noise (NDS) in V/$\sqrt{Hz}$')#plt.semilogx()plt.loglog()plt.grid(True, which="both")#plt.savefig('NSD of white noise.png')plt.show()

author: miro123
author_rank: Frequent Contributor
timestamp: July 01, 2025, 08:39:56 am
content: I just awake very old thread. The reason is that the topic starter created great Github repohttps://github.com/macaba/NSD

author: MiDi
author_rank: Frequent Contributor
timestamp: July 02, 2025, 05:06:03 pm
content: Some options to get a smooth NSD plot:Python LPSDMatlab LTPDAWindows/Linux NSD (macaba)

author: radiolistener
author_rank: Super Contributor
timestamp: July 08, 2025, 09:59:42 am
content: I wrote the same code for Octave:Code:pkg load signal;% Input datafs = 1; % sample rateN = 1000000; % sample countrand('seed', 0); % init random number generatorsignal = rand(1, N); % generate analog noise with range [0, 1)signal -= mean(signal); % remove DC% Welch method to estimate power spectral densitynfft = 2^13;window_size = 2^8;[psd, f] = pwelch(signal, bartlett(window_size), [], nfft, fs);asd = sqrt(psd); % Convert to amplitude spectral density (ASD)% Remove zero freq to display results on log-scale axisvalid_idx = (f > 0);f = f(valid_idx);asd = asd(valid_idx);% Plotsemilogx(f, asd, 'b');xlabel('Hz');ylabel('V/√Hz');xlim([0.001 fs/2*0.99]);ylim([0.4 max(asd)*1.015]);title('Noise Spectral Density');grid on;grid minor;print('data-nsd-octave.png', '-dpng');Works about 30% faster than python code posted by MiDi.This code shows a different curve than python code from previous posts because Octave and Python using different random number generator, so they generate different random numbers for the same seed. To do comparison, I saved random data and results from Python code and compared it with Octave result for the same data, see the second picture with comparison results. Looks identical.

author: LooseJunkHater
author_rank: Frequent Contributor
timestamp: July 10, 2025, 04:29:57 pm
content: Quote from: miro123 on July 01, 2025, 08:39:56 amTook a brief look at the Git page and it looks like I would only simply need to input a .csv file into your program and it'll spit out the graphs/NSD, is that correct? If so, how are you generating the .csv files? Do you have a MCU reading the output voltages from an analog NSD amplifier device (ex. LFLNA-80) and then placing the data into a .CSV, or another way?

author: Hedrix
author_rank: Contributor
timestamp: July 11, 2025, 12:07:09 pm
content: Yes, like that, generate your .csv however you want, be it an ADC over USB logging to csv, multimeter over GPIB/Ethernet, oscilloscope etc, with whatever software or python script you like.The only thing you need to know is your sample rate (that should be as accurately known and stable as possible) and, if applicable, gain (e.g. if you measuring something referred to the input of the amplifier

author: radiolistener
author_rank: Super Contributor
timestamp: July 16, 2025, 04:42:13 pm
content: I’m working on phase noise measurement using a sound card with subsequent analysis of recorded signals. To verify the method, I’m looking for a real carrier signal recording (for example, a WAV file) together with the corresponding phase noise plot measured using professional equipment (for example a phase noise analyzer).Ideally, it could be a carrier from some oscillator or signal generator with known jitter or phase noise level, or something similar.I’d greatly appreciate if someone could share such test data. My goal is to validate my processing and phase noise plot generation.Thank you in advance!

author: David Hess
author_rank: Super Contributor
timestamp: July 16, 2025, 07:59:34 pm
content: Can't you generate and verify such a wave file from MathCAD or Mathematica or whatever you are using?

author: radiolistener
author_rank: Super Contributor
timestamp: July 16, 2025, 08:10:44 pm
content: I’m using Linux and Octave. However, I don’t have ready-made tools or scripts to generate a signal together with a verified, correct phase noise curve in dBc/Hz.If you (or someone) could help by sharing code or a method that generates such a test signal and produces a reliable phase noise plot from it, I would greatly appreciate it. This would be very valuable for me to validate my measurement and analysis approach.I can write such code in Octave myself, but I lack reference data to compare against in order to verify the correctness of the calculations.As I understand, this could be, for example, the result of measuring a signal generator output on a phase noise analyzer, recorded simultaneously as an audio file using a reasonably good sound card. Even better would be if the phase noise plot is generated directly by software from the recorded signal.I simply need some test vectors - a WAV file together with its corresponding phase noise plot, to verify that the graphs I generate are correct.I would prefer a recording of a real signal because I have attempted to simulate phase noise mathematically, but the results differ significantly from classical phase noise measurements of oscillators commonly found in literature and online. I am not sure whether this discrepancy is due to incorrect phase noise plot construction or improper simulation of the signal with the specified jitter level.For example, here’s the code in Octave. It simulate 1 kHz carrier with 100 ps jitter and plot its phase noise.However, I’m not fully confident that it works correctly, as I don’t have any reference data to compare and validate the results.Code:pkg load signal;% Parametersfs = 384000; % Sample rate (Hz)N = 2^20; % Number of samplesf0 = 1000; % Carrier frequency (Hz)jitter_rms_sec = 100 * 1e-12; % Jitter 100 ps rms% Time vectort = (0:N-1)'/fs;% Generate phase noisepn_level = 2*pi*f0*jitter_rms_sec; % Phase noise stddev in radiansphase_error = pn_level * randn(N, 1);% Generate signal with phase noisephase_carrier = 2*pi*f0*t;signal = cos(phase_carrier + phase_error);% Measure jitter for checkjitter = phase_error / (2 * pi * f0); % secondsfprintf('jitter: %.3f ps peak / %.3f ps rms\n', max(abs(jitter))*1e+12, rms(jitter)*1e+12);fprintf('SNR: %.3f dBFS\n', -20*log10(2*pi*fs*rms(jitter)));% Analyzeanalytic = hilbert(signal);phase = detrend(unwrap(angle(analytic)));% PSD of phase fluctuations[psd, f] = pwelch(phase, hanning(2^8), [], 2^13, fs);% Convert to dBc/HzL_dBcHz = 10*log10(psd/2);% Plotfigure;plot(f, L_dBcHz);grid on;grid minor;xlim([0 fs/16]);xlabel('Offset (Hz)');ylabel('dBc/Hz');title('Phase Noise');print('phase-noise.png', '-dpng');PS: code was updated to fix jitter simulation

author: Leo Bodnar
author_rank: Frequent Contributor
timestamp: August 10, 2025, 09:28:00 pm
content: http://www.stable32.comcan generate different kinds of noise that you can analyse and compare to your code results.Leo