Better documentation + examples
This commit is contained in:
43
examples/common.py
Normal file
43
examples/common.py
Normal file
@@ -0,0 +1,43 @@
|
||||
import math
|
||||
import sys
|
||||
from typing import Literal
|
||||
|
||||
from fn_gen import DG2052
|
||||
|
||||
|
||||
N_CYCLES = 500 # Cycles
|
||||
AMPLIFICATION = 13/2 # dB
|
||||
V_STEPS = 10 # steps
|
||||
F_STEPS = 30 # steps
|
||||
FREQ_START = 10 # Hz
|
||||
FREQ_STOP = 1000 # Hz
|
||||
STEP_DURATION = 10 # sec
|
||||
|
||||
|
||||
def abs(x) -> float:
|
||||
"""
|
||||
Gets the absolute value of the input.
|
||||
"""
|
||||
return math.sqrt(x * x)
|
||||
|
||||
|
||||
def close_output(fg: DG2052, channel: Literal[1, 2]):
|
||||
"""
|
||||
Closes the output channel of the function generator.
|
||||
"""
|
||||
fg.set_output(channel, False)
|
||||
fg.close()
|
||||
sys.exit(0)
|
||||
|
||||
|
||||
def get_preamplified(amplification: float, post: float) -> float:
|
||||
"""
|
||||
Calculates the pre amplification value from the amplification and the post amplification value.
|
||||
"""
|
||||
return post / (10 ** (amplification / 20))
|
||||
|
||||
def get_postamplified(amplification: float, pre: float) -> float:
|
||||
"""
|
||||
Calculates the pre amplification value from the amplification and the post amplification value.
|
||||
"""
|
||||
return pre * (10 ** (amplification / 20))
|
||||
137
examples/discrete_sweep.py
Normal file
137
examples/discrete_sweep.py
Normal file
@@ -0,0 +1,137 @@
|
||||
import time
|
||||
import argparse
|
||||
import fn_gen.errors as fg_err
|
||||
from common import (
|
||||
close_output,
|
||||
get_preamplified,
|
||||
get_postamplified,
|
||||
AMPLIFICATION,
|
||||
N_CYCLES,
|
||||
V_STEPS,
|
||||
F_STEPS,
|
||||
FREQ_START,
|
||||
FREQ_STOP,
|
||||
STEP_DURATION,
|
||||
)
|
||||
from fn_gen import DG2052
|
||||
import numpy as np
|
||||
|
||||
|
||||
def calculate_n_samples(freq: float, ts: float, n_cycles: int) -> int:
|
||||
"""
|
||||
Calculates the number of samples based on the frequency of the signal, the sampling time and the number of cycles within one step.
|
||||
|
||||
Parameters
|
||||
---------
|
||||
freq: int
|
||||
The frequency of the signal
|
||||
ts: float
|
||||
The sampling time
|
||||
n_cycles: int
|
||||
The number of cycles within a step
|
||||
|
||||
Returns
|
||||
------
|
||||
n_samples: int
|
||||
The number of samples (can be multiplied by the sampling time (ts) to get the total duration)
|
||||
"""
|
||||
return int(round(n_cycles / (ts * freq)))
|
||||
|
||||
|
||||
def discrete_sweep(
|
||||
v_min: float,
|
||||
v_max: float,
|
||||
v_steps: int,
|
||||
adaptive: bool,
|
||||
step_duration: int,
|
||||
freq_start: int,
|
||||
freq_stop: int,
|
||||
f_steps: int,
|
||||
):
|
||||
##################### PROGRAM START ###########
|
||||
freqs = np.logspace(np.log10(freq_start), np.log10(freq_stop), f_steps)
|
||||
v_min = get_preamplified(AMPLIFICATION, v_min)
|
||||
v_max = get_preamplified(AMPLIFICATION, v_max)
|
||||
volts = np.linspace(v_min, v_max, v_steps)
|
||||
print(freqs)
|
||||
fg = DG2052("TCPIP::192.168.1.11::INSTR")
|
||||
channel = 2
|
||||
try:
|
||||
print(fg.whoami())
|
||||
print("")
|
||||
print(f"Output{channel} Impedance: {fg.get_output_impedance(channel)} Ohm")
|
||||
print(f"Output{channel} Load: {fg.get_output_load(channel)} Ohm")
|
||||
print(f"Output{channel} Voltage Limits: {fg.get_output_volt_limits(channel)} V")
|
||||
for v in volts:
|
||||
for freq in freqs:
|
||||
sampling_rate = 10 * freq
|
||||
n_samples = calculate_n_samples(freq, 1 / sampling_rate, N_CYCLES)
|
||||
if adaptive:
|
||||
step_duration = n_samples * (1 / sampling_rate)
|
||||
print(f"V: {get_postamplified(AMPLIFICATION, v)} V")
|
||||
print(f"Freq: {freq} Hz")
|
||||
print(f"Duration: {step_duration} s")
|
||||
print(f"N_Samples: {n_samples} samples")
|
||||
fg.set_output(channel, False)
|
||||
fg.set_sine_wave(channel, freq, v, 0, 0)
|
||||
fg.set_output(channel, True)
|
||||
print(
|
||||
f"Output{channel}: {fg.get_output_signal(channel)} | {fg.get_output_state(channel)}"
|
||||
)
|
||||
time.sleep(step_duration)
|
||||
# fg.set_output(channel, False)
|
||||
print(f"Output{channel} State: {fg.get_output_state(channel)}")
|
||||
except fg_err.ValueOutOfBoundsError as err:
|
||||
print(err)
|
||||
except fg_err.UndefinedValueError as err:
|
||||
print(err)
|
||||
except KeyboardInterrupt:
|
||||
close_output(fg, channel)
|
||||
finally:
|
||||
close_output(fg, channel)
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
parser = argparse.ArgumentParser(
|
||||
description="This program is for testing the DG2052 function genrator library. It does a discrete sweep with the supplied parameters."
|
||||
)
|
||||
parser.add_argument(
|
||||
"--vmin", type=float, required=True, help="The minimum voltage supplied"
|
||||
)
|
||||
parser.add_argument(
|
||||
"--vmax", type=float, required=True, help="The maximum voltage supplied"
|
||||
)
|
||||
parser.add_argument(
|
||||
"--v-steps", type=int, default=V_STEPS, help="The number of voltage steps"
|
||||
)
|
||||
parser.add_argument(
|
||||
"--freq-start", type=int, default=FREQ_START, help="The starting frequency"
|
||||
)
|
||||
parser.add_argument(
|
||||
"--freq-stop", type=int, default=FREQ_STOP, help="The stop frequency"
|
||||
)
|
||||
parser.add_argument(
|
||||
"--f-steps", type=int, default=F_STEPS, help="The number of steps"
|
||||
)
|
||||
parser.add_argument(
|
||||
"--step-duration",
|
||||
type=int,
|
||||
default=STEP_DURATION,
|
||||
help="The duration of each step",
|
||||
)
|
||||
parser.add_argument(
|
||||
"--adaptive-step",
|
||||
action="store_true",
|
||||
help="Adapts the step duration to the frequency of the step",
|
||||
)
|
||||
args = parser.parse_args()
|
||||
discrete_sweep(
|
||||
v_min=args.vmin,
|
||||
v_max=args.vmax,
|
||||
v_steps=args.v_steps,
|
||||
adaptive=args.adaptive_step,
|
||||
step_duration=args.step_duration,
|
||||
freq_start=args.freq_start,
|
||||
freq_stop=args.freq_stop,
|
||||
f_steps=args.f_steps,
|
||||
)
|
||||
@@ -12,13 +12,12 @@ def generate_sine_wave(v: float, freq: int, phase: int):
|
||||
try:
|
||||
print(fg.whoami())
|
||||
print("")
|
||||
# input("Press Enter to start...")
|
||||
fg.set_sine_wave(channel, freq, v, 0, phase)
|
||||
print(
|
||||
f"Output{channel}: {fg.get_output_signal(channel)} | {fg.get_output_state(channel)}"
|
||||
)
|
||||
fg.set_output(channel, True)
|
||||
print(f"Voltage: {get_postamplified(AMPLIFICATION, v):.2f} V")
|
||||
print(f"Voltage: {get_postamplified(AMPLIFICATION, v):.2f} V | Pre_amplified: {v} V")
|
||||
print(f"Frequency: {freq} Hz")
|
||||
print(f"Output{channel} State: {fg.get_output_state(channel)}")
|
||||
while True:
|
||||
|
||||
6
examples/stop_channels.py
Normal file
6
examples/stop_channels.py
Normal file
@@ -0,0 +1,6 @@
|
||||
from fn_gen import DG2052
|
||||
|
||||
if __name__ == "__main__":
|
||||
fg = DG2052("TCPIP::192.168.1.11::INSTR")
|
||||
for channel in [1, 2]:
|
||||
fg.set_output(channel, False)
|
||||
135
examples/sweep_2.py
Normal file
135
examples/sweep_2.py
Normal file
@@ -0,0 +1,135 @@
|
||||
import time
|
||||
import argparse
|
||||
|
||||
import fn_gen.errors as fg_err
|
||||
from common import close_output, abs, get_preamplified
|
||||
from fn_gen import DG2052
|
||||
from fn_gen.enums import SweepSignalType, SweepSpacing, SweepTriggerSource
|
||||
|
||||
|
||||
def sweep_over_signal(
|
||||
signal: str,
|
||||
v_min: float,
|
||||
v_max: float,
|
||||
delay: int,
|
||||
duration: int,
|
||||
freq_start: int,
|
||||
freq_stop: int,
|
||||
phase: int,
|
||||
spacing: str,
|
||||
):
|
||||
fg = DG2052("TCPIP::192.168.1.11::INSTR")
|
||||
v_min = get_preamplified(13.0, v_min)
|
||||
v_max = get_preamplified(13.0, v_max)
|
||||
v = (v_max - v_min)/2
|
||||
channel = 2
|
||||
# signal_type = SweepSignalType.SINE
|
||||
match signal:
|
||||
case "sine":
|
||||
fg.set_sine_wave(channel, freq_start, v, 0, 0)
|
||||
case "square":
|
||||
fg.set_square_wave(channel, freq_start, v, 0, 0)
|
||||
case "ramp":
|
||||
fg.set_ramp(channel, freq_start, v, 0, 0)
|
||||
spacing_type = SweepSpacing.LOG
|
||||
match spacing:
|
||||
case "lin":
|
||||
spacing_type = SweepSpacing.LIN
|
||||
case "log":
|
||||
spacing_type = SweepSpacing.LOG
|
||||
try:
|
||||
print(fg.whoami())
|
||||
print(f"\nOutput{channel} Impedance: {fg.get_output_impedance(channel)} Ohm")
|
||||
print(f"Output{channel} Load: {fg.get_output_load(channel)} Ohm")
|
||||
print(f"Output{channel} Voltage Limits: {fg.get_output_volt_limits(channel)} V")
|
||||
print(
|
||||
f"Output{channel}: {fg.get_output_signal(channel)} | {fg.get_output_state(channel)}"
|
||||
)
|
||||
fg.set_output(channel, True)
|
||||
time.sleep(delay)
|
||||
# fg.trigger_sweep(channel)
|
||||
t0 = time.time()
|
||||
t1 = time.time()
|
||||
freq = freq_start
|
||||
freq_delta = (freq_stop - freq_start) / (duration*10_000)
|
||||
while (t1 - t0) < duration:
|
||||
print(f"Current Frequency: {fg.get_output_signal(channel)}")
|
||||
if spacing_type == SweepSpacing.LIN:
|
||||
freq = freq + freq_delta
|
||||
match signal:
|
||||
case "sine":
|
||||
fg.set_sine_wave(channel, freq, v, 0, 0)
|
||||
case "square":
|
||||
fg.set_square_wave(channel, freq, v, 0, 0)
|
||||
case "ramp":
|
||||
fg.set_ramp(channel, freq, v, 0, 0)
|
||||
time.sleep(0.0001)
|
||||
t1 = time.time()
|
||||
print(f"Output{channel} State: {fg.get_output_state(channel)}")
|
||||
except fg_err.ValueOutOfBoundsError as err:
|
||||
print(err)
|
||||
except fg_err.UndefinedValueError as err:
|
||||
print(err)
|
||||
except KeyboardInterrupt:
|
||||
pass
|
||||
finally:
|
||||
close_output(fg, channel)
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
parser = argparse.ArgumentParser(
|
||||
description="This program is for testing the DG2052 function genrator library. It sweeps over a signal with the supplied parameters."
|
||||
)
|
||||
parser.add_argument(
|
||||
"-s",
|
||||
"--signal",
|
||||
type=str,
|
||||
choices=["sine", "square", "ramp"],
|
||||
default="sine",
|
||||
help='The type of signal being sweeped',
|
||||
)
|
||||
parser.add_argument(
|
||||
"--vmin", type=float, default=0, help="The minimum voltage supplied"
|
||||
)
|
||||
parser.add_argument(
|
||||
"--vmax", type=float, default=1, help="The maximum voltage supplied"
|
||||
)
|
||||
parser.add_argument(
|
||||
"-d",
|
||||
"--delay",
|
||||
type=int,
|
||||
default=0,
|
||||
help="The buffer time before the sweep starts",
|
||||
)
|
||||
parser.add_argument(
|
||||
"--duration", type=int, default=5 * 60, help="The duration of the sweep"
|
||||
)
|
||||
parser.add_argument(
|
||||
"--freq-start", type=int, default=10, help="The start frequency of the sweep"
|
||||
)
|
||||
parser.add_argument(
|
||||
"--freq-stop", type=int, default=1000, help="The stop frequency of the sweep"
|
||||
)
|
||||
parser.add_argument(
|
||||
"-p",
|
||||
"--phase",
|
||||
type=int,
|
||||
default=0,
|
||||
help="The phase shift of the signal generated (must be between 0 and 360)",
|
||||
)
|
||||
parser.add_argument(
|
||||
"--spacing",
|
||||
type=str,
|
||||
choices=["lin", "log"],
|
||||
default="log",
|
||||
help='The spacing of the sweep',
|
||||
)
|
||||
args = parser.parse_args()
|
||||
if (
|
||||
args.phase not in range(0, 360)
|
||||
or args.spacing not in ["lin", "log"]
|
||||
or args.signal not in ["sine", "square", "ramp"]
|
||||
):
|
||||
parser.print_help()
|
||||
exit(1)
|
||||
sweep_over_signal(args.signal, args.vmin, args.vmax, args.delay, args.duration, args.freq_start, args.freq_stop, args.phase, args.spacing)
|
||||
Reference in New Issue
Block a user