homodyne_code.h
1 #include "homodyne.h"
2 #include "data.h"
3 #include "controller.h"
4 
5 #include <odindata/fitting.h>
6 
7 template<recoDim interpolDim, int interpolIndex, int firstOrthoIndex, int secondOrthoIndex>
9  Log<Reco> odinlog(c_label(),"process");
10 
11  Range all=Range::all();
12 
13  ComplexData<3>& data=rd.data(Rank<3>());
14  TinyVector<int,3> shape=data.shape();
15  int nipol=shape(interpolIndex);
16 
17  int startindex=0;
18 
19  if(interpolDim==readout) {
20  if(rd.coord().adcend<(nipol-1)) {
21  ODINLOG(odinlog,errorLog) << "Not implemented: Interpolation at end of readout" << STD_endl;
22  return false;
23  }
24  startindex=rd.coord().adcstart;
25  } else {
26  if(rd.interpolated) measlines.update(*(rd.interpolated)); // take previously interpolated coords into account
27  ivector indexvec=measlines.get_indices(rd.coord());
28  startindex=indexvec.minvalue();
29  }
30 
31  float center=0.5*float(nipol-1);
32  int endindex=nipol-1-startindex;
33  ODINLOG(odinlog,normalDebug) << "startindex/endindex/center=" << startindex << "/" << endindex << "/" << center << STD_endl;
34 
35  if(float(startindex)<center) { // True homodyne reco
36  ODINLOG(odinlog,normalDebug) << "Homodyne reco"<< STD_endl;
37 
38  ComplexData<3> symmetric(shape); symmetric=STD_complex(0.0);
39 
40  if(startindex>0) { // Don't do this for fully-sampled k-space
41 
42  // symmetric part
43  Range symrange(startindex,endindex);
44  if(interpolIndex==0) symmetric(symrange,all,all)=data(symrange,all,all);
45  if(interpolIndex==1) symmetric(all,symrange,all)=data(all,symrange,all);
46  if(interpolIndex==2) symmetric(all,all,symrange)=data(all,all,symrange);
47  symmetric.fft();
48 
49  // pre weighting
50  fvector transition(endindex-startindex+1);
51  transition.fill_linear(0.0,1.0);
52  ComplexData<1> weight(shape(interpolIndex));
53  weight=STD_complex(1.0);
54  TinyVector<int,3> index;
55  for(int i=0; i<startindex; i++) weight(i)=STD_complex(0.0); // make sure we blank all non-acquired lines
56  for(int i=0; i<int(transition.size()); i++) weight(startindex+i)=transition[i];
57  for(int iortho1=0; iortho1<shape(firstOrthoIndex); iortho1++) {
58  index(firstOrthoIndex)=iortho1;
59  for(int iortho2=0; iortho2<shape(secondOrthoIndex); iortho2++) {
60  index(secondOrthoIndex)=iortho2;
61  for(int ipol=0; ipol<shape(interpolIndex); ipol++) {
62  index(interpolIndex)=ipol;
63  data(index)*=weight(ipol);
64  }
65  }
66  }
67  }
68 
69 
70  // do the FFT
71  data.fft();
72 
73 
74  if(startindex>0) { // Don't do this for fully-sampled k-space
75 
76  // phase correction
77  data*=expc(float2imag(-phase(symmetric)));
78 
79  // take real part
80  ComplexData<3> realpart(shape);
81  realpart=float2real(creal(data));
82  data.reference(realpart);
83  }
84 
85 
86  } else if(fabs(float(startindex)-center)<=1.0) { // Just mirror k-space
87  ODINLOG(odinlog,significantDebug) << "Conjugate-mirror reco with startindex=" << startindex << STD_endl;
88 
89  if(interpolDim!=line) {
90  ODINLOG(odinlog,errorLog) << "Not implemented: Conjugate-mirror reco in dimension " << recoDimLabel[interpolDim] << STD_endl;
91  return false;
92  }
93 
94 
95  int nread=shape(2);
96 
97 
98  // Apply phase correction using the central line
99 
100  data.partial_fft(TinyVector<bool,3>(false,false,true)); // FFT in read
101 
102  ComplexData<1> centline(data(shape(0)/2,startindex,all));
103 
104  Data<float,1> centphase(centline.phasemap());
105  Data<float,1> centmagn(cabs(centline));
106  Data<float,1> centerr(nread);
107  for(int iread=0; iread<nread; iread++) centerr(iread)=secureInv(pow(centmagn(iread),2));
108 
109  LinearFunction linf;
110  linf.fit(centphase,centerr);
111 
112  for(int iread=0; iread<nread; iread++) {
113  data(all,all,iread)*=expc(STD_complex(0.0, -(iread*linf.m.val+linf.c.val)));
114  }
115 
116  data.partial_fft(TinyVector<bool,3>(false,false,true),false); // inv FFT in read
117 
118 
119  ComplexData<1> oneline(nread);
120  int nmeas=nipol-startindex;
121  for(int iphase3d=0; iphase3d<shape(0); iphase3d++) {
122  for(int iline=1; iline<nmeas; iline++) {
123 
124  // mirror remaining lines
125  int isrc=startindex+iline;
126  int idst=startindex-iline;
127  if(idst>=0) {
128  oneline=conjc(data(iphase3d,isrc,all).reverse(0));
129  if(!(nread%2)) oneline.shift(0,1); // for even nread, the center frequency is at nread/2
130  data(iphase3d,idst,all)=oneline;
131  }
132  }
133  }
134 
135  if(!(nread%2)) data(all,0,all)=STD_complex(0.0); // zero-fill garbage from cyclic shift
136 
137  // do the FFT
138  data.fft();
139 
140 /*
141  Data<float,3>(creal(data)).autowrite("creal_"+rd.coord().print(RecoIndex::filename)+".jdx");
142  Data<float,3>(cimag(data)).autowrite("cimag_"+rd.coord().print(RecoIndex::filename)+".jdx");
143  Data<float,3>(cabs(data)).autowrite("cabs_"+rd.coord().print(RecoIndex::filename)+".jdx");
144  Data<float,3>(phase(data)).autowrite("phase_"+rd.coord().print(RecoIndex::filename)+".jdx");
145 */
146 
147 
148  } else {
149  ODINLOG(odinlog,errorLog) << "startindex=" << startindex << " larger than center=" << center << STD_endl;
150  return false;
151  }
152 
153  return execute_next_step(rd,controller);
154 }
155 
157 
158 
159 template<recoDim interpolDim, int interpolIndex, int firstOrthoIndex, int secondOrthoIndex>
161  Log<Reco> odinlog(c_label(),"query");
162  if(context.mode==RecoQueryContext::prep) {
163  if(interpolDim!=readout) {
164  if(!measlines.init(context.coord, context.controller)) return false;
165  }
166  }
167  return RecoStep::query(context);
168 }