Notifications
Clear all
Search result for: id10=WA 0852 2611 9277 Design Interior Rumah Luas Tanah 100 Daerah Bogor Tengah Kota Bogor
Page 1 / 3
Next
A CAD file of MagArrow can be downloaded here if you want to Design such a mounting structure.
Attachment : MagArrow Shell.zip
Please note that the external helical antenna is NOT in the CAD file.
With the provided 10-feet suspension cables, the magnetic noise due to most commercial drones can be ignored. However, some MagArrow customers experience stability issue, especially in windy conditions.
For a small number of drones, the MagArrow can be attached to the landing gear directly with acceptable noises (line-levelling is still required in data processing).
For most drones, however, this configuration causes too much noise. A half rigid mounting Design may solve this problem. It has 2 rigid bars with hinges on one side and 2 flexible cables on the other. On the ground, the rigid side folds to the side. While in the air, gravity will keep the MagArrow further away from the drone. Drone noise can be greatly suppressed since the noise follows 1/R^3. A factor of 2 increase in the separation can lead to a factor of 8 decrease in noise.
Please make sure the hinges and the rigid bars are made of non-magnetic material.
Many of our customers have found out that widening the attaching points of a MagArrow can greatly improve its stability (reducing swings) during flights.
If you are interested in Designing a customized mounting fixture, a CAD file of a MagArrow baseplate can be found here:
In a general sense, the exploration depth of a magnetometer is unlimited. It is certainly sensitive to the Earth's field and this is generated in the Earth's Core, some 5000 km beneath our feet. But for practical purposes, the depth of exploration is determined from survey results by the spatial width of the magnetic field anomaly as observed at the Earth's surface. For discrete objects, the depth of exploration is nominally 1/2 of the width of the magnetic anomaly. This topic is discussed in our Portable Magnetometer Operation Manual. This Manual covers many topics related to survey Design and interpretation including exploration depth. As you will see, survey Design will have a large influence on the depth of investigation.
Raw Data
MagArrow data is imported into Survey Manager in the form of .MAGDATA files, downloaded from the MagArrow. The .MAGDATA file contains measurements from different sensors inside the MagArrow: 1000Hz magnetometer readings; accelerometer, gyro, compass, temperature readings; and GPS info.
MFAM assigns a fiducial number, or “FID” to each magnetometer reading, in a cycle from 1 to 1000 that repeats every second. In the instrument, the magnetometer readings and the GPS sentence data are synchronized so that the “FID-1” magnetometer record is matched with the GPS location and timing information.
Exports to CSV and Geosoft file formats 1000Hz un-filtered export
The 1000Hz export provides the original raw magnetometer data plus some simple interpolations:
• Magnetometer reading: The raw magnetic field values are exported without application of a filter. [While these raw measurements are the output of a filter inside the MFAM sensor: a 9-pole Butterworth low pass filter with a -3dB point at 400Hz, that filter is considered part of the sensor for this description.]
• Auxiliary sensors: Gyro, accelerometer, and temperature are acquired once per every 5 magnetometer readings, and are reported only when acquired. Compass readings are acquired one per every 10 magnetometer readings and are reported only when acquired.
• GPS NMEA sentence: Reported with the associated FID-1 mag record. A few individual fields from the GPS are also broken out from the GPS sentence and reported separately, without interpolation.
• Interpolated GPS fields: Time, date, latitude, longitude, and track (course over ground) are linearly interpolated between GPS readings.
Decimated exports
Each of the exports at frequencies from 10 Hz to 100 Hz is a decimation – data are filtered by a low-pass filter and then down-sampled to the target sample rate. Each low-pass filter (a different one for each decimation) is a symmetric finite impulse response (or FIR) filter, with the following Design goals:
• -3dB attenuation at 0.75 * Nyquist frequency (e.g., the -3dB point for the 10Hz decimation is 3.75Hz)
• Significant attenuation of 50Hz and 60Hz signals.
• Reasonably flat response in the pass band.
Linear phase (or zero phase, or constant group delay) filters.
These filters are not Kalman filters. The filters are applied to fields in the decimations as follows:
• Magnetometer readings: Magnetometer readings are decimated: the FIR is applied, then the data are down-sampled to the target rate.
• Aux sensors: Aux sensors are first up-sampled to 1000Hz by linear interpolation of values between individual readings (which occur once every 5 mag readings for gyro, accelerometer, and temperature, and once every 10 mag readings for compass). Then these 1000Hz values are decimated in the same process as the magnetometer readings.
• Latitude and longitude are first up-sampled to 1000Hz by linear interpolation of values between successive GPS data (once per second), then these 1000 Hz values are decimated in the same process as the magnetometer readings.
• Time, date, and track are linearly interpolated as in the raw, unfiltered 1000Hz export.
Merging filtered and unfiltered data.
Some of the values in an individual line of data are filtered: mag readings, aux sensors, etc. Other measurements are not filtered: time and date, GPS sentences, record counters, and the simple interpolated fields. These two sets of values – filtered and unfiltered, must be reported in individual lines that contain values of both types. The question “How should the two sets of values be matched?” is addressed as follows:
A decimation filter has a center. For example, a single filter result that weighs 499 individual measurements running from record number 752 to record number 1250 (in DSP terms, it is the result of the convolution of 499 input values with 499 filter weights), is centered on record number 1001. The result is the “filtered value of record 1001”. In a single line along with this value should be the other filtered results centered on record number 1001 plus the unfiltered raw and interpolated values that were recorded as part of the original, raw record 1001.
The down-sampling part of decimation involves keeping some results and discarding others; down-sampling from 1000Hz to 100Hz includes discarding 9 out of 10 results. During exports, Survey Manager keeps the “FID 1” record, because it includes the original GPS information, then discards the next 9 records (if it’s a 100Hz decimation), and then repeats the pattern, each time starting with FID 1.
If you have questions about the MagArrow decimations, please contact your Geometrics account manager.
@ellipsis You are welcome! From the front of the front eyelets to the rear of the rear eyelets, it is a little more than 27 inches. So, your CAD reading is corret.
@rzhang thank you. I’m not sure if I’m reading the CAD file correctly. Is it 27.288 inches between the front and rear eyelets for cable attachments?
@ellipsis We would recommend the rigid part to be ~ 1m. So with the landing gear, the MagArrow is about 1.5m from the drone.
Great idea. What would be a recommended minimum distance below the drone?
Hi All,
We are using the Teensy 4.1 as a logger (Adafruit GPS is linked with the Teensy) for the MFAM SX. Below is the code for the Arduino IDE (Teensy), for people who might find it useful,
Roi
#include <NativeEthernet.h>
#include <SD.h>
// ---- NETWORK CONFIGURATION ----
byte mac[] = { 0xDE, 0xAD, 0xBE, 0xEF, 0xFE, 0xED };
IPAddress ip(192, 168, 2, 10);
IPAddress mfamIP(192, 168, 2, 2);
uint16_t mfamPort = 1000;
EthernetClient client;
// ---- PACKET STRUCTURE ----
const int PACKET_SIZE = 1380;
const int SAMPLE_SIZE = 32;
const int HEADER_SIZE = 16;
const int NUM_SAMPLES = 40;
const int SD_CHIP_SELECT = BUILTIN_SDCARD;
uint8_t buffer[PACKET_SIZE];
int bufferPos = 0;
// ---- SD CARD ----
File logFile;
bool sdReady = false;
unsigned long sampleCount = 0;
unsigned long fileStartTime = 0;
char filename[32];
// ---- AUXILIARY CHANNEL STORAGE ----
double gyroX = 0, gyroY = 0, gyroZ = 0, gyroT = 0;
double accelX = 0, accelY = 0, accelZ = 0, accelT = 0;
double compassX = 0, compassY = 0, compassZ = 0, compassT = 0;
// ---- GPS FROM ADAFRUIT MODULE ON SERIAL1 (Pin 0 = RX) ----
char gpsBuffer[256];
int gpsBufferPos = 0;
char gpsString[128] = "";
char gpsDate[12] = "00/00/00";
char gpsTime[16] = "00:00:00.000";
bool gpsFix = false;
uint8_t tsStatus = 0;
// ---- OUTPUT CONTROL ----
// Set to 1 to log every sample, 10 for 100Hz, 20 for 50Hz, etc.
const int DOWNSAMPLE_FACTOR = 1; // 50 Hz output
int downsampleCounter = 0;
// How many minutes per file. Set to 10, 20, 60, etc.
const int FILE_MINUTES = 10;
// ---- LED INDICATOR ----
// Off = starting up
// Very slow blink (every 3 sec) = connected and logging
// Fast blink (4/sec) = connected but no data arriving
// Solid on = no SD card
// 3 quick flashes then pause = cannot connect to MFAM
const int LED_PIN = 13;
unsigned long lastBlinkTime = 0;
bool ledState = false;
unsigned long lastDataTime = 0;
// ---- FUNCTION PROTOTYPES ----
void createNewFile();
void parsePacket(uint8_t* pkt);
void parseAuxChannels(uint8_t* sample, uint16_t frameID);
void readGPS();
void parseGPRMC(char* sentence);
void writeSample(unsigned long timestamp, uint16_t fiducial, double mag1, uint16_t mag1s,
double mag2, uint16_t mag2s, uint16_t sysStatus);
int16_t toSigned16(uint16_t val);
void createNewFile() {
static int fileNumber = 0;
// On first call, find the next available file number
if (fileNumber == 0) {
char testName[32];
for (int i = 1; i <= 99999; i++) {
snprintf(testName, sizeof(testName), "MFAM_%05d.txt", i);
if (!SD.exists(testName)) {
fileNumber = i - 1; // Will be incremented below
break;
}
}
}
fileNumber++;
snprintf(filename, sizeof(filename), "MFAM_%05d.txt", fileNumber);
logFile = SD.open(filename, FILE_WRITE);
if (logFile) {
logFile.println("Mag 1,Mag 2,Fid,SysS,Mg1S,Mg2S,Gyro X,Gyro Y,Gyro Z,Gyro T,Accel X,Accel Y,Accel Z,Accel T,CompassX,CompassY,CompassZ,Comp T,Date,Time,TS Status,GPS");
logFile.flush();
fileStartTime = millis();
Serial.print("Logging to: ");
Serial.println(filename);
} else {
Serial.print("ERROR: Could not create ");
Serial.println(filename);
}
}
void setup() {
Serial.begin(115200);
delay(2000);
// Start GPS serial port (Adafruit Ultimate GPS defaults to 9600 baud)
Serial1.begin(9600);
pinMode(LED_PIN, OUTPUT);
digitalWrite(LED_PIN, LOW);
memset(gpsString, 0, sizeof(gpsString));
// Initialize SD card
if (SD.begin(SD_CHIP_SELECT)) {
sdReady = true;
Serial.println("SD card ready.");
} else {
Serial.println("WARNING: No SD card found. Serial output only.");
digitalWrite(LED_PIN, HIGH);
}
// Initialize Ethernet
Ethernet.begin(mac, ip);
if (Ethernet.hardwareStatus() == EthernetNoHardware) {
Serial.println("ERROR: No Ethernet hardware found!");
while (true) {}
}
Serial.print("Teensy IP: ");
Serial.println(Ethernet.localIP());
Serial.print("Connecting to MFAM at ");
Serial.print(mfamIP);
Serial.print(":");
Serial.println(mfamPort);
if (client.connect(mfamIP, mfamPort)) {
Serial.println("Connected to MFAM!");
} else {
Serial.println("Connection failed!");
}
Serial.println("Waiting for GPS fix...");
if (sdReady) {
createNewFile();
}
Serial.println("Mag 1,Mag 2,Fid,SysS,Mg1S,Mg2S,Gyro X,Gyro Y,Gyro Z,Gyro T,Accel X,Accel Y,Accel Z,Accel T,CompassX,CompassY,CompassZ,Comp T,Date,Time,TS Status,GPS");
}
void loop() {
// Always read GPS data from Serial1
readGPS();
if (!client.connected()) {
Serial.println("Disconnected. Reconnecting...");
if (sdReady && logFile) {
logFile.flush();
}
for (int i = 0; i < 3; i++) {
digitalWrite(LED_PIN, HIGH);
delay(100);
digitalWrite(LED_PIN, LOW);
delay(100);
}
delay(1400);
client.connect(mfamIP, mfamPort);
if (client.connected()) {
lastDataTime = millis();
}
return;
}
while (client.available()) {
buffer[bufferPos] = client.read();
bufferPos++;
if (bufferPos >= PACKET_SIZE) {
parsePacket(buffer);
bufferPos = 0;
lastDataTime = millis();
}
}
// LED patterns
if (sdReady) {
if (millis() - lastDataTime > 3000) {
if (millis() - lastBlinkTime > 125) {
ledState = !ledState;
digitalWrite(LED_PIN, ledState ? HIGH : LOW);
lastBlinkTime = millis();
}
} else {
if (millis() - lastBlinkTime > 1500) {
ledState = !ledState;
digitalWrite(LED_PIN, ledState ? HIGH : LOW);
lastBlinkTime = millis();
}
}
}
// New file every FILE_MINUTES minutes
if (sdReady && logFile && (millis() - fileStartTime > (unsigned long)FILE_MINUTES * 60UL * 1000UL)) {
logFile.close();
createNewFile();
}
}
// ---- GPS READING FROM ADAFRUIT MODULE ON SERIAL1 ----
void readGPS() {
while (Serial1.available()) {
char c = Serial1.read();
if (c == '$') {
gpsBufferPos = 0;
}
if (gpsBufferPos < (int)sizeof(gpsBuffer) - 1) {
gpsBuffer[gpsBufferPos] = c;
gpsBufferPos++;
}
if (c == '\n' || c == '\r') {
gpsBuffer[gpsBufferPos] = '\0';
if (strncmp(gpsBuffer, "$GPRMC", 6) == 0 || strncmp(gpsBuffer, "$GNRMC", 6) == 0) {
// Save full sentence for logging
strncpy(gpsString, gpsBuffer, sizeof(gpsString) - 1);
gpsString[sizeof(gpsString) - 1] = '\0';
// Remove trailing newline/carriage return
int slen = strlen(gpsString);
while (slen > 0 && (gpsString[slen - 1] == '\n' || gpsString[slen - 1] == '\r')) {
gpsString[slen - 1] = '\0';
slen--;
}
parseGPRMC(gpsBuffer);
}
gpsBufferPos = 0;
}
}
}
void parseGPRMC(char* sentence) {
// $GPRMC,HHMMSS.sss,A,lat,N,lon,W,speed,course,DDMMYY,...
char copy[256];
strncpy(copy, sentence, sizeof(copy) - 1);
copy[sizeof(copy) - 1] = '\0';
char* token = strtok(copy, ",");
int field = 0;
while (token != NULL && field < 10) {
switch (field) {
case 1: // Time
if (strlen(token) >= 6) {
snprintf(gpsTime, sizeof(gpsTime), "%c%c:%c%c:%s",
token[0], token[1], token[2], token[3], token + 4);
}
break;
case 2: // Fix status
gpsFix = (token[0] == 'A');
break;
case 9: // Date
if (strlen(token) >= 6) {
snprintf(gpsDate, sizeof(gpsDate), "%c%c/%c%c/%c%c",
token[0], token[1], token[2], token[3], token[4], token[5]);
}
break;
}
token = strtok(NULL, ",");
field++;
}
// Update GPS bits of tsStatus
tsStatus = (tsStatus & 0x0C); // Keep MFAM PPS bits (3,2)
tsStatus |= 0x01; // Bit 0: RMC sentence received
if (gpsFix) {
tsStatus |= 0x02; // Bit 1: GPS fix valid
}
}
// ---- MFAM DATA PARSING ----
int16_t toSigned16(uint16_t val) {
if (val > 32767) return (int16_t)(val - 65536);
return (int16_t)val;
}
void parseAuxChannels(uint8_t* sample, uint16_t frameID) {
uint8_t auxID = (frameID >> 11) & 0x07;
uint16_t aux0 = sample[16] | (sample[17] << 8);
uint16_t aux1 = sample[18] | (sample[19] << 8);
uint16_t aux2 = sample[20] | (sample[21] << 8);
uint16_t aux3 = sample[22] | (sample[23] << 8);
switch (auxID) {
case 1:
compassX = toSigned16(aux0) / 0.01333333;
compassY = toSigned16(aux1) / 0.01333333;
compassZ = toSigned16(aux2) / 0.01333333;
compassT = toSigned16(aux3) / 128.0 + 25.0;
break;
case 2:
gyroX = toSigned16(aux0) / 16.384;
gyroY = toSigned16(aux1) / 16.384;
gyroZ = toSigned16(aux2) / 16.384;
gyroT = toSigned16(aux3) / 512.0 + 23.0;
break;
case 4:
accelX = toSigned16(aux0) / 16384.0;
accelY = toSigned16(aux1) / 16384.0;
accelZ = toSigned16(aux2) / 16384.0;
accelT = toSigned16(aux3) / 512.0 + 23.0;
break;
default:
break;
}
}
void writeSample(unsigned long timestamp, uint16_t fiducial, double mag1, uint16_t mag1s,
double mag2, uint16_t mag2s, uint16_t sysStatus) {
char tsStr[12];
snprintf(tsStr, sizeof(tsStr), "%d%d%d%d%d%d%d%d",
(tsStatus >> 7) & 1, (tsStatus >> 6) & 1, (tsStatus >> 5) & 1, (tsStatus >> 4) & 1,
(tsStatus >> 3) & 1, (tsStatus >> 2) & 1, (tsStatus >> 1) & 1, tsStatus & 1);
char sysHex[8], m1sHex[8], m2sHex[8];
snprintf(sysHex, sizeof(sysHex), "%04X", sysStatus);
snprintf(m1sHex, sizeof(m1sHex), "%04X", mag1s);
snprintf(m2sHex, sizeof(m2sHex), "%04X", mag2s);
char line[512];
snprintf(line, sizeof(line),
"%10.4f,%10.4f,%4d,%s,%s,%s,%10.2f,%10.2f,%10.2f,%5.1f,%8.5f,%8.5f,%8.5f,%5.1f,%8.1f,%8.1f,%8.1f,%5.1f,%s,%s,%s,%s",
mag1, mag2, fiducial, sysHex, m1sHex, m2sHex,
gyroX, gyroY, gyroZ, gyroT,
accelX, accelY, accelZ, accelT,
compassX, compassY, compassZ, compassT,
gpsDate, gpsTime, tsStr, gpsString);
if (sdReady && logFile) {
logFile.println(line);
if (sampleCount % 1000 == 0) {
logFile.flush();
}
}
if (sampleCount % 500 == 0) {
Serial.println(line);
}
}
void parsePacket(uint8_t* pkt) {
// Get PPS bits from MFAM system status
uint16_t firstSysStatus = pkt[HEADER_SIZE + 2] | (pkt[HEADER_SIZE + 3] << 8);
uint8_t mfamPPSbits = (firstSysStatus >> 12) & 0x0C;
tsStatus = (tsStatus & 0x03) | mfamPPSbits;
for (int i = 0; i < NUM_SAMPLES; i++) {
int offset = HEADER_SIZE + (i * SAMPLE_SIZE);
uint16_t frameID = pkt[offset] | (pkt[offset + 1] << 8);
uint16_t fiducial = frameID & 0x07FF;
uint16_t sysStatus = pkt[offset + 2] | (pkt[offset + 3] << 8);
uint32_t mag1raw = pkt[offset + 4] | (pkt[offset + 5] << 8) |
((uint32_t)pkt[offset + 6] << 16) | ((uint32_t)pkt[offset + 7] << 24);
double mag1 = mag1raw * 0.05 / 1000.0;
uint16_t mag1status = pkt[offset + 8] | (pkt[offset + 9] << 8);
uint32_t mag2raw = pkt[offset + 10] | (pkt[offset + 11] << 8) |
((uint32_t)pkt[offset + 12] << 16) | ((uint32_t)pkt[offset + 13] << 24);
double mag2 = mag2raw * 0.05 / 1000.0;
uint16_t mag2status = pkt[offset + 14] | (pkt[offset + 15] << 8);
parseAuxChannels(pkt + offset, frameID);
sampleCount++;
downsampleCounter++;
if (downsampleCounter >= DOWNSAMPLE_FACTOR) {
downsampleCounter = 0;
writeSample(millis(), fiducial, mag1, mag1status, mag2, mag2status, sysStatus);
}
}
}
🧭 How to Import Geophone Elevation Data into Plotrefa
If you have measured relative or absolute geophone elevations, you can incorporate these into your velocity model in Plotrefa to produce more geologically realistic results.
📄 Step 1: Prepare the Elevation File
Create an ASCII text file with two columns:
The left column contains geophone horizontal positions (in meters or feet).
The right column contains the corresponding elevation values.
Example:
0.0 100.0 5.0 101.2 10.0 101.5 ... 100.0 89.0
✅ Tip: While it’s recommended to have an elevation for each geophone, it’s not strictly required. Plotrefa will interpolate missing elevations as needed.
📥 Step 2: Import the Elevation Data
Open Plotrefa.
From the top menu, go to:Velocity model > Import elevation data file
Navigate to your file and double-click it to import.📌 Note: There is no default file extension, so ensure your file is visible in the dialog.
The elevation profile will now display alongside your data.
🎯 Step 3: Interpret Your Data
Once your elevation profile is imported:
Proceed with your velocity modeling or time-term inversion.
The resulting velocity model will be drawn relative to the elevation profile, accounting for topography.
Example Outputs:
Attachment : seismic_velocity_profile.png
The cables between the sensors and the MFAM module are flexible circuit boards, and the length is limited to 20 inches.
It is possible to remove the MFAM module from the Development kit box and then reconnect it using a ribbon cable. That would allow you to extend the MFAM module and sensors away from the Dev Kit box. Our engineers have tested it to 4 meters.
Below are some details about the ribbon cable.
The connector on the MFAM unit is Samtec FSH-110-04-F-DH. Its mating connector is Samtec SFMH-110-02-L-D-WT.
The easiest option for an extender cable between the MFAM and the Dev Kit is a pair of cable assemblies from Samtec www.samtec.com which has male/female mass terminate connectors put onto a ribbon cable. These connectors plug directly into the MFAM I/O connector and also into the Development Kit. We are comfortable with lengths to 10 feet total. The samtec P/N for this cable is: FFMD-10-T-60.00-01-F-N
The ‘60.00’ number specifies the cable length in inches (which equals 5 feet). We have found that there is generally a 2-4 week lead, time since they are made to order and not an off-the-shelf part.
(There is another solution as well if you want to make adapter boards at each end (Dev Kit and MFAM). The exact Samtec mates for the MFAM / Dev Kit connectors are made in PCB mount connectors only, so if you make simple small adapter board to adapt the samtec connector to another connector of your choice. We've done this with ExpressPCB which is fast and inexpensive. A board set from ExpressPCB is about $70 including shipping. Our Engineering Team has a Design and parts list they can send you if you're interested in going this route.)
Page 1 / 3
Next