Partie HW faite a peu près
This commit is contained in:
parent
3c053bf278
commit
524ec7bf09
4 changed files with 195 additions and 99 deletions
6
releves_experimentaux/data.md
Normal file
6
releves_experimentaux/data.md
Normal file
File diff suppressed because one or more lines are too long
7
releves_experimentaux/data_8Ohm.md
Normal file
7
releves_experimentaux/data_8Ohm.md
Normal file
File diff suppressed because one or more lines are too long
8
releves_experimentaux/mic_impedance.md
Normal file
8
releves_experimentaux/mic_impedance.md
Normal file
|
@ -0,0 +1,8 @@
|
|||
Microphone as source follower. 175uA DC @ ~3V Vds
|
||||
|
||||
X = [62.0, 68.0, 75.0, 82.0, 91.0, 100.0, 110.00000000000001, 120.0, 130.0, 150.0, 160.0, 180.0, 200.0, 220.00000000000003, 240.0, 270.0, 300.0, 330.0, 360.0, 390.0, 430.0, 470.0, 509.99999999999994, 560.0, 620.0, 680.0, 750.0, 819.9999999999999, 910.0, 1000.0, 1100.0, 1200.0, 1300.0, 1500.0, 1600.0, 1800.0, 2000.0, 2200.0, 2400.0, 2700.0, 3000.0, 3300.0, 3600.0, 3900.0, 4300.0, 4700.0, 5100.0, 5600.0, 6200.0, 6800.0, 7500.0, 8200.0, 9100.0, 10000.0, 11000.0, 12000.0, 13000.0, 15000.0, 16000.0, 18000.0, 20000.0]
|
||||
|
||||
H = [(0.47012032175840673+0.01812983402014712j), (0.470773859825163+0.01694020487348213j), (0.47014391070243977+0.015085538991270814j), (0.47015580025611164+0.01290140838256883j), (0.4707965853705939+0.012540456593345836j), (0.4702655782670737+0.01146515427066669j), (0.47001958941149374+0.009066724097094081j), (0.4698897845061736+0.008590954654956465j), (0.4703328317106061+0.007680708662404258j), (0.47059597197084874+0.006947035949722949j), (0.4704696033876575+0.00577097334067109j), (0.4706101838316291+0.004496916581939091j), (0.4700645514757954+0.004640777774023917j), (0.46970384793911085+0.0038522275542666844j), (0.47072172644838994+0.004356868460710158j), (0.46985620214068086+0.0027604993703299464j), (0.4706992493463072+0.002204339769185796j), (0.47106305332005566+0.0021205228985848017j), (0.47028285448669327+0.0018612810692497153j), (0.4691514968724328+0.002292957901098495j), (0.4701873122263507+0.0002420230304226658j), (0.4689285261898509+0.0007289920633161568j), (0.46956552462586804-0.0007236174387345418j), (0.4678562305849072-0.0006907393785490914j), (0.46836755615019-0.0006038427857997494j), (0.4689235574748159-0.0016181768655454802j), (0.46876318278299123-0.0017764947735754034j), (0.4683097999229312-0.0027640827428271906j), (0.46786090676077974-0.002610856644027095j), (0.46753731928396514-0.002241714250446953j), (0.46801984732360963-0.002119721318204412j), (0.4663227653685854-0.0016727148025411536j), (0.4663031260029301-0.0022085460059039328j), (0.4658401896506971-0.0020177518020752486j), (0.46612388968980756-0.002207265245165768j), (0.4645078371101538-0.0028048732307074937j), (0.46394264877360886-0.0021639899863904162j), (0.4642719966632143-0.0015964764527535004j), (0.4632949784333158-0.0018359364430161399j), (0.46339335082824507-0.0007557123371271958j), (0.46374916001466004-0.0006997385251981024j), (0.46251209195262455-0.00011522690154944387j), (0.46177373985629666+0.0005354488426995059j), (0.4630923556768662+0.0009618057371807924j), (0.46250026655427934+0.002019603274076546j), (0.46115066695013796+0.002618340722087239j), (0.4599367294994153+0.001487858985361092j), (0.45947368133692446+0.0026319865902357893j), (0.4607616438306012+0.004473565837816463j), (0.46123373027180997+0.0039563877327196545j), (0.4612432999999601+0.004773317207737592j), (0.46113397679743406+0.006135235798210173j), (0.46122910037870635+0.005727347168252464j), (0.46150279974005726+0.007471744392586996j), (0.46260297120248955+0.007760981385780426j), (0.461474728572703+0.010231892504492484j), (0.46216777324979+0.009433273729074564j), (0.46091102876674295+0.010621600555034331j), (0.46093670915980167+0.012440290976269985j), (0.46216882884840704+0.014888096834763371j), (0.46407411135079274+0.015274025203592433j)]
|
||||
|
||||
|
||||
We get a ~12kOhm output impedance, and negligible output capacitance.
|
|
@ -25,130 +25,169 @@ fade_time = 0
|
|||
|
||||
|
||||
def audio_callback(in_data, frame_count, time_info, status):
|
||||
global fade_time
|
||||
global change_f
|
||||
global new_f
|
||||
global current_phase
|
||||
global normalized_f
|
||||
global trans_done
|
||||
global fade_time
|
||||
global change_f
|
||||
global new_f
|
||||
global current_phase
|
||||
global normalized_f
|
||||
global trans_done
|
||||
|
||||
if change_f == True:
|
||||
change_f = False
|
||||
trans_done = False
|
||||
fade_time = 0
|
||||
if change_f == True:
|
||||
change_f = False
|
||||
trans_done = False
|
||||
fade_time = 0
|
||||
|
||||
if(fade_time != 2*trans_len):
|
||||
if(fade_time < trans_len):
|
||||
last_fade = fade_time + frame_count
|
||||
envelope = outro[fade_time:last_fade]
|
||||
fade_time = min(last_fade, trans_len)
|
||||
elif(fade_time >= trans_len and fade_time < 2*trans_len):
|
||||
normalized_f = new_f
|
||||
if(new_f == 0):
|
||||
current_phase = 0. # Avoid weird sub-audio behavior
|
||||
last_fade = fade_time + frame_count
|
||||
envelope = intro[fade_time - trans_len:last_fade - trans_len]
|
||||
fade_time = min(last_fade, 2*trans_len)
|
||||
if(fade_time != 2*trans_len):
|
||||
if(fade_time < trans_len):
|
||||
last_fade = fade_time + frame_count
|
||||
envelope = outro[fade_time:last_fade]
|
||||
fade_time = min(last_fade, trans_len)
|
||||
elif(fade_time >= trans_len and fade_time < 2*trans_len):
|
||||
normalized_f = new_f
|
||||
if(new_f == 0):
|
||||
current_phase = 0. # Avoid weird sub-audio behavior
|
||||
last_fade = fade_time + frame_count
|
||||
envelope = intro[fade_time - trans_len:last_fade - trans_len]
|
||||
fade_time = min(last_fade, 2*trans_len)
|
||||
|
||||
if(fade_time == 2*trans_len):
|
||||
trans_done = True
|
||||
if(fade_time == 2*trans_len):
|
||||
trans_done = True
|
||||
|
||||
sine = np.sin(2 * np.pi * (current_phase + np.arange(frame_count)*normalized_f))
|
||||
delta = frame_count*normalized_f
|
||||
delta -= np.floor(delta)
|
||||
sine = np.sin(2 * np.pi * (current_phase + np.arange(frame_count)*normalized_f))
|
||||
delta = frame_count*normalized_f
|
||||
delta -= np.floor(delta)
|
||||
|
||||
if(delta + current_phase > 1):
|
||||
current_phase += delta - 1
|
||||
else:
|
||||
current_phase += delta
|
||||
if(delta + current_phase > 1):
|
||||
current_phase += delta - 1
|
||||
else:
|
||||
current_phase += delta
|
||||
|
||||
if(fade_time != 2*trans_len):
|
||||
sine *= envelope
|
||||
if(fade_time != 2*trans_len):
|
||||
sine *= envelope
|
||||
|
||||
return (sine.astype(np.float32).tobytes(), pa.paContinue)
|
||||
return (sine.astype(np.float32).tobytes(), pa.paContinue)
|
||||
|
||||
paudio = pa.PyAudio()
|
||||
|
||||
audio_strm = paudio.open(format=pa.paFloat32,
|
||||
channels=1,
|
||||
rate=44100,
|
||||
output=True,
|
||||
input=False,
|
||||
stream_callback=audio_callback,
|
||||
start=True)
|
||||
channels=1,
|
||||
rate=44100,
|
||||
output=True,
|
||||
input=False,
|
||||
stream_callback=audio_callback,
|
||||
start=True)
|
||||
print(paudio.get_default_output_device_info())
|
||||
print(audio_strm.is_active())
|
||||
|
||||
|
||||
|
||||
def acquire_samples(sc_frequency, oscillo):
|
||||
global new_f
|
||||
global change_f
|
||||
global trans_done
|
||||
new_f = sc_frequency
|
||||
change_f = True
|
||||
while (change_f == True) or (trans_done == False):
|
||||
time.sleep(0.05)
|
||||
time.sleep(0.2)
|
||||
global new_f
|
||||
global change_f
|
||||
global trans_done
|
||||
|
||||
oscillo.write("acquire:state run")
|
||||
oscillo.write("data:source CH1")
|
||||
input_ch = oscillo.query_binary_values("curve?",datatype="b",container=np.array).astype(np.float64)
|
||||
oscillo.write("data:source CH2")
|
||||
output_ch = oscillo.query_binary_values("curve?",datatype="b",container=np.array).astype(np.float64)
|
||||
new_f = sc_frequency
|
||||
change_f = True
|
||||
while (change_f == True) or (trans_done == False):
|
||||
time.sleep(0.01)
|
||||
time.sleep(0.1)
|
||||
|
||||
return input_ch, output_ch
|
||||
oscillo.write("acquire:state run")
|
||||
oscillo.write("data:source CH1")
|
||||
input_ch = oscillo.query_binary_values("curve?",datatype="b",container=np.array).astype(np.float64)
|
||||
oscillo.write("data:source CH2")
|
||||
output_ch = oscillo.query_binary_values("curve?",datatype="b",container=np.array).astype(np.float64)
|
||||
|
||||
return input_ch, output_ch
|
||||
|
||||
def manage_measures(f_list, oscillo): # These are NOT normalized frequencies
|
||||
hscales = [0.25, 100e-3, 50e-3, 25e-3, 10e-3, 5e-3, 2.5e-3, 1e-3, 500e-6, 250e-6, 100e-6, 50e-6, 25e-6, 10e-6]
|
||||
hscales_str = ["2.5e-1", "1.0e-1", "5.0e-2", "2.5e-2", "1.0e-2", "5.0e-3", "2.5e-3", "1.0e-3", "5.0e-4", "2.5e-4", "1.0e-4", "5.0e-5", "2.5e-5", "1.0e-5"]
|
||||
hscales = [0.25, 100e-3, 50e-3, 25e-3, 10e-3, 5e-3, 2.5e-3, 1e-3, 500e-6, 250e-6, 100e-6, 50e-6, 25e-6, 10e-6]
|
||||
hscales_str = ["2.5e-1", "1.0e-1", "5.0e-2", "2.5e-2", "1.0e-2", "5.0e-3", "2.5e-3", "1.0e-3", "5.0e-4", "2.5e-4", "1.0e-4", "5.0e-5", "2.5e-5", "1.0e-5"]
|
||||
|
||||
hscale_index = 0
|
||||
current_hscale = hscales[hscale_index]
|
||||
hscale_index = 0
|
||||
current_hscale = hscales[hscale_index]
|
||||
|
||||
cal_A = []
|
||||
cal_B = []
|
||||
cal_done = False
|
||||
|
||||
H = []
|
||||
vscales = [0.25, 100e-3, 50e-3, 25e-3]
|
||||
vscales_str = ["2.5e-1", "1.0e-1", "5.0e-2", "2.5e-2"]
|
||||
vscale_index = 0
|
||||
current_vscale = vscales[vscale_index]
|
||||
|
||||
W = sc.signal.windows.flattop(2500)
|
||||
cal_A = []
|
||||
cal_B = []
|
||||
cal_done = False
|
||||
|
||||
for f in f_list:
|
||||
sc_frequency = np.round(2**20/44100 * f)/2**20
|
||||
num_periods = f * 10 * current_hscale
|
||||
while(num_periods >= 5 * 2.5):
|
||||
hscale_index += 1
|
||||
current_hscale = hscales[hscale_index]
|
||||
num_periods = f * 10 * current_hscale
|
||||
print("horizontal:main:scale " + hscales_str[hscale_index])
|
||||
oscillo.write("horizontal:main:scale " + hscales_str[hscale_index])
|
||||
cal_done = False
|
||||
H = []
|
||||
|
||||
print(f, " : ", current_hscale,"s/div, ", num_periods, " periods")
|
||||
A, B = acquire_samples(sc_frequency, oscillo)
|
||||
if not cal_done:
|
||||
cal_A, cal_B = acquire_samples(0., oscillo)
|
||||
cal_done = True
|
||||
print(A)
|
||||
print(B)
|
||||
A, B = (A - cal_A)*W, (B - cal_B)*W
|
||||
f_acq = 250./current_hscale
|
||||
rel_f = f / f_acq
|
||||
W = sc.signal.windows.flattop(2500)
|
||||
|
||||
# Obtain the Fourier transforms of A, B @ rel_f, with flattop windowing
|
||||
V = np.exp(-2.0j * np.pi * np.arange(2500) * rel_f)
|
||||
h = np.sum(B*V)/np.sum(A*V)
|
||||
print("H(", f, ") = ", h)
|
||||
H.append(h)
|
||||
return H
|
||||
for f in f_list:
|
||||
sc_frequency = np.round(2**20/44100 * f)/2**20
|
||||
num_periods = f * 10 * current_hscale
|
||||
update_hscale = False
|
||||
while(num_periods >= 5 * 2.5):
|
||||
hscale_index += 1
|
||||
current_hscale = hscales[hscale_index]
|
||||
num_periods = f * 10 * current_hscale
|
||||
update_hscale = True
|
||||
|
||||
if update_hscale:
|
||||
print("horizontal:main:scale " + hscales_str[hscale_index])
|
||||
oscillo.write("horizontal:main:scale " + hscales_str[hscale_index])
|
||||
cal_done = False
|
||||
|
||||
print(f, " : ", current_hscale,"s/div, ", num_periods, " periods")
|
||||
A, B = acquire_samples(sc_frequency, oscillo)
|
||||
|
||||
is_sat, is_under = False, True
|
||||
for x in B:
|
||||
is_sat |= (abs(x) >= 127)
|
||||
is_under &= ~(abs(x) >= 64)
|
||||
|
||||
while((is_sat and vscale_index != 0) or (is_under and vscale_index != len(vscales)-1)):
|
||||
if(is_sat):
|
||||
print("We have saturation")
|
||||
vscale_index-=1
|
||||
elif(is_under):
|
||||
print("We are wasting bits")
|
||||
vscale_index+=1
|
||||
current_vscale = vscales[vscale_index]
|
||||
osci.write("ch2:scale " + vscales_str[vscale_index])
|
||||
cal_done = False
|
||||
A, B = acquire_samples(sc_frequency, oscillo)
|
||||
|
||||
is_sat, is_under = False, True
|
||||
for x in B:
|
||||
is_sat |= (abs(x) >= 120)
|
||||
is_under &= ~(abs(x) >= 64)
|
||||
|
||||
|
||||
if not cal_done:
|
||||
cal_A, cal_B = acquire_samples(0., oscillo)
|
||||
cal_done = True
|
||||
print(A)
|
||||
print(B)
|
||||
A, B = (A - cal_A)*W, (B - cal_B)*W
|
||||
f_acq = 250./current_hscale
|
||||
rel_f = f / f_acq
|
||||
|
||||
B *= current_vscale/vscales[0]
|
||||
|
||||
# Obtain the Fourier transforms of A, B @ rel_f, with flattop windowing
|
||||
V = np.exp(-2.0j * np.pi * np.arange(2500) * rel_f)
|
||||
h = np.sum(B*V)/np.sum(A*V)
|
||||
print("H(", f, ") = ", h)
|
||||
H.append(h)
|
||||
return H
|
||||
|
||||
def find_oscillo():
|
||||
rm = pyvisa.ResourceManager()
|
||||
R = rm.list_resources()
|
||||
print(R)
|
||||
# if R.empty():
|
||||
# print("No device found")
|
||||
# exit(1)
|
||||
return rm.open_resource(R[0])
|
||||
rm = pyvisa.ResourceManager()
|
||||
R = rm.list_resources()
|
||||
print(R)
|
||||
# if R.empty():
|
||||
# print("No device found")
|
||||
# exit(1)
|
||||
return rm.open_resource(R[0])
|
||||
|
||||
|
||||
osci = find_oscillo()
|
||||
|
@ -176,17 +215,53 @@ osci.write("trigger:main:type EDGE")
|
|||
osci.write("acquire:mode sample")
|
||||
osci.write("acquire:stopafter sequence")
|
||||
osci.write("data:encdg RIBinary")
|
||||
decade = [1.0, 1.2, 1.5, 1.8, 2.2, 2.7, 3.3, 3.9, 4.7, 5.6, 6.8, 8.2]
|
||||
|
||||
X = [68., 82] + list(np.array(decade)*([100.]*len(decade))) + list(np.array(decade) * ([1000.]*len(decade))) + [1e4, 1.2e4, 1.5e4, 1.8e4]
|
||||
|
||||
def build_spoints(decade):
|
||||
res = []
|
||||
power_of_ten = 10
|
||||
while(power_of_ten <= 100000):
|
||||
for x in decade:
|
||||
f = x * power_of_ten
|
||||
if(60. <= f and f <= 20000.):
|
||||
res.append(f)
|
||||
power_of_ten *= 10
|
||||
return res
|
||||
|
||||
|
||||
e12 = [1.0, 1.2, 1.5, 1.8, 2.2, 2.7, 3.3, 3.9, 4.7, 5.6, 6.8, 8.2]
|
||||
e24 = [1.0, 1.1, 1.2, 1.3, 1.5, 1.6, 1.8, 2.0, 2.2, 2.4, 2.7, 3.0, 3.3, 3.6, 3.9, 4.3, 4.7, 5.1, 5.6, 6.2, 6.8, 7.5, 8.2, 9.1]
|
||||
e48 = [1.00, 1.05, 1.10, 1.15, 1.21, 1.27, 1.33, 1.40, 1.47, 1.54, 1.62, 1.69, 1.78, 1.87, 1.96, 2.05, 2.15, 2.26, 2.37, 2.49, 2.61, 2.74, 2.87, 3.01, 3.16, 3.32, 3.48, 3.65, 3.83, 4.02, 4.22, 4.42, 4.64, 4.87, 5.11, 5.36, 5.62, 5.90, 6.19, 6.49, 6.81, 7.15, 7.50, 7.87, 8.25, 8.66, 9.09, 9.53]
|
||||
|
||||
X = build_spoints(e24)
|
||||
|
||||
print(X)
|
||||
|
||||
H = manage_measures(X, osci)
|
||||
Y = 20 * np.log10(np.abs(H))
|
||||
|
||||
phase = np.angle(H, deg=True)
|
||||
for i in range(1, len(phase)):
|
||||
while(abs(phase[i] - phase[i - 1]) >= 180):
|
||||
if(phase[i] >= phase[i-1]):
|
||||
phase[i] -= 360
|
||||
else:
|
||||
phase[i] += 360
|
||||
|
||||
print(X)
|
||||
print(H)
|
||||
|
||||
print("Corrected phase/magnitude :")
|
||||
print(phase)
|
||||
print(Y)
|
||||
|
||||
fig, axes = plt.subplots(nrows = 2, ncols=1, sharex = True)
|
||||
axes[0].semilogx(X,Y)
|
||||
axes[0].grid()
|
||||
axes[1].semilogx(X, np.angle(H, deg=True))
|
||||
axes[1].semilogx(X, phase)
|
||||
axes[1].grid()
|
||||
plt.show(block = False)
|
||||
|
||||
plt.figure(2)
|
||||
plt.plot(X, phase)
|
||||
plt.show()
|
||||
|
|
Loading…
Add table
Reference in a new issue