Task 557: .PLANET File Format
Task 557: .PLANET File Format
File Format Specifications for .PLANET
The .PLANET file format appears to be a variation or misnomer for the MSI Planet antenna pattern format, which is an ASCII text file used for storing RF antenna radiation patterns. This format is commonly associated with RF propagation tools like Planet (originally developed by MSI). Files typically use .msi or .pln extensions, but based on the query, I'll treat it as .PLANET with the same structure. The format consists of header fields with metadata, followed by horizontal and vertical radiation pattern data. The structure is line-based, with keywords for sections, and data points are tab- or space-separated.
List of all the properties of this file format intrinsic to its file system:
- NAME: The name of the antenna (string).
- MAKE: The manufacturer of the antenna (string).
- FREQUENCY: The design frequency of the antenna (string, e.g., "380 MHz").
- H WIDTH: Horizontal beamwidth in degrees (integer).
- V WIDTH: Vertical beamwidth in degrees (integer).
- FRONT TO BACK: Front-to-back ratio in dB (float).
- GAIN: Antenna gain (string, e.g., "15 dBi").
- HORIZONTAL: Number of horizontal pattern data points (integer), followed by that many lines of angle (float in degrees) and loss (float in dB relative to max gain).
- VERTICAL: Number of vertical pattern data points (integer), followed by that many lines of angle (float in degrees) and loss (float in dB relative to max gain).
Two direct download links for files of format .PLANET:
I was unable to find direct download links for files specifically with the .PLANET extension, as this exact extension does not appear in standard searches. The closest format (.msi or .pln) is available from manufacturer sites, but often requires registration or is bundled in ZIP archives. For illustration, here are links to resources with example content that can be saved as .PLANET files:
- https://amphenolprocom.com/images/shop/catalog/Procomlab/MSIdata/Description-of-Planet-antenna-datafile-GB.pdf (Contains an example file structure in PDF; extract the text example to create a .PLANET file).
- https://www.scribd.com/doc/295436637/MSI-Planet-Antenna-File-Format (PDF with format description and example data; extract to create a .PLANET file).
Ghost blog embedded HTML JavaScript for drag-and-drop .PLANET file dumper:
- Python class for .PLANET file handling:
class PlanetFile:
def __init__(self, filepath):
self.filepath = filepath
self.properties = {}
def read(self):
with open(self.filepath, 'r') as f:
content = f.readlines()
current_section = None
section_count = 0
for line in content:
line = line.strip()
if not line:
continue
parts = line.split()
if parts[0] == 'NAME':
self.properties['name'] = ' '.join(parts[1:])
elif parts[0] == 'MAKE':
self.properties['make'] = ' '.join(parts[1:])
elif parts[0] == 'FREQUENCY':
self.properties['frequency'] = ' '.join(parts[1:])
elif parts[0] == 'H' and parts[1] == 'WIDTH':
self.properties['h_width'] = int(parts[2])
elif parts[0] == 'V' and parts[1] == 'WIDTH':
self.properties['v_width'] = int(parts[2])
elif parts[0] == 'FRONT' and parts[1] == 'TO' and parts[2] == 'BACK':
self.properties['front_to_back'] = float(parts[3])
elif parts[0] == 'GAIN':
self.properties['gain'] = ' '.join(parts[1:])
elif parts[0] == 'HORIZONTAL':
current_section = 'horizontal'
section_count = int(parts[1])
self.properties['horizontal'] = []
elif parts[0] == 'VERTICAL':
current_section = 'vertical'
section_count = int(parts[1])
self.properties['vertical'] = []
elif current_section and section_count > 0:
angle, loss = map(float, parts)
self.properties[current_section].append((angle, loss))
section_count -= 1
if section_count == 0:
current_section = None
def print_properties(self):
for key, value in self.properties.items():
print(f"{key.upper()}: {value}")
def write(self, new_properties=None):
if new_properties:
self.properties = new_properties
with open(self.filepath, 'w') as f:
f.write(f"NAME {self.properties.get('name', '')}\n")
f.write(f"MAKE {self.properties.get('make', '')}\n")
f.write(f"FREQUENCY {self.properties.get('frequency', '')}\n")
f.write(f"H WIDTH {self.properties.get('h_width', 0)}\n")
f.write(f"V WIDTH {self.properties.get('v_width', 0)}\n")
f.write(f"FRONT TO BACK {self.properties.get('front_to_back', 0.0)}\n")
f.write(f"GAIN {self.properties.get('gain', '')}\n")
if 'horizontal' in self.properties:
f.write(f"HORIZONTAL {len(self.properties['horizontal'])}\n")
for angle, loss in self.properties['horizontal']:
f.write(f"{angle} {loss}\n")
if 'vertical' in self.properties:
f.write(f"VERTICAL {len(self.properties['vertical'])}\n")
for angle, loss in self.properties['vertical']:
f.write(f"{angle} {loss}\n")
# Example usage:
# pf = PlanetFile('example.PLANET')
# pf.read()
# pf.print_properties()
# pf.write() # Overwrites with current properties
- Java class for .PLANET file handling:
import java.io.*;
import java.util.*;
public class PlanetFile {
private String filepath;
private Map<String, Object> properties = new HashMap<>();
public PlanetFile(String filepath) {
this.filepath = filepath;
}
public void read() throws IOException {
properties.clear();
try (BufferedReader br = new BufferedReader(new FileReader(filepath))) {
String line;
String currentSection = null;
int sectionCount = 0;
List<double[]> horizontal = new ArrayList<>();
List<double[]> vertical = new ArrayList<>();
while ((line = br.readLine()) != null) {
line = line.trim();
if (line.isEmpty()) continue;
String[] parts = line.split("\\s+");
if (parts[0].equals("NAME")) {
properties.put("name", String.join(" ", Arrays.copyOfRange(parts, 1, parts.length)));
} else if (parts[0].equals("MAKE")) {
properties.put("make", String.join(" ", Arrays.copyOfRange(parts, 1, parts.length)));
} else if (parts[0].equals("FREQUENCY")) {
properties.put("frequency", String.join(" ", Arrays.copyOfRange(parts, 1, parts.length)));
} else if (parts[0].equals("H") && parts[1].equals("WIDTH")) {
properties.put("h_width", Integer.parseInt(parts[2]));
} else if (parts[0].equals("V") && parts[1].equals("WIDTH")) {
properties.put("v_width", Integer.parseInt(parts[2]));
} else if (parts[0].equals("FRONT") && parts[1].equals("TO") && parts[2].equals("BACK")) {
properties.put("front_to_back", Double.parseDouble(parts[3]));
} else if (parts[0].equals("GAIN")) {
properties.put("gain", String.join(" ", Arrays.copyOfRange(parts, 1, parts.length)));
} else if (parts[0].equals("HORIZONTAL")) {
currentSection = "horizontal";
sectionCount = Integer.parseInt(parts[1]);
} else if (parts[0].equals("VERTICAL")) {
currentSection = "vertical";
sectionCount = Integer.parseInt(parts[1]);
} else if (currentSection != null && sectionCount > 0) {
double angle = Double.parseDouble(parts[0]);
double loss = Double.parseDouble(parts[1]);
if (currentSection.equals("horizontal")) {
horizontal.add(new double[]{angle, loss});
} else if (currentSection.equals("vertical")) {
vertical.add(new double[]{angle, loss});
}
sectionCount--;
if (sectionCount == 0) {
currentSection = null;
}
}
}
properties.put("horizontal", horizontal);
properties.put("vertical", vertical);
}
}
public void printProperties() {
for (Map.Entry<String, Object> entry : properties.entrySet()) {
System.out.println(entry.getKey().toUpperCase() + ": " + entry.getValue());
}
}
public void write() throws IOException {
try (BufferedWriter bw = new BufferedWriter(new FileWriter(filepath))) {
bw.write("NAME " + properties.getOrDefault("name", "") + "\n");
bw.write("MAKE " + properties.getOrDefault("make", "") + "\n");
bw.write("FREQUENCY " + properties.getOrDefault("frequency", "") + "\n");
bw.write("H WIDTH " + properties.getOrDefault("h_width", 0) + "\n");
bw.write("V WIDTH " + properties.getOrDefault("v_width", 0) + "\n");
bw.write("FRONT TO BACK " + properties.getOrDefault("front_to_back", 0.0) + "\n");
bw.write("GAIN " + properties.getOrDefault("gain", "") + "\n");
@SuppressWarnings("unchecked")
List<double[]> horizontal = (List<double[]>) properties.get("horizontal");
if (horizontal != null) {
bw.write("HORIZONTAL " + horizontal.size() + "\n");
for (double[] point : horizontal) {
bw.write(point[0] + " " + point[1] + "\n");
}
}
@SuppressWarnings("unchecked")
List<double[]> vertical = (List<double[]>) properties.get("vertical");
if (vertical != null) {
bw.write("VERTICAL " + vertical.size() + "\n");
for (double[] point : vertical) {
bw.write(point[0] + " " + point[1] + "\n");
}
}
}
}
// Example usage:
// public static void main(String[] args) throws IOException {
// PlanetFile pf = new PlanetFile("example.PLANET");
// pf.read();
// pf.printProperties();
// pf.write();
// }
}
- JavaScript class for .PLANET file handling:
class PlanetFile {
constructor(filepath) {
this.filepath = filepath;
this.properties = {};
}
async read() {
// Note: In Node.js, use fs module; this assumes Node environment
const fs = require('fs');
const content = fs.readFileSync(this.filepath, 'utf8').split('\n').map(line => line.trim());
let currentSection = null;
let sectionCount = 0;
content.forEach(line => {
if (!line) return;
const parts = line.split(/\s+/);
if (parts[0] === 'NAME') this.properties.name = parts.slice(1).join(' ');
else if (parts[0] === 'MAKE') this.properties.make = parts.slice(1).join(' ');
else if (parts[0] === 'FREQUENCY') this.properties.frequency = parts.slice(1).join(' ');
else if (parts[0] === 'H' && parts[1] === 'WIDTH') this.properties.h_width = parseInt(parts[2]);
else if (parts[0] === 'V' && parts[1] === 'WIDTH') this.properties.v_width = parseInt(parts[2]);
else if (parts[0] === 'FRONT' && parts[1] === 'TO' && parts[2] === 'BACK') this.properties.front_to_back = parseFloat(parts[3]);
else if (parts[0] === 'GAIN') this.properties.gain = parts.slice(1).join(' ');
else if (parts[0] === 'HORIZONTAL') {
currentSection = 'horizontal';
sectionCount = parseInt(parts[1]);
this.properties.horizontal = [];
} else if (parts[0] === 'VERTICAL') {
currentSection = 'vertical';
sectionCount = parseInt(parts[1]);
this.properties.vertical = [];
} else if (currentSection && sectionCount > 0) {
const angle = parseFloat(parts[0]);
const loss = parseFloat(parts[1]);
this.properties[currentSection].push({ angle, loss });
sectionCount--;
if (sectionCount === 0) currentSection = null;
}
});
}
printProperties() {
for (const [key, value] of Object.entries(this.properties)) {
console.log(`${key.toUpperCase()}: ${JSON.stringify(value)}`);
}
}
write() {
const fs = require('fs');
let data = `NAME ${this.properties.name || ''}\n`;
data += `MAKE ${this.properties.make || ''}\n`;
data += `FREQUENCY ${this.properties.frequency || ''}\n`;
data += `H WIDTH ${this.properties.h_width || 0}\n`;
data += `V WIDTH ${this.properties.v_width || 0}\n`;
data += `FRONT TO BACK ${this.properties.front_to_back || 0.0}\n`;
data += `GAIN ${this.properties.gain || ''}\n`;
if (this.properties.horizontal) {
data += `HORIZONTAL ${this.properties.horizontal.length}\n`;
this.properties.horizontal.forEach(p => data += `${p.angle} ${p.loss}\n`);
}
if (this.properties.vertical) {
data += `VERTICAL ${this.properties.vertical.length}\n`;
this.properties.vertical.forEach(p => data += `${p.angle} ${p.loss}\n`);
}
fs.writeFileSync(this.filepath, data);
}
}
// Example usage:
// const pf = new PlanetFile('example.PLANET');
// await pf.read();
// pf.printProperties();
// pf.write();
- C++ class for .PLANET file handling:
#include <iostream>
#include <fstream>
#include <vector>
#include <string>
#include <sstream>
#include <utility>
class PlanetFile {
private:
std::string filepath;
std::string name;
std::string make;
std::string frequency;
int h_width;
int v_width;
double front_to_back;
std::string gain;
std::vector<std::pair<double, double>> horizontal;
std::vector<std::pair<double, double>> vertical;
public:
PlanetFile(const std::string& fp) : filepath(fp), h_width(0), v_width(0), front_to_back(0.0) {}
void read() {
std::ifstream file(filepath);
if (!file.is_open()) {
std::cerr << "Error opening file" << std::endl;
return;
}
std::string line, current_section;
int section_count = 0;
while (std::getline(file, line)) {
std::istringstream iss(line);
std::string token;
iss >> token;
if (token == "NAME") {
std::getline(iss, name);
} else if (token == "MAKE") {
std::getline(iss, make);
} else if (token == "FREQUENCY") {
std::getline(iss, frequency);
} else if (token == "H" && (iss >> token) && token == "WIDTH") {
iss >> h_width;
} else if (token == "V" && (iss >> token) && token == "WIDTH") {
iss >> v_width;
} else if (token == "FRONT" && (iss >> token) && token == "TO" && (iss >> token) && token == "BACK") {
iss >> front_to_back;
} else if (token == "GAIN") {
std::getline(iss, gain);
} else if (token == "HORIZONTAL") {
current_section = "horizontal";
iss >> section_count;
horizontal.clear();
} else if (token == "VERTICAL") {
current_section = "vertical";
iss >> section_count;
vertical.clear();
} else if (!current_section.empty() && section_count > 0) {
double angle, loss;
std::istringstream data_line(line);
data_line >> angle >> loss;
if (current_section == "horizontal") {
horizontal.emplace_back(angle, loss);
} else if (current_section == "vertical") {
vertical.emplace_back(angle, loss);
}
section_count--;
if (section_count == 0) current_section = "";
}
}
file.close();
}
void print_properties() {
std::cout << "NAME: " << name << std::endl;
std::cout << "MAKE: " << make << std::endl;
std::cout << "FREQUENCY: " << frequency << std::endl;
std::cout << "H WIDTH: " << h_width << std::endl;
std::cout << "V WIDTH: " << v_width << std::endl;
std::cout << "FRONT TO BACK: " << front_to_back << std::endl;
std::cout << "GAIN: " << gain << std::endl;
std::cout << "HORIZONTAL: " << std::endl;
for (const auto& p : horizontal) {
std::cout << p.first << " " << p.second << std::endl;
}
std::cout << "VERTICAL: " << std::endl;
for (const auto& p : vertical) {
std::cout << p.first << " " << p.second << std::endl;
}
}
void write() {
std::ofstream file(filepath);
if (!file.is_open()) {
std::cerr << "Error opening file for write" << std::endl;
return;
}
file << "NAME" << name << "\n";
file << "MAKE" << make << "\n";
file << "FREQUENCY" << frequency << "\n";
file << "H WIDTH " << h_width << "\n";
file << "V WIDTH " << v_width << "\n";
file << "FRONT TO BACK " << front_to_back << "\n";
file << "GAIN" << gain << "\n";
file << "HORIZONTAL " << horizontal.size() << "\n";
for (const auto& p : horizontal) {
file << p.first << " " << p.second << "\n";
}
file << "VERTICAL " << vertical.size() << "\n";
for (const auto& p : vertical) {
file << p.first << " " << p.second << "\n";
}
file.close();
}
};
// Example usage:
// int main() {
// PlanetFile pf("example.PLANET");
// pf.read();
// pf.print_properties();
// pf.write();
// return 0;
// }