# Program to parse a TVStudy U_CelData.csv file and plot cells with interference from a selected source # Very manual operation -- obtain the ix_source ID number from the sources.csv file in the same directory as the U_CelData.csv file # Version 0.1 - successful creation of list of cells with population and unique interference from the selected ix source ID! # Version 0.2 - sorted results by D/U and population and output as a new csv file of cells with unique interference only # Version 0.3 - Plot interference cells using simplekml # Version 0.4 - Calculate power reduction required to reduced new ix to 0.5% and display cells protected in csv file and kml file # Version 0.5 - Remove absolute paths, clean up floating point string formatting to- show only 3 decimal places # Version 0.6 - Change icon colors for different kml plots -- red for cells to clear, default yellow for rest, add ERP calc if available # Version 0.7 - Add cells where unique ix is permitted to kml plot as green icons # Version 0.8 - Fix major issue when sorting D/U ratio as a string by adding an IX_level field to to the list # Version 0.9 - Generate text file with summary data # Version 1.0 - Fixed bug in ix_from_source generation, add variable to change allowable interference threshold and display in summary # Version 1.1 - Include SNR Factor when calculating power reduction # Version 1.2 - Resolve some formatting issues with csv files # Version 1.3 - Simplify interference calculation using data from the study's tvstudy.txt file instead of modified station's unique interference to victim. This works when there is only one new source of interference in the study. from operator import itemgetter # Required to sort the cell list import simplekml # Used to generate the kml file import math # Used in interference calculation to round calculated 0.5% population ix value up to next integer value # Change variables as needed for the study CsvFile = "WBIN_U_CelData.csv" # Copy U_CelData.csv from the victim scenario B folder - add call to make it easier to identify ix_source = '1' # This is usually "1" but verify in scenario B sources.csv to be sure Current_ix_free_pop = 4008759 # Obtain from Scenario A ix free population for victim in study's tvstudy.txt Study_ix_free_pop = 3986938 # Obtain from Scenario B ix_free_population for victim in study;s tvstudy.txt file # Existing_unique_ix = 30945 # Obtain from unique ix from source in tvstudy.txt file in victim station Scenario "A" folder study_ERP = 250.0 # Power in kW - Obtain from new study parameters ix_threshold = 0.005 # De minimis interference threshold as a decimal fraction. Example: 0.005 for full power, 0.02 for LPTV try: csvData = open(CsvFile, mode='r') except: print(CsvFile + ' not found. Exiting') exit() count = 0 ixdata = [] data = [] # Save only cells that have both interference and population for line in csvData : if (line.strip() != ''): data = line.strip().split(',') if((data[16].strip() == '1') & (int(data[4]) > 0)) : ixdata.append(data) count = count + 1 print(count) # Determine cells with unique interference from ix_source and count total amount of unique interference # You can check this number against TVStudy output to verify correct processing ixdata_by_cell = sorted(ixdata,key=itemgetter(0)) ix_pop = 0 data = [] temp_item = [] lastCellID = '' ix_from_source = [] for item in ixdata_by_cell : if item[0] != lastCellID : if temp_item != [] : ix_from_source.append(temp_item) ix_pop = ix_pop + int(temp_item[4]) temp_item = [] if item[5] == ix_source : temp_item = item temp_item.append((float(temp_item[14]) + float(temp_item[15]) - float(temp_item[13]))) lastCellID = item[0] else : temp_item = [] lastCellID = item[0] if(len(temp_item) > 0) : ix_from_source.append(temp_item) ix_pop = ix_pop + int(temp_item[4]) print(len(ix_from_source)) print(ix_pop) #Sort ix_from_source first by IX_level (low to high) ixdata_sort_by_ix = sorted(ix_from_source,key=itemgetter(19)) # Output sorted data as a CSV file ix_output_file = CsvFile+'_ix_analysis_from_source_#'+ix_source+'-v1.3.csv' ix_output = open(ix_output_file,'w') header = 'Key'+','+'Point_Lat'+','+'Point_Lon'+','+'Point_Area'+','+'Point_Pop'+','+'U_Source_Key'+','+'Site_Num'+','+'D_Source_Key'+','+'D_Field_Str'+','+' Serv_Flag'+','+'U_Field_Str'+','+'Rcv_Pat_Adj'+','+'Bearing'+','+'DU_Ratio'+','+'DU_Thres'+','+'SNR_Fact'+','+'Causes_Ix'+','+'D_KWX_Flag'+','+'U_KWX_Flag' + ',' + 'IX_level \n' ix_output.write(header) for line in ixdata_sort_by_ix : csvout = line[0] + ',' + line[1] + ',' + line[2] + ',' + line[3] + ',' + line[4] + ',' + line[5] + ',' + line[6] + ',' + line[7] + ',' + line[8] + ',' + line[9] + ',' + line[10] + ',' + line[11] + ',' + line[12] + ',' + line[13] + ',' + line[14] + ',' + line[15] + ',' + line[16] + ',' + line[17] + ',' + line[18] + ',' + '{:2.3f}'.format(float(line[19])) + '\n' ix_output.write(csvout) ix_output.close csvout = '' # Create a KML file showing cells with unique interference kml = simplekml.Kml(open=1) for Key, Point_Lat, Point_Lon, Point_Area, Point_Pop, U_Source_Key, Site_Num, D_Source_Key, D_Field_Str, Serv_Flag, U_Field_Str, Rcv_Pat_Adj, Bearing, DU_Ratio, DU_Thres, SNR_Fact, Causes_Ix, D_KWX_Flag, U_KWX_Flag, IX_level in ixdata_sort_by_ix : pnt = kml.newpoint() pnt.name = Key pnt.description = 'Point_Pop: ' + Point_Pop + ' DU_Ratio: ' + DU_Ratio + ' DU_Thres: ' + DU_Thres + ' IX_level(dB): ' + '{:2.3f}'.format(float(DU_Thres) - float(DU_Ratio)) pnt.coords = [('-'+Point_Lon, Point_Lat)] kml.save(CsvFile+"_Unique_IX_from_source_#"+ix_source+".kml") # Calculate de minimis interference and round up to next integer. Add to existing unique interference to determine new interference limit ix_new_allowed = math.floor(Current_ix_free_pop * ix_threshold) # math.floor rounds down result to nearest integer ix_over_limit = Current_ix_free_pop - Study_ix_free_pop - ix_new_allowed print('Current_ix_free_pop = ' + str(Current_ix_free_pop)) print('ix_new_allowed = ' + str(ix_new_allowed)) print('ix_over_limit = ' + str(ix_over_limit)) # Test to see if new interference is within total allowed interference, if so, exit program if ix_over_limit <= 0 : print("New interference to " + str(ix_pop) + " people is less than allowed de minimis ") print("Exiting...") exit() # Step through ixdata_sort_by_ix until interference drops below de minimis IX_level pop_to_clear = ix_over_limit pop_removed = 0 power_reduction = 0 cells_to_clear = [] cells_ix_permitted = [] for cell in ixdata_sort_by_ix : if pop_removed < pop_to_clear : Pop = int(cell[4]) Excess_power = cell[19] cells_to_clear.append(cell) pop_removed = pop_removed + Pop if Excess_power > power_reduction : power_reduction = Excess_power else : cells_ix_permitted.append(cell) print('Power reduction required = ' + '{:2.3f}'.format(power_reduction) + ' dB') maximum_ERP = study_ERP * (math.pow(10,-(power_reduction/10))) print('Maximum ERP allowed for this scenario = ' + '{:4.3f}'.format(maximum_ERP)) # Create new csv file with only cells to cells_to_clear ix_output_file = CsvFile+"_cells_to_clear_for_source_#"+ix_source+"-v1.3.csv" ix_output = open(ix_output_file,'w') header = 'Key'+','+'Point_Lat'+','+'Point_Lon'+','+'Point_Area'+','+'Point_Pop'+','+'U_Source_Key'+','+'Site_Num'+','+'D_Source_Key'+','+'D_Field_Str'+','+' Serv_Flag'+','+'U_Field_Str'+','+'Rcv_Pat_Adj'+','+'Bearing'+','+'DU_Ratio'+','+'DU_Thres'+','+'SNR_Fact'+','+'Causes_Ix'+','+'D_KWX_Flag'+','+'U_KWX_Flag' +','+'IX_level(dB) \n' ix_output.write(header) for line in cells_to_clear : csvout = line[0] + ',' + line[1] + ',' + line[2] + ',' + line[3] + ',' + line[4] + ',' + line[5] + ',' + line[6] + ',' + line[7] + ',' + line[8] + ',' + line[9] + ',' + line[10] + ',' + line[11] + ',' + line[12] + ',' + line[13] + ',' + line[14] + ',' + line[15] + ',' + line[16] + ',' + line[17] + ',' + line[18] + ',' + '{:2.3f}'.format(float(line[19])) + '\n' ix_output.write(csvout) ix_output.close cvsout = '' # Create new kml file showing only cells to clear kml = simplekml.Kml(open=1) for Key, Point_Lat, Point_Lon, Point_Area, Point_Pop, U_Source_Key, Site_Num, D_Source_Key, D_Field_Str, Serv_Flag, U_Field_Str, Rcv_Pat_Adj, Bearing, DU_Ratio, DU_Thres, SNR_Fact, Causes_Ix, D_KWX_Flag, U_KWX_Flag, IX_level in cells_to_clear : pnt = kml.newpoint() pnt.name = Key pnt.iconstyle.color = simplekml.Color.red pnt.description = 'Point_Pop: ' + Point_Pop + ' DU_Ratio: ' + DU_Ratio + ' DU_Thres: ' + DU_Thres + ' IX_level(dB): ' + '{:2.3f}'.format(float(IX_level)) pnt.coords = [('-'+Point_Lon, Point_Lat)] for Key, Point_Lat, Point_Lon, Point_Area, Point_Pop, U_Source_Key, Site_Num, D_Source_Key, D_Field_Str, Serv_Flag, U_Field_Str, Rcv_Pat_Adj, Bearing, DU_Ratio, DU_Thres, SNR_Fact, Causes_Ix, D_KWX_Flag, U_KWX_Flag, IX_level in cells_ix_permitted : pnt = kml.newpoint() pnt.name = Key pnt.iconstyle.color = simplekml.Color.lightgreen pnt.description = 'Point_Pop: ' + Point_Pop + ' DU_Ratio: ' + DU_Ratio + ' DU_Thres: ' + DU_Thres + ' IX_level(dB): ' + '{:2.3f}'.format(float(IX_level)) pnt.coords = [('-'+Point_Lon, Point_Lat)] kml.save(CsvFile+"_cells_to_clear_for_source_#"+ix_source+"-v1.3.kml") # Create a summary file with power level and population data summary_file = CsvFile + '_Results_Summary-v1.3.txt' summary = open(summary_file, 'w') summary.write('Summary of results from processing ' + CsvFile + '\n') summary.write('\n') summary.write('Current interference free coverage: ' + str(Current_ix_free_pop) + '\n') # summary.write('Existing unique interference from source: ' + str(Existing_unique_ix) + '\n') summary.write('Allowed de minimis interference (' + '{:2.2f}'.format(float(ix_threshold*100)) + '%) : ' + str(ix_new_allowed) + '\n') summary.write('ERP studied : ' + '{:4.3f}'.format(float(study_ERP)) + ' kW \n') summary.write('\n') summary.write('Total unique interference from study: ' + str(ix_pop) + '\n') summary.write('Interference above de minimis: ' + str(pop_to_clear) + '\n') summary.write('\n') summary.write('Power reduction required for de minimis interference (dB): ' + '{:3.3f}'.format(float(power_reduction)) + '\n') summary.write('Maximum ERP permitted in this scenario (kW): ' + '{:4.3f}'.format(float(maximum_ERP)) + '\n') summary.write('\n')