Coverage for kwave/reconstruction/converter.py: 0%
53 statements
« prev ^ index » next coverage.py v6.5.0, created at 2022-10-24 11:52 -0700
« prev ^ index » next coverage.py v6.5.0, created at 2022-10-24 11:52 -0700
1import scipy
2import uff
3import numpy as np
4from kwave import NotATransducer
5from uff.linear_array import LinearArray
6import time
9def build_channel_data(sensor_data: np.ndarray,
10 kgrid,
11 not_transducer: NotATransducer,
12 sampling_frequency,
13 prf,
14 focal_depth):
15 number_scan_lines = sensor_data.shape[1]
16 input_signal = not_transducer.input_signal
17 transducer = not_transducer.transducer
19 x0 = np.arange(0, 96) * transducer.element_width * kgrid.dy
20 x0 = x0 - (x0.max() / 2)
22 unique_excitations = uff.excitation.Excitation(
23 waveform=input_signal,
24 sampling_frequency=sampling_frequency,
25 pulse_shape='Gaussian'
26 )
28 probe = LinearArray(
29 number_elements=transducer.number_elements * 4,
30 pitch=transducer.element_width * kgrid.dy + transducer.element_spacing * kgrid.dx,
31 element_width=transducer.element_width * kgrid.dy,
32 element_height=transducer.element_length * kgrid.dx,
33 transform=uff.transform.Transform(uff.transform.Translation(0, 0, 0), uff.transform.Rotation(0, 0, 0))
34 )
36 ####### Move to LinearArray.update
38 if probe.pitch and probe.number_elements:
40 # for all lines in this block, probe.element_geometry[0] is hard coded as 0. Should be dynamic!
42 # update perimeter
43 if probe.element_width and probe.element_height:
45 if not probe.element_geometry:
46 probe.element_geometry = [uff.element_geometry.ElementGeometry(
47 uff.perimeter.Perimeter([
48 uff.Position(0, 0, 0),
49 uff.Position(0, 0, 0),
50 uff.Position(0, 0, 0),
51 uff.Position(0, 0, 0),
52 ])
53 )]
55 if not probe.element_geometry[0].perimeter:
56 probe.element_geometry.perimeter = uff.perimeter.Perimeter([
57 uff.Position(0, 0, 0),
58 uff.Position(0, 0, 0),
59 uff.Position(0, 0, 0),
60 uff.Position(0, 0, 0),
61 ])
63 probe.element_geometry[0].perimeter.position[0] = uff.Position(x=-probe.element_width / 2,
64 y=-probe.element_height / 2, z=0)
65 probe.element_geometry[0].perimeter.position[1] = uff.Position(x=probe.element_width / 2,
66 y=-probe.element_height / 2, z=0)
67 probe.element_geometry[0].perimeter.position[2] = uff.Position(x=probe.element_width / 2,
68 y=probe.element_height / 2, z=0)
69 probe.element_geometry[0].perimeter.position[3] = uff.Position(x=-probe.element_width / 2,
70 y=probe.element_height / 2, z=0)
72 # compute element position in the x-axis
73 x0_local = np.arange(1, probe.number_elements + 1) * probe.pitch
74 x0_local = x0_local - x0_local.mean()
75 x0_local = x0_local.astype(np.float32)
77 # create array of elements
78 probe.element = []
79 for n in range(probe.number_elements):
80 element = uff.Element(
81 transform=uff.Transform(
82 translation=uff.Translation(x=x0_local[n], y=0, z=0),
83 rotation=uff.Rotation(x=0, y=0, z=0)
84 ),
85 # linear array can only have a single perimenter impulse_response
86 # impulse_response=[], # probe.element_impulse_response,
87 element_geometry=probe.element_geometry[0]
88 )
90 probe.element.append(element)
92 ####### Move end
94 unique_waves = []
95 for n in range(number_scan_lines):
96 wave = uff.Wave(
97 wave_type=uff.WaveType.CONVERGING,
98 origin=uff.SphericalWaveOrigin(
99 position=uff.Position(x=x0[n], z=focal_depth)
100 ),
101 aperture=uff.Aperture(
102 origin=uff.Position(x=x0[n]),
103 fixed_size=transducer.element_length*kgrid.dx, # wrong, correct one is in below
104 # fixed_size=[active_aperture*el_pitch, el_height],
105 window='rectangular'
106 )
107 )
108 unique_waves.append(wave)
110 unique_events = []
111 lag = 1.370851370851371e-06 # (length(input_signal) / 2 + 1) * dt
112 downsample_factor = 1
113 first_sample_time = 650e-9 * np.ones((number_scan_lines, 1)) # CHANGE
115 for n in range(number_scan_lines):
116 # we select a time zero reference point: in this case the location of the first element fired
117 arg_min = np.argmax(np.sqrt((x0[n] - x0) ** 2 + focal_depth ** 2))
118 time_zero_reference_point = x0[arg_min]
120 transmit_wave = uff.TransmitWave(
121 wave=n,
122 time_zero_reference_point=uff.TimeZeroReferencePoint(x=time_zero_reference_point, y=0, z=0),
123 time_offset=lag,
124 weight=1
125 )
127 # transmit and receive channel
128 # channel_mapping = np.arange(n, number_elements + n).tolist()
129 channel_mapping = np.arange(n, transducer.number_elements + n)[None, :].T # shape: [number_elements x 1]
130 transmit_setup = uff.TransmitSetup(
131 probe=1, # different from Matlab
132 channel_mapping=channel_mapping,
133 transmit_waves=[transmit_wave] # should be list!
134 )
136 # active_elment_positions = channel_data.probes{1}.get_elements_centre();
138 receive_setup = uff.ReceiveSetup(
139 probe=1, # different from Matlab
140 time_offset=first_sample_time[n],
141 channel_mapping=channel_mapping,
142 sampling_frequency=sampling_frequency / downsample_factor
143 )
145 unique_event = uff.Event(
146 transmit_setup=transmit_setup,
147 receive_setup=receive_setup
148 )
150 unique_events.append(unique_event)
152 sequence = []
153 for n in range(len(unique_events)):
154 sequence.append(uff.TimedEvent(
155 event=n,
156 time_offset=(n - 1) / prf
157 ))
159 channel_data = uff.channel_data.ChannelData(
160 data=sensor_data,
161 probes=[probe],
162 unique_excitations=[unique_excitations],
163 unique_waves=unique_waves,
164 unique_events=unique_events,
165 description='US B-Mode Linear Transducer Scan, kWave.',
166 authors='kWave.py',
167 sound_speed=not_transducer.sound_speed,
168 system='kWave.py',
169 country_code='DE',
170 local_time=time.strftime('%Y-%m-%dTHH:MM:SS+00'), # fix
171 repetition_rate=prf / len(unique_events),
172 sequence=sequence
173 )
174 return channel_data