-
Notifications
You must be signed in to change notification settings - Fork 1
Expand file tree
/
Copy pathofdmDecoder.c
More file actions
1618 lines (1415 loc) · 82.8 KB
/
ofdmDecoder.c
File metadata and controls
1618 lines (1415 loc) · 82.8 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
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
973
974
975
976
977
978
979
980
981
982
983
984
985
986
987
988
989
990
991
992
993
994
995
996
997
998
999
1000
#include <fftw3.h>
#include <stdlib.h>
#include <stdio.h>
#include <unistd.h>
#include <fcntl.h>
#include <stdint.h>
#include <math.h>
#include <complex.h>
#include <string.h>
#include <errno.h>
#include <time.h>
#include "utilities.h"
buffered_data_return_t interpolateSample(const circular_buffer_double_t *inputSamples, sample_double_t *outputSample, OFDM_state_t *OFDMstate, debugPlots_t debugPlots)
{
// convert from output sample time to input sample time
//double output_clock = OFDMstate->samplerAccumulatedPhase; // the fractional number on samples accumulated up to the current input sample
//int output_sample = OFDMstate->sample;
//int input_clock = inputSamples->n;
if(debugPlots.OFDMinterpolatorEnabled)
{
fprintf(debugPlots.OFDMinterpolatorStdin, "%i %i %f\n", inputSamples->n, 0, inputSamples->buffer[inputSamples->insertionIndex]);
}
// determine if we've recieved enough samples, or need to wait for more
if(inputSamples->n <= OFDMstate->samplerAccumulatedPhase + ceil((double)inputSamples->length / 2) - 1) // if last input index is at least half the interpolation filter width in the future, then we can process samples until it's not (The architecture doesn't really allow us to generate multiple output samples for one input sample, so we'll just generate once. This assumes that the input sample rate is always higher than the output sample rate)
return AWAITING_SAMPLES;
// if so, use the kernel to interpolate between input samples to generate an output sample
outputSample->sample = 0;
for(int i = 0; i < inputSamples->length; i++)
{
// multiply by impulse response at given offset, and sum
int inputSampleIndex = (inputSamples->insertionIndex + 1 + i) % inputSamples->length; // the index in the buffer of the current input sample being used
int inputSampleTime = inputSamples->n - inputSamples->length + 1 + i; // the time of the current input sample
double filterCoordinate = (double)inputSampleTime - OFDMstate->samplerAccumulatedPhase; // the position on the interpolation filter to multiply by the input sample
double inputSample = inputSamples->buffer[inputSampleIndex];
double filterValue = filterCoordinate < -1 || filterCoordinate > 1 ? // piece wise function for the 'tent' filter kernel
0 :
filterCoordinate < 0 ?
filterCoordinate + 1 :
-filterCoordinate + 1;
outputSample->sample += inputSample * filterValue; // convolve the filter kernel with the input samples to get one output sample.
// can't use an actual convolution algo since the output samples' phases will likely change
// for every output sample as the sample rate ratio is adjusted
}
// graph the interpolator debug plot
if(debugPlots.OFDMinterpolatorEnabled)
{
fprintf(debugPlots.OFDMinterpolatorStdin, "%f %i %f\n", OFDMstate->samplerAccumulatedPhase, 1, outputSample->sample);
}
// output a sample
outputSample->sampleRate = OFDMstate->sampleRate; // the assumed sample rate, though it will be slightly different depending on the sampling ratio
outputSample->sampleIndex = OFDMstate->sample;
// increase the output sample clock's phase
//OFDMstate->resamplingRatio = ((double)OFDMstate->sampleRate / (1 + 25./1000000))/ inputSamples->sampleRate;
OFDMstate->resamplingRatio = ((double)OFDMstate->sampleRate * (1 - OFDMstate->samplingFrequencyOffsetEstimate))/ inputSamples->sampleRate;
OFDMstate->samplerAccumulatedPhase += 1 / OFDMstate->resamplingRatio; // add one clock duration to the sampler time
OFDMstate->sample++;
// graph the offset used on the SFO estimator plot
if(debugPlots.OFDMsfoEstimatorEnabled && outputSample->sampleIndex % (OFDMstate->symbolPeriod / 100) == 0)
{
fprintf(debugPlots.OFDMsfoEstimatorStdin, "%f %i %f\n", ((double)outputSample->sampleIndex - OFDMstate->ofdmPhaseOffset - OFDMstate->ofdmPeriod) / OFDMstate->symbolPeriod, 2, OFDMstate->samplingFrequencyOffsetEstimate * pow(10, 6));
}
return RETURNED_SAMPLE;
// on major issue with this topology is that sometimes I'll need to output two samples after recieving only one.
// but only if the input sample rate is lower than the output sample rate
// I'm able to output no samples after recieving some, but not more than one sample. And the function isn't called again until a new input
// sample is ready. I think the main reason for this issue is that my entire processing function tree is initiated for each recieved sample from the sound card, so effectively it's only called at the sampling frequency, but I may need to call it slightly more often, or a lot more often depending on the resampling ratio
//
// One other solution is to simply have an output sample buffer in addition to an input sample buffer,
// with a value attached that specifies how many new values there are, or some other marker
// so the consumer knows what samples need to be processed. or else I just have to run
// the consumer multiple times for each new sample
}
buffered_data_return_t averagingFilter(const circular_buffer_double_t *inputSamples, sample_double_t *outputSample, double *runningAverage)
{
/*
double average = 0;
// convlutional method
for(int i = 0; i < inputSamples->length; i++)
{
average += inputSamples->buffer[i];
}
average /= inputSamples->length;
outputSample->sampleIndex = inputSamples->n - inputSamples->length / 2; // center the filter so it averages before and after in a sliding window
outputSample->sampleRate = inputSamples->sampleRate;
outputSample->sample = average;
return RETURNED_SAMPLE;
*/
// iterative method
//static double iterativeAverage = 0;
int lateIndex = inputSamples->insertionIndex; // newest index
int earlyIndex = (inputSamples->insertionIndex + 1) % inputSamples->length; // oldest index
*runningAverage += (inputSamples->buffer[lateIndex] - inputSamples->buffer[earlyIndex]) / inputSamples->length;
outputSample->sampleIndex = inputSamples->n - inputSamples->length / 2; // center the filter so it averages before and after in a sliding window
outputSample->sampleRate = inputSamples->sampleRate;
outputSample->sample = *runningAverage;
return RETURNED_SAMPLE;
}
// detect the most likely/optimal for the channel conditions ofdm frame start time
buffered_data_return_t timingPeakDetectionFilter(const circular_buffer_double_t *inputSamples, sample_double_t *outputSample, sample_double_t *windowAverage, OFDM_state_t *OFDMstate, debugPlots_t debugPlots)
{
// width of input window should be some 4 times larger than guard interval
sample_double_t minimumFirstHalf = {0};
minimumFirstHalf.sample = inputSamples->buffer[(inputSamples->insertionIndex + 1) % inputSamples->length]; // equals value of first sample
minimumFirstHalf.sampleIndex = inputSamples->n - inputSamples->length + 1;
minimumFirstHalf.sampleRate = inputSamples->sampleRate;
sample_double_t minimumSecondHalf = {0};
minimumSecondHalf.sample = inputSamples->buffer[inputSamples->insertionIndex]; // equals value of last sample
minimumSecondHalf.sampleIndex = inputSamples->n;
minimumSecondHalf.sampleRate = inputSamples->sampleRate;
sample_double_t maximum = {0};
maximum.sample = inputSamples->buffer[(inputSamples->insertionIndex + 1 + inputSamples->length / 2) % inputSamples->length]; // equals value right in the middle
maximum.sampleIndex = inputSamples->n - inputSamples->length + inputSamples->length / 2;
maximum.sampleRate = inputSamples->sampleRate;
sample_double_t thresholdFirstHalf = {0};
thresholdFirstHalf.sample = inputSamples->buffer[(inputSamples->insertionIndex + 1) % inputSamples->length]; // equals value of first sample
thresholdFirstHalf.sampleIndex = inputSamples->n - inputSamples->length + 1;
thresholdFirstHalf.sampleRate = inputSamples->sampleRate;
sample_double_t thresholdSecondHalf = {0};
thresholdSecondHalf.sample = inputSamples->buffer[inputSamples->insertionIndex]; // equals value of last sample
thresholdSecondHalf.sampleIndex = inputSamples->n;
thresholdSecondHalf.sampleRate = inputSamples->sampleRate;
/*
// width of input window should be some 4 times larger than guard interval
sample_double_t minimumFirstHalf = {0};
//minimumFirstHalf.sample = inputSamples->buffer[inputSamples->insertionIndex + 1]; // equals value of first sample
minimumFirstHalf.sample = 10; // equals value of first sample
//minimumFirstHalf.sampleIndex = inputSamples->n - inputSamples->length + 1;
minimumFirstHalf.sampleIndex = -1;
minimumFirstHalf.sampleRate = inputSamples->sampleRate;
sample_double_t minimumSecondHalf = {0};
//minimumSecondHalf.sample = inputSamples->buffer[inputSamples->insertionIndex + 1]; // equals value of first sample
minimumSecondHalf.sample = 10; // equals value of first sample
//minimumSecondHalf.sampleIndex = inputSamples->n - inputSamples->length + 1;
minimumSecondHalf.sampleIndex = -1;
minimumSecondHalf.sampleRate = inputSamples->sampleRate;
sample_double_t maximum = {0};
//maximum.sample = inputSamples->buffer[inputSamples->insertionIndex + 1]; // equals value of first sample
maximum.sample = -1; // equals value of first sample
//maximum.sampleIndex = inputSamples->n - inputSamples->length + 1;
maximum.sampleIndex = -1;
maximum.sampleRate = inputSamples->sampleRate;
*/
// if first and second half minimums are below some threshold
// if maximum overall is above some threshold
// if the maximum occurs between the minima
//double lowerThreshold = 0.2;
//double upperThreshold = 0.25;
//double lowerThreshold = windowAverage == 0 ? 0.1 : windowAverage->sample / 3;
//double upperThreshold = windowAverage == 0 ? 0.1 : windowAverage->sample * 1.5;
//double lowerThreshold = OFDMstate->receivedRMS.sample == 0 ? 0.5 : OFDMstate->receivedRMS.sample;
//double upperThreshold = OFDMstate->receivedRMS.sample == 0 ? 1 : OFDMstate->receivedRMS.sample * 2;
//double upperThreshold = lowerThreshold * 1.25;
double lowerThreshold = 0.001;
double upperThreshold = 0.4;
if(debugPlots.OFDMtimingSyncEnabled && inputSamples->n % 500 == 0)
{
fprintf(debugPlots.OFDMtimingSyncStdin, "%i %i %f\n", inputSamples->n, 9, lowerThreshold);
fprintf(debugPlots.OFDMtimingSyncStdin, "%i %i %f\n", inputSamples->n, 10, upperThreshold);
}
// only run the convolution if it's likely to be close, because it's really slow
if(minimumFirstHalf.sample < lowerThreshold && minimumSecondHalf.sample < lowerThreshold && maximum.sample > upperThreshold)
{
for(int i = 0; i < inputSamples->length; i++)
{
double value = inputSamples->buffer[(inputSamples->insertionIndex + 1 + i) % inputSamples->length];
double index = inputSamples->n - inputSamples->length + 1 + i;
if(value >= maximum.sample)
{
// maximum overall
maximum.sample = value;
maximum.sampleIndex = index;
}
if(i < inputSamples->length / 2 && value < minimumFirstHalf.sample)
{
// determine minimum of first half of samples
minimumFirstHalf.sample = value;
minimumFirstHalf.sampleIndex = index;
}
if(i >= inputSamples->length / 2 && value <= minimumSecondHalf.sample)
{
// minimum of last half of samples
minimumSecondHalf.sample = value;
minimumSecondHalf.sampleIndex = index;
}
}
double threshold = lowerThreshold;
//double threshold = maximum.sample * 0.1;
//threshold = threshold < lowerThreshold ? lowerThreshold : threshold;
for(int i = 0; i < inputSamples->length; i++)
{
double value = inputSamples->buffer[(inputSamples->insertionIndex + 1 + i) % inputSamples->length];
double index = inputSamples->n - inputSamples->length + 1 + i;
// get closest to the threshold in the first half
//double threshold = (lowerThreshold + upperThreshold) / 2;
if(index < maximum.sampleIndex && fabs(value - threshold) < fabs(thresholdFirstHalf.sample - threshold))
{
// determine minimum of first half of samples
thresholdFirstHalf.sample = value;
thresholdFirstHalf.sampleIndex = index;
}
// get the closest to the threshold in the second half
if(index >= maximum.sampleIndex && fabs(value - threshold) < fabs(thresholdSecondHalf.sample - threshold))
{
// minimum of last half of samples
thresholdSecondHalf.sample = value;
thresholdSecondHalf.sampleIndex = index;
}
}
outputSample->sample = 0;
outputSample->sampleIndex = 0;
outputSample->sampleRate = inputSamples->sampleRate;
if(minimumSecondHalf.sample < lowerThreshold && minimumFirstHalf.sample < lowerThreshold && maximum.sample > upperThreshold && minimumFirstHalf.sampleIndex < maximum.sampleIndex&& minimumSecondHalf.sampleIndex > maximum.sampleIndex)
{
// the offset is the index value of the maximum
outputSample->sample = 1;
//outputSample->sampleIndex = maximum.sampleIndex; // index is the offset of maximum
int centerOfPlateu = (thresholdFirstHalf.sampleIndex + thresholdSecondHalf.sampleIndex) / 2; // head a bit ahead of the center of the plateu, near the end of it ideally
outputSample->sampleIndex = centerOfPlateu + OFDMstate->guardPeriod / 2 * 3 / 4; // head a bit ahead of the center of the plateu, near the end of it ideally
//outputSample->sampleIndex = centerOfPlateu; // head a bit ahead of the center of the plateu, near the end of it ideally
// graph the correlation function
if(debugPlots.OFDMtimingSyncEnabled)
{
fprintf(debugPlots.OFDMtimingSyncStdin, "%i %i %f\n", thresholdFirstHalf.sampleIndex, 7, threshold);
fprintf(debugPlots.OFDMtimingSyncStdin, "%i %i %f\n", centerOfPlateu - OFDMstate->guardPeriod / 2, 7, maximum.sample);
fprintf(debugPlots.OFDMtimingSyncStdin, "%i %i %f\n", centerOfPlateu, 7, maximum.sample);
fprintf(debugPlots.OFDMtimingSyncStdin, "%i %i %f\n", centerOfPlateu + OFDMstate->guardPeriod / 2, 7, maximum.sample);
fprintf(debugPlots.OFDMtimingSyncStdin, "%i %i %f\n", thresholdSecondHalf.sampleIndex, 7, threshold);
fprintf(debugPlots.OFDMtimingSyncStdin, "%i %i %f\n", outputSample->sampleIndex, 6, threshold);
fprintf(debugPlots.OFDMtimingSyncStdin, "%i %i %f\n", outputSample->sampleIndex, 6, maximum.sample);
fprintf(debugPlots.OFDMtimingSyncStdin, "%i %i %f\n", outputSample->sampleIndex, 6, 1.);
}
return RETURNED_SAMPLE; // only return a sample when preamble is detected
}
}
return AWAITING_SAMPLES;
}
buffered_data_return_t demodualteOFDM( const sample_double_t *sample, OFDM_state_t *OFDMstate, debugPlots_t debugPlots)
{
if(OFDMstate->initialized == 0)
{
initializeOFDMstate(OFDMstate);
OFDMstate->dataOutput = fopen("receiverSequence", "w");
// initialize the state
OFDMstate->state.frame = SEARCHING;
OFDMstate->state.frameStart = sample->sampleIndex;
// initialize buffer to hold input samples for further processing
initializeCircularBuffer_double(&OFDMstate->preambleDetectorInputBuffer, OFDMstate->symbolPeriod * 1.5, OFDMstate->sampleRate);
OFDMstate->disableSFOestimation = 0;
srand(time(NULL));
if(OFDMstate->disableSFOestimation)
{
//OFDMstate->samplingFrequencyOffsetEstimate = 48/pow(10,6);
//OFDMstate->samplingFrequencyOffsetEstimate = (rand()%120 - 60)/pow(10, 6); // initial assumed sampling error. can be set to an inital value for testing the estimator
//OFDMstate->samplingFrequencyOffsetResidual = -OFDMstate->samplingFrequencyOffsetEstimate;
OFDMstate->samplingFrequencyOffsetEstimate = 0 / pow(10,6);
OFDMstate->samplingFrequencyOffsetResidual = 0;
} else {
//OFDMstate->samplingFrequencyOffsetEstimate = (rand()%120 - 60)/pow(10, 6); // initial assumed sampling error. can be set to an inital value for testing the estimator
OFDMstate->samplingFrequencyOffsetEstimate = 0/pow(10,6);
//OFDMstate->samplingFrequencyOffsetEstimate = 0;
OFDMstate->samplingFrequencyOffsetResidual = 0;
}
OFDMstate->pilotSymbolsLength = OFDMstate->channels / OFDMstate->pilotSymbolsPitch;
OFDMstate->pilotSymbols = malloc(sizeof(complex double) * OFDMstate->pilotSymbolsLength);
OFDMstate->initialChannelEstimate = malloc(sizeof(complex double) * OFDMstate->channels); // estimate generated during preamble
for(int k = 0; k < OFDMstate->channels; k++)
OFDMstate->initialChannelEstimate[k] = 1;
OFDMstate->channelEstimate = malloc(sizeof(complex double) * OFDMstate->channels);
for(int k = 0; k < OFDMstate->channels; k++)
OFDMstate->channelEstimate[k] = 1;
OFDMstate->pilotChannelEstimate = malloc(sizeof(complex double) * OFDMstate->pilotSymbolsLength);
for(int i = 0; i < OFDMstate->pilotSymbolsLength; i++)
OFDMstate->pilotChannelEstimate[i] = 1;
// initialize channel simulation buffer
OFDMstate->simulateChannel = 0;
if(OFDMstate->simulateChannel)
{
initializeOverlapAndSaveBuffer(&OFDMstate->channelSimulationBuffer, 5912);
// initialize impulse response buffer
initializeCircularBuffer_double(&OFDMstate->channelImpulseResponse, 5912, 0);
}
initializeCircularBuffer_double(&OFDMstate->sampleInterpolatorBuffer, 2, 0);
initializeCircularBuffer_double(&OFDMstate->autoCorrelationAverageBuffer, 500, 0);
initializeCircularBuffer_double(&OFDMstate->timingFilterInputBuffer, OFDMstate->symbolPeriod * 1.1, 0);
// initialize a buffer to store the second preamble symbol, ie, the first of two identical symbols for sample frequency offset estimation
initializeCircularBuffer_complex(&OFDMstate->sfoFirstSymbol, OFDMstate->channels, 0);
//initializeCircularBuffer_double(&OFDMstate->OFDMsymbol.timeDomain, OFDMstate->ofdmPeriod, 0);
// I'm assuming that fftw_complex is the same width as double complex, which it seems to be
//initializeCircularBuffer_fftw_complex(&OFDMstate->OFDMsymbol.frequencyDomain, OFDMstate->channels, 0);
// make two buffers to hold the results of DFTs for the first and second half of the symmetric preamble/pilot symbol for sample frequency offset detection
initializeCircularBuffer_fftw_complex(&OFDMstate->IQrateDetectorFirstHalf.frequencyDomain, OFDMstate->ofdmPeriod / 4 + 1, 0);
initializeCircularBuffer_fftw_complex(&OFDMstate->IQrateDetectorSecondHalf.frequencyDomain, OFDMstate->ofdmPeriod / 4 + 1, 0);
// the IQ rate detector time domains point to the first and second half of the time sample buffer
OFDMstate->IQrateDetectorFirstHalf.timeDomain.buffer = &OFDMstate->OFDMsymbol.timeDomain.buffer[0];
OFDMstate->IQrateDetectorFirstHalf.timeDomain.length = OFDMstate->OFDMsymbol.timeDomain.length / 2;
OFDMstate->IQrateDetectorSecondHalf.timeDomain.buffer = &OFDMstate->OFDMsymbol.timeDomain.buffer[OFDMstate->OFDMsymbol.timeDomain.length / 2];
OFDMstate->IQrateDetectorSecondHalf.timeDomain.length = OFDMstate->OFDMsymbol.timeDomain.length / 2;
// generate fftw plans
OFDMstate->fftwPlan = fftw_plan_dft_r2c_1d(
OFDMstate->OFDMsymbol.timeDomain.length,
OFDMstate->OFDMsymbol.timeDomain.buffer,
(fftw_complex*)OFDMstate->OFDMsymbol.frequencyDomain.buffer,
FFTW_MEASURE);
OFDMstate->fftwRateDetectorFirstHalfPlan = fftw_plan_dft_r2c_1d(
OFDMstate->IQrateDetectorFirstHalf.timeDomain.length,
OFDMstate->IQrateDetectorFirstHalf.timeDomain.buffer,
(fftw_complex*)OFDMstate->IQrateDetectorFirstHalf.frequencyDomain.buffer,
FFTW_MEASURE);
OFDMstate->fftwRateDetectorSecondHalfPlan = fftw_plan_dft_r2c_1d(
OFDMstate->IQrateDetectorSecondHalf.timeDomain.length,
OFDMstate->IQrateDetectorSecondHalf.timeDomain.buffer,
(fftw_complex*)OFDMstate->IQrateDetectorSecondHalf.frequencyDomain.buffer,
FFTW_MEASURE);
// FYI, I never deallocate the buffers or destroy the plans. Could be bad I guess
// fftw manual says deallocate the arrays with fftw_free() and destroy the plans with fftw_destroy_plan()
// run once
OFDMstate->initialized = 1;
}
sample_double_t equalizedSample;
equalizedSample = *sample;
// run the sample interpolator
//
//
sample_double_t retimedSample;
//retimedSample = equalizedSample;
OFDMstate->sampleInterpolatorBuffer.n = equalizedSample.sampleIndex;
OFDMstate->sampleInterpolatorBuffer.sampleRate = equalizedSample.sampleRate;
OFDMstate->sampleInterpolatorBuffer.phase = 0;
OFDMstate->sampleInterpolatorBuffer.buffer[OFDMstate->sampleInterpolatorBuffer.insertionIndex] = equalizedSample.sample;
buffered_data_return_t returnValue = interpolateSample(&OFDMstate->sampleInterpolatorBuffer, &retimedSample, OFDMstate, debugPlots);
//buffered_data_return_t returnValue = RETURNED_SAMPLE;
//retimedSample = equalizedSample;
OFDMstate->sampleInterpolatorBuffer.insertionIndex = (OFDMstate->sampleInterpolatorBuffer.insertionIndex + 1) % OFDMstate->sampleInterpolatorBuffer.length;
if(returnValue != RETURNED_SAMPLE)
return AWAITING_SAMPLES;
//retimedSample = equalizedSample;
// then move on to the preamble detector
OFDMstate->preambleDetectorInputBuffer.buffer[OFDMstate->preambleDetectorInputBuffer.insertionIndex] = retimedSample.sample;
// add sample to the ofdm symbol window buffer
OFDMstate->preambleDetectorInputBuffer.n = retimedSample.sampleIndex;
// run general channel statistics for autocorrelation and RMS determination
// run the state machine
switch(OFDMstate->state.frame)
{
case SEARCHING:
// auto correlation filter preample detector
// simplified iterative version of the auto correlation
static double iterativeAutocorrelation = 0;
static double secondHalfEnergy = 0;
OFDMstate->autoCorrelation.sample = 0;
OFDMstate->autoCorrelation.sampleIndex = OFDMstate->preambleDetectorInputBuffer.n - OFDMstate->ofdmPeriod;
int firstHalfFirstIndex = (OFDMstate->preambleDetectorInputBuffer.insertionIndex + OFDMstate->preambleDetectorInputBuffer.length - OFDMstate->ofdmPeriod) % OFDMstate->preambleDetectorInputBuffer.length;
int firstHalfSecondIndex = (firstHalfFirstIndex + OFDMstate->ofdmPeriod / 2) % OFDMstate->preambleDetectorInputBuffer.length;
int secondHalfFirstIndex = (firstHalfSecondIndex) % OFDMstate->preambleDetectorInputBuffer.length;
int secondHalfSecondIndex = (secondHalfFirstIndex + OFDMstate->ofdmPeriod / 2) % OFDMstate->preambleDetectorInputBuffer.length;
if(secondHalfFirstIndex < 0) // fix possible negatives due to subtraction
secondHalfFirstIndex += OFDMstate->preambleDetectorInputBuffer.length;
double point_d = OFDMstate->preambleDetectorInputBuffer.buffer[firstHalfFirstIndex]; // d oldest sample
double point_dl = OFDMstate->preambleDetectorInputBuffer.buffer[firstHalfSecondIndex]; // d+L middle sample
double point_dl2 = OFDMstate->preambleDetectorInputBuffer.buffer[secondHalfFirstIndex]; // d+L middle sample
double point_d2l = OFDMstate->preambleDetectorInputBuffer.buffer[secondHalfSecondIndex]; // d+2L most recent sample
iterativeAutocorrelation = iterativeAutocorrelation +
point_dl * point_d2l -
point_d * point_dl;
secondHalfEnergy = secondHalfEnergy +
pow(point_d2l, 2) -
pow(point_dl, 2);
OFDMstate->receivedRMS.sample = sqrt(secondHalfEnergy / OFDMstate->preambleDetectorInputBuffer.length);
OFDMstate->receivedRMS.sampleRate = 0;
OFDMstate->receivedRMS.sampleIndex = 0;
// I think this causes issues with quiet tones auto correlating to high values and triggering a frame detection. I don't know the solution
//OFDMstate->autoCorrelation.sample = fabs(iterativeAutocorrelation) / secondHalfEnergy; // normalization to remove average gain dependance
//if(secondHalfEnergy == 0)
//OFDMstate->autoCorrelation.sample = 0; // eliminate divide by zero error
// uncomment to disable the shitty auto gain
//OFDMstate->autoCorrelation.sample = (iterativeAutocorrelation / 10); // enable if the autocorrelation normalization is to be ignored
//OFDMstate->autoCorrelation.sample = sqrt(fabs(iterativeAutocorrelation) / ((double)OFDMstate->preambleDetectorInputBuffer.length / 2)); // enable if the autocorrelation normalization is to be ignored
double iterAuto_2 = pow(iterativeAutocorrelation, 2);
double secHaEn_2 = pow(secondHalfEnergy, 2);
OFDMstate->autoCorrelation.sample = secHaEn_2 == 0 ? 0 : iterAuto_2/ secHaEn_2; // enable if the autocorrelation normalization is to be ignored
// average filtered auto correlation signal
OFDMstate->autoCorrelationAverageBuffer.buffer[OFDMstate->autoCorrelationAverageBuffer.insertionIndex] = OFDMstate->autoCorrelation.sample;
OFDMstate->autoCorrelationAverageBuffer.n = OFDMstate->autoCorrelation.sampleIndex;
static double runningAverage = 0; // for the averaging function
sample_double_t averageValue = {0};
averagingFilter(&OFDMstate->autoCorrelationAverageBuffer, &averageValue, &runningAverage);
OFDMstate->autoCorrelationAverageBuffer.insertionIndex = (OFDMstate->autoCorrelationAverageBuffer.insertionIndex + 1) % OFDMstate->autoCorrelationAverageBuffer.length;
OFDMstate->timingFilterInputBuffer.buffer[OFDMstate->timingFilterInputBuffer.insertionIndex] = averageValue.sample;
OFDMstate->timingFilterInputBuffer.n = averageValue.sampleIndex;
static double autocorrelationAverage = 0;
sample_double_t windowAverage = {0};
averagingFilter(&OFDMstate->timingFilterInputBuffer, &windowAverage, &autocorrelationAverage);
sample_double_t timingSignal = {0};
//timingSignal.sample = 1;
//buffered_data_return_t returnValue = AWAITING_SAMPLES;
buffered_data_return_t returnValue = timingPeakDetectionFilter(&OFDMstate->timingFilterInputBuffer, &timingSignal, &windowAverage, OFDMstate, debugPlots);
OFDMstate->timingFilterInputBuffer.insertionIndex = (OFDMstate->timingFilterInputBuffer.insertionIndex + 1) % OFDMstate->timingFilterInputBuffer.length;
// graph the correlation function
if(debugPlots.OFDMtimingSyncEnabled && retimedSample.sampleIndex % 500 == 0)
{
fprintf(debugPlots.OFDMtimingSyncStdin, "%i %i %f\n", retimedSample.sampleIndex, 1, retimedSample.sample);
//fprintf(debugPlots.OFDMtimingSyncStdin, "%i %i %f\n", averageValue.sampleIndex, 8, windowAverage.sample);
fprintf(debugPlots.OFDMtimingSyncStdin, "%i %i %f\n", averageValue.sampleIndex, 4, averageValue.sample);
fprintf(debugPlots.OFDMtimingSyncStdin, "%i %i %f\n", averageValue.sampleIndex, 11, OFDMstate->receivedRMS.sample);
//fprintf(debugPlots.OFDMtimingSyncStdin, "%i %i %f\n", averageValue.sampleIndex, 12, iterAuto_2);
//fprintf(debugPlots.OFDMtimingSyncStdin, "%i %i %f\n", averageValue.sampleIndex, 13, secHaEn_2);
}
// preambe triggered
if(returnValue == RETURNED_SAMPLE)
{
// save the timing offset
OFDMstate->ofdmPhaseOffset = timingSignal.sampleIndex;
// draw the preamble buffer to the decoder chart
if(debugPlots.OFDMdecoderEnabled)
{
for(int i = 0; i < OFDMstate->preambleDetectorInputBuffer.length; i++)
{
int preambleBufferIndex = (OFDMstate->preambleDetectorInputBuffer.insertionIndex + 1 + i) % OFDMstate->preambleDetectorInputBuffer.length;
int timeIndex = i - OFDMstate->preambleDetectorInputBuffer.length + 1 + (OFDMstate->preambleDetectorInputBuffer.n - OFDMstate->ofdmPhaseOffset + OFDMstate->guardPeriod);
fprintf(debugPlots.OFDMdecoderStdin, "%i %i %f\n",timeIndex, 0, OFDMstate->preambleDetectorInputBuffer.buffer[preambleBufferIndex]);
}
}
OFDMstate->OFDMsymbol.timeDomain.insertionIndex = 0; // set indexes to the last sample inserted
OFDMstate->OFDMsymbol.timeDomain.n = 0;
OFDMstate->OFDMsymbol.timeDomain.sampleRate = OFDMstate->preambleDetectorInputBuffer.sampleRate;
// change state to active
OFDMstate->state.frame = ACTIVE;
OFDMstate->state.field = PREAMBLE;
OFDMstate->state.symbolIndex = 0;
OFDMstate->state.processedSymbols = 0; // how many symbols have been processed so far total
}
break;
case ACTIVE:
// check if there are enough samples in the preamble buffer to do the next symbol
int correctedBufferTime = OFDMstate->preambleDetectorInputBuffer.n - OFDMstate->ofdmPhaseOffset + OFDMstate->guardPeriod;
int symbolIndex = correctedBufferTime / OFDMstate->symbolPeriod; // calculate the symbol that's currently being filled in the buffer
// draw the raw samples for debug purposes
if(debugPlots.OFDMdecoderEnabled)
{
fprintf(debugPlots.OFDMdecoderStdin, "%i %i %f\n", correctedBufferTime, 1, OFDMstate->preambleDetectorInputBuffer.buffer[OFDMstate->preambleDetectorInputBuffer.insertionIndex]);
}
// check if there are enough samples in the input buffers to process the next sample
// ie, is the calculated symbolIndex greater than the last processed symbol index
if(symbolIndex > OFDMstate->state.processedSymbols)
{
// it's time to tear out an ofdmPeriod of samples into the fftw buffer and do the math
for(int i = 0; i < OFDMstate->ofdmPeriod; i++)
{
// determine where it is in the buffer
int preambleIndex = (OFDMstate->preambleDetectorInputBuffer.insertionIndex + (OFDMstate->state.processedSymbols * OFDMstate->symbolPeriod + OFDMstate->guardPeriod + i - correctedBufferTime)) % OFDMstate->preambleDetectorInputBuffer.length;
if(preambleIndex < 0)
preambleIndex += OFDMstate->preambleDetectorInputBuffer.length;
// copy it in order to the fftw buffer
// correct for estimated RMS
OFDMstate->OFDMsymbol.timeDomain.buffer[i] = OFDMstate->preambleDetectorInputBuffer.buffer[preambleIndex] / OFDMstate->receivedRMS.sample;
if(debugPlots.OFDMdecoderEnabled)
{
// draw snipped out portion
//int plotIndex = 3 + OFDMstate->state.processedSymbols;
int plotIndex = 3;
fprintf(debugPlots.OFDMdecoderStdin, "%li %i %f\n", OFDMstate->state.processedSymbols * OFDMstate->symbolPeriod + i + OFDMstate->guardPeriod, plotIndex, OFDMstate->OFDMsymbol.timeDomain.buffer[i] - 7);
}
}
// do the fft
fftw_execute(OFDMstate->fftwPlan);
// correct for channel estimate
for(int k = 0; k < OFDMstate->channels; k++)
{
// normalize the dft and correct for channel effects
//OFDMstate->OFDMsymbol.frequencyDomain.buffer[k] /= OFDMstate->channelEstimate[k] * sqrt(OFDMstate->ofdmPeriod);
OFDMstate->OFDMsymbol.frequencyDomain.buffer[k] /= sqrt(OFDMstate->ofdmPeriod);
}
// debug chart for the subchannel IQ plots
if(debugPlots.OFDMrawIQEnabled)
{
// draw a point for every subchannel
for(int k = 0; k < OFDMstate->channels; k++)
{
// plot index for coloring preamble samples
int plotIndex = 0;
if(OFDMstate->state.field == PREAMBLE && OFDMstate->state.symbolIndex < 2) // first preamble symbol
plotIndex = 1;
else if(OFDMstate->state.field == PREAMBLE && OFDMstate->state.symbolIndex < 4) // first preamble symbol
plotIndex = 2;
else if(OFDMstate->state.field == DATA && OFDMstate->state.symbolIndex < 10) // first preamble symbol
plotIndex = 3;
plotPointPerSubchannel(
debugPlots.OFDMrawIQStdin,
OFDMstate->OFDMsymbol.frequencyDomain.buffer[k],
k,
8,
OFDMstate->channels,
plotIndex);
}
}
// then do different things with the data depending on the field
switch(OFDMstate->state.field)
{
case PREAMBLE:
// use the symbols of the preamble to estimate sampling frequency offset and do channel estimation
// random integer for reconstructing signal
long int randomInteger;
// do SFO estimation on the preamble samples by running the FFT on the first half and the second half independently
// this is for symetric symbols (just the first two)
if(OFDMstate->state.symbolIndex < 2)
{
fftw_execute(OFDMstate->fftwRateDetectorFirstHalfPlan);
fftw_execute(OFDMstate->fftwRateDetectorSecondHalfPlan);
double samplingFrequencyOffsetEstimate = 0;
double normalizationFactor = 0;
// calculate sampling frequency offset (skip DC and highest frequency in the DFTs)
//for(int i = 1; i < OFDMstate->channels / 2 - 1; i++)
for(int k = 1; k < OFDMstate->channels - 1; k++)
{
if(k % 2 == 0)
{
int i = k / 2;
constellation_complex_t constellation = OFDMstate->constellations[0];
lrand48_r(&OFDMstate->preamblePilotsPRNG, &randomInteger);
complex double expectedIQ = constellation.points[randomInteger % constellation.length];
// estimate sampling frequency offset
// does not take into account the length of a guard interval inbetween
// result is in samplingFrequencyOffsetEstimateratio of sampling frequency offset
samplingFrequencyOffsetEstimate +=
(
carg(
OFDMstate->IQrateDetectorFirstHalf.frequencyDomain.buffer[i] /
OFDMstate->IQrateDetectorSecondHalf.frequencyDomain.buffer[i]
) / (2 * M_PI * i) * i
);
normalizationFactor += i;
}
}
samplingFrequencyOffsetEstimate /= normalizationFactor;
if(debugPlots.OFDMsfoEstimatorEnabled)
{
fprintf(
debugPlots.OFDMsfoEstimatorStdin,
"%i %i %f\n",
OFDMstate->state.symbolIndex,
0,
OFDMstate->samplingFrequencyOffsetEstimate * pow(10, 6)
);
fprintf(debugPlots.OFDMsfoEstimatorStdin, "%i %i %f\n", OFDMstate->state.symbolIndex, 1, samplingFrequencyOffsetEstimate * pow(10,6));
}
// adjust the offset estimate
if(!OFDMstate->disableSFOestimation)
OFDMstate->samplingFrequencyOffsetEstimate += samplingFrequencyOffsetEstimate * 0.9;// * 0.7;// * 0.70;
// there is an issue with this correction, since the offset may not take effect before the next OFDM due to buffering
}
// then do SFO estimation again on the on the next two symbol
// two or three steps should be enough to get close, then we'll use pilot symbols to track the phases and correct for residual SFO
// using phase corrections only rather than resampling corrections
// we'll also use the third preamble symbol for channel estimation, so estimation will happen before the fine SFO correction, should be ok?
// the next two conditions are for full length repeated symbols
// I'm not doing anything with the first preamble symbol right now
// for the second, store the decoded IQ values into a buffer
else if(OFDMstate->state.symbolIndex % 2 == 0)
{
for(int k = 1; k < OFDMstate->channels - 1; k++) // skip DC and Niquist
{
constellation_complex_t constellation = OFDMstate->constellations[0];
lrand48_r(&OFDMstate->preamblePilotsPRNG, &randomInteger);
complex double expectedIQ = constellation.points[randomInteger % constellation.length];
complex double receivedIQ = OFDMstate->OFDMsymbol.frequencyDomain.buffer[k];
// copy values
OFDMstate->sfoFirstSymbol.buffer[k] = receivedIQ;
// measure the channel response on each corrected symbol
OFDMstate->initialChannelEstimate[k] = receivedIQ / expectedIQ;
OFDMstate->channelEstimate[k] = OFDMstate->initialChannelEstimate[k];
/*
fprintf(
OFDMstate->dataOutput,
"n=%i k=%i %li: %lf+%lfi : %lf+%lfi : %lf+%lfi abs-> %lf %li\n",
OFDMstate->state.symbolIndex,
k,
randomInteger,
creal(expectedIQ),
cimag(expectedIQ),
creal(receivedIQ),
cimag(receivedIQ),
creal(OFDMstate->initialChannelEstimate[k]),
cimag(OFDMstate->initialChannelEstimate[k]),
cabs(OFDMstate->initialChannelEstimate[k]),
OFDMstate->state.processedSymbols
);
*/
}
}
// and on the third, do some calculations to estimate the sampling frequency offset
else if(OFDMstate->state.symbolIndex % 2 == 1)
{
double samplingFrequencyOffsetEstimate = 0;
double normalizationFactor = 0;
// calculate sampling frequency offset (skip DC and highest frequency
for(int k = 1; k < OFDMstate->channels - 1; k++)
{
// estimate sampling frequency offset
// takes into account the additional time for phasing due to the guard period, which was not included in Sliskovic2001, due to my usage of two independant complete OFDM symbols with a guard period in between
// result is in samplingFrequencyOffsetEstimateratio of sampling frequency offset
samplingFrequencyOffsetEstimate += carg(OFDMstate->sfoFirstSymbol.buffer[k] / OFDMstate->OFDMsymbol.frequencyDomain.buffer[k]) / (2 * M_PI * k * ((double)OFDMstate->guardPeriod / OFDMstate->ofdmPeriod + 1)) * k;
normalizationFactor += k;
}
samplingFrequencyOffsetEstimate /= normalizationFactor;
if(debugPlots.OFDMsfoEstimatorEnabled)
{
fprintf(debugPlots.OFDMsfoEstimatorStdin, "%i %i %f\n", OFDMstate->state.symbolIndex, 0, OFDMstate->samplingFrequencyOffsetEstimate * pow(10, 6));
fprintf(debugPlots.OFDMsfoEstimatorStdin, "%i %i %f\n", OFDMstate->state.symbolIndex, 1, samplingFrequencyOffsetEstimate * pow(10,6));
}
// adjust the offset estimate
samplingFrequencyOffsetEstimate *= 1;// weight
if(!OFDMstate->disableSFOestimation)
OFDMstate->samplingFrequencyOffsetEstimate += samplingFrequencyOffsetEstimate;
}
// check if it's time to exit the preamble
if(OFDMstate->state.symbolIndex == 3)
{
OFDMstate->state.field = DATA;
OFDMstate->state.symbolIndex = -1; // reset the symbol index for the data field
}
break;
case DATA:
double samplingFrequencyOffsetEstimate = 0;
double normalizationFactor = 0;
// for each channel, estimate SFO and the channel, for pilots
for(int k = 1; k < OFDMstate->channels - 1; k++)
{
// calculating original data and pilot symbols
long int randomIntegerPilot;
//long int randomIntegerData;
//lrand48_r(&OFDMstate->predefinedDataPRNG, &randomIntegerPilot);
//lrand48_r(&OFDMstate->predefinedDataPRNG, &randomIntegerData);
// grab pilot symbols and calculate an estimate for sampling frequency offset
if(k % OFDMstate->pilotSymbolsPitch == 0) // pilot channels
{
if(OFDMstate->state.symbolIndex == 0)
{
// first pilot symbol
//for(int i = 1; i < OFDMstate->pilotSymbolsLength + 1; i++)
//for(int k = 1; k < OFDMstate->channels - 1; k++)
{
//if(k%OFDMstate->pilotSymbolsPitch == 0)
{
int i = k / OFDMstate->pilotSymbolsPitch; // index into pilot symbol arrays
constellation_complex_t constellation = OFDMstate->constellations[0];
lrand48_r(&OFDMstate->pilotsPRNG, &randomIntegerPilot);
complex double expectedIQ = constellation.points[randomIntegerPilot % constellation.length]; // multiply by the BPSK expected pilot to remove randomness
complex double receivedIQ = OFDMstate->OFDMsymbol.frequencyDomain.buffer[k];
complex double currentPilotSymbol = receivedIQ * expectedIQ; // multiply by the BPSK expected pilot to remove randomness
// store pilot symbol for next symbol calculations
OFDMstate->pilotSymbols[i] = currentPilotSymbol;
//fprintf(OFDMstate->dataOutput, "n=%i k=%i %li: %lf+%lfi : %lf+%lfi : %lf+%lfi %li\n", OFDMstate->state.symbolIndex, k, randomIntegerPilot, creal(expectedIQ), cimag(expectedIQ), creal(receivedIQ), cimag(receivedIQ), creal(currentPilotSymbol), cimag(currentPilotSymbol), OFDMstate->state.processedSymbols);
}
}
} else if(OFDMstate->state.symbolIndex > 0)
{
// for each channel skip DC and highest frequency
//for(int k = 1; k < OFDMstate->channels - 1; k++)
{
//for(int i = 1; i < OFDMstate->pilotSymbolsLength + 1; i++)
//if(k % OFDMstate->pilotSymbolsPitch == 0)
//for(int i = OFDMstate->pilotSymbolsLength / 5; i < OFDMstate->pilotSymbolsLength * 3 / 5; i++)
{
// calculate sampling frequency offset
// calculate channel index from pilot index
//int k = i * OFDMstate->pilotSymbolsPitch;
int i = k / OFDMstate->pilotSymbolsPitch; // index into pilot symbol arrays
// estimate sampling frequency offset
// takes into account the additional time for phasing due to the guard period, which was not included in Sliskovic2001, due to my usage of two independant complete OFDM symbols with a guard period in between
// result is in samplingFrequencyOffsetEstimateratio of sampling frequency offset
constellation_complex_t constellation = OFDMstate->constellations[0];
lrand48_r(&OFDMstate->pilotsPRNG, &randomIntegerPilot);
complex double expectedIQ = constellation.points[randomIntegerPilot % constellation.length]; // multiply by the BPSK expected pilot to remove randomness
complex double receivedIQ = OFDMstate->OFDMsymbol.frequencyDomain.buffer[k];
complex double currentPilotSymbol= receivedIQ * expectedIQ; // multiply by the BPSK expected pilot to remove randomness
/*
fprintf(
OFDMstate->dataOutput,
"n=%i k=%i %li: %lf+%lfi : %lf+%lfi : %lf+%lfi %li\n",
OFDMstate->state.symbolIndex,
k,
randomIntegerPilot,
creal(expectedIQ),
cimag(expectedIQ),
creal(receivedIQ),
cimag(receivedIQ),
creal(currentPilotSymbol),
cimag(currentPilotSymbol),
OFDMstate->state.processedSymbols
);
*/
// estimate channel for pilots
OFDMstate->pilotChannelEstimate[i] = receivedIQ / expectedIQ / OFDMstate->initialChannelEstimate[k];
// estimate SFO
double samplingFrequencyOffsetEstimateChange =
carg(OFDMstate->pilotSymbols[i] / (currentPilotSymbol))
/ (2 * M_PI * k * ((double)OFDMstate->guardPeriod / OFDMstate->ofdmPeriod + 1))
* k;
// move pilot value to the old buffer
OFDMstate->pilotSymbols[i] = currentPilotSymbol;
// testing the idea of excluding noisy pilot channels
// according to the amplitude of it's channel estimation
// Should update this in the future to use the calculated SNR of
// a particular pilot channel
if(cabs(OFDMstate->channelEstimate[k]) < 0.5)
continue;
samplingFrequencyOffsetEstimate += samplingFrequencyOffsetEstimateChange;
normalizationFactor += k;
}
}
}
} else { // data channels.I think this needs to be moved to it's own for loop, so the equalizer can have up to date info from pilots for this symbol
// doing nothing here
}
}
if(OFDMstate->state.symbolIndex > 0) // calculations for SFO estimation using pilot channels
{
// finish calculations for samplingFrequencyOffset
samplingFrequencyOffsetEstimate = normalizationFactor == 0 ? 0 : samplingFrequencyOffsetEstimate / normalizationFactor;
if(debugPlots.OFDMsfoEstimatorEnabled)
fprintf(debugPlots.OFDMsfoEstimatorStdin,
"%i %i %f\n"
"%i %i %f\n"
"%i %i %f\n",
OFDMstate->state.symbolIndex + 4, 3, OFDMstate->samplingFrequencyOffsetResidual * pow(10, 6),
OFDMstate->state.symbolIndex + 4, 4, samplingFrequencyOffsetEstimate * pow(10,6),
OFDMstate->state.symbolIndex + 4, 5, (OFDMstate->samplingFrequencyOffsetResidual + OFDMstate->samplingFrequencyOffsetEstimate) * pow(10, 6));
// decaying weight, with a minimum floor
double initialValue = 1;
double decayConstant = 10; // time in samples until the weight falls to 1/e of initial value
double minimum = 0.01; // minimum value
//double minimum = initialValue; // disables the exponential decay bit
double weight = initialValue * exp(-OFDMstate->state.symbolIndex / decayConstant);
weight = weight < minimum ? minimum : weight;
// adjust the offset estimate
if(!OFDMstate->disableSFOestimation)
{
// store the offset into the residual for phase corrections since initial channel estimation
OFDMstate->samplingFrequencyOffsetResidual += samplingFrequencyOffsetEstimate * weight;// * 0.70;
// correct the resampler rate for future symbols
OFDMstate->samplingFrequencyOffsetEstimate += samplingFrequencyOffsetEstimate * weight;// * 0.70;
}
}
double errorRate = 0;
// now process each data channel
for(int k = 1; k < OFDMstate->channels - 1; k++)
{
// correct for channel equalization
// no pilot info available for first symbol
if(OFDMstate->state.symbolIndex != 0)
{
// update the channelEstimate using information from the pilots
int pilotBeforeIndex = floor((double)k / OFDMstate->pilotSymbolsPitch);
pilotBeforeIndex = pilotBeforeIndex < 1 ? 1 : pilotBeforeIndex;
double pilotBeforeWeight = 1 - (double)(k % OFDMstate->pilotSymbolsPitch - 1) / OFDMstate->pilotSymbolsPitch;
int pilotAfterIndex = ceil((double)k / OFDMstate->pilotSymbolsPitch);
pilotAfterIndex = pilotAfterIndex > OFDMstate->pilotSymbolsLength - 2 ? OFDMstate->pilotSymbolsLength - 2 : pilotAfterIndex;
double pilotAfterWeight = 1 - pilotBeforeWeight;
// linear interpolation between nearby pilot symbol channel estimates
complex double newEstimate =
pilotBeforeWeight * OFDMstate->pilotChannelEstimate[pilotBeforeIndex] +
pilotAfterWeight * OFDMstate->pilotChannelEstimate[pilotAfterIndex];
newEstimate *= OFDMstate->initialChannelEstimate[k];
// limit corrections to high SNR pilots
//if(cabs(OFDMstate->pilotChannelEstimate[pilotBeforeIndex]) > 0.5 &&
//cabs(OFDMstate->pilotChannelEstimate[pilotAfterIndex]) > 0.5)
if(1) // use all pilots
{
if(OFDMstate->state.symbolIndex == 0)
{
OFDMstate->channelEstimate[k] = newEstimate;
} else {
OFDMstate->channelEstimate[k] = newEstimate;
}
}
}
// correct for channel estimate, only for the data channels
OFDMstate->OFDMsymbol.frequencyDomain.buffer[k] /= OFDMstate->channelEstimate[k];
// plot corrected IQ data
if(debugPlots.OFDMdataIQEnabled)
{
plotPointPerSubchannel(
debugPlots.OFDMdataIQStdin,
OFDMstate->OFDMsymbol.frequencyDomain.buffer[k],
k,
sqrt(2) * 4,
OFDMstate->channels,
0);
}
// make sure it's not a pilot channel, otherwise the random number gen gets out of sync
if(k % OFDMstate->pilotSymbolsPitch != 0)
{
long int randomIntegerData;
// run a discriminator to classify the recieved symbols
// TODO
constellation_complex_t constellation = OFDMstate->constellations[k%(OFDMstate->constellationsLength - 1) + 1];
complex double receivedIQ = OFDMstate->OFDMsymbol.frequencyDomain.buffer[k];
// I'll try an easy inefficient algorithm, just test for nearest constellation point
int decodedConstellationIndex = quantizeIQsample(&constellation, receivedIQ);
if(0)
{
// checking the accuracy of the channel estimation given known data
// picking a sequential constellation, and a random point in that constellation discluding the first entry
lrand48_r(&OFDMstate->predefinedDataPRNG, &randomIntegerData);
int expectedConstellationIndex = randomIntegerData % constellation.length;
complex double expectedIQ = constellation.points[expectedConstellationIndex];
//fprintf(OFDMstate->dataOutput, "n=%i k=%i %li: %lf+%lfi : %lf+%lfi %li\n", OFDMstate->state.symbolIndex, k, randomIntegerData, creal(expectedIQ), cimag(expectedIQ), creal(receivedIQ), cimag(receivedIQ), OFDMstate->state.processedSymbols);
if(decodedConstellationIndex != expectedConstellationIndex)
errorRate += 1. / OFDMstate->channels;
/*
fprintf(OFDMstate->dataOutput,
"n=%i k=%i integer=%li expected vs received Index=\t%i,%i\n",
OFDMstate->state.symbolIndex,
k,
randomIntegerData,
expectedConstellationIndex,
decodedConstellationIndex);
*/
if(expectedIQ != 0) // make sure we can actually make an estimate, expected symbol isn't at the origin
{
complex double estimatedEqualizerError = receivedIQ / expectedIQ;
// debug chart for the subchannel IQ plots
if(debugPlots.OFDMequalizerErrorIQEnabled)
{
plotPointPerSubchannel(
debugPlots.OFDMequalizerErrorIQStdin,
estimatedEqualizerError,
k,
4,
OFDMstate->channels,
k);
}
}
} else {
reverseHuffmanTree(OFDMstate, &constellation, decodedConstellationIndex);
}
}
// plot channel estimate for all subchannels
if(debugPlots.OFDMequalizerIQEnabled)
{
plotPointPerSubchannel(
debugPlots.OFDMequalizerIQStdin,
OFDMstate->channelEstimate[k],
k,
4,
OFDMstate->channels,
k + OFDMstate->channels);
}
}
/*
fprintf(OFDMstate->dataOutput,
"n=%i errorRate=%f\n",
OFDMstate->state.symbolIndex,
errorRate);
*/
break;
}
// mark that this symbol was extracted and processed, increment the symbol index
OFDMstate->state.processedSymbols++;
OFDMstate->state.symbolIndex++;
}
break;
}
// increment insertion index of input buffer
OFDMstate->preambleDetectorInputBuffer.insertionIndex = (OFDMstate->preambleDetectorInputBuffer.insertionIndex + 1) % OFDMstate->preambleDetectorInputBuffer.length;