src.acoustools.Export.Holo

Export to .holo file -> List of holograms

The holo format stores each phase and amplitude as a 5 bit integer with each phase and ampplitude being discritised to 32 levels

The result of this is then compressed using pythons zlib (https://docs.python.org/3/library/zlib.html) Internally stored as blocks of phase and amplitude seperated by 2^6-1 eg phase1 <11111> amplitude1 <11111> phase2 <11111> amplitude2 <11111> ...

  1'''
  2Export to .holo file -> List of holograms\n
  3The holo format stores each phase and amplitude as a 5 bit integer with each phase and ampplitude being discritised to 32 levels \n
  4The result of this is then compressed using pythons zlib (https://docs.python.org/3/library/zlib.html)
  5Internally stored as blocks of phase and amplitude seperated by 2^6-1 eg phase1 <11111> amplitude1 <11111> phase2 <11111> amplitude2 <11111> ...
  6'''
  7
  8import torch, io, zlib
  9from acoustools.Utilities.Utilities import batch_list
 10from acoustools.Utilities.Setup import device,DTYPE
 11# from acoustools.Constants import wavelength
 12
 13from torch import Tensor
 14
 15def compress(hologram:Tensor, levels:int=32) -> list[Tensor]:
 16    '''
 17    @private
 18    '''
 19    phase_divs = 2*3.1415/levels
 20    phase_levels = torch.angle(hologram)/phase_divs
 21    phase_levels += levels / 2
 22
 23    amp_divs = 1/levels
 24    amp_levels = torch.abs(hologram)/amp_divs
 25
 26    torch.round_(phase_levels).to(torch.int8)
 27    torch.round_(amp_levels).to(torch.int8)
 28    
 29    return phase_levels, amp_levels
 30
 31def decompress(hologram:list, amplitudes:list, levels:int=32) -> list[Tensor]:
 32    '''
 33    @private
 34    '''
 35    phase_divs = 2*3.1415/levels
 36    phases = [(p - levels/2) * phase_divs for p in hologram]
 37
 38    amp_divs = 1/levels
 39    amplitudes = [a * amp_divs for a in amplitudes]
 40    
 41
 42    holo = [a*torch.e ** (1j*p) for a,p in zip(amplitudes,phases)]
 43    holo = torch.tensor(holo, device=device,dtype=DTYPE).unsqueeze_(0).unsqueeze_(2)
 44    return holo
 45
 46
 47def save_holograms(holos:list[Tensor]|Tensor, fname:str):
 48    '''
 49    Save holograms in .holo format. 
 50    :param holos: Holograms to use
 51    :param fname:  filename to use. Will append .holo is no extension provides
 52    '''
 53    if '.' not in fname:
 54        fname += '.holo'
 55    # pickle.dump(holos, open(fname, 'wb'))
 56    
 57    # with open(fname, 'wb') as file:
 58    with io.BytesIO() as file:
 59        for holo in holos:
 60            phase, amp = compress(holo.squeeze())
 61            for p in phase:
 62                p = int(p.item())
 63                file.write((p).to_bytes(5, byteorder='big', signed=False))
 64            file.write((2**6-1).to_bytes(5, byteorder='big', signed=False))
 65            for a in amp:
 66                a = int(a.item())
 67                file.write((a).to_bytes(5, byteorder='big', signed=False))
 68            file.write((2**6-1).to_bytes(5, byteorder='big', signed=False))
 69        
 70        new_data = zlib.compress(file.getbuffer())
 71        f = open(fname, 'wb')
 72        f.write(new_data)
 73        f.close()
 74
 75def load_holograms(path:str) -> list[Tensor]:
 76    '''
 77    Reads .holo file
 78    :param path: Path to read
 79    :returns holgrams:
 80    '''
 81    if '.' not in path:
 82        path += '.holo'
 83    # holos = pickle.load(open(path, 'rb'))
 84
 85    with open(path, 'rb') as file:
 86        phases = []
 87        amps = []
 88        holos = []
 89        reading_amps = 0
 90        data = file.read()
 91        data = zlib.decompress(data)
 92        for bits in batch_list(data,5):
 93            j = int.from_bytes(bits, byteorder='big')
 94            if j < 2**6-1:
 95                if not reading_amps:
 96                    phases.append(j)
 97                else:
 98                    amps.append(j)
 99            else:
100                if reading_amps == 0:
101                    reading_amps = 1
102                else:
103                    reading_amps = 0
104                    holos.append([phases, amps])
105                    phases = []
106                    amps = []
107        xs = []
108        for h in holos:
109            x = decompress(h[0], h[1])
110            xs.append(x)
111
112    return xs
def save_holograms(holos: list[torch.Tensor] | torch.Tensor, fname: str):
48def save_holograms(holos:list[Tensor]|Tensor, fname:str):
49    '''
50    Save holograms in .holo format. 
51    :param holos: Holograms to use
52    :param fname:  filename to use. Will append .holo is no extension provides
53    '''
54    if '.' not in fname:
55        fname += '.holo'
56    # pickle.dump(holos, open(fname, 'wb'))
57    
58    # with open(fname, 'wb') as file:
59    with io.BytesIO() as file:
60        for holo in holos:
61            phase, amp = compress(holo.squeeze())
62            for p in phase:
63                p = int(p.item())
64                file.write((p).to_bytes(5, byteorder='big', signed=False))
65            file.write((2**6-1).to_bytes(5, byteorder='big', signed=False))
66            for a in amp:
67                a = int(a.item())
68                file.write((a).to_bytes(5, byteorder='big', signed=False))
69            file.write((2**6-1).to_bytes(5, byteorder='big', signed=False))
70        
71        new_data = zlib.compress(file.getbuffer())
72        f = open(fname, 'wb')
73        f.write(new_data)
74        f.close()

Save holograms in .holo format.

Parameters
  • holos: Holograms to use
  • fname: filename to use. Will append .holo is no extension provides
def load_holograms(path: str) -> list[torch.Tensor]:
 76def load_holograms(path:str) -> list[Tensor]:
 77    '''
 78    Reads .holo file
 79    :param path: Path to read
 80    :returns holgrams:
 81    '''
 82    if '.' not in path:
 83        path += '.holo'
 84    # holos = pickle.load(open(path, 'rb'))
 85
 86    with open(path, 'rb') as file:
 87        phases = []
 88        amps = []
 89        holos = []
 90        reading_amps = 0
 91        data = file.read()
 92        data = zlib.decompress(data)
 93        for bits in batch_list(data,5):
 94            j = int.from_bytes(bits, byteorder='big')
 95            if j < 2**6-1:
 96                if not reading_amps:
 97                    phases.append(j)
 98                else:
 99                    amps.append(j)
100            else:
101                if reading_amps == 0:
102                    reading_amps = 1
103                else:
104                    reading_amps = 0
105                    holos.append([phases, amps])
106                    phases = []
107                    amps = []
108        xs = []
109        for h in holos:
110            x = decompress(h[0], h[1])
111            xs.append(x)
112
113    return xs

Reads .holo file

Parameters
  • path: Path to read :returns holgrams: