Skip to content

Instantly share code, notes, and snippets.

@raytroop
Last active June 2, 2026 14:26
Show Gist options
  • Select an option

  • Save raytroop/97db3b35727cfd99a9811b63acd8a7fd to your computer and use it in GitHub Desktop.

Select an option

Save raytroop/97db3b35727cfd99a9811b63acd8a7fd to your computer and use it in GitHub Desktop.
The quantization noise is **odd harmonics of the input signal**
# modified from https://github.com/wulffern/aic2023/blob/main/ex/q.py
#!/usr/bin/env python3
import numpy as np
import matplotlib.pyplot as plt
#- Enable hanning window
hann = True
#- Create a time vector
N = 2**13
t = np.linspace(0,N,N)
#- Create the "continuous time" signal
fdivide = 2**6
f1 = 1/fdivide - 1/N
x_s = np.sin(2*np.pi*f1*t) + + 1/2**15*np.random.randn(N)
#----------------------------------------------
#- Model an ADC
#----------------------------------------------
## Sample
#- Sampling frequency is 1/nfs of the time vector
nfs = 4
x_sn = x_s[0::nfs]
def adc(x,bits):
levels = 2**bits
y = np.round(x*levels)/levels
return y
# To discrete value
bits = 1
y_sn1 = adc(x_sn,1)
y_sn10 = adc(x_sn,10)
print(np.max(y_sn1))
print(np.max(y_sn10))
print(np.max(x_s))
#----------------------------------------------
# Plot spectrum
#----------------------------------------------
def freqDomain(x,hann=True):
N = len(x)
# Use hanning window to prevent FFT bin energy spread
if(hann):
w = np.hanning(N+1)
else:
w = np.ones(N+1)
# Convert to frequency domain
X= np.fft.fftshift(np.fft.fft(np.multiply(w[0:N],x)))
# Normalize to max output power
X = X/np.max(np.abs(X))
return X
X_s = freqDomain(x_s,hann)
X_sn = freqDomain(x_sn,hann)
Y_sn1 = freqDomain(y_sn1,hann)
Y_sn10 = freqDomain(y_sn10,hann)
M = len(Y_sn1)
f_xs = np.arange(0,N,1) - N/2
f_xn = np.arange(0,M,1) - M/2
plt.subplot(1,4,1)
plt.plot(f_xs,20*np.log10(np.abs(X_s)))
plt.xlabel("Continuous time, continuous value")
plt.ylabel("Frequency Domain"); plt.title("continuous input")
plt.ylim(-160,0)
plt.subplot(1,4,2)
plt.plot(f_xn,20*np.log10(np.abs(X_sn)))
plt.xlabel("Discrete time, continuous value")
plt.ylabel("Frequency Domain"); plt.title("sampled input")
plt.ylim(-160,0)
plt.subplot(1,4,3)
plt.plot(f_xn,20*np.log10(np.abs(Y_sn1)))
plt.xlabel("Discrete time, Discrete value"); plt.title("quantized output, " + str(bits) + "-bit")
plt.text(M*1/5,-20,str(1) + "-bit\nf1 =" + str(int(f1*N)) + "\nf3 =" + str(int(f1*N*3)) + "\nf5 =" + str(int(f1*N*5)) )
plt.ylim(-160,0)
plt.subplot(1,4,4)
plt.plot(f_xn,20*np.log10(np.abs(Y_sn10)))
plt.xlabel("Discrete time, Discrete value"); plt.title("quantized output, " + str(10) + "-bit")
plt.text(M*1/5,-20,str(10) + "-bit\nf1 =" + str(int(f1*N)) + "\nf3 =" + str(int(f1*N*3)) + "\nf5 =" + str(int(f1*N*5)) )
plt.ylim(-160,0)
fig = plt.gcf()
fig.set_size_inches(12, 7)
plt.tight_layout()
plt.savefig("l6_quant.svg")
plt.show()
@raytroop

raytroop commented Jun 2, 2026

Copy link
Copy Markdown
Author
l6_quant

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment