Seite 1 von 1
Kapazitätsmessgerät mit dem NE555, pyaudio und tkinter
Verfasst: Sonntag 3. Januar 2021, 00:20
von kaytec
Hallo,
habe ein Kapazitätsmessgerät zum Messen von kleinen Kapazitäten gebastelt.
Nachbau der Schaltung auf Platine zur Messung über die Soundkarte:
http://www.elexs.de/radio4.htm
Erklärung zur Berechnung der Kapazität am NE555 als astabile Kippstufe:
http://www.elektronik-kompendium.de/sit ... 310131.htm
Code: Alles auswählen
#/usr/bin/env python
# -*- coding: utf-8
import tkinter as tk
import numpy as np
from functools import partial
import pyaudio
WIDTH = 270
HEIGHT = 100
RA = 1 # kOhm
RB = 5 # kOhm
RESISTANCE = (RA + RB * 2) * 0.69
class Capacitance_NE555(object):
def __init__(self,
resistance,
rate = 44100,
frames_per_buffer = 1024):
self.py_audio = pyaudio.PyAudio()
self.resistance = resistance
self.rate = rate
self.frames_per_buffer = frames_per_buffer
self.cap_reference = None
def __enter__(self):
return self
def __exit__(self, *args):
self.release()
def start_stream(self):
self.stream = self.py_audio.open(format= pyaudio.paInt16,
channels = 1,
rate = self.rate,
frames_per_buffer = \
self.frames_per_buffer,
input = True)
def stop_stream(self):
self.stream.stop_stream()
self.stream.close()
def get_frequency(self, stream_data):
past_mean = False
f = 0
for data in stream_data:
if data >= np.mean(stream_data) and past_mean== False:
past_mean = True
f=f+1
elif data <= np.mean(stream_data):
past_mean = False
return f / (len(stream_data) / self.rate)
def measure(self):
data = list()
for i in range(0, int(self.rate/ self.frames_per_buffer)):
result = 1 / self.get_frequency(
np.frombuffer(
self.stream.read(1024),
dtype=np.int16)
) / self.resistance * 100000000
result = result - self.cap_reference if self.cap_reference else\
result
data.append(result)
if self.cap_reference:
return np.mean(data)
else:
self.cap_reference = np.mean(data)
def release(self):
self.stream.stop_stream()
self.stream.close()
self.py_audio.terminate()
class CapacitanceUI(tk.LabelFrame):
UPDATE_INTERVAL = 2000
CALIBRATION = 50
def __init__(self, parent, capacitance_ne555, width, height):
tk.LabelFrame.__init__(self, parent, text = "CAPACITANCE",
relief = "solid")
self.capacitance = capacitance_ne555
self.width = width
self.height = height
self.parent = parent
self.calibration = True
self.display_conf = {"cap" : (
self.width / 2,
self.height / 2,
"{0:2.2f} pf",
"system 18 bold",
"blue",
"cap"),
"info" :(
self.width / 2,
self.height / 2,
"{0}",
"system 18 bold",
"magenta",
"info")}
self.display = tk.Canvas(self, width = width, height = height,
bg="cyan")
self.display.pack(padx = 5, pady = 5)
self.update_cap_display(0, "cap")
self.start_button = tk.Button(self, text="START", width = 7,
command = self.measure)
self.start_button.pack(side = tk.LEFT, padx = 30)
self.calibrate_button = tk.Button(self, text = "CALIBRATE", width = 7,
command = partial(self.measure, True))
self.calibrate_button.pack(side = tk.RIGHT, padx = 30)
self.measure(True)
def update_cap_display(self, text, tag):
width, height, text_conf, font, color, tag = self.display_conf[tag]
self.display.delete(tag)
self.display.create_text(width, height, text = text_conf.format(text),
font = font, fill = color,tag = tag)
def measure(self, calibrate = False):
self.display.delete("all")
self.update_cap_display("", "info")
self.capacitance.start_stream()
if calibrate:
self.capacitance.cap_reference = None
frequency = self.capacitance.measure()
display_text = ["CALIBATRED", "info"] if calibrate else\
[frequency, "cap"]
self.update_cap_display(display_text[0], display_text[1])
def release(self):
self.parent.destroy()
def main():
root = tk.Tk()
root.title("CAPACITANCE")
with Capacitance_NE555(RESISTANCE) as capacitance_ne555:
capacitance_ui = CapacitanceUI(root, capacitance_ne555, WIDTH, HEIGHT)
capacitance_ui.pack(expand=tk.YES, padx=5, pady=5)
root.protocol("WM_DELETE_WINDOW",capacitance_ui.release)
root.mainloop()
if __name__ == '__main__':
main()
Gruß Frank
Re: Kapazitätsmessgerät mit dem NE555, pyaudio und tkinter
Verfasst: Sonntag 3. Januar 2021, 08:36
von kaytec
Hallo,
noch Fehler gefunden - Stream nach dem Messen nicht gestoppt.
Code: Alles auswählen
#/usr/bin/env python
# -*- coding: utf-8
import tkinter as tk
import numpy as np
from functools import partial
import pyaudio
WIDTH = 270
HEIGHT = 100
RA = 1 # kOhm
RB = 5 # kOhm
RESISTANCE = (RA + RB * 2) * 0.69
class Capacitance_NE555(object):
def __init__(self,
resistance,
rate = 44100,
frames_per_buffer = 1024):
self.py_audio = pyaudio.PyAudio()
self.resistance = resistance
self.rate = rate
self.frames_per_buffer = frames_per_buffer
self.cap_reference = None
def __enter__(self):
return self
def __exit__(self, *args):
self.release()
def start_stream(self):
self.stream = self.py_audio.open(format= pyaudio.paInt16,
channels = 1,
rate = self.rate,
frames_per_buffer = \
self.frames_per_buffer,
input = True)
def stop_stream(self):
self.stream.stop_stream()
self.stream.close()
def get_frequency(self, stream_data):
past_mean = False
f = 0
for data in stream_data:
if data >= np.mean(stream_data) and past_mean== False:
past_mean = True
f=f+1
elif data <= np.mean(stream_data):
past_mean = False
return f / (len(stream_data) / self.rate)
def measure(self):
data = list()
for i in range(0, int(self.rate/ self.frames_per_buffer)):
result = 1 / self.get_frequency(
np.frombuffer(
self.stream.read(1024),
dtype=np.int16)
) / self.resistance * 100000000
result = result - self.cap_reference if self.cap_reference else\
result
data.append(result)
if self.cap_reference:
return np.mean(data)
else:
self.cap_reference = np.mean(data)
def release(self):
self.stream.stop_stream()
self.stream.close()
self.py_audio.terminate()
class CapacitanceUI(tk.LabelFrame):
def __init__(self, parent, capacitance_ne555, width, height):
tk.LabelFrame.__init__(self, parent, text = "CAPACITANCE",
relief = "solid")
self.capacitance = capacitance_ne555
self.width = width
self.height = height
self.parent = parent
self.display_conf = {"cap" : (
self.width / 2,
self.height / 2,
"{0:2.2f} pf",
"system 18 bold",
"blue",
"cap"),
"info" :(
self.width / 2,
self.height / 2,
"{0}",
"system 18 bold",
"magenta",
"info")}
self.display = tk.Canvas(self, width = width, height = height,
bg="cyan")
self.display.pack(padx = 5, pady = 5)
self.update_cap_display(0, "cap")
self.start_button = tk.Button(self, text="START", width = 7,
command = self.measure)
self.start_button.pack(side = tk.LEFT, padx = 30)
self.calibrate_button = tk.Button(self, text = "CALIBRATE", width = 7,
command = partial(self.measure, True))
self.calibrate_button.pack(side = tk.RIGHT, padx = 30)
self.measure(True)
def update_cap_display(self, text, tag):
width, height, text_conf, font, color, tag = self.display_conf[tag]
self.display.delete(tag)
self.display.create_text(width, height, text = text_conf.format(text),
font = font, fill = color,tag = tag)
def measure(self, calibrate = False):
self.display.delete("all")
self.update_cap_display("", "info")
self.capacitance.start_stream()
if calibrate:
self.capacitance.cap_reference = None
frequency = self.capacitance.measure()
display_text = ["CALIBRATED", "info"] if calibrate else\
[frequency, "cap"]
self.update_cap_display(display_text[0], display_text[1])
self.capacitance.stop_stream()
def release(self):
self.parent.destroy()
def main():
root = tk.Tk()
root.title("CAPACITANCE")
with Capacitance_NE555(RESISTANCE) as capacitance_ne555:
capacitance_ui = CapacitanceUI(root, capacitance_ne555, WIDTH, HEIGHT)
capacitance_ui.pack(expand=tk.YES, padx=5, pady=5)
root.protocol("WM_DELETE_WINDOW",capacitance_ui.release)
root.mainloop()
if __name__ == '__main__':
main()
Gruß Frank
Re: Kapazitätsmessgerät mit dem NE555, pyaudio und tkinter
Verfasst: Sonntag 3. Januar 2021, 11:48
von kaytec
Hallo,
Zeile 59 kann auch in --> "for i in range(0, int(self.rate / self.frames_per_buffer * 0.5)):" geändert werden. Die Verkürzung hat bei meinen Versuchen keinen Unterschied erzeugt.
Gruß Frank
Re: Kapazitätsmessgerät mit dem NE555, pyaudio und tkinter
Verfasst: Montag 4. Januar 2021, 02:02
von kaytec
Hallo,
jetzt mit Frequenzanzeige.
Code: Alles auswählen
#/usr/bin/env python
# -*- coding: utf-8
import tkinter as tk
import numpy as np
from functools import partial
import pyaudio
WIDTH = 270
HEIGHT = 100
RA = 1 # kOhm
RB = 5 # kOhm
RESISTANCE = (RA + RB * 2) * 0.69
class Capacitance_NE555(object):
def __init__(self,
resistance,
rate = 44100,
frames_per_buffer = 1024):
self.py_audio = pyaudio.PyAudio()
self.resistance = resistance
self.rate = rate
self.frames_per_buffer = frames_per_buffer
self.cap_reference = None
self.ref_frequency = None
self.measure_frequency = None
def __enter__(self):
return self
def __exit__(self, *args):
self.release()
def start_stream(self):
self.stream = self.py_audio.open(format= pyaudio.paInt16,
channels = 1,
rate = self.rate,
frames_per_buffer = \
self.frames_per_buffer,
input = True)
def stop_stream(self):
self.stream.stop_stream()
self.stream.close()
def get_frequency(self, stream_data):
past_mean = False
f = 0
for data in stream_data:
if data >= np.mean(stream_data) and past_mean== False:
past_mean = True
f=f+1
elif data <= np.mean(stream_data):
past_mean = False
return f / (len(stream_data) / self.rate)
def measure(self):
frequencyies = list()
for i in range(0, int(self.rate / self.frames_per_buffer * 0.5)):
frequency = self.get_frequency(
np.frombuffer(
self.stream.read(self.frames_per_buffer),
dtype=np.int16))
frequencyies.append(frequency)
if self.ref_capacity:
self.measure_frequency = np.mean(frequencyies)
return 1 / self.measure_frequency / self.resistance * 100000000 \
- self.ref_capacity , self.measure_frequency
else:
self.ref_frequency = np.mean(frequencyies)
self.ref_capacity = 1 / self.ref_frequency / self.resistance \
* 100000000
return None, self.ref_frequency
def release(self):
self.stream.stop_stream()
self.stream.close()
self.py_audio.terminate()
class CapacitanceUI(tk.LabelFrame):
def __init__(self, parent, capacitance_ne555, width, height):
tk.LabelFrame.__init__(self, parent, text = "CAPACITANCE",
relief = "solid")
self.capacitance = capacitance_ne555
self.width = width
self.height = height
self.parent = parent
self.display_conf = {"cap" : (
self.width / 2,
self.height / 2,
"{0:2.2f} pf",
"system 18 bold",
"blue",
"cap"),
"freq" : (
self.width / 2,
20,
"{0:2.2f} Hz",
"system 10 bold",
"green",
"freq"),
"info" :(
self.width / 2,
self.height / 2,
"{0}",
"system 18 bold",
"magenta",
"info")}
self.display = tk.Canvas(self, width = width, height = height,
bg="cyan")
self.display.pack(padx = 5, pady = 5)
self.update_cap_display(0, "cap")
self.start_button = tk.Button(self, text="START", width = 7,
command = self.measure)
self.start_button.pack(side = tk.LEFT, padx = 30, pady = 5)
self.calibrate_button = tk.Button(self, text = "CALIBRATE", width = 7,
command = partial(self.measure, True))
self.calibrate_button.pack(side = tk.RIGHT, padx = 30, pady = 5)
self.measure(True)
def update_cap_display(self, text, tag):
width, height, text_conf, font, color, tag = self.display_conf[tag]
self.display.delete(tag)
self.display.create_text(width, height, text = text_conf.format(text),
font = font, fill = color,tag = tag)
def measure(self, calibrate = False):
self.display.delete("all")
self.capacitance.start_stream()
if calibrate:
self.capacitance.ref_capacity = None
capacity, frequency = self.capacitance.measure()
display_text = ["CALIBRATED", "info"] if calibrate else\
[capacity, "cap"]
self.update_cap_display(display_text[0], display_text[1])
self.update_cap_display(frequency, "freq")
self.capacitance.stop_stream()
def release(self):
self.parent.destroy()
def main():
root = tk.Tk()
root.title("CAPACITANCE")
with Capacitance_NE555(RESISTANCE) as capacitance_ne555:
capacitance_ui = CapacitanceUI(root, capacitance_ne555, WIDTH, HEIGHT)
capacitance_ui.pack(expand=tk.YES, padx=5, pady=5)
root.protocol("WM_DELETE_WINDOW",capacitance_ui.release)
root.mainloop()
if __name__ == '__main__':
main()
Re: Kapazitätsmessgerät mit dem NE555, pyaudio und tkinter
Verfasst: Samstag 16. Januar 2021, 22:10
von kaytec
Hallo,
Jetzt läuft der stream während der Messung weiter und es kann so auch der Stellbereich bei Drehkondensatoren beobachtet werden. Zu der "callback mode" habe ich nicht wirklich brauchbare Beispiele gefunden und ich hoffe meine Lösung ist ok.
Code: Alles auswählen
#/usr/bin/env python
# -*- coding: utf-8
import tkinter as tk
import numpy as np
import pyaudio
WIDTH = 270
HEIGHT = 150
RA = 1 # kOhm
RB = 5 # kOhm
RESISTANCE = (RA + RB * 2) * 0.69
class Capacitance_NE555(object):
def __init__(self,
resistance,
rate = 44100,
frames_per_buffer = 1024):
self.py_audio = pyaudio.PyAudio()
self.stream = None
self.stream_data = None
self.resistance = resistance
self.rate = rate
self.frames_per_buffer = frames_per_buffer
self.ref_capacity = None
self.ref_frequency = None
self.measure_frequency = None
def __enter__(self):
return self
def __exit__(self, *args):
self.release()
def start_stream(self):
self.stream = self.py_audio.open(format= pyaudio.paInt16,
channels = 1,
rate = self.rate,
frames_per_buffer = \
self.frames_per_buffer,
input = True,
stream_callback = self.callback)
def stop_stream(self):
if self.stream:
self.stream.stop_stream()
self.stream.close()
self.stream = None
def callback(self, in_data, frame_count, time_info, status):
self.stream_data = in_data
return (in_data, pyaudio.paContinue)
def get_frequency(self, stream_data):
past_mean = False
f = 0
for data in stream_data:
if data >= np.mean(stream_data) and past_mean== False:
past_mean = True
f=f+1
elif data <= np.mean(stream_data):
past_mean = False
return f / (len(stream_data) / self.rate)
def measure(self):
if self.stream_data:
frequencyies = list()
for i in range(0, int(self.rate / self.frames_per_buffer * 0.1)):
frequency = self.get_frequency(np.frombuffer(
self.stream_data,
dtype=np.int16))
frequencyies.append(frequency)
if self.ref_capacity:
self.measure_frequency = np.mean(frequencyies)
return 1 / self.measure_frequency / self.resistance * 100000000 \
- self.ref_capacity , self.measure_frequency
else:
self.ref_frequency = np.mean(frequencyies)
self.ref_capacity = 1 / self.ref_frequency / self.resistance \
* 100000000
return None, self.ref_frequency
def release(self):
if self.stream:
self.stop_stream()
self.py_audio.terminate()
class CapacitanceUI(tk.LabelFrame):
def __init__(self, parent, capacitance_ne555, width, height):
tk.LabelFrame.__init__(self, parent, text = "CAPACITANCE",
relief = "solid")
self.capacitance = capacitance_ne555
self.width = width
self.height = height
self.parent = parent
self.after_id = None
self.display_conf = {"cap" : (
self.width / 2,
self.height / 2,
"{0:2.2f} pf",
"system 27 bold",
"blue",
"cap"),
"freq" : (
self.width / 2,
20,
"{0:2.2f} Hz",
"system 15 bold",
"green",
"freq"),
"info" :(
self.width / 2,
self.height / 2,
"{0}",
"system 18 bold",
"magenta",
"info")}
self.display = tk.Canvas(self, width = width, height = height,
bg="cyan")
self.display.pack(padx = 5, pady = 5)
self.update_cap_display(0, "cap")
self.start_button = tk.Button(self, text="START", width = 7,
command = self.start_stop_measure)
self.start_button.pack(side = tk.LEFT, padx = 30, pady = 5)
self.calibrate_button = tk.Button(self, text = "CALIBRATE", width = 7,
command = self.calibrate)
self.calibrate_button.pack(side = tk.RIGHT, padx = 30, pady = 5)
self.calibrate()
def calibrate(self):
self.start_button.config(state = "disabled")
self.capacitance.ref_capacity = None
self.start_stop_measure()
self.after_id = self.after(100, self.start_stop_measure)
def update_cap_display(self, text, tag):
width, height, text_conf, font, color, tag = self.display_conf[tag]
self.display.delete(tag)
self.display.create_text(width, height, text = text_conf.format(text),
font = font, fill = color,tag = tag)
def start_stop_measure(self):
if self.after_id:
self.after_cancel(self.after_id)
self.after_id = None
self.start_button.config(state = "normal")
self.calibrate_button.config(state = "normal")
self.start_button.config(text = "START")
self.capacitance.stop_stream()
else:
self.calibrate_button.config(state = "disabled")
self.start_button.config(text = "STOP")
self.capacitance.start_stream()
self.measure()
def measure(self):
if self.after_id:
self.display.delete("all")
if self.capacitance.measure():
capacity, frequency = self.capacitance.measure()
self.update_cap_display(capacity, "cap")
self.update_cap_display(frequency, "freq")
self.after_id = self.after(100, self.measure)
def release(self):
if self.after_id:
self.after_cancel(self.after_id)
self.parent.destroy()
def main():
root = tk.Tk()
root.title("CAPACITANCE")
with Capacitance_NE555(RESISTANCE) as capacitance_ne555:
capacitance_ui = CapacitanceUI(root, capacitance_ne555, WIDTH, HEIGHT)
capacitance_ui.pack(expand=tk.YES, padx=5, pady=5)
root.protocol("WM_DELETE_WINDOW",capacitance_ui.release)
root.mainloop()
if __name__ == '__main__':
main()
Gruß Frank
Re: Kapazitätsmessgerät mit dem NE555, pyaudio und tkinter
Verfasst: Sonntag 17. Januar 2021, 06:17
von kaytec
Hallo,
noch Fehler behoben.
Code: Alles auswählen
#/usr/bin/env python
# -*- coding: utf-8
import tkinter as tk
import numpy as np
import pyaudio
WIDTH = 270
HEIGHT = 150
RA = 1 # kOhm
RB = 5 # kOhm
RESISTANCE = (RA + RB * 2) * 0.69
class Capacitance_NE555(object):
def __init__(self,
resistance,
rate = 44100,
frames_per_buffer = 1024):
self.py_audio = pyaudio.PyAudio()
self.stream = None
self.stream_data = None
self.resistance = resistance
self.rate = rate
self.frames_per_buffer = frames_per_buffer
self.ref_capacity = None
def __enter__(self):
return self
def __exit__(self, *args):
self.release()
def start_stream(self):
self.stream = self.py_audio.open(format= pyaudio.paInt16,
channels = 1,
rate = self.rate,
frames_per_buffer = \
self.frames_per_buffer,
input = True,
stream_callback = self.callback)
def stop_stream(self):
if self.stream:
self.stream.stop_stream()
self.stream.close()
self.stream = None
def callback(self, in_data, frame_count, time_info, status):
self.stream_data = in_data
return (in_data, pyaudio.paContinue)
def get_frequency(self, stream_data):
past_mean = False
f = 0
for data in stream_data:
if data >= np.mean(stream_data) and past_mean== False:
past_mean = True
f=f+1
elif data <= np.mean(stream_data):
past_mean = False
return f / (len(stream_data) / self.rate)
def measure(self):
if self.stream_data:
frequencyies = list()
for i in range(0, int(self.rate / self.frames_per_buffer * 0.1)):
frequency = self.get_frequency(np.frombuffer(
self.stream_data,
dtype=np.int16))
frequencyies.append(frequency)
if self.ref_capacity:
return 1 / np.mean(frequencyies) / self.resistance * 100000000 \
- self.ref_capacity , np.mean(frequencyies)
else:
ref_frequency = np.mean(frequencyies)
self.ref_capacity = 1 / ref_frequency / self.resistance \
* 100000000
return 0, ref_frequency
def release(self):
if self.stream:
self.stop_stream()
self.py_audio.terminate()
class CapacitanceUI(tk.LabelFrame):
def __init__(self, parent, capacitance_ne555, width, height):
tk.LabelFrame.__init__(self, parent, text = "CAPACITANCE",
relief = "solid")
self.capacitance = capacitance_ne555
self.width = width
self.height = height
self.parent = parent
self.after_id = None
self.display_conf = {"cap" : (
self.width / 2,
self.height / 2,
"{0:2.2f} pf",
"system 27 bold",
"blue",
"cap"),
"freq" : (
self.width / 2,
20,
"{0:2.2f} Hz",
"system 15 bold",
"green",
"freq"),
"info" :(
self.width / 2,
self.height / 2,
"{0}",
"system 18 bold",
"magenta",
"info")}
self.display = tk.Canvas(self, width = width, height = height,
bg="cyan")
self.display.pack(padx = 5, pady = 5)
self.update_cap_display(0, "cap")
self.start_button = tk.Button(self, text="START", width = 7,
command = self.start_stop_measure)
self.start_button.pack(side = tk.LEFT, padx = 30, pady = 5)
self.calibrate_button = tk.Button(self, text = "CALIBRATE", width = 7,
command = self.calibrate)
self.calibrate_button.pack(side = tk.RIGHT, padx = 30, pady = 5)
self.calibrate()
def calibrate(self):
self.start_button.config(state = "disabled")
self.capacitance.ref_capacity = None
self.start_stop_measure()
self.after_id = self.after(100, self.start_stop_measure)
def update_cap_display(self, text, tag):
width, height, text_conf, font, color, tag = self.display_conf[tag]
self.display.delete(tag)
self.display.create_text(width, height, text = text_conf.format(text),
font = font, fill = color,tag = tag)
def start_stop_measure(self):
if self.after_id:
self.after_cancel(self.after_id)
self.after_id = None
self.start_button.config(state = "normal")
self.calibrate_button.config(state = "normal")
self.start_button.config(text = "START")
self.capacitance.stop_stream()
else:
self.calibrate_button.config(state = "disabled")
self.start_button.config(text = "STOP")
self.capacitance.start_stream()
self.measure()
def measure(self):
if self.after_id:
self.display.delete("all")
capacity, frequency = self.capacitance.measure()
self.update_cap_display(capacity, "cap")
self.update_cap_display(frequency, "freq")
self.after_id = self.after(100, self.measure)
def release(self):
if self.after_id:
self.after_cancel(self.after_id)
self.parent.destroy()
def main():
root = tk.Tk()
root.title("CAPACITANCE")
with Capacitance_NE555(RESISTANCE) as capacitance_ne555:
capacitance_ui = CapacitanceUI(root, capacitance_ne555, WIDTH, HEIGHT)
capacitance_ui.pack(expand=tk.YES, padx=5, pady=5)
root.protocol("WM_DELETE_WINDOW",capacitance_ui.release)
root.mainloop()
if __name__ == '__main__':
main()
Re: Kapazitätsmessgerät mit dem NE555, pyaudio und tkinter
Verfasst: Sonntag 17. Januar 2021, 09:51
von kaytec
Hallo,
noch eine grafische Anzeige für das gemessene Signal reingebastelt.
Code: Alles auswählen
#/usr/bin/env python
# -*- coding: utf-8
import tkinter as tk
import numpy as np
import pyaudio
WIDTH = 300
HEIGHT = 170
RA = 1 # kOhm
RB = 5 # kOhm
RESISTANCE = (RA + RB * 2) * 0.69
class Capacitance_NE555(object):
def __init__(self,
resistance,
rate = 44100,
frames_per_buffer = 1024):
self.py_audio = pyaudio.PyAudio()
self.stream = None
self.stream_data = None
self.resistance = resistance
self.rate = rate
self.frames_per_buffer = frames_per_buffer
self.ref_capacity = None
def __enter__(self):
return self
def __exit__(self, *args):
self.release()
def start_stream(self):
self.stream = self.py_audio.open(format= pyaudio.paInt16,
channels = 1,
rate = self.rate,
frames_per_buffer = \
self.frames_per_buffer,
input = True,
stream_callback = self.callback)
def stop_stream(self):
if self.stream:
self.stream.stop_stream()
self.stream.close()
self.stream = None
def callback(self, in_data, frame_count, time_info, status):
self.stream_data = in_data
return (in_data, pyaudio.paContinue)
def calibrate(self):
self.ref_capacity = None
def get_frequency(self, stream_data):
past_mean = False
f = 0
for data in stream_data:
if data >= np.mean(stream_data) and past_mean== False:
past_mean = True
f=f+1
elif data <= np.mean(stream_data):
past_mean = False
return f / (len(stream_data) / self.rate)
def measure(self):
if self.stream_data:
frequencyies = list()
stream_data = list()
for i in range(0, int(self.rate / self.frames_per_buffer * 0.1)):
np_data = np.frombuffer(self.stream_data,
dtype = np.int16)
frequency = self.get_frequency(np_data)
stream_data.append(np_data)
frequencyies.append(frequency)
if self.ref_capacity:
return 1 / np.mean(frequencyies) / self.resistance * 100000000 \
- self.ref_capacity , np.mean(frequencyies), stream_data
else:
ref_frequency = np.mean(frequencyies)
self.ref_capacity = 1 / ref_frequency / self.resistance \
* 100000000
return 0, ref_frequency, None
def release(self):
if self.stream:
self.stop_stream()
self.py_audio.terminate()
class CapacitanceUI(tk.LabelFrame):
def __init__(self, parent, capacitance_ne555, width, height):
tk.LabelFrame.__init__(self, parent, text = "CAPACITANCE",
relief = "solid")
self.capacitance = capacitance_ne555
self.width = width
self.height = height
self.parent = parent
self.after_id = None
self.display_conf = {"cap" : (
self.width / 2,
self.height / 2 - 10,
"{0:2.2f} pf",
"system 27 bold",
"blue",
"cap"),
"freq" : (
self.width / 2,
20,
"{0:2.2f} Hz",
"system 15 bold",
"green",
"freq"),
"info" :(
self.width / 2,
self.height / 2,
"{0}",
"system 18 bold",
"magenta",
"info")}
self.display = tk.Canvas(self, width = width, height = height,
bg="cyan")
self.display.pack(padx = 5, pady = 5)
self.update_cap_display(0, "cap")
self.start_button = tk.Button(self, text="START", width = 7,
command = self.start_stop_measure)
self.start_button.pack(side = tk.LEFT, padx = 30, pady = 5)
self.calibrate_button = tk.Button(self, text = "CALIBRATE", width = 7,
command = self.calibrate)
self.calibrate_button.pack(side = tk.RIGHT, padx = 30, pady = 5)
self.calibrate()
def calibrate(self):
for x in range(self.width):
self.display.delete("freq_line{0}".format(x))
self.start_button.config(state = "disabled")
self.capacitance.calibrate()
self.start_stop_measure()
self.after_id = self.after(100, self.start_stop_measure)
def update_cap_display(self, text, tag):
width, height, text_conf, font, color, tag = self.display_conf[tag]
self.display.delete(tag)
self.display.create_text(width, height, text = text_conf.format(text),
font = font, fill = color,tag = tag)
def update_signal_line(self, points, tag):
self.display.delete(tag)
x, y, x_2, y_2 = points
self.display.create_line(x, y, x_2, y_2, tag = tag )
def start_stop_measure(self):
if self.after_id:
self.after_cancel(self.after_id)
self.after_id = None
self.start_button.config(state = "normal")
self.calibrate_button.config(state = "normal")
self.start_button.config(text = "START")
self.capacitance.stop_stream()
else:
self.calibrate_button.config(state = "disabled")
self.start_button.config(text = "STOP")
self.capacitance.start_stream()
self.measure()
def measure(self):
if self.after_id:
capacity, frequency, np_data = self.capacitance.measure()
self.update_cap_display(capacity, "cap")
self.update_cap_display(frequency, "freq")
start_x, start_y = 0, 0
self.update_signal_line((0,
self.height - 30,
self.width,
self.height - 30),
"zero_line")
if np_data:
for data in np_data[-1][0: self.width]:
data = data / self.height
self.update_signal_line((start_x,
start_y + self.height - 30,
start_x + 1,
data + self.height - 30),
"freq_line{0}".format(start_x))
start_x += 1
start_y = data
self.after_id = self.after(100, self.measure)
def release(self):
if self.after_id:
self.after_cancel(self.after_id)
self.parent.destroy()
def main():
root = tk.Tk()
root.title("CAPACITANCE")
with Capacitance_NE555(RESISTANCE) as capacitance_ne555:
capacitance_ui = CapacitanceUI(root, capacitance_ne555, WIDTH, HEIGHT)
capacitance_ui.pack(expand=tk.YES, padx=5, pady=5)
root.protocol("WM_DELETE_WINDOW",capacitance_ui.release)
root.mainloop()
if __name__ == '__main__':
main()
Gruß Frank
Re: Kapazitätsmessgerät mit dem NE555, pyaudio und tkinter
Verfasst: Sonntag 17. Januar 2021, 10:29
von Sirius3
Wenn ich so einen Code sehe, kann ich nicht still bleiben:
Code: Alles auswählen
def get_frequency(self, stream_data):
past_mean = False
f = 0
for data in stream_data:
if data >= np.mean(stream_data) and past_mean== False:
past_mean = True
f=f+1
elif data <= np.mean(stream_data):
past_mean = False
return f / (len(stream_data) / self.rate)
Du rechnest für jeden Datenpunkt zwei mal den Mittelwert über alle Datenpunkte aus. So viel Rechenzeitverschwendung kommt mir selten unter.
Code: Alles auswählen
def get_frequency(self, stream_data):
past_mean = False
f = 0
stream_mean = np.mean(stream_data)
for data in stream_data:
if data >= stream_mean and past_mean == False:
past_mean = True
f += 1
elif data <= stream_mean:
past_mean = False
return f / (len(stream_data) / self.rate)
Und das ganze kann man natürlich mit numpy noch vektorisieren:
Code: Alles auswählen
def get_frequency(self, stream_data):
stream_mean = np.mean(stream_data)
past_mean = (stream_data > stream_mean).astype(int)
f = (np.diff(past_mean) > 0).sum()
return f / (len(stream_data) / self.rate)
In der nächsten Methode rechnest Du auch vieles doppelt. Die for-Schleife und damit die ganze Funktion machen auf den ersten Blick nichts sinnvolles:
Code: Alles auswählen
def measure(self):
if self.stream_data:
frequencyies = list()
stream_data = list()
for i in range(int(self.rate / self.frames_per_buffer * 0.1)):
# TODO: get new stream_data from anywhere
np_data = np.frombuffer(self.stream_data, dtype=np.int16)
frequency = self.get_frequency(np_data)
stream_data.append(np_data)
frequencyies.append(frequency)
ref_frequency = np.mean(frequencyies)
capacity = 1 / ref_frequency / self.resistance * 100000000
if not self.ref_capacity:
self.ref_capacity = capacity
stream_data = None
return capacity - self.ref_capacity, ref_frequency, stream_data
# TODO: what happens in this case?
raise RuntimeError("no stream data")
Re: Kapazitätsmessgerät mit dem NE555, pyaudio und tkinter
Verfasst: Sonntag 17. Januar 2021, 11:07
von kaytec
Danke Sirius3,
- die Verschwendung der Rechenzeit war mir nicht bewusst bei "np.mean ()"
- das Vektorisieren sieht schön aus, doch die Messergebnisse und die grafische Anzeige stimmt nicht mehr - habe das Signal mit meiner Version und
Audacity verglichen. Beide sehen mal gleich aus !
- Die Daten aus dem "Inputstream" kommen kontinuierlich aus:
Code: Alles auswählen
def callback(self, in_data, frame_count, time_info, status):
self.stream_data = in_data
return (in_data, pyaudio.paContinue)
- mit "if self.stream_data:" warte ich nur bis der stream auch wiklich läuft.
Gruß Frank
Re: Kapazitätsmessgerät mit dem NE555, pyaudio und tkinter
Verfasst: Sonntag 17. Januar 2021, 11:36
von Sirius3
Die kommen eben nicht kontinuierlich, weil Du die beiden Funktionen nicht synchronisierst. Alles ist sehr fragil und nicht robust. Benutzte Queues, um die Daten vom Callback in die anderen Funktionen zu übertragen.
Re: Kapazitätsmessgerät mit dem NE555, pyaudio und tkinter
Verfasst: Sonntag 17. Januar 2021, 12:14
von kaytec
Hallo Sirius3,
du wirst recht haben, doch ich habe natürlich mit meinem Halbwissen und meinen amateurhaften Schätzgeräten die Funktion überprüft. Die Werte sind recht genau und auch die Überprüfung mit einem Signalgenerator (Handy) hat immer eine aktuelle Änderung des grafischen Signals (bis 20Khz) zur Folge. Es wird auch immer die gerade gewählte Wellenform angezeigt (Sinus, Square, Saw). Die Änderung der Kondensatoren im laufenden Betrieb ergibt auch eine sofortige Werteänderung in der Anzeige. So müssten der Stream doch sehr kontinuierlich und aktuell sein ?
Gruß
Re: Kapazitätsmessgerät mit dem NE555, pyaudio und tkinter
Verfasst: Sonntag 17. Januar 2021, 12:23
von __deets__
Es liegt in der Natur solcher Probleme, dass die oft nicht schwarz-weiss sind. Dein jetziger Code arbeitet asynchron vor sich hin. Das fuehrt dazu, dass er im Zweifel den gleichen Buffer mehrfach bearbeitet, oder mal einen ueberspringt. Das kann man natuerlich unterschiedlich bewerten, aber erstmal ist das ein Fakt, und fuehrt zu glitches.
Wenn du das besser machen *willst*, dann kannst du eben eine Queue benutzen, um die Frames oder besser noch das Ergebnis von measure zu buffern, und im after-Handler dann eben ggf. mehrere Werte nacheinander zu updaten, oder mal auszusetzen.
Re: Kapazitätsmessgerät mit dem NE555, pyaudio und tkinter
Verfasst: Sonntag 17. Januar 2021, 12:30
von kaytec
Danke __deets__,
Ich möchte es natürlich besser machen - falls es meine Fähigkeiten zulassen. Ich arbeite mit Menschen und da ist die Welt nur in allen Farben schön - auch mit allen Problemen, die mit dieser Vielfältigkeit einhergehen.
Gruß
Re: Kapazitätsmessgerät mit dem NE555, pyaudio und tkinter
Verfasst: Sonntag 17. Januar 2021, 12:36
von __deets__
Ausser einer eher unterhaendigen Unterstellung, dass Leute, die nicht mit Menschen arbeiten, eine eher Einfaeltige und wenig bunte Welt um sich herum haben, kann ich mit diesem Satz nichts anfangen. Ein Bezug zu diesem Problem jedenfalls wird mir nicht ersichlich. Aber ich arbeite auch nicht mit Menschen, sondern nur mit Computern.
Re: Kapazitätsmessgerät mit dem NE555, pyaudio und tkinter
Verfasst: Sonntag 17. Januar 2021, 12:44
von kaytec
Hallo __deets__,
war keine Anspielung, sondern nur ein Vergleich zu "schwarz-weiss". Wollte dir nicht auf die Füße treten !
Gruß
Re: Kapazitätsmessgerät mit dem NE555, pyaudio und tkinter
Verfasst: Montag 25. Januar 2021, 21:03
von kaytec
Hallo,
ein Versuch ohne Messung - nur mit Ausgabe der Streamdaten.
Code: Alles auswählen
#/usr/bin/env python
# -*- coding: utf-8
import tkinter as tk
import numpy as np
import pyaudio
import time
from threading import Thread, Event
from functools import partial
import queue
WIDTH = 256
HEIGHT = 200
MEASURE_TIME = 0.025
class ReadLineInAudioThreadClient(object):
def __init__(self, queue):
self.queue = queue
self.run_event = None
def stop(self):
self.run_event.set()
def start(self, measure_time):
self.run_event = Event()
self.thread = Thread(target=partial (self.worker_thread,
measure_time))
self.thread.daemon = True
self.thread.start()
def worker_thread(self, measure_time):
with ReadLineInAudio(measure_time) \
as read_line_in_audio:
read_line_in_audio.start_stream()
while not self.run_event.is_set():
self.queue.put(read_line_in_audio.read_data())
self.run_event.wait(measure_time)
class ReadLineInAudio(object):
def __init__(self,
measure_time,
channels = 1,
rate = 44100,
frames_per_buffer = 256):
self.py_audio = pyaudio.PyAudio()
self.rate = rate
self.frames_per_buffer = frames_per_buffer
self.measure_time = measure_time
self.channels = channels
def __enter__(self):
return self
def __exit__(self, *args):
self.release()
def start_stream(self):
self.stream = self.py_audio.open(format= pyaudio.paInt16,
channels = self.channels,
rate = self.rate,
frames_per_buffer = \
self.frames_per_buffer,
input = True,
stream_callback = self.callback)
time.sleep(0.1)
def callback(self, in_data, frame_count, time_info, status):
self.stream_data = in_data
return (in_data, pyaudio.paContinue)
def read_data(self):
return np.frombuffer(self.stream_data,
dtype = np.int16)
def release(self):
try:
self.stream.stop_stream()
self.stream.close()
except AttributeError as er:
print(er)
self.py_audio.terminate()
class CapacitanceUI(tk.LabelFrame):
def __init__(self,
parent,
width,
height,
measure_time):
tk.LabelFrame.__init__(self, parent, text = "LINE_IN",
relief = "solid")
self.queue = queue.Queue()
self.read_line_in_audio_thread_client = \
ReadLineInAudioThreadClient(self.queue)
self.measure_time = measure_time
self.width = width
self.height = height
self.parent = parent
self.after_id = None
self.display = tk.Canvas(self, width = width, height = height,
bg = "black")
self.display.pack(padx = 5, pady = 5)
self.start_button = tk.Button(self, text = "START", width = 7,
command = self.start_measure)
self.start_button.pack(side = tk.LEFT, padx = 30, pady = 5)
self.stop_button = tk.Button(self, text = "STOP", width = 7,
command = self.stop_measure)
self.stop_button.pack(side = tk.RIGHT, padx = 30, pady = 5)
self.stop_button.config(state = "disabled")
def start_measure(self):
self.start_button.config(state = "disabled")
self.stop_button.config(state = "normal")
self.read_line_in_audio_thread_client.start(self.measure_time)
self.measure()
def stop_measure(self):
self.after_cancel(self.after_id)
self.read_line_in_audio_thread_client.stop()
self.start_button.config(state = "normal")
self.stop_button.config(state = "disabled")
def update_signal_line(self, points, tag):
self.display.delete(tag)
self.display.create_line(points, tag = tag, fill = "lightgreen")
def measure(self):
if not self.queue.empty():
while True:
try:
np_data = self.queue.get_nowait()
start_x, start_y = 0, 0
for data in np_data:
self.update_signal_line((start_x,
start_y + self.height / 2,
start_x + 1,
data + self.height / 2),
"freq_line{0}".format(
start_x))
start_x += 1
start_y = data
except queue.Empty:
break
self.after_id = self.after(int(self.measure_time * 1000),
self.measure)
def release(self):
if self.after_id:
self.after_cancel(self.after_id)
self.parent.destroy()
def main():
root = tk.Tk()
capacitance_ui = CapacitanceUI(root,
WIDTH,
HEIGHT,
MEASURE_TIME)
capacitance_ui.pack(expand=tk.YES, padx=5, pady=5)
root.protocol("WM_DELETE_WINDOW",capacitance_ui.release)
root.mainloop()
if __name__ == '__main__':
main()
Gruß Frank
Re: Kapazitätsmessgerät mit dem NE555, pyaudio und tkinter
Verfasst: Mittwoch 27. Januar 2021, 20:39
von Sirius3
`Thread` hat sowohl ein args-Argument als auch ein daemon.
Den Sinn der ReadLineInAudioThreadClient-Klasse verstehe ich nicht, da py_audio doch mit Callbacks arbeitet.
AttributeError ist eher eine Programmierfehler, als dass man es sinnvoll in einem Programm einsetzen kann.
Code: Alles auswählen
class ReadLineInAudio(object):
def __init__(self,
queue,
measure_time,
channels = 1,
rate = 44100,
frames_per_buffer = 256):
self.py_audio = self.stream = None
self.queue = queue
self.rate = rate
self.frames_per_buffer = frames_per_buffer
self.measure_time = measure_time
self.channels = channels
def __enter__(self):
self.start_stream()
return self
def __exit__(self, *args):
self.release()
def start_stream(self):
self.py_audio = pyaudio.PyAudio()
self.stream = self.py_audio.open(format=pyaudio.paInt16,
channels=self.channels,
rate=self.rate,
frames_per_buffer=self.frames_per_buffer,
input=True,
stream_callback=self.callback)
def callback(self, in_data, frame_count, time_info, status):
self.queue.put(np.frombuffer(in_data, dtype=np.int16))
return (in_data, pyaudio.paContinue)
def release(self):
if self.stream is not None:
self.stream.stop_stream()
self.stream.close()
self.py_audio.terminate()
self.stream = None
Re: Kapazitätsmessgerät mit dem NE555, pyaudio und tkinter
Verfasst: Mittwoch 27. Januar 2021, 22:05
von kaytec
Danke Sirius3,
das mit der den Callbacks steht auch so in der Doku und so hatte ich es auch eingebaut, damit die GUI nicht einfriert. Deets erwähnte ja Queues und die hatte ich mit einem eigenen Thread verbunden. Da fehlt mir halt Grundverständnis der Thematik ! Der AttributeError entsteht, wenn die GUI ohne gestarteten Stream geschlossen wird. Mit der Exception habe ich diese Fehlermeldung ausgeschlossen. Welche Menge an Daten machen beim Einlesen eigentlich Sinn ?
Gruß Frank
Re: Kapazitätsmessgerät mit dem NE555, pyaudio und tkinter
Verfasst: Mittwoch 27. Januar 2021, 23:32
von __blackjack__
@kaytec: Der `AttributeError` kann also nur passieren weil in der `__init__()` nicht alle Attribute angelegt werden. Sollten sie aber. Wenn es noch keinen Wert dafür gibt, dann halt mit `None`.
Re: Kapazitätsmessgerät mit dem NE555, pyaudio und tkinter
Verfasst: Donnerstag 28. Januar 2021, 21:21
von kaytec
Hallo,
nach einem Durchlauf wird "release()" ausgelöst ?
Code: Alles auswählen
import numpy as np
import pyaudio
import time
from threading import Thread, Event
from functools import partial
import queue
WIDTH = 256
HEIGHT = 200
MEASURE_TIME = 0.025
class ReadLineInAudio(object):
def __init__(self,
queue,
measure_time,
channels = 1,
rate = 44100,
frames_per_buffer = 256):
self.py_audio = self.stream = None
self.queue = queue
self.rate = rate
self.frames_per_buffer = frames_per_buffer
self.measure_time = measure_time
self.channels = channels
def __enter__(self):
self.start_stream()
return self
def __exit__(self, *args):
self.release()
def start_stream(self):
self.py_audio = pyaudio.PyAudio()
self.stream = self.py_audio.open(format=pyaudio.paInt16,
channels=self.channels,
rate=self.rate,
frames_per_buffer=self.frames_per_buffer,
input=True,
stream_callback=self.callback)
def callback(self, in_data, frame_count, time_info, status):
self.queue.put(np.frombuffer(in_data, dtype=np.int16))
return (in_data, pyaudio.paContinue)
def release(self):
if self.stream is not None:
self.stream.stop_stream()
self.stream.close()
self.py_audio.terminate()
self.stream = None
class CapacitanceUI(tk.LabelFrame):
def __init__(self,
parent,
width,
height,
measure_time):
tk.LabelFrame.__init__(self, parent, text = "LINE_IN",
relief = "solid")
self.measure_time = measure_time
self.width = width
self.height = height
self.parent = parent
self.after_id = None
self.last_start_y = 0
self.queue = queue.Queue()
self.display = tk.Canvas(self, width = width, height = height,
bg = "black")
self.display.pack(padx = 5, pady = 5)
self.start_button = tk.Button(self, text = "START", width = 7,
command = self.start_measure)
self.start_button.pack(side = tk.LEFT, padx = 30, pady = 5)
self.stop_button = tk.Button(self, text = "STOP", width = 7,
command = self.stop_measure)
self.stop_button.pack(side = tk.RIGHT, padx = 30, pady = 5)
self.stop_button.config(state = "disabled")
def start_measure(self):
self.start_button.config(state = "disabled")
self.stop_button.config(state = "normal")
with ReadLineInAudio(self.queue, self.measure_time) as real_line_in_audio:
self.measure()
def stop_measure(self):
self.after_cancel(self.after_id)
self.stop_button.config(state = "disabled")
self.start_button.config(state = "normal")
def update_signal_line(self, points, tag):
self.display.delete(tag)
self.display.create_line(points, tag = tag, fill = "lightgreen")
def measure(self):
if not self.queue.empty():
while True:
try:
np_data = self.queue.get_nowait()
start_x = 0
for data in np_data:
self.update_signal_line((start_x,
self.last_start_y + self.height / 2,
start_x + 1,
data + self.height / 2),
"freq_line{0}".format(
start_x))
start_x += 1
self.last_start_y = data
except queue.Empty:
break
self.after_id = self.after(int(self.measure_time * 1000),
self.measure)
def release(self):
if self.after_id:
self.after_cancel(self.after_id)
self.parent.destroy()
def main():
root = tk.Tk()
capacitance_ui = CapacitanceUI(root,
WIDTH,
HEIGHT,
MEASURE_TIME)
capacitance_ui.pack(expand=tk.YES, padx = 5, pady = 5)
root.protocol("WM_DELETE_WINDOW",capacitance_ui.release)
root.mainloop()
if __name__ == '__main__':
main()
Gruß Frank