-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathramp_voltage.py
More file actions
180 lines (146 loc) · 6.35 KB
/
Copy pathramp_voltage.py
File metadata and controls
180 lines (146 loc) · 6.35 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
"""
De-icing ramp logger for RTB2004 - AUTOMATIC drive-voltage from monitor.
Saves results to a clean EXCEL (.xlsx) file with proper rows and columns.
Setup (confirmed):
CH1 = amplifier MONITOR output (factor 1000:1)
-> real drive voltage at piezo = monitor reading * 1000
CH2 = accelerometer (PCB 352C65, 100 mV/g) via 480E09 power unit (GAIN = 1)
-> converted to displacement in mm
How it works:
- Logs to a backup .txt continuously during the run (so nothing is lost).
- When you press Ctrl+C, it writes a clean .xlsx with proper columns.
- Prints each reading live so you watch displacement rise as you ramp by hand.
Excel columns:
timestamp | drive_Vpp_at_piezo | frequency_Hz | accel_amp_mV |
acceleration_m_s2 | displacement_mm | displacement_um
Needs the openpyxl library (one-time): pip install openpyxl
IMPORTANT before running:
- Scope: FFT OFF, ~1 ms/div, stable trigger (trigger on C1), clean sines on both.
- CH2 accelerometer not clipped, especially at high drive.
- Amplifier Ampl. knob fixed for the whole ramp.
"""
import pyvisa
import numpy as np
import os
import time
from datetime import datetime
# ---------------- SETTINGS YOU MAY CHANGE ----------------
SCOPE_ADDR = "USB0::0x0AAD::0x01D6::206330::INSTR"
DRIVE_CH = 1
ACCEL_CH = 2
MONITOR_FACTOR = 1000.0
SENS_MV_PER_G = 100.0
GAIN = 1
G_TO_MS2 = 9.80665
LOG_INTERVAL = 2.0
DRIVE_FREQ = 500.0 # drive frequency in Hz that you set on the generator.
# Change this ONLY when you test a different frequency.
SAVE_DIR = r"C:\Users\thot_ni\Documents\Post processing\Excel data"
BASE_NAME = "frequency data" # files become "frequency data 1.xlsx", "frequency data 2.xlsx", ...
# ---------------------------------------------------------
volts_per_g = (SENS_MV_PER_G * GAIN) / 1000.0
volts_per_ms2 = volts_per_g / G_TO_MS2
COLUMNS = ["timestamp", "drive_Vpp_at_piezo", "frequency_Hz", "accel_amp_mV",
"acceleration_m_s2", "displacement_mm", "displacement_um"]
def read_channel(scope, ch_num):
ch = f"CHAN{ch_num}"
scope.write(f"{ch}:STAT ON")
head = scope.query(f"{ch}:DATA:HEAD?").strip()
x_start, x_stop, n_samples, _ = [float(v) for v in head.split(",")]
n_samples = int(n_samples)
dt = (x_stop - x_start) / (n_samples - 1)
scope.write("FORM ASC")
raw = scope.query(f"{ch}:DATA?")
volts = np.array([float(v) for v in raw.strip().split(",")])
return dt, volts
def freq_and_amp(volts, dt, target_f=None):
v_ac = volts - np.mean(volts)
n = len(v_ac)
spectrum = np.abs(np.fft.rfft(v_ac))
freqs = np.fft.rfftfreq(n, d=dt)
spectrum[0] = 0.0
k = np.argmax(spectrum) if target_f is None else np.argmin(np.abs(freqs - target_f))
f_found = freqs[k]
amp_zero_to_peak = 2.0 * spectrum[k] / n
return f_found, amp_zero_to_peak
def save_xlsx(rows, path):
"""Write all collected rows to a clean .xlsx with a header row."""
from openpyxl import Workbook
wb = Workbook()
ws = wb.active
ws.title = "ramp_log"
ws.append(COLUMNS) # header row
for r in rows:
ws.append(r)
# widen columns a little for readability
for i, _ in enumerate(COLUMNS, start=1):
ws.column_dimensions[chr(64 + i)].width = 20
wb.save(path)
# ---- connect ----
rm = pyvisa.ResourceManager()
scope = rm.open_resource(SCOPE_ADDR)
scope.timeout = 20000
print("Connected to:", scope.query("*IDN?").strip())
os.makedirs(SAVE_DIR, exist_ok=True)
# --- find the next free run number so nothing is overwritten ---
import glob, re
existing = glob.glob(os.path.join(SAVE_DIR, f"{BASE_NAME} *.xlsx"))
nums = []
for p in existing:
m = re.search(re.escape(BASE_NAME) + r" (\d+)\.xlsx$", os.path.basename(p))
if m:
nums.append(int(m.group(1)))
run_number = (max(nums) + 1) if nums else 1
xlsx_path = os.path.join(SAVE_DIR, f"{BASE_NAME} {run_number}.xlsx")
backup_path = os.path.join(SAVE_DIR, f"{BASE_NAME} {run_number}_backup.txt")
print(f"This run will be saved as: {BASE_NAME} {run_number}.xlsx")
# start/refresh the backup text file with a header
with open(backup_path, "w") as f:
f.write("\t".join(COLUMNS) + "\n")
rows = [] # collected rows, written to Excel at the end
print("-" * 78)
print(f"LOGGING STARTED. Readings every {LOG_INTERVAL:.0f} s. Ramp by hand.")
print("Drive voltage read automatically from monitor (x{:.0f}).".format(MONITOR_FACTOR))
print("Excel file is written when you press Ctrl+C. A .txt backup updates live.")
print("-" * 78)
print(f"{'time':8} {'driveVpp':>9} {'freqHz':>8} {'accelmV':>9} {'disp_um':>10}")
print("-" * 78)
try:
while True:
# Frequency is FIXED to DRIVE_FREQ (set in settings). Both channels are
# measured at exactly this frequency, so the displacement is not corrupted
# by the FFT snapping to coarse neighbouring bins.
f_drive = DRIVE_FREQ
dt1, v1 = read_channel(scope, DRIVE_CH)
_, monitor_amp_V = freq_and_amp(v1, dt1, target_f=f_drive)
monitor_pp_V = 2.0 * monitor_amp_V
drive_Vpp = monitor_pp_V * MONITOR_FACTOR
dt2, v2 = read_channel(scope, ACCEL_CH)
_, accel_amp_V = freq_and_amp(v2, dt2, target_f=f_drive)
a_ms2 = accel_amp_V / volts_per_ms2
omega = 2.0 * np.pi * f_drive
x_mm = (a_ms2 / omega**2) * 1000.0 if omega > 0 else 0.0
ts_full = datetime.now().strftime("%Y-%m-%d %H:%M:%S")
ts_short = datetime.now().strftime("%H:%M:%S")
row = [ts_full, round(drive_Vpp, 4), round(f_drive, 3),
round(accel_amp_V * 1000, 5), round(a_ms2, 5),
round(x_mm, 7), round(x_mm * 1000, 4)]
rows.append(row)
print(f"{ts_short:8} {drive_Vpp:9.3f} {f_drive:8.2f} "
f"{accel_amp_V*1000:9.3f} {x_mm*1000:10.4f}")
with open(backup_path, "a") as f:
f.write("\t".join(str(x) for x in row) + "\n")
time.sleep(LOG_INTERVAL)
except KeyboardInterrupt:
print("-" * 78)
print("LOGGING STOPPED. Writing Excel file...")
try:
save_xlsx(rows, xlsx_path)
print(f"Excel saved to: {xlsx_path}")
except Exception as e:
print(f"Could not write Excel ({e}).")
print(f"Your data is safe in the backup: {backup_path}")
print(f"(Live backup text also at: {backup_path})")
print("In Excel: plot displacement_mm vs drive_Vpp_at_piezo for the curve.")
finally:
scope.close()