[ova] more work on bin files

This commit is contained in:
jan 2025-12-30 02:51:57 -08:00
parent 80893d65ce
commit e126771248

View File

@ -14,49 +14,42 @@ logger = logging.getLogger(__name__)
@dataclass @dataclass
class OVABINData: class OVABINData:
te: NDArray[numpy.complex128] # time domain complex amplitude, polarization 1 jones: NDArray[numpy.complex128] # jones matrix data [2 x 2 x n_pts] # TODO frequency domain or time?
tm: NDArray[numpy.complex128] # time domain complex amplitude, polarization 2 df_GHz: float # delta between frequency points
dt_ns: float # delta between time points
max_freq_GHz: float # sweep's max frequency (shortest wavelength) max_freq_GHz: float # sweep's max frequency (shortest wavelength)
ng_setting: float | None # set by user (for info only)
meas_date: NDArray[numpy.int16] # 8 items: year month [week?] day hour min sec ms meas_date: NDArray[numpy.int16] # 8 items: year month [week?] day hour min sec ms
_wip_metadata: NDArray[numpy.float64] | None # unknown metadata values
@property def time_ns(self, size: int) -> NDArray[numpy.float64]:
def time_ns(self) -> NDArray[numpy.float64]: # To be used with tdr curve generated with e.g. fft(fftshift(data.jones))
""" tt_ns = fftshift(fftfreq(size, d=self.df_GHz))
Time delay (x-axis) for `te` and `tm` data return tt_ns
"""
tt = numpy.arange(self.te.size, dtype=numpy.float64) * self.dt_ns
return tt
@property @property
def wl_range_nm(self) -> NDArray[numpy.float64]: def wl_range_nm(self) -> NDArray[numpy.float64]:
freq_range = numpy.asarray([ freq_range = numpy.asarray([
self.max_freq_GHz - 1 / (2 * self.dt_ns), self.max_freq_GHz - self.df_GHz * self.jones.shape[2],
self.max_freq_GHz, self.max_freq_GHz,
]) ])
return C0 / freq_range return C0 / freq_range
@property @property
def ctr_freq_GHz(self) -> float: def ctr_freq_GHz(self) -> float:
return self.max_freq_GHz - 1 / (4 * self.dt_ns) return self.max_freq_GHz - self.df_GHz * self.jones.shape[2] / 2
def freqs(self, size: int) -> NDArray[numpy.float64]: @property
# To be used with spectrum generated with e.g. fft(fftshift(data.te)) def freqs(self) -> NDArray[numpy.float64]:
frq_GHz = fftshift(fftfreq(size, d=self.dt_ns)) + self.ctr_freq_GHz return numpy.arange(self.jones.shape[2], dtype=numpy.float64)[::-1] * self.df_GHz + self.max_freq_GHz
return frq_GHz
def wls(self, size: int) -> NDArray[numpy.float64]: @property
def wls(self) -> NDArray[numpy.float64]:
# To be used with spectrum generated with e.g. fft(fftshift(data.te)) # To be used with spectrum generated with e.g. fft(fftshift(data.te))
return C0 / self.freqs(size) return C0 / self.freqs
def window(self, size: int) -> NDArray[numpy.float64]: def window(self, size: int) -> NDArray[numpy.float64]:
# Approximation of the generalized Hamming window used when freq_windowed==True # Hann window for use before time domain fft
nn = numpy.linspace(0, 1, size) nn = numpy.linspace(0, 1, size)
alpha = 0.572 alpha = 0.500
scale = 1.5 # likely related to "incoherent power gain compensation" for Hamming window (=1.54) scale = 1
# 1.50 seems to fit the data better though
ham = alpha - (1 - alpha) * numpy.cos(2 * numpy.pi * nn) ham = alpha - (1 - alpha) * numpy.cos(2 * numpy.pi * nn)
return scale * ham return scale * ham
@ -73,28 +66,22 @@ class OVABINData:
logger.warning(f'Unexpected magic bytes: {magic}') logger.warning(f'Unexpected magic bytes: {magic}')
metadata = fromfile(dtype=numpy.float64, offset=0x00, count=2) metadata = fromfile(dtype=numpy.float64, offset=0x00, count=2)
data_count = fromfile(dtype=numpy.int32, offset=0x18, count=1)
meas_date = fromfile(dtype=numpy.int16, offset=0x49, count=8) meas_date = fromfile(dtype=numpy.int16, offset=0x49, count=8)
wl_range = fromfile(dtype=numpy.int32, offset=0x17, count=1) arr = fromfile(dtype=numpy.float64, offset=0x59, count=data_count * 2 * 4)
data_len = 4 * wl_range
arr = fromfile(dtype=numpy.float64, offset=0x59, count=data_len)
ng = fromfile(dtype=numpy.float32, offset=0x21, count=1) ng = fromfile(dtype=numpy.float32, offset=0x21, count=1)
max_freq_GHz = metadata[0] max_freq_GHz, df_GHz = metadata
#dt_ns = metadata[3] / 2
arrs = numpy.split(arr, 4) arrs = numpy.split(arr, 4 * 2)
te = arrs[0] + 1j * arrs[1] jones = (arrs[0::2] + 1j * arrs[1::2]).reshape(2, 2, -1) # TODO confirm
tm = arrs[2] + 1j * arrs[3]
result = OVABINData( result = OVABINData(
te = te, jones = jones,
tm = tm, df_GHz = df_GHz,
#dt_ns = dt_ns,
max_freq_GHz = max_freq_GHz, max_freq_GHz = max_freq_GHz,
ng_setting = ng,
meas_date = meas_date, meas_date = meas_date,
_wip_metadata = metadata[1:],
) )
return result return result
@ -105,17 +92,17 @@ Notes on .bin file format (OVA)
0x00: 9D A8 5A 6B C8 D0 0C 41 13 23 63 4D 22 74 C4 3F 0x00: 9D A8 5A 6B C8 D0 0C 41 13 23 63 4D 22 74 C4 3F
|max_freq_GHZ (f64)------ | f64 ??----------------- | |max_freq_GHZ (f64)------ | f64 ??----------------- |
C0/freq = wl_nm 5.848e6 ~> 51.3nm if GHz C0/freq = wl_nm 0.1597... df_GHz
could be dt in ps? not sure what changes this, if anything
0x10: 40 53 33 33 4F 56 41 00 00 00 01 00 00 00 00 00 0x10: 40 53 33 33 4F 56 41 00 00 00 01 00 00 00 00 00
| S 3 3 | O V A | wl range | | S 3 3 | O V A | ? | data_count |??|f64------
1 = biggest range (58.97nm), others are exponents of 2 smaller (resolution) 0x10000 = biggest range (58.97nm)
effectively length of each sub-array (x 4 arrays) this * 8bytes * 2(complex) * 4 (jones matrix) = data length in bytes
0x20: 00 00 80 20 40 01 00 00 00 00 00 00 00 00 00 00 0x20: 00 00 80 20 40 01 00 00 00 00 00 00 00 00 00 00
| ng (f32) |----........| -DUT length (m)|----........|
??? average count average count
0x30: 00 00 00 00 00 00 38 98 40 00 00 00 00 00 00 00 0x30: 00 00 00 00 00 00 38 98 40 00 00 00 00 00 00 00
??????????? ???????????